Skip to content

Commit a0d05c2

Browse files
committed
feat: add footer to blog listing post and adjust spacing
1 parent 3eaf605 commit a0d05c2

File tree

1 file changed

+134
-110
lines changed

1 file changed

+134
-110
lines changed

src/app/blog/page.tsx

Lines changed: 134 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,21 @@ import {
1111
Text,
1212
} from '@radix-ui/themes';
1313
import { IconArrowLeft } from '@tabler/icons-react';
14+
import { type Metadata } from 'next';
1415
import Image from 'next/image';
1516
import Link from 'next/link';
1617
import { type FC } from 'react';
1718

19+
import { Footer } from '@/components/footer';
1820
import { firstName, lastName } from '@/constants/me';
1921
import { routes } from '@/constants/site-config';
2022
import { getArticles } from '@/lib/queries';
2123
import { dateFormatter } from '@/lib/utils';
2224

25+
const sm = 768;
26+
const md = 1024;
27+
const containerMaxWidth = 1136;
28+
2329
const BlogPage: FC = async () => {
2430
const articles = await getArticles();
2531
const featuredArticle = articles.reduce((highestViewedArticle, article) =>
@@ -28,121 +34,139 @@ const BlogPage: FC = async () => {
2834

2935
return (
3036
<Container>
31-
<Section>
32-
<Button asChild highContrast size="3" variant="ghost">
33-
<Link href={routes.home.pathname}>
34-
<IconArrowLeft size={20} />
35-
{firstName} {lastName}
36-
</Link>
37-
</Button>
38-
<Card asChild mt="8" variant="ghost">
39-
<Link href={`${routes.blog.pathname}/${featuredArticle.slug}`}>
40-
<Grid asChild columns={{ sm: '2' }} gapX="5" gapY="4">
41-
<article>
42-
<div>
43-
<Box
44-
className="aspect-video rounded-[var(--card-border-radius)]"
45-
overflow="hidden"
46-
position="relative"
47-
style={{ boxShadow: 'var(--base-card-surface-box-shadow)' }}
48-
>
49-
{featuredArticle.coverPhoto ? (
50-
<Image
51-
fill
52-
alt={featuredArticle.title}
53-
className="object-cover"
54-
src={featuredArticle.coverPhoto}
55-
sizes={[
56-
`(min-width: 1136px) ${1136 / 2}px`, // container size 4 max width = 1136px
57-
'(min-width: 768px) 50vw', // breakpoint sm = 768px
58-
'100vw',
59-
].join(',')}
60-
/>
37+
<Section asChild>
38+
<main>
39+
<Button asChild highContrast size="3" variant="ghost">
40+
<Link href={routes.home.pathname}>
41+
<IconArrowLeft size={20} />
42+
{firstName} {lastName}
43+
</Link>
44+
</Button>
45+
<Heading mt="2" size="9">
46+
Blog
47+
</Heading>
48+
<Card asChild mt="8" variant="ghost">
49+
<Link href={`${routes.blog.pathname}/${featuredArticle.slug}`}>
50+
<Grid asChild columns={{ sm: '2' }} gapX="5" gapY="4">
51+
<article>
52+
<div>
53+
<Box
54+
className="aspect-video rounded-[var(--card-border-radius)]"
55+
overflow="hidden"
56+
position="relative"
57+
style={{
58+
boxShadow: 'var(--base-card-surface-box-shadow)',
59+
}}
60+
>
61+
{featuredArticle.coverPhoto ? (
62+
<Image
63+
fill
64+
alt={featuredArticle.title}
65+
className="object-cover"
66+
src={featuredArticle.coverPhoto}
67+
sizes={[
68+
`(min-width: ${containerMaxWidth}px) ${containerMaxWidth / 2}px`,
69+
`(min-width: ${sm}px) 50vw`,
70+
'100vw',
71+
].join(',')}
72+
/>
73+
) : null}
74+
</Box>
75+
</div>
76+
<Flex direction="column" gap={{ initial: '2', sm: '3' }}>
77+
{featuredArticle.categories &&
78+
featuredArticle.categories.length > 0 ? (
79+
<Flex gap="3">
80+
{featuredArticle.categories.map((category) => (
81+
<Badge key={category} size="3">
82+
{category}
83+
</Badge>
84+
))}
85+
</Flex>
6186
) : null}
62-
</Box>
63-
</div>
64-
<div>
65-
{featuredArticle.categories &&
66-
featuredArticle.categories.length > 0 ? (
67-
<Flex gap="3">
68-
{featuredArticle.categories.map((category) => (
69-
<Badge key={category} size="3">
70-
{category}
71-
</Badge>
72-
))}
73-
</Flex>
74-
) : null}
75-
<Heading mt="4" size={{ initial: '4', xs: '6', md: '8' }}>
76-
{featuredArticle.title}
77-
</Heading>
78-
<Text
79-
className="line-clamp-3"
80-
mt="2"
81-
size={{ initial: '3', md: '4' }}
82-
>
83-
{featuredArticle.description}
84-
</Text>
85-
<Text color="gray" mt="2" size={{ initial: '2', md: '3' }}>
86-
{dateFormatter.format(featuredArticle.createdAt)}
87-
</Text>
88-
</div>
89-
</article>
90-
</Grid>
91-
</Link>
92-
</Card>
93-
<Grid columns={{ xs: '2', md: '3' }} gap="5" mt="8">
94-
{articles
95-
.filter(({ id }) => id !== featuredArticle.id)
96-
.map(
97-
({ id, createdAt, coverPhoto, slug, title, categories = [] }) => (
98-
<Card key={id} asChild variant="ghost">
99-
<Link href={`${routes.blog.pathname}/${slug}`}>
100-
<article>
101-
<Box
102-
className="aspect-video rounded-[var(--card-border-radius)]"
103-
overflow="hidden"
104-
position="relative"
105-
style={{
106-
boxShadow: 'var(--base-card-surface-box-shadow)',
107-
}}
108-
>
109-
{coverPhoto ? (
110-
<Image
111-
fill
112-
alt={title}
113-
className="object-cover"
114-
src={coverPhoto}
115-
sizes={[
116-
`(min-width: 1136px) ${1136 / 2}px`, // container size 4 max width = 1136px
117-
'(min-width: 1024px) 33vw', // breakpoint md = 1024px
118-
'(min-width: 768px) 50vw', // breakpoint sm = 768px
119-
'100vw',
120-
].join(',')}
121-
/>
122-
) : null}
123-
</Box>
124-
{categories.length > 0 ? (
125-
<Flex gap="2" mt="3" wrap="wrap">
126-
{categories.map((category) => (
127-
<Badge key={category}>{category}</Badge>
128-
))}
87+
<Heading size={{ initial: '4', xs: '6', md: '8' }}>
88+
{featuredArticle.title}
89+
</Heading>
90+
<Text
91+
className="line-clamp-3"
92+
size={{ initial: '3', md: '4' }}
93+
>
94+
{featuredArticle.description}
95+
</Text>
96+
<Text as="p" color="gray" size={{ initial: '2', md: '3' }}>
97+
{dateFormatter.format(featuredArticle.createdAt)}
98+
</Text>
99+
</Flex>
100+
</article>
101+
</Grid>
102+
</Link>
103+
</Card>
104+
<Grid columns={{ xs: '2', md: '3' }} gap="5" mt="8">
105+
{articles
106+
.filter(({ id }) => id !== featuredArticle.id)
107+
.map(
108+
({
109+
id,
110+
createdAt,
111+
coverPhoto,
112+
slug,
113+
title,
114+
categories = [],
115+
}) => (
116+
<Card key={id} asChild variant="ghost">
117+
<Link href={`${routes.blog.pathname}/${slug}`}>
118+
<article>
119+
<Box
120+
className="aspect-video rounded-[var(--card-border-radius)]"
121+
overflow="hidden"
122+
position="relative"
123+
style={{
124+
boxShadow: 'var(--base-card-surface-box-shadow)',
125+
}}
126+
>
127+
{coverPhoto ? (
128+
<Image
129+
fill
130+
alt={title}
131+
className="object-cover"
132+
src={coverPhoto}
133+
sizes={[
134+
`(min-width: ${containerMaxWidth}px) ${containerMaxWidth / 3}px`,
135+
`(min-width: ${md}px) 33vw`,
136+
`(min-width: ${sm}px) 50vw`,
137+
'100vw',
138+
].join(',')}
139+
/>
140+
) : null}
141+
</Box>
142+
<Flex direction="column" gap="2" mt="4">
143+
{categories.length > 0 ? (
144+
<Flex gap="2" wrap="wrap">
145+
{categories.map((category) => (
146+
<Badge key={category}>{category}</Badge>
147+
))}
148+
</Flex>
149+
) : null}
150+
<Heading size="3">{title}</Heading>
151+
<Text as="p" color="gray" size="2">
152+
{dateFormatter.format(createdAt)}
153+
</Text>
129154
</Flex>
130-
) : null}
131-
<Heading mt="3" size="3">
132-
{title}
133-
</Heading>
134-
<Text color="gray" mt="2" size="2">
135-
{dateFormatter.format(createdAt)}
136-
</Text>
137-
</article>
138-
</Link>
139-
</Card>
140-
),
141-
)}
142-
</Grid>
155+
</article>
156+
</Link>
157+
</Card>
158+
),
159+
)}
160+
</Grid>
161+
</main>
143162
</Section>
163+
<Footer />
144164
</Container>
145165
);
146166
};
147167

168+
export const metadata = {
169+
title: routes.blog.name,
170+
} satisfies Metadata;
171+
148172
export default BlogPage;

0 commit comments

Comments
 (0)