Skip to content

Commit 70f5446

Browse files
committed
fix(blog): 한글 글 경로와 모바일 쉘 정렬 수정
1 parent aa120f2 commit 70f5446

6 files changed

Lines changed: 82 additions & 12 deletions

File tree

blog/services/post-repository.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ ${'x'.repeat(5000)}
9797
expect(await getFeedData(privateSlug)).toBeNull();
9898
});
9999

100+
it('resolves percent-encoded slugs', () => {
101+
const slug = '말하는-구조를-잃어버린-것-같았다';
102+
103+
expect(getFolderSlug(encodeURIComponent(slug))).toBe(slug);
104+
});
105+
100106
it('returns null for non-existent posts folder slug', () => {
101107
expect(getFolderSlug('missing-folder-slug')).toBeNull();
102108
});

blog/services/post-repository.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ const shouldLogContentIssues = process.env.NODE_ENV !== 'test';
1616
const slugToFolderCache = new Map<string, string>();
1717
let cachedSortedFeedData: FeedData[] | null = null;
1818

19+
function normalizeSlug(slug: string): string {
20+
try {
21+
return decodeURIComponent(slug);
22+
} catch {
23+
return slug;
24+
}
25+
}
26+
1927
function logContentIssue(message: string): void {
2028
if (!shouldLogContentIssues) {
2129
return;
@@ -252,15 +260,17 @@ function loadMetadata(folderPath: string): FeedFrontmatter | null {
252260

253261
// Get folder path from slug (using cache or scanning)
254262
export function getFolderSlug(slug: string): string | null {
263+
const normalizedSlug = normalizeSlug(slug);
264+
255265
// Check cache first
256-
if (slugToFolderCache.has(slug)) {
257-
return slugToFolderCache.get(slug)!;
266+
if (slugToFolderCache.has(normalizedSlug)) {
267+
return slugToFolderCache.get(normalizedSlug)!;
258268
}
259269

260270
// Populate slug cache by loading full feed index first
261271
getSortedFeedData({ includePrivate: true });
262-
if (slugToFolderCache.has(slug)) {
263-
return slugToFolderCache.get(slug)!;
272+
if (slugToFolderCache.has(normalizedSlug)) {
273+
return slugToFolderCache.get(normalizedSlug)!;
264274
}
265275

266276
if (isProduction) {
@@ -272,7 +282,7 @@ export function getFolderSlug(slug: string): string | null {
272282

273283
for (const folderPath of allFolders) {
274284
const metadata = loadMetadata(folderPath);
275-
if (metadata?.slug === slug) {
285+
if (metadata?.slug === normalizedSlug) {
276286
return folderPath;
277287
}
278288
}

site/shell/AppShell/AppShell.test.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ vi.mock('next/navigation', () => ({
88
}));
99

1010
describe('AppShell', () => {
11-
it('keeps Archive and Resume visible with external links in the identity rail', () => {
11+
it('keeps primary navigation and external links available', () => {
1212
const { container } = render(
1313
<AppShell>
1414
<main>content</main>
@@ -27,10 +27,9 @@ describe('AppShell', () => {
2727
primaryNavigation.queryByRole('link', { name: 'Tech' })
2828
).not.toBeInTheDocument();
2929
expect(screen.getAllByLabelText('Ark 외부 링크')).toHaveLength(1);
30-
expect(container.querySelector('.ark-site-identity')).toContainElement(
30+
expect(container.querySelector('footer')).toContainElement(
3131
screen.getByLabelText('Ark 외부 링크')
3232
);
33-
expect(container.querySelector('footer')).toBeNull();
3433
expect(
3534
container.querySelector('[data-page-layout="home"]')
3635
).toBeInTheDocument();

site/shell/AppShell/AppShell.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,14 @@ export default function AppShell({ children }: AppShellProps) {
8484
ark
8585
</Link>
8686
</header>
87-
<ExternalLinks />
8887
</aside>
8988

9089
<div className="ark-site-content">{children}</div>
9190

91+
<footer className="ark-site-footer">
92+
<ExternalLinks />
93+
</footer>
94+
9295
<nav aria-label="Ark 주요 탐색" className="ark-site-navigation">
9396
{PRIMARY_LINKS.map((item) => {
9497
const isActive = item.isActive(pathname);

styles/globals.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@
6060
min-width: 0;
6161
}
6262

63+
.ark-site-footer {
64+
grid-column: 1;
65+
grid-row: 1;
66+
align-self: end;
67+
}
68+
6369
.ark-home-statement {
6470
max-width: 34rem;
6571
margin: 0;
@@ -164,7 +170,7 @@
164170
.ark-site-external-links {
165171
display: flex;
166172
flex-direction: column;
167-
margin-top: auto;
173+
margin-top: 0;
168174
pointer-events: auto;
169175
}
170176

styles/viewport/mobile.css

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
grid-template-areas:
1010
'identity'
1111
'navigation'
12-
'content';
12+
'content'
13+
'footer';
1314
row-gap: var(--space-4);
1415
min-height: auto;
1516
}
@@ -38,6 +39,10 @@
3839
grid-area: content;
3940
}
4041

42+
.ark-site-footer {
43+
grid-area: footer;
44+
}
45+
4146
.ark-site-navigation {
4247
grid-area: navigation;
4348
flex-direction: row;
@@ -77,7 +82,6 @@
7782
}
7883

7984
.ark-site-grid[data-page-layout='home'] .ark-site-external-links {
80-
grid-area: external;
8185
display: flex;
8286
flex-direction: column;
8387
align-self: end;
@@ -87,6 +91,48 @@
8791
margin-bottom: var(--space-8);
8892
}
8993

94+
.ark-site-grid[data-page-layout='home'] .ark-site-footer {
95+
grid-area: external;
96+
align-self: end;
97+
justify-self: start;
98+
margin-bottom: var(--space-8);
99+
}
100+
101+
.ark-site-grid[data-page-layout='content'] {
102+
grid-template-columns: minmax(0, 1fr) auto;
103+
grid-template-areas:
104+
'identity navigation'
105+
'content content'
106+
'footer footer';
107+
column-gap: var(--space-4);
108+
}
109+
110+
.ark-site-grid[data-page-layout='content'] .ark-site-navigation {
111+
grid-area: navigation;
112+
flex-direction: row;
113+
align-self: center;
114+
justify-self: end;
115+
gap: var(--space-4);
116+
padding-top: 0;
117+
}
118+
119+
.ark-site-grid[data-page-layout='content'] .ark-site-content {
120+
grid-area: content;
121+
}
122+
123+
.ark-site-grid[data-page-layout='content'] .ark-site-footer {
124+
grid-area: footer;
125+
border-top: 1px solid var(--color-divider);
126+
padding-top: var(--space-6);
127+
padding-bottom: var(--space-2);
128+
}
129+
130+
.ark-site-grid[data-page-layout='content'] .ark-site-external-links {
131+
flex-direction: row;
132+
justify-content: center;
133+
gap: var(--space-4);
134+
}
135+
90136
.ark-site-grid[data-page-layout='home'] .ark-site-content {
91137
grid-area: content;
92138
align-self: start;

0 commit comments

Comments
 (0)