文件内容
assets/note-template.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{TITLE}}</title>
<style>
:root {
--bg: #1a1a2e;
--surface: #16213e;
--card: #1e2a45;
--card2: #243352;
--border: rgba(255,255,255,.08);
--border2: rgba(255,255,255,.12);
--accent: #d97559;
--blue: #5b8dee;
--green: #3ecf8e;
--purple: #9b7cf4;
--amber: #f0a946;
--text: #f0ede8;
--text2: #a8a49e;
--text3: #6b6762;
--sidebar: 200px;
--r: 14px;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{background:var(--bg);color:var(--text);font-family:-apple-system,'PingFang SC','Noto Sans SC',sans-serif;font-size:15px;line-height:1.7;display:flex;min-height:100vh}
/* SIDEBAR */
.sidebar{width:var(--sidebar);flex-shrink:0;position:sticky;top:0;height:100vh;overflow-y:auto;background:var(--surface);border-right:1px solid var(--border);display:flex;flex-direction:column;padding:20px 0 32px}
.sidebar::-webkit-scrollbar{width:3px}
.sidebar::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}
.sb-logo{padding:0 16px 20px;border-bottom:1px solid var(--border);margin-bottom:12px}
.sb-logo-icon{width:32px;height:32px;background:var(--accent);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:16px;margin-bottom:8px}
.sb-logo h2{font-size:13px;font-weight:700;color:var(--text)}
.sb-logo p{font-size:11px;color:var(--text3);margin-top:2px;line-height:1.4}
.nav-a{display:flex;align-items:center;gap:9px;padding:8px 16px;font-size:13px;color:var(--text2);cursor:pointer;border-left:2px solid transparent;text-decoration:none;transition:all .12s}
.nav-a:hover{color:var(--text);background:rgba(255,255,255,.05)}
.nav-a.active{color:var(--accent);border-left-color:var(--accent);background:rgba(217,117,89,.08);font-weight:500}
.nav-icon{font-size:13px;width:18px;text-align:center;flex-shrink:0}
.nav-sep{height:1px;background:var(--border);margin:8px 16px}
/* MAIN */
.main{flex:1;min-width:0;padding:40px 48px 80px 40px}
/* HERO */
.hero{background:linear-gradient(135deg,var(--card) 0%,#111a35 100%);border:1px solid var(--border2);border-radius:20px;padding:44px 40px;margin-bottom:44px;position:relative;overflow:hidden}
.hero::before{content:'';position:absolute;top:-120px;right:-80px;width:340px;height:340px;background:radial-gradient(circle,rgba(217,117,89,.18) 0%,transparent 65%);pointer-events:none}
.hero::after{content:'';position:absolute;bottom:-100px;left:40px;width:280px;height:280px;background:radial-gradient(circle,rgba(91,141,238,.1) 0%,transparent 65%);pointer-events:none}
.hero-badge{display:inline-flex;align-items:center;gap:6px;background:rgba(217,117,89,.15);border:1px solid rgba(217,117,89,.35);color:#f0a98a;font-size:11px;font-weight:600;letter-spacing:1.2px;text-transform:uppercase;padding:4px 12px;border-radius:99px;margin-bottom:18px}
.hero h1{font-size:42px;font-weight:800;letter-spacing:-.5px;line-height:1.15;margin-bottom:6px;color:var(--text)}
.hero-sub{font-size:14px;color:var(--text3);margin-bottom:24px}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:24px}
.chip{padding:4px 12px;border-radius:99px;font-size:12px;background:rgba(255,255,255,.06);border:1px solid var(--border2);color:var(--text2)}
.hero-quote{background:rgba(62,207,142,.07);border:1px solid rgba(62,207,142,.2);border-radius:10px;padding:14px 18px;font-size:14px;color:#a7f3d0;font-style:italic;line-height:1.75}
/* SECTION */
.sec{margin-bottom:44px;scroll-margin-top:20px}
.sec-hd{display:flex;align-items:center;gap:10px;margin-bottom:18px;padding-bottom:12px;border-bottom:1px solid var(--border)}
.sec-n{width:26px;height:26px;min-width:26px;background:var(--accent);border-radius:7px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:800;color:#fff}
.sec-title{font-size:17px;font-weight:700}
/* CARDS */
.card{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:20px 22px;margin-bottom:12px}
.g2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.g3{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
/* DIAGRAM */
.diag{background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:18px 20px;margin-bottom:12px;overflow-x:auto}
.diag-lbl{font-size:11px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;color:var(--text3);margin-bottom:14px}
/* TIMELINE */
.tl{position:relative;padding-left:26px}
.tl::before{content:'';position:absolute;left:7px;top:6px;bottom:6px;width:1.5px;background:linear-gradient(to bottom,var(--accent),var(--purple),var(--green))}
.tl-it{position:relative;margin-bottom:16px}
.tl-d{position:absolute;left:-22px;top:4px;width:12px;height:12px;border-radius:50%;border:2px solid var(--bg)}
.tl-y{font-size:10px;font-weight:700;letter-spacing:1px;color:var(--text3);text-transform:uppercase;margin-bottom:1px}
.tl-t{font-size:13px}
.tl-t strong{color:#93c5fd}
/* QUOTES */
.ql{display:flex;flex-direction:column;gap:10px}
.q{padding:14px 18px;border-radius:10px;border-left:3px solid;font-size:14px;font-style:italic;line-height:1.75}
.qa{font-style:normal;font-size:11px;color:var(--text3);margin-top:5px}
/* EQ */
.eq{background:var(--card2);border:1px solid rgba(91,141,238,.25);border-radius:var(--r);padding:24px;text-align:center;font-family:'JetBrains Mono','Fira Code',monospace}
.eq-m{font-size:22px;font-weight:800;color:#93c5fd;letter-spacing:3px;margin-bottom:5px}
.eq-s{font-size:11px;color:var(--text3);letter-spacing:.8px}
/* SUBTITLE VIEWER */
.sub-bar{display:flex;gap:10px;align-items:center;margin-bottom:12px;flex-wrap:wrap}
.sub-inp{flex:1;min-width:180px;background:var(--card2);border:1px solid var(--border2);border-radius:8px;padding:8px 14px;color:var(--text);font-size:13px;outline:none}
.sub-inp:focus{border-color:var(--accent)}
.sub-inp::placeholder{color:var(--text3)}
.sub-ct{font-size:12px;color:var(--text3);flex-shrink:0}
.sub-yt{font-size:12px;color:var(--accent);text-decoration:none;flex-shrink:0}
.sub-list{height:460px;overflow-y:auto;background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:4px}
.sub-list::-webkit-scrollbar{width:4px}
.sub-list::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}
.si{display:flex;gap:12px;align-items:baseline;padding:8px 12px;border-radius:8px;cursor:pointer;transition:background .1s}
.si:hover{background:var(--card2)}
.si-ts{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--accent);flex-shrink:0;padding-top:1px}
.si-tx{font-size:13px;color:var(--text2);line-height:1.5}
.si-tx mark{background:rgba(240,169,70,.25);color:var(--amber);border-radius:3px;padding:0 2px}
@media(max-width:820px){.sidebar{display:none}.main{padding:24px 20px 60px}}
@media(max-width:560px){.g2,.g3{grid-template-columns:1fr}.hero h1{font-size:30px}}
</style>
</head>
<body>
<!-- SIDEBAR: filled by Claude -->
<nav class="sidebar">
{{SIDEBAR_NAV}}
</nav>
<!-- MAIN: filled by Claude -->
<main class="main">
<!-- SUMMARY SECTION -->
<div class="sec" id="summary">
<div class="sec-hd"><div class="sec-n" style="background:var(--green)">✦</div><div class="sec-title">核心论点总结</div></div>
<div class="card" style="font-size:14px;line-height:2;color:var(--text2)">
{{SUMMARY}}
</div>
</div>
{{MAIN_CONTENT}}
<!-- KEYFRAMES GALLERY (only rendered if {{KEYFRAMES_JSON}} is non-empty) -->
<div class="sec" id="keyframes">
<div class="sec-hd"><div class="sec-n">🎬</div><div class="sec-title">关键画面</div></div>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px" id="kfGrid"></div>
</div>
<!-- SUBTITLE SECTION -->
<div class="sec" id="subtitles">
<div class="sec-hd"><div class="sec-n">{{SUBTITLE_SEC_NUM}}</div><div class="sec-title">原始字幕</div></div>
<div class="sub-bar">
<input class="sub-inp" id="si" placeholder="搜索字幕内容…" oninput="fs(this.value)">
<span class="sub-ct" id="sc"></span>
<a class="sub-yt" href="{{VIDEO_URL}}" target="_blank">↗ 原视频</a>
</div>
<div class="sub-list" id="sl"></div>
</div>
</main>
<script>
const S={{SUBTITLE_JSON}};
const KF={{KEYFRAMES_JSON}};
// Render keyframes gallery
(function(){
const grid=document.getElementById('kfGrid');
if(!grid||!KF||!KF.length){
const sec=document.getElementById('keyframes');
if(sec) sec.style.display='none';
return;
}
const vid='{{VIDEO_ID}}';
grid.innerHTML=KF.map(k=>{
const u=`https://www.youtube.com/watch?v=${vid}&t=${Math.floor(k.s)}s`;
const label=(k.text||'').slice(0,80)+((k.text||'').length>80?'…':'');
return `<div style="background:var(--card);border:1px solid var(--border);border-radius:12px;overflow:hidden;cursor:pointer" onclick="window.open('${u}','_blank')">
<img src="data:image/jpeg;base64,${k.image_b64}" style="width:100%;display:block;aspect-ratio:16/9;object-fit:cover" loading="lazy">
<div style="padding:10px 12px">
<div style="font-family:monospace;font-size:11px;color:var(--accent);margin-bottom:4px">${k.t}</div>
<div style="font-size:12px;color:var(--text2);line-height:1.5">${label}</div>
</div>
</div>`;
}).join('');
})();
function rs(d,q=''){
const l=document.getElementById('sl'),c=document.getElementById('sc');
if(!d.length){l.innerHTML='<div style="padding:20px;text-align:center;color:var(--text3);font-size:13px">未找到匹配内容</div>';c.textContent='0 条';return;}
const esc=s=>s.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');
l.innerHTML=d.map(s=>{
let t=s.text.replace(/</g,'<');
if(q){const r=new RegExp(esc(q),'gi');t=t.replace(r,m=>`<mark>${m}</mark>`);}
const vid='{{VIDEO_ID}}';
const u=`https://www.youtube.com/watch?v=${vid}&t=${Math.floor(s.s)}s`;
return `<div class="si" onclick="window.open('${u}','_blank')"><span class="si-ts">${s.t}</span><span class="si-tx">${t}</span></div>`;
}).join('');
c.textContent=`${d.length} 条`;
}
function fs(q){if(!q.trim()){rs(S);return;}const low=q.toLowerCase();rs(S.filter(s=>s.text.toLowerCase().includes(low)),q);}
rs(S);
// scroll spy
const IDS={{SECTION_IDS}};
const NL={};IDS.forEach(id=>{const a=document.querySelector(`.nav-a[href="#${id}"]`);if(a)NL[id]=a;});
IDS.forEach(id=>{const el=document.getElementById(id);if(el)new IntersectionObserver(es=>es.forEach(e=>{if(e.isIntersecting&&NL[e.target.id]){document.querySelectorAll('.nav-a').forEach(a=>a.classList.remove('active'));NL[e.target.id].classList.add('active');}}),{rootMargin:'-20% 0px -60% 0px'}).observe(el);});
</script>
</body>
</html>