Skip to content

Commit 1dc655a

Browse files
committed
feat: 블로그 수정 및 기능 업데이트
- 검색 기능 추가 - 태그 시스템 추가 - 소셜 링크 업데이트
1 parent 6b80d20 commit 1dc655a

File tree

14 files changed

+767
-95
lines changed

14 files changed

+767
-95
lines changed

gatsby-config.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
module.exports = {
22
siteMetadata: {
3-
title: `zooneon's dev log`,
3+
title: `zooneon's log`,
44
description: `기록하고 공유하는 공간`,
55
author: `zooneon`,
6-
authorTagline: '신입 엔지니어 권준원입니다.',
6+
authorTagline: 'DevOps Engineer',
77
siteUrl: `https://blog.zooneon.dev`,
88
social: {
99
github: `zooneon`,
10-
instagram: `zooneon.dev`,
10+
linkedin: `junwon-kwon-b4770025b`,
1111
12-
notion: `https://zzooneon.notion.site/69fa5b3ed63d4963bdf00167d7bc68d0`,
1312
},
1413
},
1514
plugins: [
@@ -52,22 +51,12 @@ module.exports = {
5251
],
5352
},
5453
},
54+
`gatsby-plugin-image`,
5555
`gatsby-plugin-styled-components`,
5656
`gatsby-plugin-react-helmet`,
5757
`gatsby-transformer-sharp`,
5858
`gatsby-plugin-sharp`,
5959
`gatsby-plugin-catch-links`,
60-
{
61-
resolve: `gatsby-plugin-gdpr-tracking`,
62-
options: {
63-
googleAnalytics: {
64-
trackingId: `G-PB788GF0S1`,
65-
},
66-
googleAds: {
67-
trackingId: `ca-pub-8820567915675763`,
68-
},
69-
},
70-
},
7160
{
7261
resolve: `gatsby-plugin-robots-txt`,
7362
options: {
@@ -89,6 +78,6 @@ module.exports = {
8978
},
9079
},
9180
'gatsby-plugin-offline',
92-
`gatsby-plugin-advanced-sitemap`,
81+
`gatsby-plugin-sitemap`,
9382
],
9483
};

gatsby-node.js

Lines changed: 68 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,82 @@
11
const path = require(`path`);
22
const { createFilePath } = require(`gatsby-source-filesystem`);
33

4-
exports.createPages = ({ graphql, actions }) => {
4+
exports.createSchemaCustomization = ({ actions }) => {
5+
const { createTypes } = actions;
6+
const typeDefs = `
7+
type MarkdownRemark implements Node {
8+
frontmatter: Frontmatter
9+
}
10+
type Frontmatter {
11+
title: String!
12+
date: Date! @dateformat
13+
tags: [String]
14+
}
15+
`;
16+
createTypes(typeDefs);
17+
};
18+
19+
exports.createPages = async ({ graphql, actions }) => {
520
const { createPage } = actions;
621

7-
return new Promise((resolve, reject) => {
8-
const blogPost = path.resolve(`./src/templates/blog-post.js`);
9-
resolve(
10-
graphql(
11-
`
12-
{
13-
allMarkdownRemark(
14-
sort: { fields: [frontmatter___date], order: DESC }
15-
limit: 1000
16-
) {
17-
edges {
18-
node {
19-
fields {
20-
slug
21-
}
22-
frontmatter {
23-
title
24-
}
25-
}
26-
}
22+
const blogPost = path.resolve(`./src/templates/blog-post.js`);
23+
const tagTemplate = path.resolve(`./src/templates/tags.js`);
24+
25+
const result = await graphql(`
26+
{
27+
allMarkdownRemark(sort: { frontmatter: { date: DESC } }, limit: 1000) {
28+
edges {
29+
node {
30+
fields {
31+
slug
32+
}
33+
frontmatter {
34+
title
35+
tags
2736
}
2837
}
29-
`
30-
).then(result => {
31-
if (result.errors) {
32-
console.log(result.errors);
33-
reject(result.errors);
3438
}
39+
}
40+
tagsGroup: allMarkdownRemark(limit: 2000) {
41+
group(field: { frontmatter: { tags: SELECT } }) {
42+
fieldValue
43+
}
44+
}
45+
}
46+
`);
3547

36-
// Create blog posts pages.
37-
const posts = result.data.allMarkdownRemark.edges;
48+
if (result.errors) {
49+
throw result.errors;
50+
}
3851

39-
posts.forEach((post, index) => {
40-
const previous =
41-
index === posts.length - 1 ? null : posts[index + 1].node;
42-
const next = index === 0 ? null : posts[index - 1].node;
52+
// Create blog posts pages.
53+
const posts = result.data.allMarkdownRemark.edges;
4354

44-
createPage({
45-
path: post.node.fields.slug,
46-
component: blogPost,
47-
context: {
48-
slug: post.node.fields.slug,
49-
previous,
50-
next,
51-
},
52-
});
53-
});
54-
})
55-
);
55+
posts.forEach((post, index) => {
56+
const previous = index === posts.length - 1 ? null : posts[index + 1].node;
57+
const next = index === 0 ? null : posts[index - 1].node;
58+
59+
createPage({
60+
path: post.node.fields.slug,
61+
component: blogPost,
62+
context: {
63+
slug: post.node.fields.slug,
64+
previous,
65+
next,
66+
},
67+
});
68+
});
69+
70+
// Create tags pages
71+
const tags = result.data.tagsGroup.group;
72+
tags.forEach((tag) => {
73+
createPage({
74+
path: `/tags/${tag.fieldValue}/`,
75+
component: tagTemplate,
76+
context: {
77+
tag: tag.fieldValue,
78+
},
79+
});
5680
});
5781
};
5882

src/components/PostList.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import React from 'react';
2+
import { Link } from 'gatsby';
3+
import styled from 'styled-components';
4+
5+
const PostListContainer = styled.div`
6+
display: flex;
7+
flex-direction: column;
8+
gap: 2.5rem;
9+
`;
10+
11+
const PostItem = styled.article`
12+
border: 1px solid #eee;
13+
border-radius: 8px;
14+
padding: 2rem;
15+
transition: all 0.2s ease;
16+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.03);
17+
18+
&:hover {
19+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.07);
20+
transform: translateY(-3px);
21+
}
22+
`;
23+
24+
const PostTitle = styled.h2`
25+
font-size: 1.8rem;
26+
margin-bottom: 0.8rem;
27+
line-height: 1.4;
28+
29+
a {
30+
color: #333;
31+
text-decoration: none;
32+
transition: color 0.2s ease;
33+
34+
&:hover {
35+
color: #3498db;
36+
}
37+
}
38+
`;
39+
40+
const PostMeta = styled.div`
41+
display: flex;
42+
align-items: center;
43+
margin-bottom: 1.5rem;
44+
font-size: 0.95rem;
45+
color: #777;
46+
`;
47+
48+
const PostDate = styled.time`
49+
margin-right: 1.5rem;
50+
display: flex;
51+
align-items: center;
52+
53+
&::before {
54+
content: '📅';
55+
margin-right: 0.5rem;
56+
font-size: 1rem;
57+
}
58+
`;
59+
60+
const PostTags = styled.div`
61+
display: flex;
62+
gap: 0.5rem;
63+
flex-wrap: wrap;
64+
`;
65+
66+
const PostTag = styled(Link)`
67+
font-size: 0.85rem;
68+
padding: 0.2rem 0.6rem;
69+
background-color: #f5f5f5;
70+
color: #666;
71+
border-radius: 3px;
72+
text-decoration: none;
73+
transition: all 0.2s ease;
74+
75+
&:hover {
76+
background-color: #3498db;
77+
color: white;
78+
}
79+
`;
80+
81+
const PostExcerpt = styled.p`
82+
margin: 0;
83+
color: #555;
84+
line-height: 1.6;
85+
font-size: 1.1rem;
86+
`;
87+
88+
const ReadMore = styled(Link)`
89+
display: inline-block;
90+
margin-top: 1.2rem;
91+
color: #3498db;
92+
text-decoration: none;
93+
font-weight: 500;
94+
font-size: 0.95rem;
95+
transition: all 0.2s ease;
96+
97+
&:hover {
98+
color: #2980b9;
99+
text-decoration: underline;
100+
}
101+
102+
&::after {
103+
content: ' →';
104+
}
105+
`;
106+
107+
const PostList = ({ posts }) => {
108+
return (
109+
<PostListContainer>
110+
{posts.map(({ node }) => {
111+
const { frontmatter, fields, excerpt } = node;
112+
const { title, date, tags } = frontmatter;
113+
const { slug } = fields;
114+
115+
return (
116+
<PostItem key={slug}>
117+
<PostTitle>
118+
<Link to={slug}>{title}</Link>
119+
</PostTitle>
120+
<PostMeta>
121+
<PostDate>{date}</PostDate>
122+
{tags && tags.length > 0 && (
123+
<PostTags>
124+
{tags.map((tag) => (
125+
<PostTag key={tag} to={`/tags/${tag}/`}>
126+
#{tag}
127+
</PostTag>
128+
))}
129+
</PostTags>
130+
)}
131+
</PostMeta>
132+
<PostExcerpt>{excerpt}</PostExcerpt>
133+
<ReadMore to={slug}>계속 읽기</ReadMore>
134+
</PostItem>
135+
);
136+
})}
137+
</PostListContainer>
138+
);
139+
};
140+
141+
export { PostList };

src/components/bio.js

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import Image from 'gatsby-image';
55

66
import media from '../utils/media';
77
import github from '../images/social/github.svg';
8-
import instagram from '../images/social/instagram.svg';
8+
import linkedin from '../images/social/linkedin.svg';
99
import mail from '../images/social/mail.svg';
10-
import cv from '../images/social/cv.svg';
1110

1211
const Container = styled.div`
1312
display: flex;
@@ -75,11 +74,11 @@ const Bio = () => (
7574
<SocialIcon src={github} alt="github" />
7675
</a>
7776
<a
78-
href={`https://instagram.com/${social.instagram}`}
77+
href={`https://www.linkedin.com/in/${social.linkedin}`}
7978
target="_blank"
8079
rel="noopener noreferrer"
8180
>
82-
<SocialIcon src={instagram} alt="instagram" />
81+
<SocialIcon src={linkedin} alt="linkedin" />
8382
</a>
8483
<a
8584
href={`mailto:${social.mail}`}
@@ -88,13 +87,6 @@ const Bio = () => (
8887
>
8988
<SocialIcon src={mail} alt="mail" />
9089
</a>
91-
<a
92-
href={`${social.notion}`}
93-
target="_blank"
94-
rel="noopener noreferrer"
95-
>
96-
<SocialIcon src={cv} alt="notion" />
97-
</a>
9890
</TextContainer>
9991
<ImageContainer>
10092
<Image fixed={data.avatar.childImageSharp.fixed} alt={author} />
@@ -120,9 +112,8 @@ const bioQuery = graphql`
120112
authorTagline
121113
social {
122114
github
123-
instagram
115+
linkedin
124116
mail
125-
notion
126117
}
127118
}
128119
}

0 commit comments

Comments
 (0)