diff --git a/next-env.d.ts b/next-env.d.ts index ce4e94a..6936789 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,7 +1,7 @@ /// /// -import "./.next/types/routes.d.ts"; -import "./.next/types/root-params.d.ts"; +import "./.next-dev/dev/types/routes.d.ts"; +import "./.next-dev/dev/types/root-params.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/scripts/playback-smoke.ts b/scripts/playback-smoke.ts index b29d3eb..78f80ce 100644 --- a/scripts/playback-smoke.ts +++ b/scripts/playback-smoke.ts @@ -415,10 +415,9 @@ try { name + " action must be removed", ); assert.equal(await page.locator(".hk-playback-comments, .hk-playback-composer").count(), 0); - assert.deepEqual( - await page.locator(".hk-playback-dual > *").evaluateAll((nodes) => nodes.map((node) => node.className)), - ["hk-playback-like", "hk-playback-hot"], - ); + // Recommendations stay in the main column; the trending list sits in the right sidebar. + assert.equal(await page.locator(".hk-playback-body__main > .hk-playback-like").count(), 1); + assert.equal(await page.locator(".hk-playback-body__aside > .hk-playback-hot").count(), 1); assert.match( (await page.locator(".hk-playback-like").textContent()) || "", /猜你喜欢测试/, diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 404edbe..e27789a 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -35,6 +35,7 @@ import "@/styles/pages/mobile-search.css"; import "@/styles/pages/site-navigation.css"; import "@/styles/pages/home-road.css"; import "@/styles/pages/playback.css"; +import "@/styles/overrides/drama-tiles.css"; import "@/styles/overrides/pwa-safe-area.css"; import type { ReactNode } from "react"; import { PwaProvider } from "@/components/pwa/PwaProvider"; diff --git a/src/components/catalog/Cards.tsx b/src/components/catalog/Cards.tsx index 3eeda02..5426461 100644 --- a/src/components/catalog/Cards.tsx +++ b/src/components/catalog/Cards.tsx @@ -9,7 +9,6 @@ import { cardTags, categoryURL, displayName, - episodeChip, episodeLabel, episodeStatus, externalProps, @@ -49,25 +48,50 @@ export function CardTags({ ); } -/** Episode chip precedes the theme tags, matching the reference card meta row. */ +/** Genre line under the title: slash-separated theme tags (episode info lives on the cover). */ export function DramaCardMeta({ item }: { item: CatalogRecord }) { - const chip = episodeChip(item); + const tags = cardTags(item); + if (!tags.length) return null; return ( -

- {chip && ( - - {chip} - - )} - - - +

+ {tags.map((tag, index) => ( + + {index > 0 && ( + + )} + {tag.URL ? ( + + {tag.Name} + + ) : ( + {tag.Name} + )} + + ))}

); } +/** Cover corner badge: episode count first, then serial/finished state. */ +export function DramaCardEpisodes({ item }: { item: CatalogRecord }) { + const total = num(item, "TotalEpisode"), + serial = num(item, "UpdateStatus") === 1; + if (!total && !serial) return null; + return ( + + {total > 0 && ( + <> + {total} 集 ·{" "} + + )} + {serial ? "连更" : "完结"} + + ); +} export function DramaCard({ item, recent = false, @@ -94,6 +118,7 @@ export function DramaCard({ ) : str(item, "Anchor") === "原创" ? ( 原创 ) : null} +

{name} @@ -278,6 +303,7 @@ export function PlayRecommendationCard({ item }: { item: CatalogRecord }) { href={href} src={str(item, "Cover")} > +

{displayName(item)} diff --git a/src/features/playback/DramaWatchPage.tsx b/src/features/playback/DramaWatchPage.tsx index 97df4c1..39bf51c 100644 --- a/src/features/playback/DramaWatchPage.tsx +++ b/src/features/playback/DramaWatchPage.tsx @@ -25,7 +25,14 @@ import { import { coinGate } from "./model"; import { PlaybackStage } from "./PlaybackStage"; import { AppOnlyDialog } from "./AppOnlyDialog"; -import { GuessLike, HotList, PlaybackShare, Related, Synopsis } from "./Shared"; +import { + GuessLike, + HotList, + PlaybackShare, + Related, + SectionEyebrow, + Synopsis, +} from "./Shared"; export function DramaWatchPage({ data }: { data: Data }) { const p = data.playlet || {}, id = num(p, "ID"), @@ -109,7 +116,7 @@ export function DramaWatchPage({ data }: { data: Data }) { - 短剧 + 短剧库 @@ -128,178 +135,216 @@ export function DramaWatchPage({ data }: { data: Data }) { onPlaying={onPlaying} autoPlay={autoPlay} /> -
-
-
-

{name}

- {get(p, "IsFeatured") ? ( - 爆剧 - ) : anchor === "原创" ? ( - 原创 - ) : null} -
-
- {total > 0 && 全 {total} 集} - {status} - {year && {year}} - 1080P -
- {["hk-desktop-only", "hk-mobile-only"].map((device) => ( -

- {anchor && !["原创", "已注销"].includes(anchor) && ( - 主演 {anchor} - )} - {!!themes.length && ( - - {device === "hk-desktop-only" ? "题材 " : ""} - {themes.map((tag, index) => ( - - {index ? " " : ""} - {tag.URL ? ( - - {tag.Name} - - ) : ( - {tag.Name} - )} - +

+
+
+
+

+ 正在播放 + 第 {episode} 集{total > 0 ? ` / 共 ${total} 集` : ""} +

+
+

{name}

+ {get(p, "IsFeatured") ? ( + 爆剧 + ) : anchor === "原创" ? ( + 原创 + ) : null} +
+
+ {total > 0 && ( +
+
集数
+
{total} 集
+
+ )} +
+
状态
+
{status}
+
+ {year && ( +
+
上线
+
{year} 年
+
+ )} +
+
画质
+
1080P
+
+ {anchor && !["原创", "已注销"].includes(anchor) && ( +
+
主演
+
{anchor}
+
+ )} + {!!themes.length && ( +
+
题材
+
+ {themes.map((tag, index) => ( + + {index ? " / " : ""} + {tag.URL ? ( + + {tag.Name} + + ) : ( + {tag.Name} + )} + + ))} +
+
+ )} +
+
热度
+
{formatLikeCount(get(p, "HeatValue"))}
+
+
+
收藏
+
{formatLikeCount(get(p, "CountCollect"))}
+
+
+
+
+ + + + + 反馈 + +
+ +
+
+
+
+
+ EPISODES +

全集列表

+
+ + 共 {total || chapters.length} 集 {status} + + +
+ +
+
+ {(descending ? [...chapters].reverse() : chapters).map( + (chapter, index) => { + const chid = num(chapter, "ID"), + ep = + num(chapter, "CurrentEpisode") || + (descending ? chapters.length - index : index + 1); + return ( + + + {String(ep).padStart(2, "0")} + + ); + }, + )} + {!chapters.length && ( + + + 01 )} - - 热度 {formatLikeCount(get(p, "HeatValue"))} +
+
+ +