From 516528ed73ca9070b6d49c0fa93575da0b845073 Mon Sep 17 00:00:00 2001 From: Chen Gu Date: Thu, 23 Apr 2026 12:18:35 +0800 Subject: [PATCH] feat: polish spectra lab editorial details --- .gitignore | 1 + app.js | 38 ++++++++++++++++++++--- index.html | 18 +++++++++++ styles.css | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 140 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 6b78d50..76c9f06 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ spectra-lab-local.png spectra-lab-redesign.png +spectra-lab-polish.png .DS_Store diff --git a/app.js b/app.js index 9520e09..c0da016 100644 --- a/app.js +++ b/app.js @@ -4,12 +4,41 @@ const workItems = document.querySelectorAll('.work-item'); const workIndex = document.getElementById('workIndex'); const workTitle = document.getElementById('workTitle'); const workCopy = document.getElementById('workCopy'); +const stageCard = document.querySelector('.stage-card'); const revealBlocks = document.querySelectorAll('.reveal'); +const storedMode = window.localStorage.getItem('spectra-mode'); + +if (storedMode === 'light') { + document.body.classList.add('light-mode'); +} function applyMode() { const isLight = document.body.classList.contains('light-mode'); modeToggle.textContent = isLight ? 'Dark Mode' : 'Light Mode'; modeLabel.textContent = isLight ? 'Editorial Light' : 'Editorial Dark'; + window.localStorage.setItem('spectra-mode', isLight ? 'light' : 'dark'); +} + +function updateWorkStage(item) { + workItems.forEach((button) => { + button.classList.remove('is-active'); + button.setAttribute('aria-selected', 'false'); + }); + + item.classList.add('is-active'); + item.setAttribute('aria-selected', 'true'); + + stageCard?.classList.remove('is-refreshing'); + requestAnimationFrame(() => { + stageCard?.classList.add('is-refreshing'); + window.setTimeout(() => { + stageCard?.classList.remove('is-refreshing'); + }, 340); + }); + + workIndex.textContent = item.dataset.index || ''; + workTitle.textContent = item.dataset.title || ''; + workCopy.textContent = item.dataset.copy || ''; } modeToggle?.addEventListener('click', () => { @@ -19,11 +48,7 @@ modeToggle?.addEventListener('click', () => { workItems.forEach((item) => { item.addEventListener('click', () => { - workItems.forEach((button) => button.classList.remove('is-active')); - item.classList.add('is-active'); - workIndex.textContent = item.dataset.index || ''; - workTitle.textContent = item.dataset.title || ''; - workCopy.textContent = item.dataset.copy || ''; + updateWorkStage(item); }); }); @@ -40,4 +65,7 @@ const observer = new IntersectionObserver( ); revealBlocks.forEach((block) => observer.observe(block)); +if (workItems[0]) { + updateWorkStage(workItems[0]); +} applyMode(); diff --git a/index.html b/index.html index b406f4d..bd0bfbb 100644 --- a/index.html +++ b/index.html @@ -61,6 +61,20 @@

+
+
+ Design principle + Less gesture, more judgment. +
+
+ Material cue + 纸感、墨感、少量暗红,而不是数字炫光。 +
+
+ Reading rhythm + 先标题,再说明,再留下停顿。 +
+
@@ -187,6 +201,10 @@

如果第一页就把所有招式用完,观者只会记得“效果很多”。但如果页面知道何时收、何时留白、何时只用一条线和一块色面说话,它才更像真正完成度高的作品。

+
+ Spectra Lab / Editorial pass + Built for calm impact. +
diff --git a/styles.css b/styles.css index 6ce3b7e..bdf144f 100644 --- a/styles.css +++ b/styles.css @@ -86,11 +86,16 @@ a { } .topbar { + position: sticky; + top: 0; display: flex; align-items: center; justify-content: space-between; gap: 16px; - padding: 28px 0 20px; + padding: 22px 0 18px; + background: linear-gradient(180deg, color-mix(in srgb, var(--bg) 82%, transparent 18%), color-mix(in srgb, var(--bg) 58%, transparent 42%)); + backdrop-filter: blur(14px); + z-index: 8; } .brand { @@ -141,10 +146,47 @@ a { color: var(--text); } +.mode-toggle:hover { + border-color: var(--line-strong); + background: var(--accent-soft); +} + .hero { padding: 42px 0 72px; } +.hero-ledger { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 16px; + margin-top: 30px; + padding-top: 18px; + border-top: 1px solid var(--line); +} + +.ledger-item { + padding: 18px 18px 20px; + border: 1px solid var(--line); + background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.01)); +} + +.ledger-item span, +.closing-signoff span { + display: block; + text-transform: uppercase; + letter-spacing: 0.16em; + font-size: 0.72rem; + color: var(--muted); +} + +.ledger-item strong { + display: block; + margin-top: 14px; + font-size: 1rem; + line-height: 1.6; + font-weight: 600; +} + .hero-meta, .section-head, .footer { @@ -274,6 +316,11 @@ a { background: var(--accent-soft); } +.work-item.is-active .work-number, +.work-item.is-active small { + color: var(--text); +} + .work-number { font-size: 0.8rem; color: var(--muted); @@ -299,17 +346,32 @@ a { } .stage-card { + position: relative; min-height: 100%; display: flex; flex-direction: column; justify-content: flex-end; padding: 34px; + overflow: hidden; background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.06) 100%), linear-gradient(135deg, rgba(255,255,255,0.02), transparent 48%), linear-gradient(180deg, var(--panel), color-mix(in srgb, var(--panel) 80%, black 20%)); } +.stage-card::before { + content: ''; + position: absolute; + inset: 0; + pointer-events: none; + background: linear-gradient(180deg, transparent 0%, rgba(255, 255, 255, 0.04) 100%); + opacity: 0.5; +} + +.stage-card.is-refreshing { + animation: stageRefresh 320ms ease; +} + .stage-index { font-size: clamp(4.2rem, 8vw, 8rem); line-height: 0.92; @@ -354,6 +416,15 @@ a { color: rgba(20, 20, 20, 0.7); } +.closing-signoff { + display: flex; + justify-content: space-between; + gap: 16px; + margin-top: 30px; + padding-top: 18px; + border-top: 1px solid rgba(20, 20, 20, 0.12); +} + .footer { padding: 22px 0 42px; border-top: 1px solid var(--line); @@ -370,12 +441,24 @@ a { transform: translateY(0); } +@keyframes stageRefresh { + 0% { + transform: translateY(8px); + opacity: 0.86; + } + 100% { + transform: translateY(0); + opacity: 1; + } +} + @media (max-width: 1100px) { .topbar, .hero-meta, .section-head, .works-layout, .hero-grid, + .hero-ledger, .statement-grid, .system-grid, .footer { @@ -435,4 +518,8 @@ a { .closing-panel { padding: 24px; } + + .closing-signoff { + flex-direction: column; + } }