From e24bfe164de2fe72ae251127f392991c577e8e77 Mon Sep 17 00:00:00 2001 From: toom1996 Date: Sat, 29 Aug 2026 20:17:13 +0800 Subject: [PATCH] update --- .workbuddy/memory/2026-08-29.md | 32 ++ .workbuddy/memory/MEMORY.md | 8 +- _tmp_build.log | 41 ++- src/assets/astro.svg | 1 - src/assets/background.svg | 1 - src/components/BrandModal.astro | 160 +++++++++ src/components/ComingSoon.astro | 2 +- src/components/LanguageDetector.astro | 36 -- src/components/RunwayLooks.astro | 416 +--------------------- src/components/StreetSnaps.astro | 203 +---------- src/components/Welcome.astro | 210 ----------- src/components/pages/About.astro | 6 - src/components/pages/AuthForm.astro | 262 -------------- src/components/pages/Contact.astro | 6 - src/components/pages/LatestProjects.astro | 6 - src/components/pages/Login.astro | 6 - src/components/pages/Portfolio.astro | 6 - src/components/pages/Register.astro | 6 - src/components/pages/article.astro | 285 --------------- src/layouts/Layout.astro | 3 - src/lib/looks-grid.ts | 59 +++ src/lib/routes.ts | 7 +- src/pages/cn/article.astro | 15 - src/pages/cn/item/[id].astro | 18 +- src/pages/cn/street-snaps/[id].astro | 15 - src/pages/en/article.astro | 15 - src/pages/en/item/[id].astro | 18 +- src/pages/en/street-snaps/[id].astro | 15 - src/styles/look-grid.css | 257 +++++++++++++ 29 files changed, 598 insertions(+), 1517 deletions(-) create mode 100644 .workbuddy/memory/2026-08-29.md delete mode 100644 src/assets/astro.svg delete mode 100644 src/assets/background.svg create mode 100644 src/components/BrandModal.astro delete mode 100644 src/components/LanguageDetector.astro delete mode 100644 src/components/Welcome.astro delete mode 100644 src/components/pages/About.astro delete mode 100644 src/components/pages/AuthForm.astro delete mode 100644 src/components/pages/Contact.astro delete mode 100644 src/components/pages/LatestProjects.astro delete mode 100644 src/components/pages/Login.astro delete mode 100644 src/components/pages/Portfolio.astro delete mode 100644 src/components/pages/Register.astro delete mode 100644 src/components/pages/article.astro create mode 100644 src/lib/looks-grid.ts delete mode 100644 src/pages/cn/article.astro delete mode 100644 src/pages/cn/street-snaps/[id].astro delete mode 100644 src/pages/en/article.astro delete mode 100644 src/pages/en/street-snaps/[id].astro create mode 100644 src/styles/look-grid.css diff --git a/.workbuddy/memory/2026-08-29.md b/.workbuddy/memory/2026-08-29.md new file mode 100644 index 0000000..ece4702 --- /dev/null +++ b/.workbuddy/memory/2026-08-29.md @@ -0,0 +1,32 @@ +# 2026-08-29 工作日志 + +## 前端列表页重构 + 详情路由统一(17:00–17:45) + +用户要求:① 所有文章详情集成到 `/item`(含 street 详情);② 之前分析过的列表页抽象(共享 CSS / 共享 Alpine 工具 / 品牌弹窗组件)一并落地。 + +### 现状核对(重要:大部分已提前落地) +- 排查发现 RunwayLooks.astro 与 StreetSnaps.astro 的 ` \ No newline at end of file diff --git a/src/components/RunwayLooks.astro b/src/components/RunwayLooks.astro index 2614d68..faca286 100644 --- a/src/components/RunwayLooks.astro +++ b/src/components/RunwayLooks.astro @@ -1,7 +1,9 @@ --- import Breadcrumb from "@/components/Breadcrumb.astro" +import BrandModal from "@/components/BrandModal.astro" import { getSsgHotBrands } from "@/lib/api" import { getI18n } from '@/i18n/utils' +import "@/styles/look-grid.css" const { locale, t, getRelativeLocaleUrl } = getI18n(Astro) @@ -247,392 +249,22 @@ const seasonOptions: { value: string; label: string }[] = [ - -
-
-
-
-

全部品牌

- -
- -
- - -
-
-
热门推荐
-
-
    - -
  • 未找到匹配的品牌
  • -
-
-
- - -
-
-
+ + + + - - - diff --git a/src/components/pages/Contact.astro b/src/components/pages/Contact.astro deleted file mode 100644 index 157bcd6..0000000 --- a/src/components/pages/Contact.astro +++ /dev/null @@ -1,6 +0,0 @@ ---- -// 页面主体(与语言无关的内容),由根页面与 [locale] 页面共用 -import ComingSoon from "@/components/ComingSoon.astro" ---- - - diff --git a/src/components/pages/LatestProjects.astro b/src/components/pages/LatestProjects.astro deleted file mode 100644 index e4bb351..0000000 --- a/src/components/pages/LatestProjects.astro +++ /dev/null @@ -1,6 +0,0 @@ ---- -// 页面主体(与语言无关的内容),由根页面与 [locale] 页面共用 -import ComingSoon from "@/components/ComingSoon.astro" ---- - - diff --git a/src/components/pages/Login.astro b/src/components/pages/Login.astro deleted file mode 100644 index b6df1c1..0000000 --- a/src/components/pages/Login.astro +++ /dev/null @@ -1,6 +0,0 @@ ---- -// 页面主体(与语言无关的内容),由根页面与 [locale] 页面共用 -import ComingSoon from "@/components/ComingSoon.astro" ---- - - diff --git a/src/components/pages/Portfolio.astro b/src/components/pages/Portfolio.astro deleted file mode 100644 index f03a589..0000000 --- a/src/components/pages/Portfolio.astro +++ /dev/null @@ -1,6 +0,0 @@ ---- -// 页面主体(与语言无关的内容),由根页面与 [locale] 页面共用 -import ComingSoon from "@/components/ComingSoon.astro" ---- - - diff --git a/src/components/pages/Register.astro b/src/components/pages/Register.astro deleted file mode 100644 index db1283b..0000000 --- a/src/components/pages/Register.astro +++ /dev/null @@ -1,6 +0,0 @@ ---- -// 页面主体(与语言无关的内容),由根页面与 [locale] 页面共用 -import ComingSoon from "@/components/ComingSoon.astro" ---- - - diff --git a/src/components/pages/article.astro b/src/components/pages/article.astro deleted file mode 100644 index 28994ec..0000000 --- a/src/components/pages/article.astro +++ /dev/null @@ -1,285 +0,0 @@ ---- -import type { RawArticle } from "@/lib/api" -import Breadcrumb from "@/components/Breadcrumb.astro" -import { ssrBase } from "@/lib/api" - -interface Props { - article: RawArticle | null - locale?: "en" | "cn" - error?: "missing" | "failed" | null -} -const { article, locale = "en", error = null } = Astro.props - -// 把相对图片地址补全为绝对地址(服务端完成,避免浏览器再拼;base 由 ssr.ts 统一解析) -const full = (u: string): string => - !u ? "" : /^https?:\/\//i.test(u) ? u : ssrBase().replace(/\/$/, "") + u - -// 图片数组:服务端预处理为灯箱可用的 {id,url,name} -const images = (article?.images ?? []).map((im) => ({ - id: im.id, - url: full(im.image || ""), - name: im.name || "", -})) - -// 正文段落(如有) -const descParas = (article?.description || "") - .split(/\n\n+/) - .map((s) => s.trim()) - .filter(Boolean) - -// 文案(按语言切换) -const L = { - en: { - back: "← Back to Index", - source: "Source ↗", - runway: "Runway", - notFound: "Article not found", - missing: "No article ID specified", - failed: "Failed to load article. Please refresh or try later.", - }, - cn: { - back: "← 返回首页", - source: "来源 ↗", - runway: "秀场", - notFound: "未找到该文章", - missing: "未指定文章 ID", - failed: "加载文章失败,请刷新或稍后再试", - }, -} -const lbl = L[locale === "cn" ? "cn" : "en"] -const backLabel = lbl.back.replace("← ", "") -// 面包屑:首页 → 走秀档案(/shows) → 品牌筛选(带 brand_id) → 当前文章(复用项目 Breadcrumb 组件) -const homeHref = locale === "cn" ? "/cn" : "/en/" -const archiveHref = locale === "cn" ? "/cn/shows" : "/en/shows" -const crumbs: { label: string; href: string }[] = [ - { label: "Runway Looks", href: archiveHref }, -] -if (article?.brand_id) { - crumbs.push({ - label: article.brand_name || "Brand", - href: `${archiveHref}?brand_id=${article.brand_id}`, - }) -} ---- - - -
- - {article ? ( -
- - - {article.title} - - - - -

{article.title}

- - - {images.length > 0 && ( -
-
- {images.map((im, i) => ( -
- {im.name} - {im.name &&
{im.name}
} -
- ))} -
-
- )} - - - {descParas.length > 0 && ( -
- {descParas.map((p) =>

{p}

)} -
- )} - -
- ) : ( -
-

{error === "missing" ? lbl.missing : lbl.failed}

- ← {backLabel} -
- )} - - -
- -
- - - - - -
- -
- -
- - - - - - - - - - -
- -
-
- - -
- - -
- 点击图片放大 · 上下滚动查看 · Esc 关闭 -
-
- -
- - - - - diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 06d7821..5a77e7b 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -7,8 +7,6 @@ import { setApiLocale } from '@/lib/api' import { i18n } from 'astro:config/client'; import { toCodes } from 'astro:i18n'; -import LanguageDetector from '@/components/LanguageDetector.astro' - const { title } = Astro.props as { title?: string } const siteTitle = title ? `${title} — Portfolio Studio` : "Portfolio Studio" @@ -50,7 +48,6 @@ const headers = { - diff --git a/src/lib/looks-grid.ts b/src/lib/looks-grid.ts new file mode 100644 index 0000000..09871a3 --- /dev/null +++ b/src/lib/looks-grid.ts @@ -0,0 +1,59 @@ +/** + * 走秀 / 街拍 列表页共享的 Alpine 工具(从 RunwayLooks.astro / StreetSnaps.astro 抽出)。 + * 仅承载两个模块同构、且与各自筛选项无关的逻辑:加载转圈 SVG、卡片缩略图槽位、分页页码计算。 + * 页面特有逻辑(品牌弹窗、各筛选维度、取数 API)仍保留在各组件内。 + */ + +export const SPIN_SVG = + `` + +export interface CardSlot { + src: string + loaded: boolean + isLast?: boolean + moreLabel?: string +} + +/** + * 卡片底部缩略图条带:固定 count 个槽位,缺图留空(前端用 .placeholder 占位)。 + * @param images 图片数组;runway 为 string[](gallery),street 为 { image, name }[](images)。 + * @param opts.moreLabel 当图片多于 count 时,在最后一个槽位上叠加 "+N" 文案的回调。 + */ +export function makeCardSlots( + images: any[], + count = 5, + opts?: { moreLabel?: (extra: number) => string }, +): CardSlot[] { + const list = images || [] + const slots: CardSlot[] = [] + for (let i = 0; i < count; i++) { + const im = list[i] + let src = "" + if (im) src = typeof im === "string" ? im : im.image || im.src || "" + const slot: CardSlot = { src, loaded: false } + if (opts?.moreLabel && i === count - 1 && list.length > count) { + slot.isLast = true + slot.moreLabel = opts.moreLabel(list.length - count) + } + slots.push(slot) + } + return slots +} + +/** + * 分页页码:总数 <=7 全展示;否则围绕当前页展示 [1, ..., cur-1..cur+1, ..., total]。 + */ +export function buildPageList(total: number, cur: number): (number | "...")[] { + if (total <= 7) return Array.from({ length: total }, (_: any, i: number) => i + 1) + const pages: (number | "...")[] = [1] + const start = Math.max(2, cur - 1) + const end = Math.min(total - 1, cur + 1) + if (start > 2) pages.push("...") + for (let i = start; i <= end; i++) pages.push(i) + if (end < total - 1) pages.push("...") + pages.push(total) + return pages +} diff --git a/src/lib/routes.ts b/src/lib/routes.ts index 07f676b..dbbd259 100644 --- a/src/lib/routes.ts +++ b/src/lib/routes.ts @@ -19,11 +19,10 @@ export const ROUTES = { runwayLooks: '/runway-looks', // 街拍 streetSnaps: '/street-snaps', - // 动态路由(工厂函数) + // 动态路由(工厂函数)。所有详情(走秀 lookbook / 街拍)统一收口到 /item/[id], + // 由 src/pages/{locale}/item/[id].astro 按 article→street 顺序回落渲染。 item: (id: string | number) => `/item/${id}`, - article: (id: string | number) => `/article?id=${id}`, - streetSnap: (id: string | number) => `/street-snaps/${id}`, - // runwayLooksDetail: (id: string | number) => `/runway-looks/${id}`, + streetSnap: (id: string | number) => `/item/${id}`, } as const; /** 服务端:生成带 locale 前缀的完整 URL(依赖 astro:i18n,遵循 astro.config)。 */ diff --git a/src/pages/cn/article.astro b/src/pages/cn/article.astro deleted file mode 100644 index db7c7fd..0000000 --- a/src/pages/cn/article.astro +++ /dev/null @@ -1,15 +0,0 @@ ---- -import Layout from "@/layouts/Layout.astro" -import Article from "@/components/pages/article.astro" -import { getSsrArticle } from "@/lib/api" - -// 按需 SSR:服务端按 ?id= 取数并渲染(保留既有 /en/article?id= 链接,无需改动其他页面) -export const prerender = false - -const id = Astro.url.searchParams.get("id") -const { article, error } = await getSsrArticle(id, Astro.currentLocale) ---- - - -
- diff --git a/src/pages/cn/item/[id].astro b/src/pages/cn/item/[id].astro index 44139a6..fd4c8a5 100644 --- a/src/pages/cn/item/[id].astro +++ b/src/pages/cn/item/[id].astro @@ -1,15 +1,25 @@ --- import Layout from "@/layouts/Layout.astro" import Item from "@/components/Item.astro" -import { getSsrArticle } from "@/lib/api" +import StreetSnap from "@/components/StreetSnap.astro" +import { getSsrArticle, getSsrStreetSnap } from "@/lib/api" -// 按需 SSR:服务端按 ?id= 取数并渲染(保留既有 /en/items/:id 链接,无需改动其他页面) +// 按需 SSR:走秀详情与街拍详情统一收口到 /item/[id]。 +// 先按 article 取数(runway lookbook);取不到再回落 street snap,实现「所有详情进 /item」。 export const prerender = false const { id } = Astro.params -const { article, error } = await getSsrArticle(id, Astro.currentLocale) +const { article, error: articleErr } = await getSsrArticle(id, Astro.currentLocale) + +let snap = null +let snapErr: "missing" | "failed" | null = null +if (!article) { + const res = await getSsrStreetSnap(id, Astro.currentLocale) + snap = res.snap + snapErr = res.error +} --- - + {article ? : } diff --git a/src/pages/cn/street-snaps/[id].astro b/src/pages/cn/street-snaps/[id].astro deleted file mode 100644 index 00792fd..0000000 --- a/src/pages/cn/street-snaps/[id].astro +++ /dev/null @@ -1,15 +0,0 @@ ---- -import Layout from "@/layouts/Layout.astro" -import StreetSnap from "@/components/StreetSnap.astro" -import { getSsrStreetSnap } from "@/lib/api" - -// 按需 SSR:服务端按 :id 取数并渲染(保留 /cn/street-snaps/:id 链接) -export const prerender = false - -const { id } = Astro.params -const { snap, error } = await getSsrStreetSnap(id, Astro.currentLocale) ---- - - - - diff --git a/src/pages/en/article.astro b/src/pages/en/article.astro deleted file mode 100644 index db7c7fd..0000000 --- a/src/pages/en/article.astro +++ /dev/null @@ -1,15 +0,0 @@ ---- -import Layout from "@/layouts/Layout.astro" -import Article from "@/components/pages/article.astro" -import { getSsrArticle } from "@/lib/api" - -// 按需 SSR:服务端按 ?id= 取数并渲染(保留既有 /en/article?id= 链接,无需改动其他页面) -export const prerender = false - -const id = Astro.url.searchParams.get("id") -const { article, error } = await getSsrArticle(id, Astro.currentLocale) ---- - - -
- diff --git a/src/pages/en/item/[id].astro b/src/pages/en/item/[id].astro index 44139a6..fd4c8a5 100644 --- a/src/pages/en/item/[id].astro +++ b/src/pages/en/item/[id].astro @@ -1,15 +1,25 @@ --- import Layout from "@/layouts/Layout.astro" import Item from "@/components/Item.astro" -import { getSsrArticle } from "@/lib/api" +import StreetSnap from "@/components/StreetSnap.astro" +import { getSsrArticle, getSsrStreetSnap } from "@/lib/api" -// 按需 SSR:服务端按 ?id= 取数并渲染(保留既有 /en/items/:id 链接,无需改动其他页面) +// 按需 SSR:走秀详情与街拍详情统一收口到 /item/[id]。 +// 先按 article 取数(runway lookbook);取不到再回落 street snap,实现「所有详情进 /item」。 export const prerender = false const { id } = Astro.params -const { article, error } = await getSsrArticle(id, Astro.currentLocale) +const { article, error: articleErr } = await getSsrArticle(id, Astro.currentLocale) + +let snap = null +let snapErr: "missing" | "failed" | null = null +if (!article) { + const res = await getSsrStreetSnap(id, Astro.currentLocale) + snap = res.snap + snapErr = res.error +} --- - + {article ? : } diff --git a/src/pages/en/street-snaps/[id].astro b/src/pages/en/street-snaps/[id].astro deleted file mode 100644 index ba87883..0000000 --- a/src/pages/en/street-snaps/[id].astro +++ /dev/null @@ -1,15 +0,0 @@ ---- -import Layout from "@/layouts/Layout.astro" -import StreetSnap from "@/components/StreetSnap.astro" -import { getSsrStreetSnap } from "@/lib/api" - -// 按需 SSR:服务端按 :id 取数并渲染(保留 /en/street-snaps/:id 链接) -export const prerender = false - -const { id } = Astro.params -const { snap, error } = await getSsrStreetSnap(id, Astro.currentLocale) ---- - - - - diff --git a/src/styles/look-grid.css b/src/styles/look-grid.css new file mode 100644 index 0000000..b7a5b1a --- /dev/null +++ b/src/styles/look-grid.css @@ -0,0 +1,257 @@ +/* 走秀 / 街拍 列表页共享样式(从 RunwayLooks.astro / StreetSnaps.astro 抽出)。 + 两模块 UI 同构:左封面 + 右标题 + 底部 5 缩略图条带 + 侧栏筛选 + 分页 + 骨架屏。 + 类名保留各模块原前缀(.shows* / .snaps*),仅把加载动画 keyframes 统一为 looksProg/looksShim。 + 由两个列表组件在前端 frontmatter `import "@/styles/look-grid.css"` 引入,本地