From 70f5446f9162a31196d4e8c4aaf36d527b409e05 Mon Sep 17 00:00:00 2001 From: dev-wooyeon Date: Mon, 27 Jul 2026 10:50:56 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix(blog):=20=ED=95=9C=EA=B8=80=20=EA=B8=80?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=EC=99=80=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=EC=89=98=20=EC=A0=95=EB=A0=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog/services/post-repository.test.ts | 6 ++++ blog/services/post-repository.ts | 20 ++++++++--- site/shell/AppShell/AppShell.test.tsx | 5 ++- site/shell/AppShell/AppShell.tsx | 5 ++- styles/globals.css | 8 ++++- styles/viewport/mobile.css | 50 +++++++++++++++++++++++++-- 6 files changed, 82 insertions(+), 12 deletions(-) diff --git a/blog/services/post-repository.test.ts b/blog/services/post-repository.test.ts index ddf14c6..1526993 100644 --- a/blog/services/post-repository.test.ts +++ b/blog/services/post-repository.test.ts @@ -97,6 +97,12 @@ ${'x'.repeat(5000)} expect(await getFeedData(privateSlug)).toBeNull(); }); + it('resolves percent-encoded slugs', () => { + const slug = '말하는-구조를-잃어버린-것-같았다'; + + expect(getFolderSlug(encodeURIComponent(slug))).toBe(slug); + }); + it('returns null for non-existent posts folder slug', () => { expect(getFolderSlug('missing-folder-slug')).toBeNull(); }); diff --git a/blog/services/post-repository.ts b/blog/services/post-repository.ts index d1aed68..44c04b6 100644 --- a/blog/services/post-repository.ts +++ b/blog/services/post-repository.ts @@ -16,6 +16,14 @@ const shouldLogContentIssues = process.env.NODE_ENV !== 'test'; const slugToFolderCache = new Map(); let cachedSortedFeedData: FeedData[] | null = null; +function normalizeSlug(slug: string): string { + try { + return decodeURIComponent(slug); + } catch { + return slug; + } +} + function logContentIssue(message: string): void { if (!shouldLogContentIssues) { return; @@ -252,15 +260,17 @@ function loadMetadata(folderPath: string): FeedFrontmatter | null { // Get folder path from slug (using cache or scanning) export function getFolderSlug(slug: string): string | null { + const normalizedSlug = normalizeSlug(slug); + // Check cache first - if (slugToFolderCache.has(slug)) { - return slugToFolderCache.get(slug)!; + if (slugToFolderCache.has(normalizedSlug)) { + return slugToFolderCache.get(normalizedSlug)!; } // Populate slug cache by loading full feed index first getSortedFeedData({ includePrivate: true }); - if (slugToFolderCache.has(slug)) { - return slugToFolderCache.get(slug)!; + if (slugToFolderCache.has(normalizedSlug)) { + return slugToFolderCache.get(normalizedSlug)!; } if (isProduction) { @@ -272,7 +282,7 @@ export function getFolderSlug(slug: string): string | null { for (const folderPath of allFolders) { const metadata = loadMetadata(folderPath); - if (metadata?.slug === slug) { + if (metadata?.slug === normalizedSlug) { return folderPath; } } diff --git a/site/shell/AppShell/AppShell.test.tsx b/site/shell/AppShell/AppShell.test.tsx index 9b2ee37..87cfce3 100644 --- a/site/shell/AppShell/AppShell.test.tsx +++ b/site/shell/AppShell/AppShell.test.tsx @@ -8,7 +8,7 @@ vi.mock('next/navigation', () => ({ })); describe('AppShell', () => { - it('keeps Archive and Resume visible with external links in the identity rail', () => { + it('keeps primary navigation and external links available', () => { const { container } = render(
content
@@ -27,10 +27,9 @@ describe('AppShell', () => { primaryNavigation.queryByRole('link', { name: 'Tech' }) ).not.toBeInTheDocument(); expect(screen.getAllByLabelText('Ark 외부 링크')).toHaveLength(1); - expect(container.querySelector('.ark-site-identity')).toContainElement( + expect(container.querySelector('footer')).toContainElement( screen.getByLabelText('Ark 외부 링크') ); - expect(container.querySelector('footer')).toBeNull(); expect( container.querySelector('[data-page-layout="home"]') ).toBeInTheDocument(); diff --git a/site/shell/AppShell/AppShell.tsx b/site/shell/AppShell/AppShell.tsx index 84507d7..745d0b5 100644 --- a/site/shell/AppShell/AppShell.tsx +++ b/site/shell/AppShell/AppShell.tsx @@ -84,11 +84,14 @@ export default function AppShell({ children }: AppShellProps) { ark -
{children}
+
+ +
+