diff --git a/frontend/src/components/seo/SharePanel.astro b/frontend/src/components/seo/SharePanel.astro index 4fa8382..e1975d2 100644 --- a/frontend/src/components/seo/SharePanel.astro +++ b/frontend/src/components/seo/SharePanel.astro @@ -17,6 +17,7 @@ interface Props { description?: string; stats?: ShareStat[]; wechatShareQrEnabled?: boolean; + variant?: 'default' | 'compact'; } const { locale, t } = getI18n(Astro); @@ -33,7 +34,9 @@ const { : '复制链接、摘要或二维码,方便换设备继续看,也方便直接发给别人。', stats = [], wechatShareQrEnabled = false, + variant = 'default', } = Astro.props as Props; +const isCompact = variant === 'compact'; const visibleBadge = badge; const visibleTitle = title; @@ -136,10 +139,13 @@ if (wechatShareQrEnabled) { ---
-
+
@@ -149,13 +155,17 @@ if (wechatShareQrEnabled) {
-

{visibleTitle}

-

{visibleDescription}

+

+ {visibleTitle} +

+

+ {visibleDescription} +

{stats.length > 0 ? ( -
+
{stats.slice(0, 4).map((item) => (
{item.label}
@@ -166,9 +176,14 @@ if (wechatShareQrEnabled) { ) : null}
-
+
{copy.summaryTitle}
-

{safeSummary}

+

+ {safeSummary} +

@@ -217,7 +232,7 @@ if (wechatShareQrEnabled) {

{isEnglish ? 'Share channels' : '分享渠道'}

-

{visibleDescription}

+ {!isCompact &&

{visibleDescription}

}
({ const initialPopularCount = popularRangeCards.filter( ({ rangeKey, post }) => rangeKey === activeContentRange.key && matchesSelectedFilters(post), ).length; +const initialPopularVisibleKeys = new Set( + popularRangeCards + .filter(({ rangeKey, post }) => rangeKey === activeContentRange.key && matchesSelectedFilters(post)) + .sort((left, right) => { + const scoreDiff = right.item.pageViews - left.item.pageViews; + if (scoreDiff !== 0) return scoreDiff; + return right.item.readCompletes - left.item.readCompletes; + }) + .slice(0, popularPreviewLimit) + .map(({ rangeKey, post }) => `${rangeKey}:${post.slug}`), +); +const sidebarFriendLinks = friendLinks.slice(0, 3); const buildHomeUrl = ({ type = selectedType, tag = selectedTag, @@ -210,11 +222,6 @@ const postsPrompt = hasActiveFilters ? t('home.promptPostsFiltered', { count: previewCount, filters: activeFilterLabels.join(' · ') }) : t('home.promptPostsDefault', { count: previewCount }); const popularPrompt = t('home.promptPopularRange', { label: activeContentRange.label }); -const popularSortOptions = [ - { id: 'views', label: t('home.sortByViews'), icon: 'fa-eye' }, - { id: 'completes', label: t('home.sortByCompletes'), icon: 'fa-check-double' }, - { id: 'depth', label: t('home.sortByDepth'), icon: 'fa-chart-line' }, -]; const navLinks = [ { icon: 'fa-file-code', text: t('nav.articles'), href: '/articles' }, { icon: 'fa-folder', text: t('nav.categories'), href: '/categories' }, @@ -249,11 +256,34 @@ const homeShareCopy = isEnglish description: 'Use the homepage as the canonical top-level entry for people and AI search to branch into articles, taxonomies, reviews, and profile context.', } - : { + : { badge: '首页', title: '分享首页', description: '把首页发给别人,能快速看到文章、分类、评测和个人介绍等主要内容。', }; +const homeSidebarCopy = isEnglish + ? { + quickLinks: 'Quick links', + quickLinksDesc: 'Jump to the main sections of the site.', + popularTitle: 'Hot now', + popularDesc: 'Track the most-read content in the selected window.', + friendsTitle: 'Friend links', + friendsDesc: 'A few recommended sites from the blogroll.', + statsTitle: 'Site stats', + statsDesc: 'A compact snapshot of current site scale.', + aiBriefTitle: 'AI site brief', + } + : { + quickLinks: '快速入口', + quickLinksDesc: '把常用入口收进侧栏,首页阅读流更清爽。', + popularTitle: '最近热门', + popularDesc: '按当前时间窗口查看最受关注的内容。', + friendsTitle: '友情链接', + friendsDesc: '先看几个常访问的站点入口。', + statsTitle: '站点概览', + statsDesc: '快速看一下当前站点规模与内容状态。', + aiBriefTitle: '站点摘要', + }; const homeBriefHighlights = buildDiscoveryHighlights([ siteSettings.siteDescription, siteSettings.heroSubtitle, @@ -287,7 +317,7 @@ const homeFaqJsonLd = buildFaqJsonLd(homeFaqs); jsonLd={[...homeJsonLd, homeFaqJsonLd].filter(Boolean)} > - {apiError && ( @@ -364,397 +361,431 @@ const homeFaqJsonLd = buildFaqJsonLd(homeFaqs);
)} -
- -
-
-
- - - home filters - -
-

{t('common.browsePosts')}

-

- {t('common.categoriesCount', { count: categories.length })} · {t('common.tagsCount', { count: tags.length })} · {t('common.resultsCount', { count: filteredPostsCount })} -

-
-
- - -
- -
- {postTypeFilters.map(filter => ( - - - {filter.name} - - ))} -
- -
- - item.id === selectedType)?.icon || 'fa-stream'} text-[10px]`}> - {postTypeFilters.find((item) => item.id === selectedType)?.name || selectedType} - - - - {selectedCategory} - - - - {selectedTag} - -
- -
-
-
-

{t('nav.categories')}

- {categories.length} -
-
- {categories.map(category => ( - -
- -
-
-

- {category.name} -

- - {category.count ?? 0} - -
-
- ))} -
-
- -
-
-

{t('nav.tags')}

- {tags.length} -
-
- {tagEntries.map((tag) => ( - - # - {tag.name} - {tag.count} - - ))} -
-
-
-
-
- - {pinnedPost && ( -
- -
-
-
- {t('home.pinned')} - - {pinnedPost.type === 'article' ? t('common.article') : t('common.tweet')} - - - {pinnedPost.title} - -
-

{pinnedPost.date} | {t('common.readTime')}: {formatReadTime(locale, pinnedPost.readTime, t)}

-

{pinnedPost.description}

- -
-
-
- )} - -
- -
- {allPosts.length > 0 ? ( -
- {allPosts.map((post) => { - const matchesCurrentFilter = matchesSelectedFilters(post); - const filteredIndex = matchesCurrentFilter - ? allPosts.filter(matchesSelectedFilters).findIndex((item) => item.slug === post.slug) - : -1; - const isVisible = matchesCurrentFilter && filteredIndex < previewLimit; - - return ( -
tag.trim().toLowerCase()).join('|')} - data-home-pinned={post.pinned ? 'true' : 'false'} - data-home-slug={post.slug} - class:list={[!isVisible && 'hidden']} - > - +
+
+
+ +
+
+
+ + + home filters + +
+

{t('common.browsePosts')}

+

+ {t('common.categoriesCount', { count: categories.length })} · {t('common.tagsCount', { count: tags.length })} · {t('common.resultsCount', { count: filteredPostsCount })} +

- ); - })} +
+ + +
+ +
+ {postTypeFilters.map(filter => ( + + + {filter.name} + + ))} +
+ +
+ + item.id === selectedType)?.icon || 'fa-stream'} text-[10px]`}> + {postTypeFilters.find((item) => item.id === selectedType)?.name || selectedType} + + + + {selectedCategory} + + + + {selectedTag} + +
+ +
+
+
+

{t('nav.categories')}

+ {categories.length} +
+
+ {categories.map(category => ( + +
+ +
+
+

+ {category.name} +

+ + {category.count ?? 0} + +
+
+ ))} +
+
+ +
+
+

{t('nav.tags')}

+ {tags.length} +
+
+ {tagEntries.map((tag) => ( + + # + {tag.name} + {tag.count} + + ))} +
+
+
- ) : ( -
-

{t('articlesPage.emptyTitle')}

-

{t('articlesPage.emptyDescription')}

- + + {pinnedPost && ( +
+ +
+
+
+ {t('home.pinned')} + + {pinnedPost.type === 'article' ? t('common.article') : t('common.tweet')} + + + {pinnedPost.title} + +
+

{pinnedPost.date} | {t('common.readTime')}: {formatReadTime(locale, pinnedPost.readTime, t)}

+

{pinnedPost.description}

+ +
)} - {allPosts.length > 0 && ( -
0 && 'hidden']}> -

{t('articlesPage.emptyTitle')}

-

{t('articlesPage.emptyDescription')}

-
- - - {t('common.clearFilters')} - - - - {t('common.viewAllArticles')} - + +
+ +
+ {allPosts.length > 0 ? ( +
+ {allPosts.map((post) => { + const matchesCurrentFilter = matchesSelectedFilters(post); + const filteredIndex = matchesCurrentFilter + ? allPosts.filter(matchesSelectedFilters).findIndex((item) => item.slug === post.slug) + : -1; + const isVisible = matchesCurrentFilter && filteredIndex < previewLimit; + + return ( +
tag.trim().toLowerCase()).join('|')} + data-home-pinned={post.pinned ? 'true' : 'false'} + data-home-slug={post.slug} + class:list={[!isVisible && 'hidden']} + > + +
+ ); + })} +
+ ) : ( +
+

{t('articlesPage.emptyTitle')}

+

{t('articlesPage.emptyDescription')}

+ +
+ )} + {allPosts.length > 0 && ( +
0 && 'hidden']}> +

{t('articlesPage.emptyTitle')}

+

{t('articlesPage.emptyDescription')}

+ +
+ )} +
+
- )} -
-
-
- -
- -
- -
- {friendLinks.map(friend => ( - - ))} -
-
- -
-
- -
+
@@ -775,6 +806,21 @@ const homeFaqJsonLd = buildFaqJsonLd(homeFaqs);
+ +
+ +
+
+ +
+
@@ -783,6 +829,7 @@ const homeFaqJsonLd = buildFaqJsonLd(homeFaqs); is:inline define:vars={{ previewLimit, + popularPreviewLimit, categoryAccentMap, tagAccentMap, contentRangesPayload: contentRanges.map((range) => ({ @@ -1097,7 +1144,7 @@ const homeFaqJsonLd = buildFaqJsonLd(homeFaqs); }); const sortedPopular = sortPopularCards(filteredPopular); popularCards.forEach((card) => card.classList.add('hidden')); - sortedPopular.forEach((card) => { + sortedPopular.slice(0, popularPreviewLimit).forEach((card) => { card.classList.remove('hidden'); popularList?.appendChild(card); });