文件预览

note-template.html

查看 Video Notes 技能包中的文件内容。

文件内容

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,'&lt;');
    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>