From 72143f35afd3d490e121e1145a2b4942075fbf9c Mon Sep 17 00:00:00 2001 From: biss Date: Sat, 20 Jun 2026 10:11:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layouts/BaseLayout.astro | 55 +++++++++-- src/pages/posts/[slug].astro | 16 +++- src/styles/site.css | 175 ++++++++++++++++++++++------------- 3 files changed, 171 insertions(+), 75 deletions(-) diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index c1c7e38..8b48452 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -54,9 +54,18 @@ const consoleSites = [ @@ -257,25 +266,53 @@ const consoleSites = [ const button = document.querySelector('[data-theme-toggle]'); const media = window.matchMedia('(prefers-color-scheme: dark)'); const getSystemTheme = () => (media.matches ? 'dark' : 'light'); - const getTheme = () => localStorage.getItem(storageKey) || getSystemTheme(); + const getSavedTheme = () => { + try { + const theme = localStorage.getItem(storageKey); + return theme === 'dark' || theme === 'light' ? theme : null; + } catch { + return null; + } + }; + const setSavedTheme = (theme) => { + try { + if (theme === getSystemTheme()) localStorage.removeItem(storageKey); + else localStorage.setItem(storageKey, theme); + } catch { + // localStorage can be unavailable in strict privacy modes. + } + }; + const getTheme = () => getSavedTheme() || getSystemTheme(); function applyTheme(theme) { root.dataset.theme = theme; + root.dataset.themeMode = getSavedTheme() ? 'manual' : 'auto'; button?.setAttribute('aria-label', theme === 'dark' ? '切换到日间模式' : '切换到夜间模式'); - button?.setAttribute('title', theme === 'dark' ? '切换到日间模式' : '切换到夜间模式'); + button?.setAttribute( + 'title', + getSavedTheme() + ? (theme === 'dark' ? '切换到日间模式' : '切换到夜间模式') + : `跟随系统:${theme === 'dark' ? '夜间' : '日间'}模式` + ); } applyTheme(getTheme()); button?.addEventListener('click', () => { const nextTheme = root.dataset.theme === 'dark' ? 'light' : 'dark'; - localStorage.setItem(storageKey, nextTheme); + setSavedTheme(nextTheme); applyTheme(nextTheme); }); - media.addEventListener('change', () => { - if (!localStorage.getItem(storageKey)) applyTheme(getSystemTheme()); - }); + const handleSystemThemeChange = () => { + if (!getSavedTheme()) applyTheme(getSystemTheme()); + }; + + if (typeof media.addEventListener === 'function') { + media.addEventListener('change', handleSystemThemeChange); + } else if (typeof media.addListener === 'function') { + media.addListener(handleSystemThemeChange); + } })(); (() => { diff --git a/src/pages/posts/[slug].astro b/src/pages/posts/[slug].astro index e088bfc..5eddfe4 100644 --- a/src/pages/posts/[slug].astro +++ b/src/pages/posts/[slug].astro @@ -390,9 +390,17 @@ const relatedPosts = allPosts toggleButton.textContent = '展开'; toggleButton.setAttribute('aria-expanded', 'false'); + const expandCue = document.createElement('button'); + expandCue.className = 'code-block-expand-cue'; + expandCue.type = 'button'; + expandCue.setAttribute('aria-label', 'Expand code block'); + expandCue.setAttribute('aria-expanded', 'false'); + expandCue.innerHTML = ''; + toolbar.append(copyButton, toggleButton); header.append(language, toolbar); wrapper.appendChild(header); + wrapper.appendChild(expandCue); const codeLines = [...code.querySelectorAll(':scope > .line')]; if (codeLines.length > 0) { @@ -421,11 +429,15 @@ const relatedPosts = allPosts } }); - toggleButton.addEventListener('click', () => { + function toggleExpanded() { const isExpanded = wrapper.classList.toggle('is-expanded'); toggleButton.textContent = isExpanded ? '收起' : '展开'; toggleButton.setAttribute('aria-expanded', String(isExpanded)); - }); + expandCue.setAttribute('aria-expanded', String(isExpanded)); + } + + toggleButton.addEventListener('click', toggleExpanded); + expandCue.addEventListener('click', toggleExpanded); }); })(); diff --git a/src/styles/site.css b/src/styles/site.css index 909f449..b26cf26 100644 --- a/src/styles/site.css +++ b/src/styles/site.css @@ -19,14 +19,14 @@ :root[data-theme='dark'] { color-scheme: dark; - --bg: #0f171a; - --surface: #162225; - --text: #e9f0ee; - --muted: #a7b4b1; - --line: rgba(174, 205, 197, 0.18); - --accent: #72ded2; - --accent-strong: #9af0d6; - --shadow: 0 18px 48px rgba(0, 0, 0, 0.28); + --bg: #0b1014; + --surface: #141b21; + --text: #e7edf0; + --muted: #9ba9b1; + --line: rgba(166, 184, 194, 0.2); + --accent: #7dd3c7; + --accent-strong: #b7e7d4; + --shadow: 0 18px 52px rgba(0, 0, 0, 0.36); } * { @@ -49,7 +49,7 @@ body { :root[data-theme='dark'] body { background: - linear-gradient(rgba(8, 13, 16, 0.86), rgba(10, 17, 20, 0.94)), + linear-gradient(rgba(7, 10, 14, 0.9), rgba(8, 13, 17, 0.96)), url('/images/background.png') center top / cover fixed; } @@ -563,20 +563,20 @@ a { } :root[data-theme='dark'] .nav { - border-color: rgba(174, 205, 197, 0.2); + border-color: rgba(166, 184, 194, 0.2); background: - linear-gradient(135deg, rgba(29, 47, 51, 0.78), rgba(14, 23, 27, 0.54)), - rgba(12, 19, 22, 0.62); + linear-gradient(135deg, rgba(25, 35, 42, 0.82), rgba(10, 15, 20, 0.66)), + rgba(10, 15, 20, 0.68); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), inset 0 -18px 38px rgba(0, 0, 0, 0.18), - 0 18px 54px rgba(0, 0, 0, 0.34); + 0 18px 54px rgba(0, 0, 0, 0.42); } :root[data-theme='dark'] .nav::before { background: - radial-gradient(circle at 18% 0%, rgba(114, 222, 210, 0.18), transparent 32%), - linear-gradient(90deg, rgba(255, 255, 255, 0.08), transparent 42%, rgba(114, 222, 210, 0.1)); + radial-gradient(circle at 18% 0%, rgba(125, 211, 199, 0.16), transparent 32%), + linear-gradient(90deg, rgba(255, 255, 255, 0.07), transparent 42%, rgba(125, 211, 199, 0.08)); } :root[data-theme='dark'] .nav::after { @@ -589,8 +589,8 @@ a { :root[data-theme='dark'] .nav-console:hover, :root[data-theme='dark'] .theme-toggle:hover, :root[data-theme='dark'] .nav-menu-toggle:hover { - border-color: rgba(114, 222, 210, 0.26); - background: rgba(114, 222, 210, 0.12); + border-color: rgba(125, 211, 199, 0.28); + background: rgba(125, 211, 199, 0.11); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 8px 18px rgba(0, 0, 0, 0.18); @@ -601,14 +601,14 @@ a { } :root[data-theme='dark'] .control-console-panel { - border-color: rgba(174, 205, 197, 0.18); + border-color: rgba(166, 184, 194, 0.2); background: - radial-gradient(circle at 14% 0%, rgba(114, 222, 210, 0.1), transparent 34%), - linear-gradient(145deg, rgba(28, 43, 47, 0.88), rgba(12, 22, 25, 0.8)), - rgba(17, 28, 31, 0.82); + radial-gradient(circle at 14% 0%, rgba(125, 211, 199, 0.08), transparent 34%), + linear-gradient(145deg, rgba(24, 34, 42, 0.9), rgba(10, 17, 22, 0.84)), + rgba(14, 22, 28, 0.84); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), - 0 28px 80px rgba(0, 0, 0, 0.38); + 0 28px 80px rgba(0, 0, 0, 0.46); } :root[data-theme='dark'] .control-console-head h2, @@ -620,8 +620,8 @@ a { :root[data-theme='dark'] .control-site-card, :root[data-theme='dark'] .control-console-info section, :root[data-theme='dark'] .control-console-close { - border-color: rgba(114, 222, 210, 0.2); - background: rgba(114, 222, 210, 0.1); + border-color: rgba(125, 211, 199, 0.2); + background: rgba(125, 211, 199, 0.08); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08); } @@ -631,35 +631,35 @@ a { } :root[data-theme='dark'] .custom-context-menu { - border-color: rgba(174, 205, 197, 0.2); + border-color: rgba(166, 184, 194, 0.2); color: #d8e5e2; background: - linear-gradient(145deg, rgba(31, 48, 52, 0.88), rgba(13, 23, 26, 0.78)), - rgba(15, 25, 28, 0.82); + linear-gradient(145deg, rgba(27, 39, 47, 0.9), rgba(10, 17, 22, 0.82)), + rgba(14, 22, 28, 0.84); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), - 0 18px 42px rgba(0, 0, 0, 0.34); + 0 18px 42px rgba(0, 0, 0, 0.42); } :root[data-theme='dark'] .context-menu-nav :where(a, button) { - border-color: rgba(174, 205, 197, 0.16); - color: #b7c7c4; + border-color: rgba(166, 184, 194, 0.16); + color: #b7c3c8; background: rgba(255, 255, 255, 0.06); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08); } :root[data-theme='dark'] .context-menu-group { - border-top-color: rgba(174, 205, 197, 0.16); + border-top-color: rgba(166, 184, 194, 0.16); } :root[data-theme='dark'] .custom-context-menu :where(a, button):hover, :root[data-theme='dark'] .custom-context-menu :where(a, button):focus-visible { color: var(--accent); - background: rgba(114, 222, 210, 0.11); + background: rgba(125, 211, 199, 0.1); } :root[data-theme='dark'] .custom-context-menu i { - color: #a8b8b5; + color: #a8b5ba; } .hero { @@ -2235,6 +2235,7 @@ time { .prose .code-block.is-collapsible:not(.is-expanded)::after { content: ""; position: absolute; + z-index: 1; right: 0; bottom: 0; left: 0; @@ -2243,6 +2244,52 @@ time { pointer-events: none; } +.code-block-expand-cue { + appearance: none; + -webkit-appearance: none; + position: absolute; + z-index: 3; + right: 50%; + bottom: 10px; + display: none; + width: 36px; + height: 28px; + align-items: center; + justify-content: center; + border: 1px solid rgba(255, 255, 255, 0.18); + border-radius: 999px; + padding: 0; + background: rgba(22, 31, 36, 0.72); + box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18); + cursor: pointer; + transform: translateX(50%); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + transition: + border-color 0.2s ease, + background-color 0.2s ease, + transform 0.2s ease; +} + +.code-block-expand-cue span { + width: 10px; + height: 10px; + border-right: 2px solid rgba(255, 255, 255, 0.9); + border-bottom: 2px solid rgba(255, 255, 255, 0.9); + transform: translateY(-2px) rotate(45deg); +} + +.code-block-expand-cue:hover, +.code-block-expand-cue:focus-visible { + border-color: rgba(255, 255, 255, 0.36); + background: rgba(62, 184, 190, 0.82); + transform: translateX(50%) translateY(-1px); +} + +.prose .code-block.is-collapsible:not(.is-expanded) .code-block-expand-cue { + display: inline-flex; +} + .prose .code-block code { color: #e8edf2; line-height: 1.42; @@ -3882,11 +3929,11 @@ meting-js { .pagination-link, .pagination-number ) { - border-color: rgba(174, 205, 197, 0.18); + border-color: rgba(166, 184, 194, 0.18); background: - radial-gradient(circle at 14% 0%, rgba(114, 222, 210, 0.1), transparent 34%), - linear-gradient(145deg, rgba(28, 43, 47, 0.82), rgba(12, 22, 25, 0.72)), - rgba(17, 28, 31, 0.74); + radial-gradient(circle at 14% 0%, rgba(125, 211, 199, 0.08), transparent 34%), + linear-gradient(145deg, rgba(24, 34, 42, 0.84), rgba(10, 17, 22, 0.76)), + rgba(14, 22, 28, 0.78); box-shadow: var(--shadow); } @@ -3931,12 +3978,12 @@ meting-js { } :root[data-theme='dark'] .chart-legend-item { - border-color: rgba(174, 205, 197, 0.16); + border-color: rgba(166, 184, 194, 0.16); background: rgba(255, 255, 255, 0.05); } :root[data-theme='dark'] .pie-chart-track { - stroke: rgba(174, 205, 197, 0.16); + stroke: rgba(166, 184, 194, 0.16); } :root[data-theme='dark'] .line-chart-dot { @@ -3954,9 +4001,9 @@ meting-js { .post-copyright-action, .post-copyright-icon ) { - border-color: rgba(114, 222, 210, 0.22); + border-color: rgba(125, 211, 199, 0.22); color: var(--accent); - background: rgba(114, 222, 210, 0.1); + background: rgba(125, 211, 199, 0.1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08); } @@ -3980,30 +4027,30 @@ meting-js { } :root[data-theme='dark'] .article-header-cover { - background: #0d1f21; + background: #0d171d; } :root[data-theme='dark'] .article-header-cover::before { background: - linear-gradient(180deg, rgba(5, 12, 14, 0.54), rgba(7, 19, 21, 0.22) 38%, rgba(3, 10, 11, 0.82)), - linear-gradient(90deg, rgba(5, 18, 20, 0.62), rgba(12, 60, 57, 0.16) 54%, rgba(5, 18, 20, 0.44)); + linear-gradient(180deg, rgba(5, 9, 12, 0.58), rgba(8, 16, 20, 0.28) 38%, rgba(3, 8, 11, 0.86)), + linear-gradient(90deg, rgba(5, 13, 17, 0.66), rgba(20, 57, 58, 0.14) 54%, rgba(5, 13, 17, 0.48)); } :root[data-theme='dark'] .prose .code-block { - border-color: rgba(114, 222, 210, 0.2); - background: rgba(5, 10, 12, 0.96); - box-shadow: 0 14px 32px rgba(0, 0, 0, 0.24); + border-color: rgba(125, 211, 199, 0.18); + background: rgba(5, 8, 12, 0.96); + box-shadow: 0 14px 32px rgba(0, 0, 0, 0.32); } :root[data-theme='dark'] .prose :not(pre) > code { - border-color: rgba(114, 222, 210, 0.22); + border-color: rgba(125, 211, 199, 0.22); color: var(--accent); - background: rgba(114, 222, 210, 0.1); + background: rgba(125, 211, 199, 0.1); } :root[data-theme='dark'] .butterfly-note { color: #dce9e6; - background: rgba(114, 222, 210, 0.08); + background: rgba(125, 211, 199, 0.08); } :root[data-theme='dark'] .butterfly-note--disabled { @@ -4015,7 +4062,7 @@ meting-js { } :root[data-theme='dark'] .butterfly-hide-block__content { - border-left-color: rgba(114, 222, 210, 0.22); + border-left-color: rgba(125, 211, 199, 0.22); } :root[data-theme='dark'] .prose table { @@ -4025,43 +4072,43 @@ meting-js { :root[data-theme='dark'] .prose thead th { color: #effaf7; background: - linear-gradient(135deg, rgba(40, 70, 70, 0.86), rgba(22, 41, 44, 0.76)), - rgba(13, 24, 27, 0.8); + linear-gradient(135deg, rgba(35, 55, 61, 0.86), rgba(18, 31, 38, 0.78)), + rgba(12, 21, 27, 0.84); } :root[data-theme='dark'] .prose tbody tr:nth-child(even) td { - background: rgba(114, 222, 210, 0.07); + background: rgba(125, 211, 199, 0.06); } :root[data-theme='dark'] .prose tbody tr:hover td { - background: rgba(114, 222, 210, 0.12); + background: rgba(125, 211, 199, 0.1); } :root[data-theme='dark'] .prose :where(th, td) { - border-color: rgba(114, 222, 210, 0.12); + border-color: rgba(125, 211, 199, 0.12); } :root[data-theme='dark'] .site-footer { - color: rgba(197, 214, 211, 0.74); + color: rgba(199, 211, 216, 0.76); background: - linear-gradient(180deg, rgba(12, 20, 23, 0.68), rgba(8, 14, 17, 0.88)), - rgba(8, 14, 17, 0.84); + linear-gradient(180deg, rgba(10, 16, 21, 0.7), rgba(6, 10, 14, 0.9)), + rgba(7, 11, 15, 0.86); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08); } :root[data-theme='dark'] .footer-socials a { - border-color: rgba(174, 205, 197, 0.18); + border-color: rgba(166, 184, 194, 0.18); color: rgba(218, 234, 231, 0.82); background: - linear-gradient(145deg, rgba(34, 51, 55, 0.78), rgba(14, 24, 27, 0.72)), - rgba(18, 29, 32, 0.72); + linear-gradient(145deg, rgba(28, 40, 48, 0.8), rgba(10, 17, 22, 0.74)), + rgba(14, 22, 28, 0.74); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08), - 0 10px 24px rgba(0, 0, 0, 0.22); + 0 10px 24px rgba(0, 0, 0, 0.3); } :root[data-theme='dark'] .footer-bottom { - border-top-color: rgba(174, 205, 197, 0.16); + border-top-color: rgba(166, 184, 194, 0.16); } @media (min-width: 960px) {