tangled
alpha
login
or
join now
safwanyp.com
/
website
0
fork
atom
Code for my personal website
0
fork
atom
overview
issues
pulls
pipelines
feat: create pages for blog
Safwan Parker
2 years ago
656d2fb3
acb3980a
+107
2 changed files
expand all
collapse all
unified
split
src
pages
blog
[...slug].astro
index.astro
+53
src/pages/blog/[...slug].astro
···
1
1
+
---
2
2
+
import { type CollectionEntry, getCollection } from 'astro:content';
3
3
+
import Layout from '@/layouts/Layout.astro';
4
4
+
import Container from '@/components/Container.astro';
5
5
+
import DateComponent from '@/components/Date.astro';
6
6
+
import { readingTime } from '@/utils';
7
7
+
import Back from '@/components/Back.astro';
8
8
+
9
9
+
export async function getStaticPaths() {
10
10
+
const posts = (await getCollection('blog'))
11
11
+
.filter((post) => !post.data.draft)
12
12
+
.sort(
13
13
+
(a, b) =>
14
14
+
new Date(b.data.date as string).valueOf() -
15
15
+
new Date(a.data.date).valueOf()
16
16
+
);
17
17
+
18
18
+
return posts.map((post) => ({
19
19
+
params: { slug: post.slug },
20
20
+
props: post
21
21
+
}));
22
22
+
}
23
23
+
24
24
+
type Props = CollectionEntry<'blog'>;
25
25
+
26
26
+
const post = Astro.props;
27
27
+
const { Content } = await post.render();
28
28
+
---
29
29
+
30
30
+
<Layout title={post.data.title} description={post.data.description}>
31
31
+
<Container>
32
32
+
<div class='animate'>
33
33
+
<Back href='/blog'> Back to blog </Back>
34
34
+
</div>
35
35
+
<div class='space-y-1 my-10'>
36
36
+
<div class='animate flex items-center gap-1.5'>
37
37
+
<div class='font-base text-sm'>
38
38
+
<DateComponent date={new Date(post.data.date)} />
39
39
+
</div>
40
40
+
•
41
41
+
<div class='font-base text-sm'>
42
42
+
{readingTime(post.body)}
43
43
+
</div>
44
44
+
</div>
45
45
+
<div class='animate text-2xl font-semibold text-black dark:text-white'>
46
46
+
{post.data.title}
47
47
+
</div>
48
48
+
</div>
49
49
+
<article class='animate'>
50
50
+
<Content />
51
51
+
</article>
52
52
+
</Container>
53
53
+
</Layout>
+54
src/pages/blog/index.astro
···
1
1
+
---
2
2
+
import { type CollectionEntry, getCollection } from 'astro:content';
3
3
+
import Layout from '@/layouts/Layout.astro';
4
4
+
import Container from '@/components/Container.astro';
5
5
+
import NavCard from '@/components/NavCard.astro';
6
6
+
import { BLOG } from '@/config';
7
7
+
8
8
+
const data = (await getCollection('blog'))
9
9
+
.filter((post) => !post.data.draft)
10
10
+
.sort(
11
11
+
(a, b) => new Date(b.data.date).valueOf() - new Date(a.data.date).valueOf()
12
12
+
);
13
13
+
14
14
+
type Acc = {
15
15
+
[year: string]: CollectionEntry<'blog'>[];
16
16
+
};
17
17
+
18
18
+
const posts = data.reduce((acc: Acc, post) => {
19
19
+
const year = new Date(post.data.date).getFullYear().toString();
20
20
+
if (!acc[year]) {
21
21
+
acc[year] = [];
22
22
+
}
23
23
+
acc[year].push(post);
24
24
+
return acc;
25
25
+
}, {});
26
26
+
27
27
+
const years = Object.keys(posts).sort((a, b) => parseInt(b) - parseInt(a));
28
28
+
---
29
29
+
30
30
+
<Layout title={BLOG.TITLE} description={BLOG.DESCRIPTION}>
31
31
+
<Container>
32
32
+
<div class='space-y-10'>
33
33
+
<div class='animate font-semibold text-black dark:text-white'>Blog</div>
34
34
+
<div class='space-y-4'>
35
35
+
{
36
36
+
years.map((year) => (
37
37
+
<section class='animate space-y-4'>
38
38
+
<div class='font-semibold text-black dark:text-white'>{year}</div>
39
39
+
<div>
40
40
+
<ul class='flex flex-col gap-4'>
41
41
+
{posts[year].map((post) => (
42
42
+
<li>
43
43
+
<NavCard entry={post} />
44
44
+
</li>
45
45
+
))}
46
46
+
</ul>
47
47
+
</div>
48
48
+
</section>
49
49
+
))
50
50
+
}
51
51
+
</div>
52
52
+
</div>
53
53
+
</Container>
54
54
+
</Layout>