Skip to content

Commit 8e5e59c

Browse files
committed
fix: timer leak, observer leak, withAlpha helper, colophon hostname
- CelebrationEffect: guard recursive setTimeout against unmount race - SearchWithAlgolia: reuse single dropdownObserver instead of leaking per open - BlogColophon: derive hostname from URL instead of hardcoding "Medium" - theme.ts: extract withAlpha helper, replace 6 brittle slice(0,-1) patterns - Nav: replace bare wrapper div with Fragment - Navbar: reduce backdrop blur 12px → 8px
1 parent ef58212 commit 8e5e59c

6 files changed

Lines changed: 26 additions & 14 deletions

File tree

components/BlogMeta.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function BlogColophon({ author, originalUrl }: { author: string; original
6363
<ColophonNote>
6464
Originally published on{' '}
6565
<Link href={originalUrl} variant="inline">
66-
Medium
66+
{new URL(originalUrl).hostname.replace('www.', '')}
6767
</Link>
6868
.
6969
</ColophonNote>

components/CelebrationEffect.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,12 @@ export default function CelebrationEffect() {
328328

329329
spawnFirework();
330330
let timer: ReturnType<typeof setTimeout>;
331+
let stopped = false;
331332

332333
function scheduleNext() {
333334
timer = setTimeout(
334335
() => {
336+
if (stopped) return;
335337
spawnFirework();
336338
scheduleNext();
337339
},
@@ -340,7 +342,10 @@ export default function CelebrationEffect() {
340342
}
341343
scheduleNext();
342344

343-
return () => clearTimeout(timer);
345+
return () => {
346+
stopped = true;
347+
clearTimeout(timer);
348+
};
344349
}, []);
345350

346351
// fwId/particleId come from data attributes rather than a per-particle

components/Nav/Navbar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export default function Navbar({ onSideToggle, isSideFolded }: NavbarProps) {
3737
const Wrapper = styled.nav.attrs({ 'aria-label': 'Main' })<{ children?: React.ReactNode }>`
3838
align-items: center;
3939
background-color: ${theme.color.navBg};
40-
backdrop-filter: blur(12px);
41-
-webkit-backdrop-filter: blur(12px);
40+
backdrop-filter: blur(8px);
41+
-webkit-backdrop-filter: blur(8px);
4242
box-sizing: border-box;
4343
color: ${theme.color.navText};
4444
display: flex;

components/Nav/SearchWithAlgolia.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function injectStartScreen(modal: Element, latestPost: LatestPost) {
6060
let docSearchInitialized = false;
6161
let docSearchTarget: HTMLDivElement | null = null;
6262
let modalObserver: MutationObserver | null = null;
63+
let dropdownObserver: MutationObserver | null = null;
6364

6465
function initDocSearch(container: HTMLElement, latestPost: LatestPost, onReady: () => void) {
6566
if (docSearchInitialized) {
@@ -83,11 +84,13 @@ function initDocSearch(container: HTMLElement, latestPost: LatestPost, onReady:
8384
injectStartScreen(node, latestPost);
8485
const dropdown = node.querySelector('.DocSearch-Dropdown');
8586
if (dropdown) {
86-
new MutationObserver(() => {
87+
if (dropdownObserver) dropdownObserver.disconnect();
88+
dropdownObserver = new MutationObserver(() => {
8789
if (!dropdown.querySelector('.DocSearch-Dropdown-Container')) {
8890
injectStartScreen(node, latestPost);
8991
}
90-
}).observe(dropdown, { childList: true });
92+
});
93+
dropdownObserver.observe(dropdown, { childList: true });
9194
}
9295
}
9396
}

components/Nav/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ export interface NavProps {
1414

1515
const Nav = ({ isSideFolded, onSideToggle, latestPost }: NavProps) => {
1616
return (
17-
<div>
17+
<>
1818
<Navbar isSideFolded={isSideFolded} onSideToggle={onSideToggle} />
1919

2020
<Sidebar $isFolded={isSideFolded}>
2121
<SidebarMenu latestPost={latestPost} />
2222
</Sidebar>
23-
</div>
23+
</>
2424
);
2525
};
2626

utils/theme.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { createTheme } from 'styled-components';
22

3+
function withAlpha(oklch: string, alpha: number): string {
4+
return `${oklch.slice(0, -1)} / ${alpha})`;
5+
}
6+
37
// Neutral hue for achromatic code tokens (text, comment, punctuation, variable)
48
const CODE_NEUTRAL = 54;
59
const CODE_NEUTRAL_DARK = 270; // cooler neutral for dark mode
@@ -53,7 +57,7 @@ export const lightTheme = {
5357
accentLight: 'oklch(0.76 0.18 266.6)',
5458
accentLighter: 'oklch(0.85 0.12 266.6)',
5559
accentDark: 'oklch(0.56 0.22 266.6)',
56-
accentSubtle: `${lightPalette[13].slice(0, -1)} / 0.08)`,
60+
accentSubtle: withAlpha(lightPalette[13], 0.08),
5761

5862
// Borders
5963
border: 'oklch(0 0 0 / 0.1)',
@@ -75,8 +79,8 @@ export const lightTheme = {
7579

7680
// Blog (derived from P[2] warm amber ~65°)
7781
blogAccent: lightPalette[2],
78-
blogAccentSubtle: `${lightPalette[2].slice(0, -1)} / 0.08)`,
79-
blogAccentMuted: `${lightPalette[2].slice(0, -1)} / 0.4)`,
82+
blogAccentSubtle: withAlpha(lightPalette[2], 0.08),
83+
blogAccentMuted: withAlpha(lightPalette[2], 0.4),
8084

8185
// Nav (glassmorphism)
8286
navBg: 'oklch(1 0 0 / 0.85)',
@@ -211,15 +215,15 @@ export const darkColors: Partial<typeof lightTheme.color> = {
211215
accentLight: 'oklch(0.76 0.18 264.5)',
212216
accentLighter: 'oklch(0.85 0.12 264.5)',
213217
accentDark: 'oklch(0.56 0.18 264.5)',
214-
accentSubtle: `${darkPalette[13].slice(0, -1)} / 0.15)`,
218+
accentSubtle: withAlpha(darkPalette[13], 0.15),
215219
border: 'oklch(1 0 0 / 0.1)',
216220
borderStrong: 'oklch(1 0 0 / 0.15)',
217221
shadow: 'oklch(0 0 0 / 0.4)',
218222
selection: 'oklch(0.6 0.12 290 / 0.3)',
219223
linkUnderline: 'oklch(1 0 0 / 0.2)',
220224
linkUnderlineHover: 'oklch(1 0 0 / 0.45)',
221-
blogAccentSubtle: `${darkPalette[2].slice(0, -1)} / 0.12)`,
222-
blogAccentMuted: `${darkPalette[2].slice(0, -1)} / 0.25)`,
225+
blogAccentSubtle: withAlpha(darkPalette[2], 0.12),
226+
blogAccentMuted: withAlpha(darkPalette[2], 0.25),
223227
navBg: 'oklch(0.1 0.01 270 / 0.85)',
224228
navText: 'oklch(0.95 0 0)',
225229
codeBg: 'oklch(0.18 0.01 270)',

0 commit comments

Comments
 (0)