Skip to content

Commit 5bfa525

Browse files
committed
feat(ui): add subtle theme-aware icons
1 parent f50738c commit 5bfa525

10 files changed

Lines changed: 385 additions & 96 deletions

File tree

src/components/SpotlightHeader.astro

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,32 @@
11
---
2+
import UiIcon from './UiIcon.astro';
3+
24
const currentPath = Astro.url.pathname;
35
const isPhotoArchive = currentPath === '/photography/';
46
57
const navigation = [
6-
{ name: '文章', href: '/articles/' },
7-
{ name: '摄影', href: '/photography/' },
8-
{ name: '标签', href: '/tags/' },
9-
{ name: '关于', href: '/about/' },
10-
];
8+
{ name: '文章', href: '/articles/', icon: 'article' },
9+
{ name: '摄影', href: '/photography/', icon: 'camera' },
10+
{ name: '标签', href: '/tags/', icon: 'tag' },
11+
{ name: '关于', href: '/about/', icon: 'about' },
12+
] as const;
1113
---
1214

1315
<header class={`pt-8 sm:pt-10 ${isPhotoArchive ? 'spotlight-header--inverse' : ''}`}>
1416
<div class="shell">
1517
<div class="flex items-center justify-between gap-4 border-b pb-5 spotlight-header__bar" style="border-color: var(--line);">
16-
<a href="/" class="text-lg font-semibold tracking-tight spotlight-header__brand text-[var(--text)]" data-astro-prefetch style="view-transition-name: site-brand;">Joey's Notes</a>
18+
<a href="/" class="spotlight-header__brand text-lg font-semibold tracking-tight text-[var(--text)]" data-astro-prefetch style="view-transition-name: site-brand;">
19+
<UiIcon name="notebook" size={17} class="spotlight-header__brand-icon" />
20+
<span>Joey's Notes</span>
21+
</a>
1722

18-
<nav class="hidden items-center gap-7 text-sm md:flex">
23+
<nav class="hidden items-center gap-6 text-sm md:flex">
1924
{navigation.map((item) => {
2025
const active = currentPath === item.href;
2126
return (
2227
<a href={item.href} class={`relative transition spotlight-header__link ${active ? 'font-semibold text-[var(--text)]' : 'muted hover:text-[var(--text)]'}`} data-astro-prefetch>
23-
{item.name}
28+
<UiIcon name={item.icon} size={14} class="spotlight-header__nav-icon" />
29+
<span>{item.name}</span>
2430
{active && <span class="absolute -bottom-1 left-0 right-0 h-px bg-[var(--accent)]" />}
2531
</a>
2632
);
@@ -32,25 +38,26 @@ const navigation = [
3238
<button
3339
type="button"
3440
data-theme-toggle
35-
class="rounded-full border px-3 py-1.5 text-xs font-medium transition spotlight-header__button hover:bg-black/5 dark:hover:bg-white/10"
41+
class="spotlight-header__button spotlight-header__theme-toggle rounded-full border px-3 py-1.5 text-xs font-medium transition hover:bg-black/5 dark:hover:bg-white/10"
3642
style="border-color: var(--line); color: var(--text);"
3743
aria-label="切换主题"
3844
>
45+
<UiIcon name="moon" size={14} class="spotlight-header__theme-icon spotlight-header__theme-icon--dark" />
46+
<UiIcon name="sun" size={14} class="spotlight-header__theme-icon spotlight-header__theme-icon--light" />
3947
<span data-theme-toggle-label>深色</span>
4048
</button>
4149
)}
4250

4351
<details class="relative md:hidden">
44-
<summary class="cursor-pointer list-none rounded-full border px-3 py-1.5 text-xs font-medium spotlight-header__button spotlight-header__menu-toggle" style="border-color: var(--line); color: var(--text);" aria-label="导航">
45-
<span class="spotlight-header__burger" aria-hidden="true">
46-
<span></span>
47-
<span></span>
48-
<span></span>
49-
</span>
52+
<summary class="spotlight-header__button spotlight-header__menu-toggle cursor-pointer list-none rounded-full border px-3 py-1.5 text-xs font-medium" style="border-color: var(--line); color: var(--text);" aria-label="导航">
53+
<UiIcon name="menu" size={16} />
5054
</summary>
51-
<nav class="absolute right-5 mt-2 min-w-36 rounded-xl border bg-[var(--surface)] p-2 text-sm shadow-sm spotlight-header__menu" style="border-color: var(--line);">
55+
<nav class="spotlight-header__menu absolute right-5 mt-2 min-w-40 rounded-xl border bg-[var(--surface)] p-2 text-sm shadow-sm" style="border-color: var(--line);">
5256
{navigation.map((item) => (
53-
<a href={item.href} class="block rounded-lg px-3 py-2 muted hover:bg-black/5 hover:text-[var(--text)] dark:hover:bg-white/5 spotlight-header__menu-link" data-astro-prefetch>{item.name}</a>
57+
<a href={item.href} class="spotlight-header__menu-link muted flex items-center gap-2 rounded-lg px-3 py-2 hover:bg-black/5 hover:text-[var(--text)] dark:hover:bg-white/5" data-astro-prefetch>
58+
<UiIcon name={item.icon} size={14} />
59+
<span>{item.name}</span>
60+
</a>
5461
))}
5562
</nav>
5663
</details>
@@ -66,6 +73,51 @@ const navigation = [
6673
linear-gradient(180deg, #05070b 0%, #070a10 100%);
6774
}
6875

76+
.spotlight-header__brand,
77+
.spotlight-header__link,
78+
.spotlight-header__theme-toggle {
79+
display: inline-flex;
80+
align-items: center;
81+
}
82+
83+
.spotlight-header__brand {
84+
gap: 0.48rem;
85+
}
86+
87+
.spotlight-header__brand-icon {
88+
color: color-mix(in srgb, var(--accent) 72%, var(--muted));
89+
opacity: 0.82;
90+
}
91+
92+
.spotlight-header__link {
93+
gap: 0.38rem;
94+
}
95+
96+
.spotlight-header__nav-icon {
97+
opacity: 0.58;
98+
transition: opacity 0.2s ease, transform 0.2s ease;
99+
}
100+
101+
.spotlight-header__link:hover .spotlight-header__nav-icon,
102+
.spotlight-header__link.font-semibold .spotlight-header__nav-icon {
103+
opacity: 0.9;
104+
transform: translateY(-1px);
105+
}
106+
107+
.spotlight-header__theme-toggle {
108+
gap: 0.38rem;
109+
}
110+
111+
.spotlight-header__theme-icon {
112+
color: color-mix(in srgb, var(--accent) 70%, var(--muted));
113+
opacity: 0.78;
114+
}
115+
116+
:global(.dark) .spotlight-header__theme-icon--dark,
117+
:global(html:not(.dark)) .spotlight-header__theme-icon--light {
118+
display: none;
119+
}
120+
69121
.spotlight-header--inverse .spotlight-header__bar {
70122
border-color: rgba(255, 255, 255, 0.08) !important;
71123
}
@@ -76,6 +128,11 @@ const navigation = [
76128
color: rgba(248, 250, 252, 0.94) !important;
77129
}
78130

131+
.spotlight-header--inverse .spotlight-header__brand-icon,
132+
.spotlight-header--inverse .spotlight-header__theme-icon {
133+
color: rgba(245, 158, 11, 0.78);
134+
}
135+
79136
.spotlight-header--inverse .muted {
80137
color: rgba(195, 203, 214, 0.72);
81138
}
@@ -101,16 +158,7 @@ const navigation = [
101158
min-height: 2.5rem;
102159
}
103160

104-
.spotlight-header__burger {
105-
display: inline-grid;
106-
gap: 0.22rem;
107-
}
108-
109-
.spotlight-header__burger span {
110-
display: block;
111-
width: 0.95rem;
112-
height: 1.5px;
113-
border-radius: 9999px;
114-
background: currentColor;
161+
.spotlight-header__menu-toggle::-webkit-details-marker {
162+
display: none;
115163
}
116164
</style>

src/components/UiIcon.astro

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
---
2+
export interface Props {
3+
name:
4+
| 'article'
5+
| 'camera'
6+
| 'tag'
7+
| 'about'
8+
| 'notebook'
9+
| 'spark'
10+
| 'sun'
11+
| 'moon'
12+
| 'archive'
13+
| 'calendar'
14+
| 'image'
15+
| 'arrowLeft'
16+
| 'arrowRight'
17+
| 'compass'
18+
| 'rss'
19+
| 'menu'
20+
| 'exif';
21+
size?: number;
22+
strokeWidth?: number;
23+
class?: string;
24+
decorative?: boolean;
25+
}
26+
27+
const { name, size = 16, strokeWidth = 1.7, class: className = '', decorative = true } = Astro.props;
28+
const ariaHidden = decorative ? 'true' : undefined;
29+
---
30+
31+
<svg
32+
class={`ui-icon ${className}`}
33+
width={size}
34+
height={size}
35+
viewBox="0 0 24 24"
36+
fill="none"
37+
stroke="currentColor"
38+
stroke-width={strokeWidth}
39+
stroke-linecap="round"
40+
stroke-linejoin="round"
41+
aria-hidden={ariaHidden}
42+
focusable="false"
43+
>
44+
{name === 'article' && (
45+
<>
46+
<path d="M7 4.75h7.25L18 8.5v10.75H7z" />
47+
<path d="M14 4.75v4h4" />
48+
<path d="M9.75 12h4.5" />
49+
<path d="M9.75 15h3.25" />
50+
</>
51+
)}
52+
{name === 'camera' && (
53+
<>
54+
<path d="M4.75 8.25h3l1.2-1.9h6.1l1.2 1.9h3v9.25H4.75z" />
55+
<circle cx="12" cy="13" r="3.15" />
56+
<path d="M17.35 10.1h.02" />
57+
</>
58+
)}
59+
{name === 'tag' && (
60+
<>
61+
<path d="M5 5.75v5.7l7.2 7.2 6.45-6.45-7.2-7.2z" />
62+
<circle cx="8.55" cy="8.55" r=".65" />
63+
</>
64+
)}
65+
{name === 'about' && (
66+
<>
67+
<circle cx="12" cy="8" r="3" />
68+
<path d="M5.75 19.25c.85-3.1 3.05-5 6.25-5s5.4 1.9 6.25 5" />
69+
</>
70+
)}
71+
{name === 'notebook' && (
72+
<>
73+
<path d="M7.25 4.75h9.5v14.5h-9.5z" />
74+
<path d="M9.5 4.75v14.5" />
75+
<path d="M6 8h2.2" />
76+
<path d="M6 12h2.2" />
77+
<path d="M6 16h2.2" />
78+
</>
79+
)}
80+
{name === 'spark' && (
81+
<>
82+
<path d="M12 4.75l1.35 4.05 3.9 1.2-3.9 1.2L12 15.25l-1.35-4.05-3.9-1.2 3.9-1.2z" />
83+
<path d="M17.4 15.8l.55 1.65 1.55.5-1.55.5-.55 1.65-.55-1.65-1.55-.5 1.55-.5z" />
84+
</>
85+
)}
86+
{name === 'sun' && (
87+
<>
88+
<circle cx="12" cy="12" r="3.4" />
89+
<path d="M12 4.75v1.7" />
90+
<path d="M12 17.55v1.7" />
91+
<path d="M4.75 12h1.7" />
92+
<path d="M17.55 12h1.7" />
93+
<path d="M6.9 6.9l1.2 1.2" />
94+
<path d="M15.9 15.9l1.2 1.2" />
95+
<path d="M17.1 6.9l-1.2 1.2" />
96+
<path d="M8.1 15.9l-1.2 1.2" />
97+
</>
98+
)}
99+
{name === 'moon' && <path d="M17.85 14.65A6.1 6.1 0 0 1 9.35 6.15 6.8 6.8 0 1 0 17.85 14.65z" />}
100+
{name === 'archive' && (
101+
<>
102+
<path d="M5.25 7.25h13.5v12H5.25z" />
103+
<path d="M4.5 4.75h15v2.5h-15z" />
104+
<path d="M9.25 11h5.5" />
105+
</>
106+
)}
107+
{name === 'calendar' && (
108+
<>
109+
<path d="M5.25 6.75h13.5v12H5.25z" />
110+
<path d="M8.25 4.75v3" />
111+
<path d="M15.75 4.75v3" />
112+
<path d="M5.25 10h13.5" />
113+
</>
114+
)}
115+
{name === 'image' && (
116+
<>
117+
<path d="M4.75 6.25h14.5v11.5H4.75z" />
118+
<circle cx="9" cy="10" r="1.25" />
119+
<path d="M5.5 16.5l4.1-4.1 2.75 2.75 1.8-1.8 4.35 4.35" />
120+
</>
121+
)}
122+
{name === 'arrowLeft' && (
123+
<>
124+
<path d="M19 12H5" />
125+
<path d="M11 6l-6 6 6 6" />
126+
</>
127+
)}
128+
{name === 'arrowRight' && (
129+
<>
130+
<path d="M5 12h14" />
131+
<path d="M13 6l6 6-6 6" />
132+
</>
133+
)}
134+
{name === 'compass' && (
135+
<>
136+
<circle cx="12" cy="12" r="7.25" />
137+
<path d="M14.6 9.4l-1.45 3.75-3.75 1.45 1.45-3.75z" />
138+
</>
139+
)}
140+
{name === 'rss' && (
141+
<>
142+
<path d="M6 7.25c5.9 0 10.75 4.85 10.75 10.75" />
143+
<path d="M6 11.5A6.5 6.5 0 0 1 12.5 18" />
144+
<circle cx="7.1" cy="16.9" r="1.1" />
145+
</>
146+
)}
147+
{name === 'menu' && (
148+
<>
149+
<path d="M6.5 8h11" />
150+
<path d="M6.5 12h11" />
151+
<path d="M6.5 16h11" />
152+
</>
153+
)}
154+
{name === 'exif' && (
155+
<>
156+
<circle cx="12" cy="12" r="7.25" />
157+
<path d="M12 8.25v3.9" />
158+
<path d="M12 15.75h.01" />
159+
<path d="M16.4 9.2l-1.5 1" />
160+
<path d="M7.6 9.2l1.5 1" />
161+
</>
162+
)}
163+
</svg>

0 commit comments

Comments
 (0)