@ -3,10 +3,9 @@ import Layout from "@/layouts/Layout.astro"
|
||||
import Breadcrumb from "@/components/Breadcrumb.astro"
|
||||
import { getBrands, getYears, type BrandEntry } from "@/lib/api"
|
||||
import { getI18n } from '@/i18n/utils'
|
||||
import { getRelativeLocaleUrl } from 'astro:i18n'
|
||||
|
||||
|
||||
const { locale, t } = getI18n(Astro)
|
||||
const { locale, t, getRelativeLocaleUrl } = getI18n(Astro)
|
||||
|
||||
let sidebarBrands: BrandEntry[] = []
|
||||
let yearChips: number[] = []
|
||||
@ -32,13 +31,8 @@ if (!yearChips.length) yearChips = yearSeed
|
||||
<!-- 顶部:极简眉头 -->
|
||||
<header class="showshead">
|
||||
<div>
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ label: t('Home'), href: '/' },
|
||||
{ label: 'Runway Archive', href: '/shows' },
|
||||
]}
|
||||
>
|
||||
<span slot="current" x-text="crumbYear">All shows</span>
|
||||
<Breadcrumb>
|
||||
<span slot="current">{t('Runway looks')}</span>
|
||||
</Breadcrumb>
|
||||
<h1 class="showsh1">All Shows</h1>
|
||||
</div>
|
||||
@ -194,32 +188,26 @@ if (!yearChips.length) yearChips = yearSeed
|
||||
|
||||
<!-- Card List -->
|
||||
<template x-for="it in items" :key="it.id">
|
||||
<a class="showscard" :href="`${locale}/runway-looks/${it.id}`" :aria-label="`${it.brand_name} ${it.title}`">
|
||||
<a class="showscard" :href="`/${locale}/runway-looks/${it.id}`" :aria-label="`${it.brand_name} ${it.title}`">
|
||||
<div class="showscard-left">
|
||||
<div class="showscard-img" :class="{ 'is-loaded': it._imgLoaded }">
|
||||
<span class="showsspin" aria-hidden="true" x-html="SPIN_SVG"></span>
|
||||
<img :src="toAbsUrl(it.cover)" :alt="it.title" loading="lazy" @load="it._imgLoaded = true" @error="it._imgLoaded = true" :class="{ 'is-loaded': it._imgLoaded }" />
|
||||
<!-- <span class="showsbadge" x-show="isNewAdded(it.published_at)">New</span> -->
|
||||
</div>
|
||||
<div class="showscard-img" :class="{ 'is-loaded': it._imgLoaded }">
|
||||
<span class="showsspin" aria-hidden="true" x-html="SPIN_SVG"></span>
|
||||
<img :src="toAbsUrl(it.cover)" :alt="it.title" loading="lazy" @load="it._imgLoaded = true" @error="it._imgLoaded = true" :class="{ 'is-loaded': it._imgLoaded }" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="showscard-right">
|
||||
<div class="showscard-info">
|
||||
<h3 class="showscard-title" x-text="it.title"></h3>
|
||||
<p class="showscard-meta" x-text="`${it.season_code || it.year || ''} · ${ctLabel(it.collection_type)} · ${it.brand_name}`"></p>
|
||||
<div class="showscard-meta-foot">
|
||||
<span class="showscard-meta-line"><span x-html="ICON_USER"></span><span x-text="it.brand_name"></span></span>
|
||||
<span class="showscard-meta-line"><span x-html="ICON_DATE"></span><span x-text="fmtDate(it.published_at)"></span></span>
|
||||
<div class="showscard-info">
|
||||
<h3 class="showscard-title" x-text="`${it.brand_name} / ${it.title}`"></h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="showscard-strip">
|
||||
<template x-for="(slot, idx) in getCardSlots(it)" :key="idx">
|
||||
<div class="showscard-thumb" :class="{ 'placeholder': !slot.src, 'is-loaded': slot.loaded }">
|
||||
<span class="showsspin" aria-hidden="true" x-html="SPIN_SVG" x-show="slot.src"></span>
|
||||
<img x-show="slot.src" :src="toAbsUrl(slot.src)" alt="" loading="lazy" @load="slot.loaded = true" @error="slot.loaded = true" :class="{ 'is-loaded': slot.loaded }" />
|
||||
<span class="showscard-thumb-more" x-show="slot.isLast && slot.moreLabel" x-text="slot.moreLabel"></span>
|
||||
<div class="showscard-strip">
|
||||
<template x-for="(slot, idx) in getCardSlots(it)" :key="idx">
|
||||
<div class="showscard-thumb" :class="{ 'placeholder': !slot.src, 'is-loaded': slot.loaded }">
|
||||
<span class="showsspin" aria-hidden="true" x-html="SPIN_SVG" x-show="slot.src"></span>
|
||||
<img x-show="slot.src" :src="toAbsUrl(slot.src)" alt="" loading="lazy" @load="slot.loaded = true" @error="slot.loaded = true" :class="{ 'is-loaded': slot.loaded }" />
|
||||
<span class="showscard-thumb-more" x-show="slot.isLast && slot.moreLabel" x-text="slot.moreLabel"></span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
@ -643,15 +631,6 @@ if (!yearChips.length) yearChips = yearSeed
|
||||
return this.allBrands.length > 60
|
||||
},
|
||||
|
||||
// 面包屑末级:未选年份时显示默认的「2026 Edition」,选中后显示对应年份
|
||||
get crumbYear() {
|
||||
if (this.selectedYear.length) {
|
||||
const ys = [...this.selectedYear].sort()
|
||||
return ys.length === 1 ? `${ys[0]} Edition` : `${ys.join(" / ")}`
|
||||
}
|
||||
return "2026 Edition"
|
||||
},
|
||||
|
||||
// 骨架屏数量与首屏 data 数量一致,保证「加载中」与「数据完成」两阶段的网格高度相同,消除抖动
|
||||
get skeletonCount() {
|
||||
return this.size
|
||||
@ -833,12 +812,6 @@ if (!yearChips.length) yearChips = yearSeed
|
||||
|
||||
// 辅助辅助工具函数
|
||||
toAbsUrl(url: string) { return toAbs(url) },
|
||||
isNewAdded(pubAt?: number) { return Date.now() / 1000 - Number(pubAt || 0) < 60 * 60 * 24 * 14 },
|
||||
fmtDate(ts: number) {
|
||||
if (!ts) return ""
|
||||
const d = new Date(ts * 1000)
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`
|
||||
},
|
||||
ctLabel(ct?: string) {
|
||||
const map: Record<string, string> = { rtw: "Ready-to-Wear", menswear: "Menswear", couture: "Couture", resort: "Resort", pre_fall: "Pre-Fall" }
|
||||
return ct && map[ct] ? map[ct] : (ct || "")
|
||||
|
||||
Reference in New Issue
Block a user