claude again
This commit is contained in:
parent
df2267a968
commit
f3fc893675
81 changed files with 945 additions and 2813 deletions
|
|
@ -7,6 +7,14 @@ function isCurrent(href: string) {
|
|||
if (href === '/') return current === '/';
|
||||
return current.startsWith(href);
|
||||
}
|
||||
|
||||
// Local fallback: Agent 3 hasn't shipped `footerItems`/`footerOnly` yet, so we
|
||||
// derive header items locally. Header shows nav (minus Home) + Tags. RSS lives
|
||||
// in the header as a dedicated icon link.
|
||||
const headerNavItems = [
|
||||
...navItems.filter((item) => item.href !== '/'),
|
||||
{ href: '/tags/', label: 'Tags' },
|
||||
];
|
||||
---
|
||||
|
||||
<a class="skip-link" href="#content">Skip to content</a>
|
||||
|
|
@ -15,81 +23,99 @@ function isCurrent(href: string) {
|
|||
<div class="header-actions">
|
||||
<nav class="site-nav" aria-label="Primary">
|
||||
{
|
||||
navItems
|
||||
.filter((item) => item.href !== '/')
|
||||
.map((item) => (
|
||||
<a href={item.href} aria-current={isCurrent(item.href) ? 'page' : undefined}>
|
||||
{item.label}
|
||||
</a>
|
||||
))
|
||||
headerNavItems.map((item) => (
|
||||
<a href={item.href} aria-current={isCurrent(item.href) ? 'page' : undefined}>
|
||||
{item.label}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
<a class="rss-link" href="/rss.xml" aria-label="RSS feed">
|
||||
<svg
|
||||
class="rss-icon"
|
||||
viewBox="0 0 24 24"
|
||||
width="18"
|
||||
height="18"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M6.18 17.82a2.18 2.18 0 1 1-4.36 0 2.18 2.18 0 0 1 4.36 0ZM2 9.86v3.13a8.97 8.97 0 0 1 9.01 9.01h3.13A12.1 12.1 0 0 0 2 9.86Zm0-5.86V7.1A14.92 14.92 0 0 1 16.9 22H20A17.9 17.9 0 0 0 2 4Z"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="sr-only">RSS feed</span>
|
||||
</a>
|
||||
<button
|
||||
id="theme-switcher"
|
||||
class="theme-switcher"
|
||||
type="button"
|
||||
aria-label="Toggle dark theme"
|
||||
aria-label="Switch to dark theme"
|
||||
aria-pressed="false"
|
||||
>
|
||||
<span class="sr-only">Toggle theme</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<script is:inline data-theme-script>
|
||||
(() => {
|
||||
const key = 'theme';
|
||||
const legacyKey = 'dark-mode';
|
||||
const switcher = document.getElementById('theme-switcher');
|
||||
const media = matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
const getStored = () => {
|
||||
try {
|
||||
const value = localStorage.getItem(key);
|
||||
if (value === 'light' || value === 'dark') return value;
|
||||
const legacyValue = localStorage.getItem(legacyKey);
|
||||
if (legacyValue !== null) return JSON.parse(legacyValue) ? 'dark' : 'light';
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const getSystemTheme = () => (media.matches ? 'dark' : 'light');
|
||||
|
||||
const apply = (theme) => {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
if (switcher) switcher.setAttribute('aria-pressed', String(theme === 'dark'));
|
||||
};
|
||||
|
||||
apply(getStored() || getSystemTheme());
|
||||
|
||||
var key = 'theme';
|
||||
var legacyKey = 'dark-mode';
|
||||
var switcher = document.getElementById('theme-switcher');
|
||||
if (!switcher) return;
|
||||
|
||||
const reduced = matchMedia('(prefers-reduced-motion: reduce)');
|
||||
function syncSwitcher(theme) {
|
||||
switcher.setAttribute('aria-pressed', String(theme === 'dark'));
|
||||
switcher.setAttribute(
|
||||
'aria-label',
|
||||
theme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme'
|
||||
);
|
||||
}
|
||||
|
||||
const runApply = (theme) => {
|
||||
var initial = document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light';
|
||||
syncSwitcher(initial);
|
||||
|
||||
var reduced = matchMedia('(prefers-reduced-motion: reduce)');
|
||||
|
||||
function apply(theme) {
|
||||
document.documentElement.dataset.theme = theme;
|
||||
document.documentElement.style.colorScheme = theme;
|
||||
syncSwitcher(theme);
|
||||
}
|
||||
|
||||
function runApply(theme) {
|
||||
if (!reduced.matches && typeof document.startViewTransition === 'function') {
|
||||
document.startViewTransition(() => apply(theme));
|
||||
document.startViewTransition(function () {
|
||||
apply(theme);
|
||||
});
|
||||
} else {
|
||||
apply(theme);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
switcher.addEventListener('click', () => {
|
||||
const current = switcher.getAttribute('aria-pressed') === 'true' ? 'dark' : 'light';
|
||||
const next = current === 'dark' ? 'light' : 'dark';
|
||||
switcher.addEventListener('click', function () {
|
||||
var currentTheme =
|
||||
switcher.getAttribute('aria-pressed') === 'true' ? 'dark' : 'light';
|
||||
var next = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
try {
|
||||
localStorage.setItem(key, next);
|
||||
localStorage.setItem(legacyKey, JSON.stringify(next === 'dark'));
|
||||
} catch {
|
||||
// The switch still applies for the current page when storage is unavailable.
|
||||
}
|
||||
} catch (e) {}
|
||||
runApply(next);
|
||||
});
|
||||
|
||||
media.addEventListener('change', () => {
|
||||
if (!getStored()) apply(getSystemTheme());
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.rss-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: inherit;
|
||||
line-height: 0;
|
||||
}
|
||||
.rss-icon {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue