From 64af75c0a96116f43f689db5a347a5179b236144 Mon Sep 17 00:00:00 2001 From: toom1996 Date: Wed, 2 Sep 2026 21:50:30 +0800 Subject: [PATCH] update --- .workbuddy/memory/2026-09-01.md | 87 +++++++++ .workbuddy/memory/2026-09-02.md | 125 ++++++++++++ .workbuddy/memory/MEMORY.md | 96 ++++------ _tmp_build.log | Bin 2550 -> 4966 bytes _tmp_dbg.mjs | 21 ++ _tmp_verify2.mjs | 26 +++ _tmp_verify_hist.mjs | 60 ++++++ dev.log | Bin 46477 -> 1058 bytes server.err | 9 + src/components/RunwayLooks.astro | 52 ++++- src/components/StreetSnaps.astro | 50 ++++- src/i18n/dictionary.ts | 49 +++++ src/lib/api.ts | 71 ++++++- src/lib/favorites.ts | 192 +++++++++++++++++++ src/lib/history.ts | 148 ++++++++++++++ src/lib/profile.ts | 34 ++++ src/pages/cn/account.astro | 319 ++++++++++++++++++++++++------- src/pages/cn/item/[id].astro | 88 +++++++++ src/pages/cn/login.astro | 86 +++++---- src/pages/en/account.astro | 319 ++++++++++++++++++++++++------- src/pages/en/item/[id].astro | 88 +++++++++ src/pages/en/login.astro | 86 +++++---- src/styles/look-grid.css | 9 + 23 files changed, 1730 insertions(+), 285 deletions(-) create mode 100644 .workbuddy/memory/2026-09-01.md create mode 100644 .workbuddy/memory/2026-09-02.md create mode 100644 _tmp_dbg.mjs create mode 100644 _tmp_verify2.mjs create mode 100644 _tmp_verify_hist.mjs create mode 100644 server.err create mode 100644 src/lib/favorites.ts create mode 100644 src/lib/history.ts create mode 100644 src/lib/profile.ts diff --git a/.workbuddy/memory/2026-09-01.md b/.workbuddy/memory/2026-09-01.md new file mode 100644 index 0000000..03a16aa --- /dev/null +++ b/.workbuddy/memory/2026-09-01.md @@ -0,0 +1,87 @@ +# 2026-09-01 工作日志 + +## 登录页样式丢失(17:30 修复) +- 现象:用户反馈 login 页样式没了。排查发现 `src/pages/{en,cn}/login.astro` 是**裸 `` 片段页**(没有 `/`),仅靠前端 `import '@/styles/global.css'` 引入样式。Astro 在构建时对片段页不会把 import 的 CSS 注入 head,导致构建产物 `dist/.../login/index.html` 完全没有 ``,整页无样式(dev 模式下 Vite HMR 偶尔能补上,故时有时无)。 +- 修复:给两个 login 页补上完整 `(charset/viewport/title)...`,前端 `import '@/styles/global.css` 随即被注入 head;` diff --git a/src/pages/cn/item/[id].astro b/src/pages/cn/item/[id].astro index 6537ca4..1767fe0 100644 --- a/src/pages/cn/item/[id].astro +++ b/src/pages/cn/item/[id].astro @@ -3,6 +3,7 @@ import Layout from "@/layouts/Layout.astro" import Item from "@/components/Item.astro" import StreetSnap from "@/components/StreetSnap.astro" import { getSsrArticle, getSsrStreetSnap } from "@/lib/api" +import { getI18n } from "@/i18n/utils" // 按需 SSR:走秀(runway)与街拍(street snap)详情统一收口到 /item/[id]。 // 对外 id 带类型前缀(r=runway / s=snap,见后端 hashid.EncodeTyped),据此直接查对应表,无歧义、无需回落。 @@ -11,6 +12,8 @@ export const prerender = false const { id } = Astro.params const isSnap = !!id && id[0] === "s" +const { t } = getI18n(Astro) + let article = null let articleErr = null let snap = null @@ -28,8 +31,93 @@ if (isSnap) { article = data.article articleErr = data.error } + +// 供客户端「收藏 / 历史」使用的精简元信息(服务端已拿到,直接透传,避免前端再发请求)。 +const meta = isSnap + ? { id: id ?? "", type: "street", title: snap?.title ?? "", cover: snap?.cover ?? "", brand: "" } + : { id: id ?? "", type: "runway", title: article?.title ?? "", cover: article?.cover ?? "", brand: article?.brand_name ?? "" } +const saveLabel = t("save") +const savedLabel = t("saved") --- {article ? : } + + + +{(article || snap) && ( + +)} + +{/* 注意:不能用 define:vars 传 meta —— 它会把脚本包成内联 IIFE 并把 import 塞进函数体内, + 导致 SyntaxError(import 只能在模块顶层)。故改由 data-* 属性透传,脚本自行读取。 */} + diff --git a/src/pages/cn/login.astro b/src/pages/cn/login.astro index abf4e9b..e4846a8 100644 --- a/src/pages/cn/login.astro +++ b/src/pages/cn/login.astro @@ -23,8 +23,17 @@ const failLabel = t('login failed') const membersLabel = t('members') const backLabel = t('back to site') const homeUrl = href(locale, ROUTES.runwayLooks) +const pageTitle = `${loginLabel} — Portfolio Studio` --- - + + + + + + + {pageTitle} + +
- - + window.location.href = clientHref(loc, ROUTES.account) + } + }, + + submit() { + this.error = "" + this.loading = true + + login({ account: this.account, password: this.password }) + .then(() => { + const params = new URLSearchParams(window.location.search) + const redirect = params.get("redirect") + const loc = this.$el.dataset.locale || "en" + window.location.href = redirect || clientHref(loc, ROUTES.account) + }) + .catch(() => { + this.error = this.$el.dataset.failLabel || "login failed" + }) + .finally(() => { + this.loading = false + }) + }, + })) + }) + + + diff --git a/src/pages/en/account.astro b/src/pages/en/account.astro index 3b8172f..6c4c319 100644 --- a/src/pages/en/account.astro +++ b/src/pages/en/account.astro @@ -1,102 +1,277 @@ --- -import Layout from '@/layouts/Layout.astro' -import { getI18n } from '@/i18n/utils' -import { href, ROUTES } from '@/lib/routes' +import Layout from "@/layouts/Layout.astro" +import { getI18n } from "@/i18n/utils" +import { href, ROUTES } from "@/lib/routes" const { locale, t } = getI18n(Astro) -const titleLabel = t('my account') -const pleaseLabel = t('please log in') -const loginLabel = t('login') -const accountLabel = t('account') -const emailLabel = t('email') -const signOutLabel = t('sign out') -const collectionsLabel = t('my collections') -const historyLabel = t('my history') -const soonLabel = t('coming soon') +const titleLabel = t("my account") +const pleaseLabel = t("please log in") +const loginLabel = t("login") +const historyLabel = t("my history") +const loginUrl = href(locale, ROUTES.login) + "?redirect=" + encodeURIComponent(href(locale, ROUTES.account)) +const archiveUrl = href(locale, ROUTES.runwayLooks) +// 预翻译常量:Alpine 表达式里没有 t()(t 仅 Astro 服务端存在),文案一律走模板插值。 +const removeLabel = t("remove") +const itemsLabel = t("items") +const clearHistoryLabel = t("clear history") --- -
-
- + +
diff --git a/src/pages/en/item/[id].astro b/src/pages/en/item/[id].astro index 6537ca4..1767fe0 100644 --- a/src/pages/en/item/[id].astro +++ b/src/pages/en/item/[id].astro @@ -3,6 +3,7 @@ import Layout from "@/layouts/Layout.astro" import Item from "@/components/Item.astro" import StreetSnap from "@/components/StreetSnap.astro" import { getSsrArticle, getSsrStreetSnap } from "@/lib/api" +import { getI18n } from "@/i18n/utils" // 按需 SSR:走秀(runway)与街拍(street snap)详情统一收口到 /item/[id]。 // 对外 id 带类型前缀(r=runway / s=snap,见后端 hashid.EncodeTyped),据此直接查对应表,无歧义、无需回落。 @@ -11,6 +12,8 @@ export const prerender = false const { id } = Astro.params const isSnap = !!id && id[0] === "s" +const { t } = getI18n(Astro) + let article = null let articleErr = null let snap = null @@ -28,8 +31,93 @@ if (isSnap) { article = data.article articleErr = data.error } + +// 供客户端「收藏 / 历史」使用的精简元信息(服务端已拿到,直接透传,避免前端再发请求)。 +const meta = isSnap + ? { id: id ?? "", type: "street", title: snap?.title ?? "", cover: snap?.cover ?? "", brand: "" } + : { id: id ?? "", type: "runway", title: article?.title ?? "", cover: article?.cover ?? "", brand: article?.brand_name ?? "" } +const saveLabel = t("save") +const savedLabel = t("saved") --- {article ? : } + + + +{(article || snap) && ( + +)} + +{/* 注意:不能用 define:vars 传 meta —— 它会把脚本包成内联 IIFE 并把 import 塞进函数体内, + 导致 SyntaxError(import 只能在模块顶层)。故改由 data-* 属性透传,脚本自行读取。 */} + diff --git a/src/pages/en/login.astro b/src/pages/en/login.astro index abf4e9b..e4846a8 100644 --- a/src/pages/en/login.astro +++ b/src/pages/en/login.astro @@ -23,8 +23,17 @@ const failLabel = t('login failed') const membersLabel = t('members') const backLabel = t('back to site') const homeUrl = href(locale, ROUTES.runwayLooks) +const pageTitle = `${loginLabel} — Portfolio Studio` --- - + + + + + + + {pageTitle} + +
- - + window.location.href = clientHref(loc, ROUTES.account) + } + }, + + submit() { + this.error = "" + this.loading = true + + login({ account: this.account, password: this.password }) + .then(() => { + const params = new URLSearchParams(window.location.search) + const redirect = params.get("redirect") + const loc = this.$el.dataset.locale || "en" + window.location.href = redirect || clientHref(loc, ROUTES.account) + }) + .catch(() => { + this.error = this.$el.dataset.failLabel || "login failed" + }) + .finally(() => { + this.loading = false + }) + }, + })) + }) + + + diff --git a/src/styles/look-grid.css b/src/styles/look-grid.css index b7a5b1a..65a6c0f 100644 --- a/src/styles/look-grid.css +++ b/src/styles/look-grid.css @@ -255,3 +255,12 @@ @keyframes looksProg { 0% { left: -38%; } 100% { left: 100%; } } @keyframes looksShim { 0%, 100% { opacity: .85; } 50% { opacity: .55; } } + +/* ====================== 卡片收藏按钮(图片收藏入口) ====================== */ +/* 白底细边、已收藏时仅实心黑心,尽量不使用黑底白字组件 */ +.showscard-wrap { @apply relative; } +.fav-toggle { + @apply absolute right-2 top-2 z-20 grid h-9 w-9 place-items-center rounded-full border border-black/15 bg-white/85 text-black backdrop-blur-sm transition-transform duration-200 hover:scale-110 active:scale-95; +} +.fav-toggle svg { @apply h-[18px] w-[18px]; fill: none; stroke: currentColor; stroke-width: 1.6; } +.fav-toggle.is-on svg { fill: #000; stroke: #000; }