Files
ilaandClaude Opus 4.8 39713eb8ac design: 效果稿改为清淡简洁风格,T-200 完成
- play.html / list.html:从深色重金属改为浅暖纸白 + 墨色 + 单一柔和赭石强调,
  去掉颗粒/暗角/发光,UI 改用 Public Sans / Noto Sans SC;补齐焦点态、
  cursor、44px 触控、对比度、prefers-reduced-motion、aria-label
- README:设计语言更新为「清淡简洁 · Swiss/Minimal」
- 06-tasks:T-200 标记 DONE

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 17:21:14 +08:00

153 lines
7.5 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>课程列表 · 走遍美国精听</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600&family=Public+Sans:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{
--paper:#f8f6f1; --surface:#ffffff;
--ink:#2a2724; --ink-soft:#56514a; --muted:#938b7e; --faint:#c2bbae;
--hair:#e9e3d8; --hair-soft:#f0ebe1;
--accent:#a4662b; --accent-2:#c0833f; --accent-soft:#f1e8d9;
--serif:"Newsreader",Georgia,serif;
--sans:"Public Sans",system-ui,sans-serif;
--han:"Noto Sans SC",sans-serif;
}
*{margin:0;padding:0;box-sizing:border-box}
body{
font-family:var(--sans); color:var(--ink); background:var(--paper);
display:flex; justify-content:center; min-height:100vh; -webkit-font-smoothing:antialiased;
}
.phone{width:100%;max-width:440px;min-height:100vh;border-left:1px solid var(--hair);border-right:1px solid var(--hair);padding-bottom:30px;background:var(--paper)}
:focus-visible{outline:2px solid var(--accent); outline-offset:3px; border-radius:8px}
/* header */
.head{padding:32px 24px 16px}
.brand{display:flex;align-items:baseline;justify-content:space-between}
.brand h1{font-family:var(--han);font-size:24px;font-weight:500;letter-spacing:.03em}
.brand .en{font-family:var(--serif);font-style:italic;font-size:13px;color:var(--accent);letter-spacing:.01em}
.sub{font-size:11px;color:var(--muted);letter-spacing:.14em;text-transform:uppercase;margin-top:6px}
/* continue hero */
.hero{
margin:18px 20px 4px;padding:20px;border-radius:16px;position:relative;
background:var(--surface);border:1px solid var(--hair);
}
.hero .lab{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);font-weight:600}
.hero .ti{font-family:var(--serif);font-size:22px;font-weight:600;margin-top:7px;color:var(--ink)}
.hero .cn{font-family:var(--han);font-size:12.5px;color:var(--muted);margin-top:2px}
.hero .row{display:flex;align-items:center;gap:14px;margin-top:18px}
.progress{flex:1;height:6px;border-radius:6px;background:var(--hair);overflow:hidden}
.progress i{display:block;height:100%;width:38%;border-radius:6px;background:var(--accent)}
.resume{flex:none;display:flex;align-items:center;gap:6px;background:var(--accent);color:#fff;
font-weight:600;font-size:13px;border:none;border-radius:30px;padding:10px 18px;cursor:pointer;
min-height:44px;transition:.2s}
.resume:hover{background:var(--accent-2)}
/* section label */
.seclab{display:flex;align-items:center;gap:12px;padding:24px 24px 6px;color:var(--muted)}
.seclab span{font-size:11px;letter-spacing:.14em;text-transform:uppercase}
.seclab .ln{flex:1;height:1px;background:var(--hair)}
/* episode list */
.list{padding:4px 14px}
.ep{display:flex;gap:14px;align-items:center;padding:15px 12px;border-radius:12px;cursor:pointer;
transition:background .2s;position:relative}
.ep:hover{background:var(--surface)}
.ep + .ep{border-top:1px solid var(--hair-soft)}
.num{font-family:var(--serif);font-size:19px;font-style:italic;color:var(--faint);width:30px;flex:none;text-align:center}
.ep.cur .num{color:var(--accent)}
.body{flex:1;min-width:0}
.body .ti{font-family:var(--serif);font-size:18px;font-weight:500;line-height:1.25;color:var(--ink)}
.body .cn{font-family:var(--han);font-size:11.5px;color:var(--muted);margin-top:2px}
.acts{display:flex;gap:6px;margin-top:10px}
.chip{font-size:10px;letter-spacing:.04em;color:var(--ink-soft);border:1px solid var(--hair);
border-radius:6px;padding:3px 8px;display:flex;align-items:center;gap:5px;background:var(--surface)}
.chip.done{color:var(--accent);border-color:rgba(164,102,43,.35);background:var(--accent-soft)}
.chip.done::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--accent)}
.chip.noaudio{color:var(--faint);border-style:dashed;background:transparent}
.ring{flex:none;width:34px;height:34px}
.ring svg{transform:rotate(-90deg)}
.ring .bg{stroke:var(--hair)} .ring .fg{stroke:var(--accent);stroke-linecap:round}
.ep.locked{opacity:.55}
.ep.locked .body .ti{font-style:normal}
.badge{font-size:9.5px;letter-spacing:.08em;color:var(--muted);border:1px dashed var(--hair);
border-radius:20px;padding:5px 10px;flex:none}
.list .ep{animation:rise .45s both}
@keyframes rise{from{opacity:0;transform:translateY(6px)}}
@media (prefers-reduced-motion: reduce){*{animation:none!important;transition:none!important}}
</style>
</head>
<body>
<div class="phone">
<header class="head">
<div class="brand">
<h1>走遍美国</h1>
<span class="en">Family Album, U.S.A.</span>
</div>
<div class="sub">逐句精听 · Close Listening</div>
</header>
<section class="hero">
<div class="lab">继续学习</div>
<div class="ti">46 Linden Street · Act I</div>
<div class="cn">林登大街 46 号 · 第一幕</div>
<div class="row">
<div class="progress"><i></i></div>
<button class="resume">▶ 续听</button>
</div>
</section>
<div class="seclab"><span>全 26 集</span><div class="ln"></div></div>
<div class="list" id="list"></div>
</div>
<script>
// 真实数据:title / titleCn / 幕数 / 有音频幕数 / 进度(%)
const EPS = [
{n:1, ti:"46 Linden Street", cn:"林登大街46号", acts:3, audio:2, prog:38, cur:true},
{n:2, ti:"The Blind Date", cn:"相亲", acts:3, audio:3, prog:100},
{n:3, ti:"Grandpa's Trunk", cn:"祖父的行李箱", acts:3, audio:3, prog:64},
{n:4, ti:"A Piece of Cake", cn:"小菜一碟", acts:3, audio:3, prog:0},
{n:5, ti:"The Right Magic", cn:"灵丹妙药", acts:3, audio:3, prog:0},
{n:6, ti:"Thanksgiving", cn:"感恩节", acts:3, audio:3, prog:0},
{n:7, ti:"Man's Best Friend", cn:"人类最好的朋友",acts:3, audio:3, prog:0},
{n:8, ti:"You're Going to Be Fine",cn:"你会好起来的",acts:3, audio:3, prog:0},
{n:18, ti:"Making a Difference", cn:"与众不同", acts:3, audio:0, prog:0, locked:true},
{n:19, ti:"I Do", cn:"我愿意", acts:3, audio:0, prog:0, locked:true},
];
const roman = ["Ⅰ","Ⅱ","Ⅲ"];
const list = document.getElementById('list');
EPS.forEach((e,idx)=>{
const el = document.createElement('div');
el.className = 'ep' + (e.cur?' cur':'') + (e.locked?' locked':'');
el.style.animationDelay = (idx*0.04)+'s';
let chips = '';
for(let a=0;a<e.acts;a++){
if(e.locked) chips += `<span class="chip noaudio">Act ${roman[a]}</span>`;
else chips += `<span class="chip ${a<e.audio?'done':''}">Act ${roman[a]}</span>`;
}
const r=15, c=2*Math.PI*r, off=c*(1-e.prog/100);
const right = e.locked
? `<span class="badge">暂无音频</span>`
: `<div class="ring"><svg width="34" height="34"><circle class="bg" cx="17" cy="17" r="${r}" fill="none" stroke-width="3"/><circle class="fg" cx="17" cy="17" r="${r}" fill="none" stroke-width="3" stroke-dasharray="${c}" stroke-dashoffset="${off}"/></svg></div>`;
el.innerHTML = `
<div class="num">${e.n}</div>
<div class="body">
<div class="ti">${e.ti}</div>
<div class="cn">${e.cn}</div>
<div class="acts">${chips}</div>
</div>
${right}`;
list.appendChild(el);
});
</script>
</body>
</html>