Skip to content

Commit 46b2a1b

Browse files
authored
Merge pull request #40 from Han5991/feature/blog-home-posts
feat: 홈 화면 개선 및 UX/SEO 최적화
2 parents 68bd4af + 8b22a45 commit 46b2a1b

File tree

11 files changed

+397
-107
lines changed

11 files changed

+397
-107
lines changed

apps/blog/web/lib/database.types.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,24 @@ export type Json =
99
export type Database = {
1010
public: {
1111
Tables: {
12-
[_ in never]: never;
12+
post_views: {
13+
Row: {
14+
slug: string;
15+
view_count: number;
16+
updated_at: string;
17+
};
18+
Insert: {
19+
slug: string;
20+
view_count?: number;
21+
updated_at?: string;
22+
};
23+
Update: {
24+
slug?: string;
25+
view_count?: number;
26+
updated_at?: string;
27+
};
28+
Relationships: [];
29+
};
1330
};
1431
Views: {
1532
[_ in never]: never;
Lines changed: 19 additions & 0 deletions
Loading

apps/blog/web/public/sitemap.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
33
<url>
44
<loc>https://blog.sangwook.dev/</loc>
5-
<lastmod>2026-01-25</lastmod>
5+
<lastmod>2026-01-31</lastmod>
66
<priority>1.0</priority>
77
</url>
88
<url>
99
<loc>https://blog.sangwook.dev/posts/</loc>
10-
<lastmod>2026-01-25</lastmod>
10+
<lastmod>2026-01-31</lastmod>
1111
<priority>0.8</priority>
1212
</url>
1313

apps/blog/web/src/app/page.tsx

Lines changed: 122 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,159 @@
11
import Link from 'next/link';
22
import { css } from '@design-system/ui-lib/css';
33
import { SsgoiTransition } from '@ssgoi/react';
4+
import { getAllPosts } from '@/lib/posts';
5+
import { TopPosts } from '@/src/components/home/TopPosts';
6+
import { PostCard } from '@/src/components/home/PostCard';
47

58
export default function HomePage() {
9+
const allPosts = getAllPosts();
10+
const recentPosts = allPosts.slice(0, 3);
11+
612
return (
713
<SsgoiTransition id="/">
814
<div
915
className={css({
10-
minHeight: 'calc(100lvh - 231px)', // Deducting nav height
11-
display: 'flex',
12-
flexDirection: 'column',
13-
alignItems: 'center',
14-
justifyContent: 'center',
16+
minHeight: 'calc(100lvh - 231px)',
1517
bg: 'white',
16-
px: '6',
17-
textAlign: 'center',
1818
})}
1919
>
20-
<main
20+
{/* Hero Section */}
21+
<div
2122
className={css({
22-
maxWidth: '2xl',
23-
w: 'full',
23+
display: 'flex',
24+
flexDirection: 'column',
25+
alignItems: 'center',
26+
justifyContent: 'center',
27+
py: '20',
28+
px: '6',
29+
textAlign: 'center',
30+
bg: 'gray.50',
31+
borderBottomWidth: '1px',
32+
borderColor: 'gray.100',
2433
})}
2534
>
26-
<div
27-
className={css({
28-
display: 'inline-block',
29-
px: '3',
30-
py: '1',
31-
rounded: 'full',
32-
bg: 'blue.50',
33-
color: 'blue.600',
34-
fontSize: 'xs',
35-
fontWeight: 'semibold',
36-
mb: '6',
37-
borderWidth: '1px',
38-
borderColor: 'blue.100',
39-
})}
40-
>
41-
Welcome to FE Lab
42-
</div>
43-
<h1
44-
className={css({
45-
fontSize: { base: '5xl', md: '7xl' },
46-
fontWeight: 'extrabold',
47-
letterSpacing: 'tight',
48-
lineHeight: '1.1',
49-
mb: '6',
50-
color: 'gray.900',
51-
})}
52-
>
53-
Frontend <br />
54-
<span
35+
<main className={css({ maxWidth: '2xl', w: 'full' })}>
36+
<div
5537
className={css({
56-
bgGradient: 'to-r',
57-
gradientFrom: 'blue.600',
58-
gradientTo: 'purple.600',
59-
bgClip: '[text]',
60-
color: 'transparent',
38+
display: 'inline-block',
39+
px: '3',
40+
py: '1',
41+
rounded: 'full',
42+
bg: 'blue.50',
43+
color: 'blue.600',
44+
fontSize: 'xs',
45+
fontWeight: 'semibold',
46+
mb: '6',
47+
borderWidth: '1px',
48+
borderColor: 'blue.100',
6149
})}
6250
>
63-
Experiment Lab
64-
</span>
65-
</h1>
66-
<p
67-
className={css({
68-
fontSize: { base: 'lg', md: 'xl' },
69-
color: 'gray.600',
70-
mb: '10',
71-
lineHeight: 'relaxed',
72-
})}
73-
>
74-
번들러 밑바닥부터 대규모 아키텍처까지, <br />
75-
실험하고 기록하며 성장하는 프론트엔드 엔지니어의 공간입니다.
76-
</p>
51+
Welcome to FE Lab
52+
</div>
53+
<h1
54+
className={css({
55+
fontSize: { base: '5xl', md: '7xl' },
56+
fontWeight: 'extrabold',
57+
letterSpacing: 'tight',
58+
lineHeight: '1.1',
59+
mb: '6',
60+
color: 'gray.900',
61+
})}
62+
>
63+
Frontend <br />
64+
<span
65+
className={css({
66+
bgGradient: 'to-r',
67+
gradientFrom: 'blue.600',
68+
gradientTo: 'purple.600',
69+
bgClip: '[text]',
70+
color: 'transparent',
71+
})}
72+
>
73+
Experiment Lab
74+
</span>
75+
</h1>
76+
<p
77+
className={css({
78+
fontSize: { base: 'lg', md: 'xl' },
79+
color: 'gray.600',
80+
mb: '10',
81+
lineHeight: 'relaxed',
82+
})}
83+
>
84+
번들러 밑바닥부터 대규모 아키텍처까지, <br />
85+
실험하고 기록하며 성장하는 프론트엔드 엔지니어의 공간입니다.
86+
</p>
87+
88+
<div className={css({ display: 'flex', gap: '4', justifyContent: 'center' })}>
89+
<Link
90+
href="/posts"
91+
className={css({
92+
px: '8',
93+
py: '4',
94+
bg: 'gray.900',
95+
color: 'white',
96+
rounded: 'xl',
97+
fontWeight: 'semibold',
98+
transition: 'all 0.2s',
99+
_hover: {
100+
bg: 'gray.800',
101+
transform: 'translateY(-2px)',
102+
shadow: 'lg',
103+
},
104+
_active: { transform: 'translateY(0)' },
105+
})}
106+
>
107+
실험 기록 읽기
108+
</Link>
109+
</div>
110+
</main>
111+
</div>
77112

113+
{/* Top Posts Section (Client Component) */}
114+
<TopPosts posts={allPosts} />
115+
116+
{/* Recent Posts Section */}
117+
<section className={css({ py: '20', px: '6', maxWidth: '7xl', mx: 'auto', borderTopWidth: '1px', borderColor: 'gray.100' })}>
118+
<h2 className={css({ fontSize: '3xl', fontWeight: 'bold', mb: '10', textAlign: 'center' })}>
119+
✨ 최근 등록된 실험 기록
120+
</h2>
78121
<div
79122
className={css({
80-
display: 'flex',
81-
gap: '4',
82-
justifyContent: 'center',
123+
display: 'grid',
124+
gridTemplateColumns: { base: '1fr', md: '3fr' },
125+
gap: '8',
83126
})}
84127
>
128+
{recentPosts.map(post => (
129+
<PostCard key={post.slug} post={post} />
130+
))}
131+
</div>
132+
<div className={css({ mt: '12', textAlign: 'center' })}>
85133
<Link
86134
href="/posts"
87135
className={css({
88-
px: '8',
89-
py: '4',
90-
bg: 'gray.900',
91-
color: 'white',
92-
rounded: 'xl',
136+
display: 'inline-flex',
137+
alignItems: 'center',
138+
px: '6',
139+
py: '3',
140+
rounded: 'full',
141+
borderWidth: '1px',
142+
borderColor: 'gray.200',
143+
color: 'gray.600',
93144
fontWeight: 'semibold',
94145
transition: 'all 0.2s',
95146
_hover: {
96-
bg: 'gray.800',
97-
transform: 'translateY(-2px)',
98-
shadow: 'lg',
147+
borderColor: 'blue.600',
148+
color: 'blue.600',
149+
bg: 'blue.50',
99150
},
100-
_active: { transform: 'translateY(0)' },
101151
})}
102152
>
103-
실험 기록 읽기
153+
모든 기록 보기 <span className={css({ ml: '2' })}></span>
104154
</Link>
105155
</div>
106-
</main>
156+
</section>
107157
</div>
108158
</SsgoiTransition>
109159
);

apps/blog/web/src/app/posts/[...slug]/PostClient.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ export default function PostClient({ post }: { post: PostData }) {
252252
fontWeight: '500',
253253
borderWidth: '1px',
254254
borderColor: 'gray.200',
255+
whiteSpace: 'pre-wrap',
256+
wordBreak: 'break-word',
257+
overflowWrap: 'anywhere',
255258
},
256259
'& blockquote': {
257260
borderLeftWidth: '4px',
@@ -444,6 +447,9 @@ export default function PostClient({ post }: { post: PostData }) {
444447
fontWeight: '500',
445448
borderWidth: '1px',
446449
borderColor: 'gray.200',
450+
whiteSpace: 'pre-wrap',
451+
wordBreak: 'break-word',
452+
overflowWrap: 'anywhere',
447453
}),
448454
)}
449455
{...props}

apps/blog/web/src/app/posts/[...slug]/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
4040
siteName: 'Frontend Lab Blog',
4141
type: 'article',
4242
publishedTime: post.date || undefined,
43+
images: [
44+
{
45+
url: '/og-default.svg',
46+
width: 1200,
47+
height: 630,
48+
alt: 'FE Lab Blog - Frontend Experimentation',
49+
},
50+
],
4351
},
4452
twitter: {
4553
card: 'summary',

apps/blog/web/src/app/providers.tsx

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
import { type ReactNode, useState } from 'react';
44
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
5-
import { Ssgoi } from '@ssgoi/react';
6-
import { fade, drill } from '@ssgoi/react/view-transitions';
7-
import { css } from '@design-system/ui-lib/css';
85

96
export function Providers({ children }: { children: ReactNode }) {
107
const [queryClient] = useState(
@@ -26,32 +23,6 @@ export function Providers({ children }: { children: ReactNode }) {
2623
);
2724

2825
return (
29-
<QueryClientProvider client={queryClient}>
30-
<Ssgoi
31-
config={{
32-
defaultTransition: fade(),
33-
transitions: [
34-
{
35-
from: '/posts',
36-
to: '/posts/*',
37-
transition: drill({ direction: 'enter' }),
38-
},
39-
{
40-
from: '/posts/*',
41-
to: '/posts',
42-
transition: drill({ direction: 'exit', opacity: true }),
43-
},
44-
],
45-
}}
46-
>
47-
<div
48-
className={css({
49-
pos: 'relative',
50-
})}
51-
>
52-
{children}
53-
</div>
54-
</Ssgoi>
55-
</QueryClientProvider>
26+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
5627
);
5728
}

apps/blog/web/src/components/Layout.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import Link from 'next/link';
22
import { css } from '@design-system/ui-lib/css';
33
import type { ReactNode } from 'react';
44

5+
import { PageTransition } from './PageTransition';
6+
57
interface LayoutProps {
68
children: ReactNode;
79
}
810

911
export const Layout = ({ children }: LayoutProps) => {
1012
return (
11-
<div className={css({ minH: '100vh', bg: 'white', color: 'gray.900' })}>
13+
<div className={css({ minH: '100vh', bg: 'white', color: 'gray.900', display: 'flex', flexDirection: 'column' })}>
1214
<nav
1315
className={css({
1416
borderBottomWidth: '1px',
@@ -57,7 +59,9 @@ export const Layout = ({ children }: LayoutProps) => {
5759
</Link>
5860
</div>
5961
</nav>
60-
<main>{children}</main>
62+
<main className={css({ flex: 1, w: 'full' })}>
63+
<PageTransition>{children}</PageTransition>
64+
</main>
6165
<footer
6266
className={css({
6367
borderTopWidth: '1px',

0 commit comments

Comments
 (0)