├── .gitignore
├── LICENSE
├── README.md
├── assets
├── css
│ ├── base.css
│ ├── components.css
│ └── main.css
└── svg
│ └── rss.svg
├── components
└── common
│ ├── Bio
│ ├── Bio.js
│ └── index.js
│ ├── Layout
│ ├── Layout.js
│ └── index.js
│ ├── Seo
│ ├── Seo.js
│ └── index.js
│ └── index.js
├── config
└── seo.json
├── content
├── assets
│ ├── cat.jpg
│ └── profile.png
└── posts
│ ├── coding-post
│ └── coding-post.md
│ ├── first-post
│ └── first-post.md
│ ├── long-post
│ └── long-post.md
│ └── second-post
│ └── second-post.md
├── jsconfig.json
├── netlify.toml
├── next.config.js
├── package.json
├── pages
├── _app.js
├── _document.js
├── index.js
└── posts
│ └── [slug].js
├── postcss.config.js
├── public
├── favicon.ico
├── rss.xml
└── zeit.svg
├── tailwind.config.js
├── utils
├── helpers.js
├── posts.js
└── rss.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 |
21 | # debug
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | # local env files
27 | .env.local
28 | .env.development.local
29 | .env.test.local
30 | .env.production.local
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Jose Felix
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 | Next.js blog starter
3 |
4 |
5 | Start off your writing journey with this Next.js markdown blog template.
6 |
7 | ## ✏ Features
8 |
9 | - Next.js 12!
10 | - RSS Feed
11 | - Streamlined styling experience with [Tailwind.css](https://tailwindcss.com/).
12 | - Customizable typographic defaults with [Tailwind Typography](https://github.com/tailwindlabs/tailwindcss-typography)
13 | - Automatic image preview and optimization with [next-optimized-images](https://github.com/cyrilwanner/next-optimized-images).
14 | - Lazyload images.
15 | - Absolute imports.
16 | - SEO friendly.
17 | - Markdown code highlighting with [react-syntax-highlighter](https://www.npmjs.com/package/react-syntax-highlighter) and [PrismJs](https://prismjs.com/).
18 | - Dark Mode
19 | - WebP image support
20 |
21 | ## 🚀 Getting Started
22 |
23 | First, run the development server:
24 |
25 | ```bash
26 | npm run dev
27 | # or
28 | yarn dev
29 | ```
30 |
31 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
32 |
33 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
34 |
35 | ## ✍ Customizing Tailwind Typography
36 |
37 | [Tailwind Typography](https://github.com/tailwindlabs/tailwindcss-typography) is an official tailwind plugin that provides a set of `prose` classes to add beautiful typographic defaults to any vanilla HTML you don't control (like HTML rendered from Markdown, or pulled from a CMS).
38 |
39 | To customize the defaults provided by the plugin, add the overrides under the `typography` key in the theme section of the `tailwind.config.js` file. Refer to its [default styles](https://github.com/tailwindlabs/tailwindcss-typography/blob/master/src/styles.js) for more in-depth examples.
40 |
41 | For more information, please check out Tailwind Typography's [customization section](https://github.com/tailwindlabs/tailwindcss-typography#customization).
42 |
43 | ## 📖 Learn More
44 |
45 | ### Next.js
46 |
47 | To learn more about Next.js, take a look at the following resources:
48 |
49 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
50 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
51 |
52 | You can check out [the Next.js GitHub repository](https://github.com/zeit/next.js/) - your feedback and contributions are welcome!
53 |
54 | ### Tailwind CSS
55 |
56 | To learn more about Tailwind CSS, take a look at the following resources:
57 |
58 | - [Tailwind Documentation](https://tailwindcss.com/) - learn about Tailwind CSS features and API.
59 |
60 | ## ☑ Upcoming features
61 |
62 | - [ ] Add Sitemap
63 | - [x] Add RSS Feed
64 | - [x] Dark Mode
65 | - [x] Add support for WebP images
66 | - [x] Add SEO Component
67 | - [x] Add Dynamic Site Metadata
68 |
69 | ## ☁ Deploy
70 |
71 | [](https://app.netlify.com/start/deploy?repository=https://github.com/Jfelix61/nextjs-starter-blog)
72 |
73 | [](https://zeit.co/import/project?template=https://github.com/Jfelix61/nextjs-starter-blog)
74 |
--------------------------------------------------------------------------------
/assets/css/base.css:
--------------------------------------------------------------------------------
1 | a:hover {
2 | @apply underline;
3 | }
4 |
5 | span,
6 | p {
7 | @apply font-light;
8 | }
9 |
--------------------------------------------------------------------------------
/assets/css/components.css:
--------------------------------------------------------------------------------
1 | .blur {
2 | -webkit-filter: blur(5px);
3 | filter: blur(5px);
4 | transition: filter 500ms ease-in, -webkit-filter 500ms ease-in;
5 | }
6 |
7 | .blur.lazyloaded {
8 | -webkit-filter: blur(0);
9 | filter: blur(0);
10 | }
11 |
--------------------------------------------------------------------------------
/assets/css/main.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | @layer base {
6 | @import "./base.css";
7 |
8 | a {
9 | @apply text-neon-orange dark:text-yellow-500;
10 | }
11 | }
12 |
13 | @layer components {
14 | @import "./components.css";
15 | }
16 |
--------------------------------------------------------------------------------
/assets/svg/rss.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/components/common/Bio/Bio.js:
--------------------------------------------------------------------------------
1 | import clsx from "clsx";
2 |
3 | import Image from "next/image";
4 |
5 | import { getSiteMetaData } from "@utils/helpers";
6 | import profilePicture from "@/content/assets/profile.png";
7 |
8 | export function Bio({ className }) {
9 | const { author, social } = getSiteMetaData();
10 |
11 | return (
12 |
;
11 |
12 | export default CoolComponent;
13 | ```
14 |
--------------------------------------------------------------------------------
/content/posts/first-post/first-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: First post
3 | description: The first post is the most memorable one.
4 | date: 2020-04-16T11:00:00.000Z
5 | ---
6 |
7 | # h1
8 |
9 | ## h2
10 |
11 | ### h3
12 |
13 | Normal text
14 |
15 | 
16 |
--------------------------------------------------------------------------------
/content/posts/long-post/long-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Long Post
3 | date: 2020-07-28T22:40:32.169Z
4 | description: Who doesn't like a long post showcasing the different headings?
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.
--------------------------------------------------------------------------------
/content/posts/second-post/second-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Second post
3 | description: The second post is the least memorable.
4 | date: 2020-04-17T11:00:00.000Z
5 | ---
6 |
7 | # h1
8 |
9 | ## h2
10 |
11 | ### h3
12 |
13 | Normal text
14 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@components/*": ["components/*"],
6 | "@utils/*": ["utils/*"],
7 | "@assets/*": ["assets/*"],
8 | "@config/*": ["config/*"],
9 | "@/*": ["./*"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | # Directory (relative to root of your repo) that contains the deploy-ready
3 | # HTML files and assets generated by the build. If a base directory has
4 | # been specified, include it in the publish directory path.
5 | publish = "out"
6 |
7 | # Default build command.
8 | command = "npm run build && npx next export"
9 |
10 | environment = { NODE_VERSION = "12.13.1" }
11 |
12 |
13 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | webpack(config) {
3 | config.module.rules.push({
4 | test: /\.svg$/,
5 | use: ["@svgr/webpack"],
6 | });
7 |
8 | return config;
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-blog-starter",
3 | "version": "0.3.0",
4 | "description": "A Next.js template for a blog website.",
5 | "private": true,
6 | "engines": {
7 | "node": "14"
8 | },
9 | "scripts": {
10 | "dev": "next dev",
11 | "build": "next build",
12 | "start": "next start"
13 | },
14 | "dependencies": {
15 | "@svgr/webpack": "^6.1.1",
16 | "clsx": "^1.1.1",
17 | "feed": "^4.2.2",
18 | "next": "12.0.7",
19 | "next-compose-plugins": "^2.2.1",
20 | "next-themes": "^0.0.15",
21 | "react": "17.0.2",
22 | "react-dom": "17.0.2",
23 | "react-markdown": "^5.0.3",
24 | "react-syntax-highlighter": "^15.4.5",
25 | "react-toggle-dark-mode": "^1.0.4",
26 | "typeface-merriweather": "^1.1.13",
27 | "typeface-open-sans": "^1.1.13",
28 | "webp-loader": "^0.6.0"
29 | },
30 | "devDependencies": {
31 | "@tailwindcss/typography": "^0.4.1",
32 | "autoprefixer": "^10.4.0",
33 | "gray-matter": "^4.0.3",
34 | "postcss": "^8.4.4",
35 | "tailwindcss": "^2.2.19"
36 | },
37 | "license": "MIT",
38 | "repository": {
39 | "type": "git",
40 | "url": "git+https://github.com/Jfelix61/nextjs-starter-blog.git"
41 | },
42 | "homepage": "https://github.com/Jfelix61/nextjs-starter-blog#readme",
43 | "keywords": [
44 | "next.js",
45 | "blog",
46 | "template"
47 | ]
48 | }
49 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | import { ThemeProvider } from "next-themes";
2 |
3 | import "@assets/css/main.css";
4 |
5 | import "typeface-open-sans";
6 | import "typeface-merriweather";
7 |
8 | export default function MyApp({ Component, pageProps }) {
9 | return (
10 |
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/pages/_document.js:
--------------------------------------------------------------------------------
1 | import Document, { Head, Main, NextScript, Html } from "next/document";
2 |
3 | import { getSiteMetaData } from "@utils/helpers";
4 |
5 | export default class MyDocument extends Document {
6 | render() {
7 | const siteMetadata = getSiteMetaData();
8 |
9 | return (
10 |
11 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 |
3 | import { Layout, Bio, SEO } from "@components/common";
4 | import { getSortedPosts } from "@utils/posts";
5 | import { generateRssPostsFeed } from "@utils/rss";
6 |
7 | export default function Home({ posts }) {
8 | return (
9 |
10 |
11 |
12 | {posts.map(({ frontmatter: { title, description, date }, slug }) => (
13 |
14 |
15 |