Skip to content

Commit bbd52e3

Browse files
committed
tt
1 parent 66b8e2b commit bbd52e3

File tree

5 files changed

+184
-264
lines changed

5 files changed

+184
-264
lines changed

src/components/MobileHeader.astro

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
---
2+
import LanguageToggle from './LanguageToggle.astro';
3+
import { NAV_TEXT, HOME_TEXT, COMMON_TEXT } from '../i18n/ui';
4+
import { getLocalePrefix, type Locale } from '../i18n/config';
5+
import { isActiveLink as checkActiveLink } from '../utils/linkUtils';
6+
7+
interface Props {
8+
locale: Locale;
9+
currentPath: string;
10+
languageToggleTargetPath?: string;
11+
languageToggleDisabled?: boolean;
12+
}
13+
14+
const { locale, currentPath, languageToggleTargetPath, languageToggleDisabled = false } = Astro.props;
15+
16+
const nav = NAV_TEXT[locale];
17+
const home = HOME_TEXT[locale];
18+
const common = COMMON_TEXT[locale];
19+
const localePrefix = getLocalePrefix(locale);
20+
const buildPath = (path: string) => path.replace(/\/{2,}/g, '/');
21+
22+
const navLinks = [
23+
{ href: buildPath(`${localePrefix || '/'}`), label: nav.home },
24+
{ href: buildPath(`${localePrefix}/archive`), label: nav.archive },
25+
{ href: buildPath(`${localePrefix}/tags`), label: nav.tags },
26+
];
27+
28+
const isActiveLink = (href: string) => checkActiveLink(href, currentPath);
29+
---
30+
31+
<header class="mobile-header">
32+
<button
33+
id="mobile-nav-toggle"
34+
class="mobile-site-title"
35+
type="button"
36+
aria-expanded="false"
37+
aria-controls="mobile-nav-menu"
38+
>
39+
{home.siteTitle}
40+
<span class="mobile-nav-caret">▾</span>
41+
</button>
42+
<div class="mobile-controls">
43+
<LanguageToggle class="mobile-lang-toggle" targetPath={languageToggleTargetPath} disabled={languageToggleDisabled} />
44+
<button class="theme-toggle mobile-theme-toggle" type="button" aria-label={common.themeToggle}>
45+
<span id="mobile-theme-icon">○</span>
46+
</button>
47+
</div>
48+
</header>
49+
<nav class="mobile-nav-menu" id="mobile-nav-menu">
50+
<ul>
51+
{navLinks.map((link) => {
52+
const isActive = isActiveLink(link.href);
53+
return (
54+
<li>
55+
<a href={link.href} class={isActive ? 'mobile-nav-link active' : 'mobile-nav-link'}>{link.label}</a>
56+
</li>
57+
);
58+
})}
59+
</ul>
60+
</nav>

src/components/Sidebar.astro

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
import { NAV_TEXT, HOME_TEXT } from '../i18n/ui';
3+
import { getLocalePrefix, type Locale } from '../i18n/config';
4+
import { isActiveLink as checkActiveLink } from '../utils/linkUtils';
5+
6+
interface Props {
7+
locale: Locale;
8+
currentPath: string;
9+
}
10+
11+
const { locale, currentPath } = Astro.props;
12+
13+
const nav = NAV_TEXT[locale];
14+
const home = HOME_TEXT[locale];
15+
const localePrefix = getLocalePrefix(locale);
16+
const buildPath = (path: string) => path.replace(/\/{2,}/g, '/');
17+
18+
const navLinks = [
19+
{ href: buildPath(`${localePrefix || '/'}`), label: nav.home },
20+
{ href: buildPath(`${localePrefix}/archive`), label: nav.archive },
21+
{ href: buildPath(`${localePrefix}/tags`), label: nav.tags },
22+
];
23+
24+
const isActiveLink = (href: string) => checkActiveLink(href, currentPath);
25+
---
26+
27+
<aside class="sidebar">
28+
<div class="sidebar-header">
29+
<h1 class="site-title">
30+
<a href={buildPath(`${localePrefix || '/'}`)}>{home.siteTitle}</a>
31+
</h1>
32+
</div>
33+
34+
<nav class="main-nav">
35+
<div class="nav-section">
36+
<h3 class="nav-section-title">{nav.navigate}</h3>
37+
<ul class="nav-links">
38+
{navLinks.map((link) => {
39+
const isActive = isActiveLink(link.href);
40+
return (
41+
<li>
42+
<a href={link.href} class={isActive ? 'nav-link nav-link-active' : 'nav-link'}>
43+
{link.label}
44+
</a>
45+
</li>
46+
);
47+
})}
48+
</ul>
49+
</div>
50+
51+
<div class="nav-section">
52+
<h3 class="nav-section-title">{nav.links}</h3>
53+
<ul class="nav-links">
54+
<li>
55+
<a href="https://github.com/hwisu" target="_blank" rel="noopener" class="nav-link">
56+
{nav.github}
57+
<span class="external-indicator" aria-hidden="true">↗</span>
58+
</a>
59+
</li>
60+
<li>
61+
<a href="https://www.linkedin.com/in/hwisu/" target="_blank" rel="noopener" class="nav-link">
62+
{nav.linkedin}
63+
<span class="external-indicator" aria-hidden="true">↗</span>
64+
</a>
65+
</li>
66+
</ul>
67+
</div>
68+
</nav>
69+
</aside>
Lines changed: 38 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
---
2-
import { ViewTransitions } from 'astro:transitions';
2+
import BaseLayout from '../../layouts/BaseLayout.astro';
33
import { getCollection, type CollectionEntry } from 'astro:content';
44
import readingTime from 'reading-time';
5-
import LanguageToggle from '../LanguageToggle.astro';
6-
import { COMMON_TEXT, NAV_TEXT, HOME_TEXT, POST_TEXT } from '../../i18n/ui';
7-
import { getLocalePrefix, resolveLocale, type Locale } from '../../i18n/config';
8-
import { isActiveLink as checkActiveLink } from '../../utils/linkUtils';
5+
import { HOME_TEXT, POST_TEXT } from '../../i18n/ui';
6+
import { getLocalePrefix, type Locale } from '../../i18n/config';
97
import { formatDate } from '../../utils/dateFormatter';
10-
import '../../styles/global.css';
11-
import mainScript from '../../scripts/main.js?url';
128
139
interface Props {
1410
locale: Locale;
@@ -32,176 +28,51 @@ const postsWithContent = await Promise.all(
3228
);
3329
3430
const localePrefix = getLocalePrefix(locale);
35-
const nav = NAV_TEXT[locale];
36-
const common = COMMON_TEXT[locale];
3731
const home = HOME_TEXT[locale];
3832
const postText = POST_TEXT[locale];
3933
const buildPath = (path: string) => path.replace(/\/{2,}/g, '/');
40-
const navLinks = [
41-
{ href: buildPath(`${localePrefix || '/'}`), label: nav.home },
42-
{ href: buildPath(`${localePrefix}/archive`), label: nav.archive },
43-
{ href: buildPath(`${localePrefix}/tags`), label: nav.tags },
44-
];
4534
const tagsPageHref = buildPath(`${localePrefix}/tags`);
46-
const currentPath = Astro.url.pathname;
47-
const isActiveLink = (href: string) => checkActiveLink(href, currentPath);
4835
---
4936

50-
<!DOCTYPE html>
51-
<html lang={locale}>
52-
<head>
53-
<meta charset="UTF-8" />
54-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
55-
<title>{home.siteTitle}</title>
56-
<meta name="description" content={home.siteDescription} />
57-
58-
<!-- Fonts -->
59-
<link rel="preconnect" href="https://fonts.googleapis.com" />
60-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
61-
<link href="https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&display=block" rel="stylesheet" />
62-
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200..900&display=block" rel="stylesheet" />
63-
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&display=block" rel="stylesheet" />
64-
65-
<!-- Icons -->
66-
<link rel="icon" type="image/x-icon" href="/static/favicon.ico" />
67-
<link rel="icon" type="image/png" sizes="16x16" href="/static/favicon-16x16.png" />
68-
<link rel="icon" type="image/png" sizes="32x32" href="/static/favicon-32x32.png" />
69-
70-
<!-- RSS -->
71-
<link rel="alternate" type="application/rss+xml" title="Code Brewer RSS Feed" href="/feed.xml" />
37+
<BaseLayout title={home.siteTitle} description={home.siteDescription}>
38+
{postsWithContent.map(({ post, Content, readingTime, pathSlug }, index) => {
39+
const formattedDate = formatDate(post.data.date, locale);
7240

73-
<ViewTransitions />
74-
</head>
75-
<body>
76-
<!-- Mobile Header -->
77-
<header class="mobile-header">
78-
<button
79-
id="mobile-nav-toggle"
80-
class="mobile-site-title"
81-
type="button"
82-
aria-expanded="false"
83-
aria-controls="mobile-nav-menu"
41+
const readingMinutes = Math.ceil(readingTime);
42+
const readingTimeText = locale === 'ko'
43+
? `${readingMinutes}${postText.readingTime}`
44+
: `${readingMinutes} ${postText.readingTime}`;
45+
const postHref = `${localePrefix}/posts/${pathSlug}`.replace(/\/\//g, '/');
46+
return (
47+
<article
48+
class="post-article"
49+
id={pathSlug}
50+
data-index={index}
51+
data-lang={locale}
52+
data-translation-key={post.data.translationKey || ''}
8453
>
85-
{home.siteTitle}
86-
<span class="mobile-nav-caret">▾</span>
87-
</button>
88-
<div class="mobile-controls">
89-
<LanguageToggle class="mobile-lang-toggle" />
90-
<button class="theme-toggle mobile-theme-toggle" type="button" aria-label={common.themeToggle}>
91-
<span id="mobile-theme-icon">○</span>
92-
</button>
93-
</div>
94-
</header>
95-
<nav class="mobile-nav-menu" id="mobile-nav-menu" hidden>
96-
<ul>
97-
{navLinks.map((link) => {
98-
const isActive = isActiveLink(link.href);
99-
return (
100-
<li>
101-
<a href={link.href} class={isActive ? 'mobile-nav-link active' : 'mobile-nav-link'}>{link.label}</a>
102-
</li>
103-
);
104-
})}
105-
</ul>
106-
</nav>
107-
108-
<div class="layout-container">
109-
<!-- Left Sidebar -->
110-
<aside class="sidebar">
111-
<div class="sidebar-header">
112-
<h1 class="site-title">
113-
<a href={`${localePrefix || '/'}`}>{home.siteTitle}</a>
54+
<header class="post-header">
55+
<h1>
56+
<a href={postHref} class="post-title-link">{post.data.title}</a>
11457
</h1>
115-
</div>
116-
117-
<!-- Main Navigation Menu -->
118-
<nav class="main-nav">
119-
<div class="nav-section">
120-
<h3 class="nav-section-title">{nav.navigate}</h3>
121-
<ul class="nav-links">
122-
{navLinks.map((link) => (
123-
<li>
124-
<a href={link.href} class={isActiveLink(link.href) ? 'nav-link nav-link-active' : 'nav-link'}>
125-
{link.label}
126-
</a>
127-
</li>
128-
))}
129-
</ul>
58+
<div class="post-meta">
59+
<time datetime={post.data.date.toISOString()}>{formattedDate}</time>
60+
<span class="reading-time">{readingTimeText}</span>
13061
</div>
131-
132-
<div class="nav-section">
133-
<h3 class="nav-section-title">{nav.links}</h3>
134-
<ul class="nav-links">
135-
<li>
136-
<a href="https://github.com/hwisu" target="_blank" rel="noopener" class="nav-link">
137-
{nav.github}
138-
<span class="external-indicator" aria-hidden="true">↗</span>
139-
</a>
140-
</li>
141-
<li>
142-
<a href="https://www.linkedin.com/in/hwisu/" target="_blank" rel="noopener" class="nav-link">
143-
{nav.linkedin}
144-
<span class="external-indicator" aria-hidden="true">↗</span>
145-
</a>
146-
</li>
147-
</ul>
62+
<div class="post-tags">
63+
{post.data.tags.map(tag => {
64+
const tagSearchHref = `${tagsPageHref}?q=${encodeURIComponent(tag)}`;
65+
return (
66+
<a href={tagSearchHref} class="tag">{tag}</a>
67+
);
68+
})}
14869
</div>
149-
</nav>
150-
</aside>
70+
</header>
15171

152-
<!-- Right Content Area -->
153-
<main class="content-area">
154-
<div class="content-shell">
155-
<div class="content-controls">
156-
<LanguageToggle />
157-
<button class="theme-toggle" type="button" aria-label={common.themeToggle}>
158-
<span id="theme-icon">○</span>
159-
</button>
160-
</div>
161-
{postsWithContent.map(({ post, Content, readingTime, pathSlug }, index) => {
162-
const formattedDate = formatDate(post.data.date, locale);
163-
164-
const readingMinutes = Math.ceil(readingTime);
165-
const readingTimeText = locale === 'ko'
166-
? `${readingMinutes}${postText.readingTime}`
167-
: `${readingMinutes} ${postText.readingTime}`;
168-
const postHref = `${localePrefix}/posts/${pathSlug}`.replace(/\/\//g, '/');
169-
return (
170-
<article
171-
class="post-article"
172-
id={pathSlug}
173-
data-index={index}
174-
data-lang={locale}
175-
data-translation-key={post.data.translationKey || ''}
176-
>
177-
<header class="post-header">
178-
<h1>
179-
<a href={postHref} class="post-title-link">{post.data.title}</a>
180-
</h1>
181-
<div class="post-meta">
182-
<time datetime={post.data.date.toISOString()}>{formattedDate}</time>
183-
<span class="reading-time">{readingTimeText}</span>
184-
</div>
185-
<div class="post-tags">
186-
{post.data.tags.map(tag => {
187-
const tagSearchHref = `${tagsPageHref}?q=${encodeURIComponent(tag)}`;
188-
return (
189-
<a href={tagSearchHref} class="tag">{tag}</a>
190-
);
191-
})}
192-
</div>
193-
</header>
194-
195-
<div class="post-content">
196-
<Content />
197-
</div>
198-
</article>
199-
);
200-
})}
72+
<div class="post-content">
73+
<Content />
20174
</div>
202-
</main>
203-
</div>
204-
205-
<script is:inline type="module" src={mainScript}></script>
206-
</body>
207-
</html>
75+
</article>
76+
);
77+
})}
78+
</BaseLayout>

0 commit comments

Comments
 (0)