update
This commit is contained in:
@ -134,7 +134,7 @@ const displayTitle = (snap?.title || "").replace(/\t/g, " · ")
|
||||
}
|
||||
|
||||
{/* 登录后追加的额外图片:extraImages 由客户端 loadAuthedState() 在已登录时填充,未登录为空不渲染 */}
|
||||
<template x-for="(im, i) in extraImages" :key="im.url">
|
||||
<template x-for="(im, i) in extraImages" :key="im.url" >
|
||||
<figure
|
||||
:data-image-index="5 + i"
|
||||
:data-image-url="im.url"
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
---
|
||||
import Layout from "@/layouts/Layout.astro"
|
||||
import RunwayLookCard from "@/components/RunwayLookCard.astro"
|
||||
import { getSsrArticle } from "@/lib/ssr"
|
||||
import { getI18n } from "@/lib/i18n"
|
||||
import { config } from "@/lib/config"
|
||||
|
||||
// 走秀(runway)详情视图,en/cn 两页共用(语言由 Astro.currentLocale 运行时决定)。
|
||||
// 注意:export const prerender = false 必须留在页面文件(Astro 只读页面模块的该导出),
|
||||
// 故 id 由页面从 Astro.params 取出后作为 prop 透传进来。
|
||||
interface Props {
|
||||
id?: string
|
||||
}
|
||||
|
||||
const { id } = Astro.props
|
||||
const { locale, t } = getI18n(Astro)
|
||||
|
||||
let article = null
|
||||
let articleErr = null
|
||||
let preview = false
|
||||
let imageTotal = 0
|
||||
|
||||
const data = await getSsrArticle(id, Astro.currentLocale)
|
||||
article = "article" in data ? data.article : null
|
||||
articleErr = data.error
|
||||
preview = data.preview ?? false
|
||||
imageTotal = data.imageTotal ?? 0
|
||||
|
||||
// 供客户端「收藏 / 历史」使用的精简元信息(服务端已拿到,直接透传,避免前端再发请求)。
|
||||
// id 优先取接口回传的规范 id(带类型前缀):用户若通过旧的无前缀链接进来,也保证写入规范形式。
|
||||
const canonId = String(article?.id ?? id ?? "")
|
||||
const meta = { id: canonId, type: "runway", title: article?.title ?? "", cover: article?.cover ?? "", brand: article?.brand_name ?? "" }
|
||||
|
||||
// 详情页动态 TDK:标题用「品牌 + 系列」,描述/关键词按语言生成(避免嵌套反引号,用拼接)。
|
||||
const SITE_NAME = config.siteName ?? "Xisoa"
|
||||
const runwayName = article ? (article.brand_name + " " + article.title).trim() : ""
|
||||
const detailTitle = runwayName || SITE_NAME
|
||||
const detailDesc = locale === "cn"
|
||||
? `${detailTitle} 走秀造型共 ${imageTotal} 张,查看细节图与系列信息,收录于 ${SITE_NAME} 时尚档案。`
|
||||
: `${detailTitle} — ${imageTotal} runway looks with detail images and collection info, in the ${SITE_NAME} fashion archive.`
|
||||
const detailKeywords = `${article?.brand_name || ""},runway,runway looks,fashion week,${SITE_NAME}`.replace(/^,/, "")
|
||||
|
||||
const saveLabel = t("save")
|
||||
const savedLabel = t("saved")
|
||||
---
|
||||
|
||||
<Layout title={detailTitle} description={detailDesc} keywords={detailKeywords}>
|
||||
<RunwayLookCard article={article} error={articleErr} preview={preview} imageTotal={imageTotal} />
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
#fav-fab.is-active .fav-heart { fill: currentColor; }
|
||||
</style>
|
||||
|
||||
{article && (
|
||||
<button login-required id="fav-fab" type="button"
|
||||
data-id={meta.id}
|
||||
data-type={meta.type}
|
||||
data-title={meta.title}
|
||||
data-cover={meta.cover}
|
||||
data-brand={meta.brand}
|
||||
data-save-label={saveLabel}
|
||||
data-saved-label={savedLabel}
|
||||
class="fixed bottom-6 right-6 z-50 inline-flex items-center gap-2 rounded-full border border-black/40 bg-white/90 px-5 py-3 text-[11px] font-bold uppercase tracking-[0.2em] text-black shadow-sm backdrop-blur transition-colors hover:bg-black hover:text-white">
|
||||
<svg class="fav-heart h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21C12 21 4 14.5 4 8.8C4 6.1 6.1 4 8.7 4C10.3 4 11.5 4.8 12 6C12.5 4.8 13.7 4 15.3 4C17.9 4 20 6.1 20 8.8C20 14.5 12 21 12 21Z"/></svg>
|
||||
<span id="fav-label">{saveLabel}</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<script>
|
||||
import { initDetailFav } from "@/lib/detailFav"
|
||||
initDetailFav()
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
---
|
||||
import Layout from "@/layouts/Layout.astro"
|
||||
import StreetSnapCard from "@/components/StreetSnapCard.astro"
|
||||
import { getSsrStreetSnap } from "@/lib/ssr"
|
||||
import { getI18n } from "@/lib/i18n"
|
||||
import { config } from "@/lib/config"
|
||||
|
||||
// 街拍(street snap)详情视图,en/cn 两页共用(语言由 Astro.currentLocale 运行时决定)。
|
||||
// 注意:export const prerender = false 必须留在页面文件(Astro 只读页面模块的该导出),
|
||||
// 故 id 由页面从 Astro.params 取出后作为 prop 透传进来。
|
||||
interface Props {
|
||||
id?: string
|
||||
}
|
||||
|
||||
const { id } = Astro.props
|
||||
const { locale, t } = getI18n(Astro)
|
||||
|
||||
let snap = null
|
||||
let snapErr = null
|
||||
let preview = false
|
||||
let imageTotal = 0
|
||||
|
||||
const data = await getSsrStreetSnap(id, Astro.currentLocale)
|
||||
snap = "snap" in data ? data.snap : null
|
||||
snapErr = data.error
|
||||
preview = data.preview ?? false
|
||||
imageTotal = data.imageTotal ?? 0
|
||||
|
||||
// 供客户端「收藏 / 历史」使用的精简元信息(服务端已拿到,直接透传,避免前端再发请求)。
|
||||
const canonId = String(snap?.id ?? id ?? "")
|
||||
const meta = { id: canonId, type: "street", title: snap?.title ?? "", cover: snap?.cover ?? "", brand: "" }
|
||||
|
||||
// 详情页动态 TDK:标题用街拍标题,描述/关键词按语言生成(避免嵌套反引号,用拼接)。
|
||||
const SITE_NAME = config.siteName ?? "Xisoa"
|
||||
const baseName = snap?.title || ""
|
||||
const detailTitle = baseName || SITE_NAME
|
||||
const detailDesc = locale === "cn"
|
||||
? `${detailTitle} —— 来自全球街头的时尚抓拍,收录于 ${SITE_NAME} 时尚档案。`
|
||||
: `${detailTitle} — street style snaps from cities around the world, in the ${SITE_NAME} fashion archive.`
|
||||
const detailKeywords = `${snap?.title || ""},street style,street snaps,fashion,${SITE_NAME}`.replace(/^,/, "")
|
||||
|
||||
const saveLabel = t("save")
|
||||
const savedLabel = t("saved")
|
||||
---
|
||||
|
||||
<Layout title={detailTitle} description={detailDesc} keywords={detailKeywords}>
|
||||
<StreetSnapCard snap={snap} error={snapErr} preview={preview} imageTotal={imageTotal} />
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
#fav-fab.is-active .fav-heart { fill: currentColor; }
|
||||
</style>
|
||||
|
||||
{snap && (
|
||||
<button login-required id="fav-fab" type="button"
|
||||
data-id={meta.id}
|
||||
data-type={meta.type}
|
||||
data-title={meta.title}
|
||||
data-cover={meta.cover}
|
||||
data-brand={meta.brand}
|
||||
data-save-label={saveLabel}
|
||||
data-saved-label={savedLabel}
|
||||
class="fixed bottom-6 right-6 z-50 inline-flex items-center gap-2 rounded-full border border-black/40 bg-white/90 px-5 py-3 text-[11px] font-bold uppercase tracking-[0.2em] text-black shadow-sm backdrop-blur transition-colors hover:bg-black hover:text-white">
|
||||
<svg class="fav-heart h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21C12 21 4 14.5 4 8.8C4 6.1 6.1 4 8.7 4C10.3 4 11.5 4.8 12 6C12.5 4.8 13.7 4 15.3 4C17.9 4 20 6.1 20 8.8C20 14.5 12 21 12 21Z"/></svg>
|
||||
<span id="fav-label">{saveLabel}</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<script>
|
||||
import { initDetailFav } from "@/lib/detailFav"
|
||||
initDetailFav()
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user