diff --git a/CHANGELOG.md b/CHANGELOG.md index 920dff6..d722d8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed + +- **SEO-Friendly Project and Event Filters**: Replace client-side-only filters with server-rendered, shareable query-string URLs for project category/language and event type; add explicit empty states, request-time event status calculation, and page-specific bilingual meta descriptions across list, policy, and blog pages + ## [0.4.0] - 2026-07-17 ### Added diff --git a/src/layouts/MarkdownLayout.astro b/src/layouts/MarkdownLayout.astro index 49ba81c..2cbcdb6 100644 --- a/src/layouts/MarkdownLayout.astro +++ b/src/layouts/MarkdownLayout.astro @@ -7,6 +7,7 @@ export interface Props { frontmatter: { title?: string; titleEn?: string; + description?: string; }; } @@ -14,6 +15,7 @@ const { frontmatter } = Astro.props; const metadata: MetaData = { title: frontmatter?.title, + description: frontmatter?.description, }; --- diff --git a/src/pages/[...blog]/[...page].astro b/src/pages/[...blog]/[...page].astro index e449371..d381667 100644 --- a/src/pages/[...blog]/[...page].astro +++ b/src/pages/[...blog]/[...page].astro @@ -23,6 +23,8 @@ const currentPage = page.currentPage ?? 1; const metadata = { title: `Blog${currentPage > 1 ? ` — Page ${currentPage}` : ''}`, + description: + '讯飞开源博客 — Articles from the iFLYTEK open source community: technical deep dives, project updates, release notes and community news.', robots: { index: blogListRobots?.index && currentPage === 1, follow: blogListRobots?.follow, diff --git a/src/pages/[...blog]/[category]/[...page].astro b/src/pages/[...blog]/[category]/[...page].astro index 4d3bc52..bb7dfc9 100644 --- a/src/pages/[...blog]/[category]/[...page].astro +++ b/src/pages/[...blog]/[category]/[...page].astro @@ -18,13 +18,6 @@ const { page, category } = Astro.props as Props; const currentPage = page.currentPage ?? 1; -const metadata = { - title: `Category '${category.title}' ${currentPage > 1 ? ` — Page ${currentPage}` : ''}`, - robots: { - index: blogCategoryRobots?.index, - follow: blogCategoryRobots?.follow, - }, -}; const categoryMeta: Record = { tech: { titleZh: '技术博客', @@ -48,6 +41,15 @@ const cat = categoryMeta[category.slug] || { description: `${category.title} 相关文章`, descriptionEn: `${category.title} related posts`, }; + +const metadata = { + title: `Category '${category.title}' ${currentPage > 1 ? ` — Page ${currentPage}` : ''}`, + description: `${cat.description} — ${cat.descriptionEn}`, + robots: { + index: blogCategoryRobots?.index, + follow: blogCategoryRobots?.follow, + }, +}; --- diff --git a/src/pages/[...blog]/[tag]/[...page].astro b/src/pages/[...blog]/[tag]/[...page].astro index 86a767b..2b61d7f 100644 --- a/src/pages/[...blog]/[tag]/[...page].astro +++ b/src/pages/[...blog]/[tag]/[...page].astro @@ -21,6 +21,7 @@ const currentPage = page.currentPage ?? 1; const metadata = { title: `Posts by tag '${tag.title}'${currentPage > 1 ? ` — Page ${currentPage} ` : ''}`, + description: `标签 '${tag.title}' 下的文章 — Posts tagged '${tag.title}' from the iFLYTEK open source blog.`, robots: { index: blogTagRobots?.index, follow: blogTagRobots?.follow, diff --git a/src/pages/adopters.astro b/src/pages/adopters.astro index 335a0e6..0a16c46 100644 --- a/src/pages/adopters.astro +++ b/src/pages/adopters.astro @@ -4,6 +4,8 @@ import { getCollection } from 'astro:content'; const metadata = { title: 'Adopters', + description: + '谁在使用讯飞开源项目 — Companies and organizations adopting iFLYTEK open source projects in production, and how to add your organization to the list.', }; const adopters = await getCollection('adopter'); diff --git a/src/pages/cla.astro b/src/pages/cla.astro index 390f346..d5ac734 100644 --- a/src/pages/cla.astro +++ b/src/pages/cla.astro @@ -2,7 +2,14 @@ import MarkdownLayout from '~/layouts/MarkdownLayout.astro'; --- - +

diff --git a/src/pages/contribute.astro b/src/pages/contribute.astro index 566f026..eb18291 100644 --- a/src/pages/contribute.astro +++ b/src/pages/contribute.astro @@ -9,6 +9,8 @@ export const prerender = false; const metadata = { title: 'Contribute', + description: + '参与贡献科大讯飞开源社区 — How to contribute to iFLYTEK open source: find good first issues, submit pull requests, sign the CLA and join the community.', }; // Load projects count diff --git a/src/pages/events.astro b/src/pages/events.astro index 97df25e..f878cfb 100644 --- a/src/pages/events.astro +++ b/src/pages/events.astro @@ -1,21 +1,26 @@ --- import Layout from '~/layouts/PageLayout.astro'; import { getCollection } from 'astro:content'; -import { events } from '~/data/events'; +import { events as eventsData } from '~/data/events'; + +export const prerender = false; const metadata = { title: 'Events', + description: + '科大讯飞开源社区活动 — iFLYTEK open source community events: meetups, hackathons, workshops and conferences, with the latest community news.', }; // Auto-determine status based on event date vs current date const now = new Date(); const todayStr = now.toISOString().split('T')[0]; -events.forEach((event) => { - event.status = event.date === todayStr ? 'ongoing' : event.date > todayStr ? 'upcoming' : 'past'; -}); - -// Sort by date descending -events.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); +const events = eventsData + .map((event) => ({ + ...event, + status: (event.date === todayStr ? 'ongoing' : event.date > todayStr ? 'upcoming' : 'past') as + 'ongoing' | 'upcoming' | 'past', + })) + .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); const typeLabels: Record = { conference: 'Conference', @@ -36,6 +41,15 @@ const typeColors: Record = { // Get unique types for filter const eventTypes = [...new Set(events.map((e) => e.type))]; +// URL-driven filter state so filtered views are crawlable and shareable +const typeParam = Astro.url.searchParams.get('type') || 'all'; +const activeType = (eventTypes as string[]).includes(typeParam) ? typeParam : 'all'; +const filteredEvents = activeType === 'all' ? events : events.filter((e) => e.type === activeType); + +const activeChipClass = 'bg-primary-600 text-white'; +const inactiveChipClass = + 'bg-gray-100 text-gray-700 transition-colors hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700'; + // Blog posts for news section const posts = await getCollection('post'); const newsPosts = posts @@ -75,22 +89,28 @@ const newsPosts = posts

- + { eventTypes.map((type) => ( - + )) }
@@ -98,8 +118,8 @@ const newsPosts = posts
{ - events.map((event, index) => ( -
+ filteredEvents.map((event, index) => ( +
{/* Timeline line & dot */}
@@ -114,7 +134,7 @@ const newsPosts = posts ]} />
- {index < events.length - 1 &&
} + {index < filteredEvents.length - 1 &&
}
{/* Event Card */} @@ -251,44 +271,4 @@ const newsPosts = posts ) } - - - diff --git a/src/pages/landscape.astro b/src/pages/landscape.astro index b545eaf..6503e35 100644 --- a/src/pages/landscape.astro +++ b/src/pages/landscape.astro @@ -4,6 +4,8 @@ import { getProjectsWithStats } from '~/utils/project-stats'; const metadata = { title: 'Landscape', + description: + '讯飞开源全景图 — The iFLYTEK open source landscape: an at-a-glance map of all projects organized by category, from AI Agent platforms to developer tools.', }; const projects = await getProjectsWithStats(); diff --git a/src/pages/projects.astro b/src/pages/projects.astro index 2f6470f..e02b416 100644 --- a/src/pages/projects.astro +++ b/src/pages/projects.astro @@ -7,6 +7,8 @@ export const prerender = false; const metadata = { title: 'Projects', + description: + '探索科大讯飞开源项目生态 — Explore iFLYTEK open source projects covering AI Agent, agentic workflow, developer tools and more, filterable by category and language.', }; const projects = await getProjectsWithStats(); @@ -34,6 +36,31 @@ const categoryLabels: Record = { // Total stats const totalStars = sortedProjects.reduce((sum, p) => sum + (p.data.stars || 0), 0); const totalForks = sortedProjects.reduce((sum, p) => sum + (p.data.forks || 0), 0); + +// URL-driven filter state so filtered views are crawlable and shareable +const { searchParams } = Astro.url; +const categoryParam = searchParams.get('category') || 'all'; +const languageParam = searchParams.get('language') || 'all'; +const activeCategory = categories.includes(categoryParam) ? categoryParam : 'all'; +const activeLanguage = languages.includes(languageParam) ? languageParam : 'all'; + +const filteredProjects = sortedProjects.filter( + (p) => + (activeCategory === 'all' || p.data.category === activeCategory) && + (activeLanguage === 'all' || (p.data.languages || []).includes(activeLanguage)) +); + +const buildFilterUrl = (category: string, language: string) => { + const params = new URLSearchParams(); + if (category !== 'all') params.set('category', category); + if (language !== 'all') params.set('language', language); + const query = params.toString(); + return query ? `/projects?${query}` : '/projects'; +}; + +const activeChipClass = 'bg-primary-600 text-white'; +const inactiveChipClass = + 'bg-gray-100 text-gray-700 transition-colors hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700'; --- @@ -85,26 +112,32 @@ const totalForks = sortedProjects.reduce((sum, p) => sum + (p.data.forks || 0),
- + { categories.map((cat) => ( - + )) }
@@ -113,21 +146,27 @@ const totalForks = sortedProjects.reduce((sum, p) => sum + (p.data.forks || 0), { languages.length > 0 && (
- + {languages.map((lang) => ( - + ))}
) @@ -136,12 +175,8 @@ const totalForks = sortedProjects.reduce((sum, p) => sum + (p.data.forks || 0),
{ - sortedProjects.map((project) => ( -
+ filteredProjects.map((project) => ( +
sum + (p.data.forks || 0), }
+ { + filteredProjects.length === 0 && ( +
+

+ 没有符合当前筛选条件的项目 +

+ + + 清除筛选 + + +
+ ) + } +
- - - diff --git a/src/pages/security.astro b/src/pages/security.astro index 6a4d643..eeff4f5 100644 --- a/src/pages/security.astro +++ b/src/pages/security.astro @@ -2,7 +2,14 @@ import MarkdownLayout from '~/layouts/MarkdownLayout.astro'; --- - +

如果你在本项目中发现安全问题,请遵循以下指南。

diff --git a/src/pages/values.astro b/src/pages/values.astro index 7151f27..d5ae409 100644 --- a/src/pages/values.astro +++ b/src/pages/values.astro @@ -2,7 +2,14 @@ import MarkdownLayout from '~/layouts/MarkdownLayout.astro'; --- - +

科大讯飞开源社区建立在我们共同遵循的价值观之上,这些价值观指引着我们的互动、决策与成长。