├── .gitignore
├── LICENSE
├── README.md
├── content
├── media
│ └── salty_egg.jpg
├── pages
│ └── about.md
└── posts
│ ├── hello-world.md
│ ├── my-second-post.md
│ └── new-beginnings.md
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── package.json
├── postcss.config.js
├── src
├── components
│ ├── Footer.js
│ ├── Header.js
│ ├── Layout.js
│ ├── PostCard.js
│ ├── pagination.js
│ └── seo.js
├── images
│ └── icon.png
├── pages
│ └── 404.js
├── styles
│ └── global.css
└── templates
│ ├── blog-page.js
│ ├── blog-post.js
│ └── index.js
├── tailwind.config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .cache/
3 | public
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Whatk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 介绍
2 | 基于 Gatsby、Tailwindcss 的博客,emmmmm 不知道属不属于 Gatsby 主题,个人认为算是一个手脚架?
3 | 是在上手 Gatsby 过程中摸出来的,很简单很基本的一个博客,可以自行小改后拿来使用,或作为开发参考。
4 |
5 | * Tailwindcss
6 | * MarkDown
7 | * 夜间模式
8 | * 多页文章列表
9 | * 深色模式
10 | * 响应式
11 | * ~~简洁~~
12 |
13 | 演示:https://gatsby-simple-tailwindcss-blog.pages.dev/
14 |
15 | ---
16 | content
17 | ├── media (媒体(图片等))
18 | ├── pages (独立页面)
19 | └── posts (文章)
20 | ---
21 |
22 | ## 🚀 Quick start
23 |
24 | 1. **Create a Gatsby site.**
25 |
26 | Use the Gatsby CLI ([install instructions](https://www.gatsbyjs.com/docs/tutorial/part-0/#gatsby-cli)) to create a new site, specifying the blog starter.
27 |
28 | ```shell
29 | # create a new Gatsby site using the blog starter
30 | gatsby new gatsby-simple-tailwindcss-blog https://github.com/whatk233/gatsby-simple-tailwindcss-blog
31 | ```
32 |
33 | 1. **Start developing.**
34 |
35 | Navigate into your new site’s directory and start it up.
36 |
37 | ```shell
38 | cd gatsby-simple-tailwindcss-blog/
39 | gatsby develop
40 | ```
41 |
42 | 1. **Open the source code and start editing!**
43 |
44 | Your site is now running at `http://localhost:8000`!
45 |
46 | _Note: You'll also see a second link: _`http://localhost:8000/___graphql`_. This is a tool you can use to experiment with querying your data. Learn more about using this tool in the [Gatsby tutorial](https://www.gatsbyjs.com/tutorial/part-five/#introducing-graphiql)._
47 |
48 |
49 | ## 🎓 Learning Gatsby
50 |
51 | Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.com/). Here are some places to start:
52 |
53 | - **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.com/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process.
54 |
55 | - **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.com/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar.
56 |
57 | ## 💫 Deploy
58 | [](https://app.netlify.com/start/deploy?repository=https://github.com/whatk233/gatsby-simple-tailwindcss-blog)
--------------------------------------------------------------------------------
/content/media/salty_egg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whatk233/gatsby-simple-tailwindcss-blog/bedd560804132b750055b4f483d2ccb9a2d02b31/content/media/salty_egg.jpg
--------------------------------------------------------------------------------
/content/pages/about.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 关于
3 | date: "2021-07-23T02:12:03.284Z"
4 | description: "关于"
5 | ---
6 |
7 |
8 | simple blog , simple function
9 |
10 | but bug is not simple :<
11 |
--------------------------------------------------------------------------------
/content/posts/hello-world.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Hello World
3 | date: "2015-05-01T22:12:03.284Z"
4 | description: "Hello World"
5 | ---
6 |
7 | This is my first post on my new fake blog! How exciting!
8 |
9 | I'm sure I'll write a lot more interesting things in the future.
10 |
11 | Oh, and here's a great quote from this Wikipedia on
12 | [salted duck eggs](https://en.wikipedia.org/wiki/Salted_duck_egg).
13 |
14 | > A salted duck egg is a Chinese preserved food product made by soaking duck
15 | > eggs in brine, or packing each egg in damp, salted charcoal. In Asian
16 | > supermarkets, these eggs are sometimes sold covered in a thick layer of salted
17 | > charcoal paste. The eggs may also be sold with the salted paste removed,
18 | > wrapped in plastic, and vacuum packed. From the salt curing process, the
19 | > salted duck eggs have a briny aroma, a gelatin-like egg white and a
20 | > firm-textured, round yolk that is bright orange-red in color.
21 |
22 | 
23 |
24 | You can also write code blocks here!
25 |
26 | ```js
27 | const saltyDuckEgg = "chinese preserved food product"
28 | ```
29 |
30 | | Number | Title | Year |
31 | | :----- | :--------------------------------------- | ---: |
32 | | 1 | Harry Potter and the Philosopher’s Stone | 2001 |
33 | | 2 | Harry Potter and the Chamber of Secrets | 2002 |
34 | | 3 | Harry Potter and the Prisoner of Azkaban | 2004 |
35 |
36 | [View raw (TEST.md)](https://raw.github.com/adamschwartz/github-markdown-kitchen-sink/master/README.md)
37 |
38 | This is a paragraph.
39 |
40 | This is a paragraph.
41 |
42 | # Header 1
43 |
44 | ## Header 2
45 |
46 | Header 1
47 | ========
48 |
49 | Header 2
50 | --------
51 |
52 | # Header 1
53 |
54 | ## Header 2
55 |
56 | ### Header 3
57 |
58 | #### Header 4
59 |
60 | ##### Header 5
61 |
62 | ###### Header 6
63 |
64 | # Header 1
65 | ## Header 2
66 | ### Header 3
67 | #### Header 4
68 | ##### Header 5
69 | ###### Header 6
70 |
71 | # Header 1
72 |
73 | ## Header 2
74 |
75 | ### Header 3
76 |
77 | #### Header 4
78 |
79 | ##### Header 5
80 |
81 | ###### Header 6
82 |
83 | # Header 1 #
84 | ## Header 2 ##
85 | ### Header 3 ###
86 | #### Header 4 ####
87 | ##### Header 5 #####
88 | ###### Header 6 ######
89 |
90 | > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
91 |
92 | > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
93 |
94 | > ## This is a header.
95 | >
96 | > 1. This is the first list item.
97 | > 2. This is the second list item.
98 | >
99 | > Here's some example code:
100 | >
101 | > Markdown.generate();
102 |
103 | > ## This is a header.
104 | > 1. This is the first list item.
105 | > 2. This is the second list item.
106 | >
107 | > Here's some example code:
108 | >
109 | > Markdown.generate();
110 |
111 | - Red
112 | - Green
113 | - Blue
114 |
115 | * Red
116 | * Green
117 | * Blue
118 |
119 | - Red
120 | - Green
121 | - Blue
122 |
123 | ```markdown
124 | - Red
125 | - Green
126 | - Blue
127 |
128 | * Red
129 | * Green
130 | * Blue
131 |
132 | - Red
133 | - Green
134 | - Blue
135 | ```
136 |
137 | - `code goes` here in this line
138 | - **bold** goes here
139 |
140 | ```markdown
141 | - `code goes` here in this line
142 | - **bold** goes here
143 | ```
144 |
145 | 1. Buy flour and salt
146 | 1. Mix together with water
147 | 1. Bake
148 |
149 | ```markdown
150 | 1. Buy flour and salt
151 | 1. Mix together with water
152 | 1. Bake
153 | ```
154 |
155 | 1. `code goes` here in this line
156 | 1. **bold** goes here
157 |
158 | ```markdown
159 | 1. `code goes` here in this line
160 | 1. **bold** goes here
161 | ```
162 |
163 | Paragraph:
164 |
165 | Code
166 |
167 |
168 |
169 | Paragraph:
170 |
171 | Code
172 |
173 | ---
174 |
175 | ---
176 |
177 | ---
178 |
179 | ---
180 |
181 | ---
182 |
183 | * * *
184 |
185 | ***
186 |
187 | *****
188 |
189 | - - -
190 |
191 | ---------------------------------------
192 |
193 | This is [an example](http://example.com "Example") link.
194 |
195 | [This link](http://example.com) has no title attr.
196 |
197 | This is [an example][id] reference-style link.
198 |
199 | [id]: http://example.com "Optional Title"
200 |
201 | This is [an example](http://example.com "Example") link.
202 |
203 | [This link](http://example.com) has no title attr.
204 |
205 | This is [an example] [id] reference-style link.
206 |
207 | [id]: http://example.com "Optional Title"
208 |
209 | _single asterisks_
210 |
211 | _single underscores_
212 |
213 | **double asterisks**
214 |
215 | **double underscores**
216 |
217 | *single asterisks*
218 |
219 | _single underscores_
220 |
221 | **double asterisks**
222 |
223 | __double underscores__
224 |
225 | This paragraph has some `code` in it.
226 |
227 | This paragraph has some `code` in it.
228 |
229 | 
230 |
231 | 
232 |
--------------------------------------------------------------------------------
/content/posts/my-second-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: My Second Post!
3 | date: "2015-05-06T23:46:37.121Z"
4 | ---
5 |
6 | Wow! I love blogging so much already.
7 |
8 | Did you know that "despite its name, salted duck eggs can also be made from
9 | chicken eggs, though the taste and texture will be somewhat different, and the
10 | egg yolk will be less rich."?
11 | ([Wikipedia Link](https://en.wikipedia.org/wiki/Salted_duck_egg))
12 |
13 | Yeah, I didn't either.
14 |
--------------------------------------------------------------------------------
/content/posts/new-beginnings.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: New Beginnings
3 | date: "2015-05-28T22:40:32.169Z"
4 | description: This is a custom description for SEO and Open Graph purposes, rather than the default generated excerpt. Simply add a description field to the frontmatter.
5 | ---
6 |
7 | Far far away, behind the word mountains, far from the countries Vokalia and
8 | Consonantia, there live the blind texts. Separated they live in Bookmarksgrove
9 | right at the coast of the Semantics, a large language ocean. A small river named
10 | Duden flows by their place and supplies it with the necessary regelialia.
11 |
12 | ## On deer horse aboard tritely yikes and much
13 |
14 | The Big Oxmox advised her not to do so, because there were thousands of bad
15 | Commas, wild Question Marks and devious Semikoli, but the Little Blind Text
16 | didn’t listen. She packed her seven versalia, put her initial into the belt and
17 | made herself on the way.
18 |
19 | - This however showed weasel
20 | - Well uncritical so misled
21 | - this is very interesting
22 | - Goodness much until that fluid owl
23 |
24 | When she reached the first hills of the **Italic Mountains**, she had a last
25 | view back on the skyline of her hometown _Bookmarksgrove_, the headline of
26 | [Alphabet Village](http://google.com) and the subline of her own road, the Line
27 | Lane. Pityful a rhetoric question ran over her cheek, then she continued her
28 | way. On her way she met a copy.
29 |
30 | ### Overlaid the jeepers uselessly much excluding
31 |
32 | But nothing the copy said could convince her and so it didn’t take long until a
33 | few insidious Copy Writers ambushed her, made her drunk with
34 | [Longe and Parole](http://google.com) and dragged her into their agency, where
35 | they abused her for their projects again and again. And if she hasn’t been
36 | rewritten, then they are still using her.
37 |
38 | > Far far away, behind the word mountains, far from the countries Vokalia and
39 | > Consonantia, there live the blind texts. Separated they live in Bookmarksgrove
40 | > right at the coast of the Semantics, a large language ocean.
41 |
42 | It is a paradisematic country, in which roasted parts of sentences fly into your
43 | mouth. Even the all-powerful Pointing has no control about the blind texts it is
44 | an almost unorthographic life One day however a small line of blind text by the
45 | name of Lorem Ipsum decided to leave for the far World of Grammar.
46 |
47 | ### According a funnily until pre-set or arrogant well cheerful
48 |
49 | The Big Oxmox advised her not to do so, because there were thousands of bad
50 | Commas, wild Question Marks and devious Semikoli, but the Little Blind Text
51 | didn’t listen. She packed her seven versalia, put her initial into the belt and
52 | made herself on the way.
53 |
54 | 1. So baboon this
55 | 2. Mounted militant weasel gregariously admonishingly straightly hey
56 | 3. Dear foresaw hungry and much some overhung
57 | 4. Rash opossum less because less some amid besides yikes jeepers frenetic
58 | impassive fruitlessly shut
59 |
60 | When she reached the first hills of the Italic Mountains, she had a last view
61 | back on the skyline of her hometown Bookmarksgrove, the headline of Alphabet
62 | Village and the subline of her own road, the Line Lane. Pityful a rhetoric
63 | question ran over her cheek, then she continued her way. On her way she met a
64 | copy.
65 |
66 | > The copy warned the Little Blind Text, that where it came from it would have
67 | > been rewritten a thousand times and everything that was left from its origin
68 | > would be the word "and" and the Little Blind Text should turn around and
69 | > return to its own, safe country.
70 |
71 | But nothing the copy said could convince her and so it didn’t take long until a
72 | few insidious Copy Writers ambushed her, made her drunk with Longe and Parole
73 | and dragged her into their agency, where they abused her for their projects
74 | again and again. And if she hasn’t been rewritten, then they are still using
75 | her. Far far away, behind the word mountains, far from the countries Vokalia and
76 | Consonantia, there live the blind texts.
77 |
78 | #### Silent delightfully including because before one up barring chameleon
79 |
80 | Separated they live in Bookmarksgrove right at the coast of the Semantics, a
81 | large language ocean. A small river named Duden flows by their place and
82 | supplies it with the necessary regelialia. It is a paradisematic country, in
83 | which roasted parts of sentences fly into your mouth.
84 |
85 | Even the all-powerful Pointing has no control about the blind texts it is an
86 | almost unorthographic life One day however a small line of blind text by the
87 | name of Lorem Ipsum decided to leave for the far World of Grammar. The Big Oxmox
88 | advised her not to do so, because there were thousands of bad Commas, wild
89 | Question Marks and devious Semikoli, but the Little Blind Text didn’t listen.
90 |
91 | ##### Wherever far wow thus a squirrel raccoon jeez jaguar this from along
92 |
93 | She packed her seven versalia, put her initial into the belt and made herself on
94 | the way. When she reached the first hills of the Italic Mountains, she had a
95 | last view back on the skyline of her hometown Bookmarksgrove, the headline of
96 | Alphabet Village and the subline of her own road, the Line Lane. Pityful a
97 | rhetoric question ran over her cheek, then she continued her way. On her way she
98 | met a copy.
99 |
100 | ###### Slapped cozy a that lightheartedly and far
101 |
102 | The copy warned the Little Blind Text, that where it came from it would have
103 | been rewritten a thousand times and everything that was left from its origin
104 | would be the word "and" and the Little Blind Text should turn around and return
105 | to its own, safe country. But nothing the copy said could convince her and so it
106 | didn’t take long until a few insidious Copy Writers ambushed her, made her drunk
107 | with Longe and Parole and dragged her into their agency, where they abused her
108 | for their projects again and again.
109 |
--------------------------------------------------------------------------------
/gatsby-browser.js:
--------------------------------------------------------------------------------
1 | import './src/styles/global.css';
--------------------------------------------------------------------------------
/gatsby-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | siteMetadata: {
3 | siteUrl: "http://localhost/",
4 | title: "Simple Blog",
5 | description: "学习 Gatsby 过程做出来的简单博客 😶",
6 | navlink: [
7 | { url: "/", label: "首页" },
8 | { url: "/about", label: "关于" },
9 | { url: "https://github.com/whatk233/gatsby-simple-tailwindcss-blog", label: "Github" },
10 | ],
11 | },
12 | plugins: [
13 | "gatsby-plugin-react-helmet",
14 | "gatsby-plugin-postcss",
15 | "gatsby-plugin-sitemap",
16 | "gatsby-plugin-image",
17 | "gatsby-plugin-sharp",
18 | {
19 | resolve: `gatsby-transformer-remark`,
20 | options: {
21 | plugins: [
22 | {
23 | resolve: `gatsby-remark-images`,
24 | options: {
25 | // It's important to specify the maxWidth (in pixels) of
26 | // the content container as this plugin uses this as the
27 | // base for generating different widths of each image.
28 | maxWidth: 590,
29 | },
30 | },
31 | ],
32 | },
33 | },
34 | {
35 | resolve: "gatsby-plugin-manifest",
36 | options: {
37 | icon: "src/images/icon.png",
38 | },
39 | },
40 | // pages createFilePath() slug is "/"
41 | {
42 | resolve: `gatsby-source-filesystem`,
43 | options: {
44 | path: `${__dirname}/content/pages`,
45 | name: `pages`,
46 | },
47 | },
48 | {
49 | resolve: `gatsby-source-filesystem`,
50 | options: {
51 | path: `${__dirname}/content`,
52 | name: `content`,
53 | },
54 | },
55 | {
56 | resolve: `gatsby-plugin-emotion`,
57 | options: {
58 | // Accepts the following options, all of which are defined by `@emotion/babel-plugin` plugin.
59 | // The values for each key in this example are the defaults the plugin uses.
60 | sourceMap: true,
61 | autoLabel: "dev-only",
62 | labelFormat: `[local]`,
63 | cssPropOptimization: true,
64 | },
65 | },
66 | ],
67 | };
68 |
--------------------------------------------------------------------------------
/gatsby-node.js:
--------------------------------------------------------------------------------
1 | const path = require(`path`);
2 | const { createFilePath } = require(`gatsby-source-filesystem`);
3 |
4 | exports.createPages = async ({ graphql, actions }) => {
5 | const { createPage } = actions;
6 |
7 | const postsListTemplate = path.resolve(`./src/templates/index.js`);
8 | const blogPostTemplate = path.resolve(`./src/templates/blog-post.js`);
9 | const blogPageTemplate = path.resolve(`./src/templates/blog-page.js`);
10 | const result = await graphql(
11 | `
12 | query MyQuery {
13 | posts: allMarkdownRemark(
14 | sort: { order: DESC, fields: frontmatter___date }
15 | filter: { fileAbsolutePath: { regex: "/content/posts/" } }
16 | limit: 1000
17 | ) {
18 | nodes {
19 | id
20 | frontmatter {
21 | title
22 | description
23 | date(formatString: "YYYY.MM.DD")
24 | }
25 | fields {
26 | slug
27 | }
28 | excerpt
29 | }
30 | }
31 | pages: allMarkdownRemark(
32 | sort: { order: DESC, fields: frontmatter___date }
33 | filter: { fileAbsolutePath: { regex: "/content/pages/" } }
34 | limit: 1000
35 | ) {
36 | nodes {
37 | id
38 | fields {
39 | slug
40 | }
41 | }
42 | }
43 | site {
44 | siteMetadata {
45 | title
46 | siteUrl
47 | description
48 | navlink {
49 | label
50 | url
51 | }
52 | }
53 | }
54 | }
55 | `
56 | );
57 |
58 | if (result.errors) {
59 | throw result.errors;
60 | }
61 |
62 | // Create single pages.
63 | const pages = result.data.pages.nodes;
64 | if (pages.length > 0) {
65 | pages.forEach((page) => {
66 | createPage({
67 | path: page.fields.slug,
68 | component: blogPageTemplate,
69 | context: {
70 | id: page.id,
71 | },
72 | });
73 | });
74 | }
75 |
76 | // Create blog posts pages.
77 | const posts = result.data.posts.nodes;
78 | if (posts.length > 0) {
79 | posts.forEach((post, index) => {
80 | const previousPostId =
81 | index === posts.length - 1 ? null : posts[index + 1].id;
82 | const nextPostId = index === 0 ? null : posts[index - 1].id;
83 | createPage({
84 | path: post.fields.slug,
85 | component: blogPostTemplate,
86 | context: {
87 | id: post.id,
88 | previousPostId,
89 | nextPostId,
90 | },
91 | });
92 | });
93 | }
94 |
95 | // Create pagination for posts list
96 | if (posts.length > 0) {
97 | // 每页显示的文章数量
98 | const postsOnPage = 8;
99 | // 获取文章总数
100 | const postsCount = Number(posts.length);
101 | // 需要页数
102 | const postsPagesCount = Math.ceil(postsCount / postsOnPage);
103 | // 文章列表
104 | let postsLists = [];
105 | // 当前文章顺序
106 | let nowPostRank = 0;
107 | // 分页生成文章列表
108 | for (let nowPage = 0; nowPage < postsPagesCount; nowPage++) {
109 | // 生成当前页面文章列表
110 | let nowPagePostsList = [];
111 | for (let index = 0; index < postsOnPage; index++) {
112 | // 将文章信息加入到当前列表中
113 | nowPagePostsList.push(posts[nowPostRank]);
114 | nowPostRank++;
115 | // 如果已到文章总数
116 | if (nowPostRank >= posts.length) {
117 | break;
118 | }
119 | }
120 | postsLists.push(nowPagePostsList);
121 | }
122 | // 创建分页
123 | postsLists.forEach((postsList, index) => {
124 | createPage({
125 | path: index == 0 ? "/" : `/page/${index + 1}`,
126 | component: postsListTemplate,
127 | context: {
128 | sitedata: result.data.site,
129 | posts: postsList,
130 | nowPageNum: index + 1,
131 | allPagesNum: postsPagesCount,
132 | previousPage: index == 0 ? null : index == 1 ? "/" : `/page/${index}`,
133 | nextPage:
134 | index < postsPagesCount - 1
135 | ? index == 0
136 | ? "/page/2"
137 | : `/page/${index + 2}`
138 | : null,
139 | },
140 | });
141 | });
142 | }
143 | };
144 |
145 | exports.onCreateNode = ({ node, actions, getNode }) => {
146 | // from https://github.com/keithnull/gatsby-starter-breeze/blob/HEAD/gatsby-node.js
147 | const { createNodeField } = actions;
148 | if (node.internal.type === `MarkdownRemark`) {
149 | // slug
150 | let slug = node.frontmatter.slug || createFilePath({ node, getNode });
151 | createNodeField({
152 | node,
153 | name: "slug",
154 | value: slug,
155 | });
156 | // date: front matter -> file name -> default date
157 | try {
158 | var date = node.frontmatter.date;
159 | if (!date) {
160 | const filename = node.fileAbsolutePath
161 | .split(/.*[\/|\\]/)[1]
162 | .split(".")[0];
163 | date = new Date(filename.substring(0, 10));
164 | if (isNaN(date)) {
165 | throw "Invalid Date";
166 | }
167 | }
168 | } catch (error) {
169 | console.warn(
170 | "Failed to get date from frontmatter or filename, use default date instead.",
171 | {
172 | slug: slug,
173 | filepath: node.fileAbsolutePath,
174 | error: error,
175 | }
176 | );
177 | date = new Date("1999-11-26");
178 | } finally {
179 | createNodeField({
180 | node,
181 | name: "date",
182 | value: date,
183 | });
184 | }
185 | }
186 | };
187 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gatsby-simple-tailwindcss-blog",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "a simple gatsby blog.",
6 | "author": "Whatk ",
7 | "bugs": {
8 | "url": "https://github.com/whatk233/gatsby-simple-tailwindcss-blog/issues"
9 | },
10 | "scripts": {
11 | "develop": "gatsby develop",
12 | "start": "gatsby develop",
13 | "build": "gatsby build",
14 | "serve": "gatsby serve",
15 | "clean": "gatsby clean"
16 | },
17 | "dependencies": {
18 | "@emotion/react": "^11.4.0",
19 | "@emotion/styled": "^11.3.0",
20 | "@tailwindcss/typography": "^0.4.1",
21 | "autoprefixer": "^10.3.1",
22 | "gatsby": "^3.9.1",
23 | "gatsby-plugin-emotion": "^6.9.0",
24 | "gatsby-plugin-image": "^1.10.1",
25 | "gatsby-plugin-manifest": "^3.9.0",
26 | "gatsby-plugin-postcss": "^4.9.0",
27 | "gatsby-plugin-react-helmet": "^4.9.0",
28 | "gatsby-plugin-sharp": "^3.10.2",
29 | "gatsby-plugin-sitemap": "^4.5.0",
30 | "gatsby-remark-images": "^5.7.0",
31 | "gatsby-source-filesystem": "^3.10.0",
32 | "gatsby-transformer-remark": "^4.6.0",
33 | "gatsby-transformer-sharp": "^3.10.0",
34 | "postcss": "^8.3.5",
35 | "react": "^17.0.1",
36 | "react-dom": "^17.0.1",
37 | "react-helmet": "^6.1.0",
38 | "tailwindcss": "^2.2.4"
39 | },
40 | "homepage": "https://github.com/gatsbyjs/gatsby-starter-blog#readme",
41 | "keywords": [
42 | "gatsby"
43 | ],
44 | "license": "MIT",
45 | "repository": {
46 | "type": "git",
47 | "url": "git+https://github.com/whatk233/gatsby-simple-tailwindcss-blog.git"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 |
3 | const Footer = ({ sitedata }) => {
4 | return (
5 |
21 | );
22 | };
23 |
24 | export default Footer;
25 |
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Link } from "gatsby";
3 |
4 | const Header = ({ sitedata, pagedata }) => {
5 | // switch btn color
6 | const switchBtnColor =
7 | typeof window !== "undefined"
8 | ? localStorage.theme === "dark"
9 | ? "text-white"
10 | : null
11 | : null;
12 |
13 | const switchTheme = () => {
14 | if (typeof window !== "undefined") {
15 | document.body.classList.add("transition");
16 | if (localStorage.theme === "dark") {
17 | document.body.classList.remove("dark");
18 | document.body.classList.remove("bg-gray-800");
19 | document
20 | .getElementById("switchThemeBtn")
21 | .classList.remove("text-white");
22 | localStorage.removeItem("theme");
23 | } else {
24 | document.body.classList.add("dark");
25 | document.body.classList.add("bg-gray-800");
26 | document.getElementById("switchThemeBtn").classList.add("text-white");
27 | localStorage.theme = "dark";
28 | }
29 | }
30 | };
31 | return (
32 | <>
33 | {pagedata ? (
34 | // page header
35 |
36 |