mirror of
https://github.com/Hmbown/DeepSeek-TUI.git
synced 2026-09-03 06:50:13 +08:00
Three shared components still chose a side of an `{ en, zh }` content pair
with their own `locale === "zh"` comparison, which is exactly what
pickText() was added for in #5338. Ten picks become nine calls — the
nested ternary in StatusBadge collapses into one — and status-badge and
getting-started-steps no longer reference a locale string at all.
pickText(pair, locale) is `locale === "zh" ? pair.zh : pair.en`, so each
substitution is an identity, not an approximation. StatusBadge's `label ?`
becomes `label ??`, equivalent here because LocalizedText is an object and
the parameter is optional.
session-media keeps its `isZh` for four hardcoded strings that need a page
dictionary rather than a pair; those come with the next group.
thinking-trace is deliberately left alone. It exports SCENES, which the
terminal-player client component imports, so adding the dictionary import
there pulls the whole barrel into the browser: the homepage's first-load
JS goes 115 kB to 125 kB. Measured, then confirmed by reverting only that
file and rebuilding back to 115 kB.
Rendered output is unchanged across all 487 built pages, compared on
visible text plus title and meta description against a clean build of the
same base.
Signed-off-by: Lstarsky0 <59827030+Lstarsky0@users.noreply.github.com>
110 lines
4.1 KiB
TypeScript
110 lines
4.1 KiB
TypeScript
/**
|
|
* <SessionMedia> — renders one entry from web/lib/media-manifest.ts.
|
|
*
|
|
* Two states, both honest:
|
|
*
|
|
* pending — a plainly labeled panel: "Recording pending release
|
|
* candidate". No mock terminal, no staged screenshot, no
|
|
* recycled clip. The panel exists so the absence of footage is
|
|
* visible and explained, not hidden.
|
|
*
|
|
* published — a <video> with the declared poster, per-locale WebVTT
|
|
* captions, a transcript link, and a GIF fallback link. The
|
|
* reduced-motion contract is structural (REDUCED_MOTION_POLICY
|
|
* = "static-poster-no-autoplay"): preload="none", no autoPlay,
|
|
* user-initiated playback only. The optional GIF is a link,
|
|
* not an autoplaying reduced-motion substitute.
|
|
*
|
|
* Server component: no client JS, SSG-safe.
|
|
*/
|
|
|
|
import { REDUCED_MOTION_POLICY, type MediaAsset } from "@/lib/media-manifest";
|
|
import { pickText } from "@/lib/i18n/dictionaries";
|
|
import { StatusBadge } from "./status-badge";
|
|
|
|
const MEDIA_PLAN_DOC =
|
|
"https://github.com/Hmbown/CodeWhale/blob/main/docs/releases/v0.9.2-media-plan.md";
|
|
const REPO_BLOB_BASE = "https://github.com/Hmbown/CodeWhale/blob/main";
|
|
|
|
export function SessionMedia({ asset, locale = "en" }: { asset: MediaAsset; locale?: string }) {
|
|
const isZh = locale === "zh";
|
|
|
|
if (asset.status === "pending") {
|
|
return (
|
|
<figure
|
|
className="session-media session-media-pending"
|
|
data-media-id={asset.id}
|
|
data-media-status={asset.status}
|
|
data-reduced-motion-policy={REDUCED_MOTION_POLICY}
|
|
>
|
|
<div className="session-media-stage">
|
|
<StatusBadge kind="pending" locale={locale} label={asset.pendingLabel} />
|
|
<p className="session-media-pending-note">
|
|
{isZh
|
|
? "还没有录像。录好之后会放在这里,附字幕、文字稿和可选的 GIF 下载。"
|
|
: "There is no recording yet. When there is, it goes here with captions, a transcript, and an optional GIF download."}
|
|
</p>
|
|
</div>
|
|
<figcaption className="session-media-caption">
|
|
<strong>{pickText(asset.title, locale)}</strong>
|
|
<span>{pickText(asset.description, locale)}</span>
|
|
<a href={MEDIA_PLAN_DOC} target="_blank" rel="noreferrer">
|
|
{isZh ? "录制计划与验收清单 ↗" : "Recording plan and acceptance checklist ↗"}
|
|
</a>
|
|
</figcaption>
|
|
</figure>
|
|
);
|
|
}
|
|
|
|
// status === "published": manifest tests require every field and verify
|
|
// file presence/byte budgets plus poster dimensions. The human recording
|
|
// checklist remains authoritative for actual video duration/dimensions.
|
|
const poster = asset.poster!;
|
|
const video = asset.video!;
|
|
const captions = asset.captions ?? [];
|
|
|
|
return (
|
|
<figure
|
|
className="session-media"
|
|
data-media-id={asset.id}
|
|
data-media-status={asset.status}
|
|
data-reduced-motion-policy={REDUCED_MOTION_POLICY}
|
|
>
|
|
<video
|
|
controls
|
|
preload="none"
|
|
poster={`/${poster.src}`}
|
|
width={video.width}
|
|
height={video.height}
|
|
aria-label={pickText(poster.alt, locale)}
|
|
>
|
|
<source src={`/${video.src}`} type="video/mp4" />
|
|
{captions.map((track) => (
|
|
<track
|
|
key={track.srclang}
|
|
kind="captions"
|
|
src={`/${track.src}`}
|
|
srcLang={track.srclang}
|
|
label={track.label}
|
|
default={track.srclang === "en"}
|
|
/>
|
|
))}
|
|
</video>
|
|
<figcaption className="session-media-caption">
|
|
<strong>{pickText(asset.title, locale)}</strong>
|
|
<span>{pickText(asset.description, locale)}</span>
|
|
{asset.gifFallback && (
|
|
<a href={`/${asset.gifFallback.src}`}>
|
|
{isZh ? "GIF 下载回退(无视频环境)" : "GIF fallback download (no-video environments)"}
|
|
</a>
|
|
)}
|
|
{asset.transcript && (
|
|
<a href={`${REPO_BLOB_BASE}/${asset.transcript}`} target="_blank" rel="noreferrer">
|
|
{isZh ? "文字稿 ↗" : "Transcript ↗"}
|
|
</a>
|
|
)}
|
|
</figcaption>
|
|
</figure>
|
|
);
|
|
}
|