From 84159db417b467259fc3b9728e10d2e63ba43e85 Mon Sep 17 00:00:00 2001 From: SepComet <202308010230@stu.csust.edu.cn> Date: Sun, 10 May 2026 15:03:48 +0800 Subject: [PATCH] Make project cards easier to scan in dense three-column grids Constraint: Keep projects page in a 3-column grid while reducing line-wrap pressure in card metadata/action areas Rejected: Keeping metadata and actions split into side-by-side columns | caused unstable wrapping and noisy visual rhythm Confidence: high Scope-risk: narrow Directive: Keep project-card internals on project-specific classes and preserve one metadata row per semantic purpose Tested: npm run build; ./scripts/deploy-homepage.sh Not-tested: Manual cross-browser visual checks beyond current deployed environment --- src/components/ProjectCard.astro | 93 +++++++++++++++++--------------- src/pages/projects/index.astro | 13 ++++- src/styles/global.css | 81 ++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 43 deletions(-) diff --git a/src/components/ProjectCard.astro b/src/components/ProjectCard.astro index 3f84283..ac4b880 100644 --- a/src/components/ProjectCard.astro +++ b/src/components/ProjectCard.astro @@ -1,7 +1,6 @@ --- import { site } from '../config'; import type { ProjectDownload } from '../data/loaders'; -import { formatDateTime } from '../utils/datetime'; interface Props { name: string; @@ -30,60 +29,70 @@ const { downloadLink = '', downloads = [], updatedAt = '', - source, + source: _source, } = Astro.props; const fallbackRepoUrl = repo && site.gitea.url ? `${site.gitea.url}/${repo}` : ''; const resolvedRepoUrl = repoUrl || fallbackRepoUrl; const visibleDownloads = downloads.filter((item) => item.name || item.url); -const sourceLabels = { - seed: '本地种子', - gitea: 'Gitea', - 'gitea+seafile': 'Gitea + Seafile', -} as const; -const updatedLabel = formatDateTime(updatedAt); +const updatedLabel = formatProjectUpdateLabel(updatedAt); + +function formatProjectUpdateLabel(value: string) { + if (!value) { + return ''; + } + + const parsed = Date.parse(value); + if (Number.isNaN(parsed)) { + return ''; + } + + const date = new Date(parsed); + const now = new Date(); + + if (date.getFullYear() < now.getFullYear()) { + return '很久之前'; + } + + return `${date.getMonth() + 1}/${date.getDate()}`; +} --- -
+
{`${name} + {featured ? : null}
-
- {repo} - {featured ? featured : null} - {source ? {sourceLabels[source]} : null} - {updatedAt ? 更新于 {updatedLabel} : null} +
+

{name}

+

{description}

-

{name}

-

{description}

+
+
+ {tags.map((tag) => {tag})} +
-
- {tags.map((tag) => {tag})} -
+
diff --git a/src/pages/projects/index.astro b/src/pages/projects/index.astro index af7dbca..8fccd63 100644 --- a/src/pages/projects/index.astro +++ b/src/pages/projects/index.astro @@ -7,6 +7,17 @@ import Layout from '../../layouts/Layout.astro'; import { getLatestDate } from '../../utils/datetime'; const projects = await loadProjects(); +const sortedProjects = [...projects].sort((a, b) => { + if (a.featured !== b.featured) { + return Number(b.featured) - Number(a.featured); + } + + const leftUpdated = Date.parse(a.updated_at || ''); + const rightUpdated = Date.parse(b.updated_at || ''); + const leftTime = Number.isNaN(leftUpdated) ? 0 : leftUpdated; + const rightTime = Number.isNaN(rightUpdated) ? 0 : rightUpdated; + return rightTime - leftTime; +}); const projectSources = [...new Set(projects.map((project) => project.source).filter(Boolean))]; const projectsUpdatedAt = getLatestDate(projects.map((project) => project.updated_at).filter(Boolean)); --- @@ -33,7 +44,7 @@ const projectsUpdatedAt = getLatestDate(projects.map((project) => project.update
{ - projects.map((project) => ( + sortedProjects.map((project) => (