Skip to content

Commit 31b0719

Browse files
authored
Initial commit
0 parents  commit 31b0719

35 files changed

+14165
-0
lines changed

.eslintrc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["next/core-web-vitals", "prettier"]
3+
}

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env.local
29+
.env.development.local
30+
.env.test.local
31+
.env.production.local
32+
33+
# vercel
34+
.vercel
35+
36+
# netlify
37+
.netlify

.prettierrc.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
printWidth: 80,
3+
semi: true,
4+
singleQuote: true,
5+
tabWidth: 2,
6+
useTabs: false,
7+
};

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 nextjs-blog-theme
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

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
![Netlify Next.js Blog Template designed by Bejamas](https://user-images.githubusercontent.com/43764894/223762618-62742b4e-9424-44a7-8e85-9f7e4e19db54.png)
2+
3+
4+
[![Deploy to Netlify Button](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/netlify-templates/nextjs-blog-theme)
5+
6+
7+
A customizable blog starter using:
8+
9+
- [Next.js](https://github.com/vercel/next.js) v14 (Pages Router)
10+
- [Tailwind](https://tailwindcss.com/) v3.0
11+
- Built-in [MDX](https://mdxjs.com/) v1 support
12+
- Includes modern design with dark & light themes
13+
14+
![Preview of blog theme. Author named Jay Doe and blog's name is "Next.js Blog Theme" with one blog post](nextjs-blog-theme-preview.png)
15+
16+
[Take a gander at the demo.](https://bejamas-nextjs-blog.netlify.app)
17+
18+
[Click here to watch the template walkthrough!](https://www.youtube.com/watch?v=63QZHs259dY)
19+
20+
## Table of Contents:
21+
22+
- [Getting Started](#getting-started)
23+
- [Setting Up Locally](#setting-up-locally)
24+
- [Using the Wizard](#using-the-setup-wizard)
25+
- [Configuring the Blog](#configuring-the-blog)
26+
- [Adding New Posts](#adding-new-posts)
27+
- [Testing](#testing)
28+
- [Included Default Testing](#included-default-testing)
29+
- [Removing Renovate](#removing-renovate)
30+
31+
## Getting Started
32+
33+
---
34+
35+
You can get started with this project in two ways: locally or using the [setup wizard](https://nextjs-wizard.netlify.app/).
36+
37+
### Setting Up Locally
38+
39+
If you're doing it locally, start with clicking the [use this template](https://github.com/netlify-templates/nextjs-blog-theme/generate) button on GitHub. This will create a new repository with this template's files on your GitHub account. Once that is done, clone your new repository and navigate to it in your terminal.
40+
41+
From there, you can install the project's dependencies by running:
42+
43+
```shell
44+
yarn install
45+
```
46+
47+
Finally, you can run your project locally with:
48+
49+
```shell
50+
yarn run dev
51+
```
52+
53+
Open your browser and visit <http://localhost:3000>, your project should be running!
54+
55+
### Using the Setup Wizard
56+
57+
![Preview of Setup Wizard showing the initial page of a setup form](nextjs-setup-wizard.png)
58+
59+
Through the [setup wizard](https://nextjs-wizard.netlify.app/), you can create your blog in a few clicks and deploy to Netlify.
60+
61+
## Configuring the blog
62+
63+
The config is based on environment variables to make it easy to integrate with any Jamstack platform, like Netlify.
64+
65+
Here are the variables you can edit:
66+
| Variable | Description | Options
67+
| --- | --- | --- |
68+
| `BLOG_NAME` | the name of your blog, displayed below the avatar ||
69+
| `BLOG_TITLE` | the main header (`h1`) on the home page ||
70+
| `BLOG_FOOTER_TEXT`| the text in the footer ||
71+
| `BLOG_THEME` | the theme to pass to Tailwind | default |
72+
| `BLOG_FONT_HEADINGS` | the font-family for all HTML headings, from `h1` to `h6`| sans-serif (default), serif, monospace|
73+
| `BLOG_FONT_PARAGRAPHS` | the font-family for all other HTML elements | sans-serif (default), serif, monospace|
74+
75+
All of the env variables can be configured through the [Wizard](https://nextjs-wizard.netlify.app/) or through setting the project's environment variables. You can do this in your Netlify dashaboard (Site settings/Build & deploy/Environment/Environment variables).
76+
77+
https://user-images.githubusercontent.com/3611928/153997545-6dcdeef0-e570-49e7-93d6-ce0d393d16c9.mp4
78+
79+
[alt: video walkthrough of editing env vars]
80+
81+
If setting an environment variable isn't your cup of tea, the defaults can be changed in [`utils/global-data.js`](/utils/global-data.js). You can also remove the variables and hard code blog information where these variables are used in the code base.
82+
83+
- `BLOG_THEME, BLOG_FONT_HEADINGS, & BLOG_FONT_PARAGRAPHS` are used in [`tailwind-preset.js`](tailwind-preset.js)
84+
- `BLOG_NAME, BLOG_TITLE, BLOG_FOOTER_TEXT` are used in [`pages/index.js`](pages/index.js) & [`pages/posts/[slug].js`](pages/posts/[slug].js) through the `globalData` object.
85+
86+
## Adding new posts
87+
88+
All posts are stored in `/posts` directory. To make a new post, create a new file with the [`.mdx` extension](https://mdxjs.com/).
89+
90+
Since the posts are written in `MDX` format you can pass props and components. That means you can use [React components](https://reactjs.org/docs/components-and-props.html) inside your posts to make them more interactive. Learn more about how to do so in the [MDX docs on content](https://mdxjs.com/docs/using-mdx/#components).
91+
92+
https://user-images.githubusercontent.com/3611928/152727802-102ec296-41c8-446d-93ed-922d11187073.mp4
93+
94+
[alt: video walkthrough of adding a new blog post]
95+
96+
## Testing
97+
98+
### Included Default Testing
99+
100+
We’ve included some tooling that helps us maintain these templates. This template currently uses:
101+
102+
- [Renovate](https://www.mend.io/free-developer-tools/renovate/) - to regularly update our dependencies
103+
104+
If your team is not interested in this tooling, you can remove them with ease!
105+
106+
### Removing Renovate
107+
108+
In order to keep our project up-to-date with dependencies we use a tool called [Renovate](https://github.com/marketplace/renovate). If you’re not interested in this tooling, delete the `renovate.json` file and commit that onto your main branch.

components/ArrowIcon.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export default function ArrowIcon({ className, color = 'text-primary' }) {
2+
return (
3+
<svg
4+
xmlns="http://www.w3.org/2000/svg"
5+
width="24"
6+
height="24"
7+
fill="none"
8+
viewBox="0 0 24 24"
9+
className={className}
10+
>
11+
<path
12+
className={`stroke-current ${color}`}
13+
strokeLinecap="round"
14+
strokeLinejoin="round"
15+
strokeWidth="2"
16+
d="M5 12h14M12 19l7-7-7-7"
17+
></path>
18+
</svg>
19+
);
20+
}

components/CustomLink.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Link from 'next/link';
2+
3+
export default function CustomLink({ as, href, ...otherProps }) {
4+
return <>
5+
<Link as={as} href={href} {...otherProps}>
6+
7+
</Link>
8+
</>;
9+
}

components/Footer.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
const sunIcon = (
2+
<svg
3+
xmlns="http://www.w3.org/2000/svg"
4+
width="25"
5+
height="24"
6+
fill="none"
7+
viewBox="0 0 25 24"
8+
className="dark:opacity-50"
9+
>
10+
<g
11+
stroke="#fff"
12+
strokeLinecap="round"
13+
strokeLinejoin="round"
14+
strokeWidth="2"
15+
clipPath="url(#clip0_192_823)"
16+
>
17+
<path d="M12.5 17a5 5 0 100-10 5 5 0 000 10zM12.5 1v2M12.5 21v2M4.72 4.22l1.42 1.42M18.86 18.36l1.42 1.42M1.5 12h2M21.5 12h2M4.72 19.78l1.42-1.42M18.86 5.64l1.42-1.42"></path>
18+
</g>
19+
<defs>
20+
<clipPath id="clip0_192_823">
21+
<path
22+
className="fill-current text-white"
23+
d="M0 0H24V24H0z"
24+
transform="translate(.5)"
25+
></path>
26+
</clipPath>
27+
</defs>
28+
</svg>
29+
);
30+
31+
const moonIcon = (
32+
<svg
33+
xmlns="http://www.w3.org/2000/svg"
34+
width="21"
35+
height="20"
36+
fill="none"
37+
viewBox="0 0 21 20"
38+
>
39+
<path
40+
stroke="#fff"
41+
strokeLinecap="round"
42+
strokeLinejoin="round"
43+
strokeWidth="2"
44+
className="stroke-current text-gray-400 dark:text-white"
45+
d="M19.5 10.79A9 9 0 119.71 1a7 7 0 009.79 9.79v0z"
46+
></path>
47+
</svg>
48+
);
49+
50+
const ThemeSwitcher = () => {
51+
return (
52+
<div className="flex mt-6 bg-white justify-center dark:bg-gray-900 rounded-3xl p-1">
53+
<button
54+
type="button"
55+
aria-label="Use Dark Mode"
56+
onClick={() => {
57+
document.documentElement.classList.add('dark');
58+
localStorage.setItem('theme', 'dark');
59+
}}
60+
className="flex items-center h-full pr-2 dark:bg-primary rounded-3xl flex justify-center align-center p-2 w-24 h-10 transition"
61+
>
62+
{moonIcon}
63+
</button>
64+
65+
<button
66+
type="button"
67+
aria-label="Use Light Mode"
68+
onClick={() => {
69+
document.documentElement.classList.remove('dark');
70+
localStorage.setItem('theme', 'light');
71+
}}
72+
className="flex items-center h-full pr-2 bg-primary dark:bg-transparent rounded-3xl flex justify-center align-center p-2 w-24 h-10 transition"
73+
>
74+
{sunIcon}
75+
</button>
76+
</div>
77+
);
78+
};
79+
80+
export default function Footer({ copyrightText }) {
81+
return (
82+
<footer className="py-16 flex flex-col items-center">
83+
<p className="dark:text-white uppercase mb-3 font-bold opacity-60">
84+
{copyrightText}
85+
</p>
86+
<ThemeSwitcher />
87+
</footer>
88+
);
89+
}

components/Header.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Link from 'next/link';
2+
3+
export default function Header({ name }) {
4+
return (
5+
<header className="pt-20 pb-12">
6+
<div className="w-12 h-12 rounded-full block mx-auto mb-4 bg-gradient-conic from-gradient-3 to-gradient-4" />
7+
<p className="text-2xl dark:text-white text-center">
8+
<Link href="/">
9+
{name}
10+
</Link>
11+
</p>
12+
</header>
13+
);
14+
}

components/Layout.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import classNames from 'classnames';
2+
import { useEffect } from 'react';
3+
import styles from './Layout.module.css';
4+
5+
export function GradientBackground({ variant, className }) {
6+
const classes = classNames(
7+
{
8+
[styles.colorBackground]: variant === 'large',
9+
[styles.colorBackgroundBottom]: variant === 'small',
10+
},
11+
className
12+
);
13+
14+
return <div className={classes} />;
15+
}
16+
17+
export default function Layout({ children }) {
18+
const setAppTheme = () => {
19+
const darkMode = localStorage.getItem('theme') === 'dark';
20+
const lightMode = localStorage.getItem('theme') === 'light';
21+
22+
if (darkMode) {
23+
document.documentElement.classList.add('dark');
24+
} else if (lightMode) {
25+
document.documentElement.classList.remove('dark');
26+
}
27+
return;
28+
};
29+
30+
const handleSystemThemeChange = () => {
31+
var darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
32+
33+
darkQuery.onchange = (e) => {
34+
if (e.matches) {
35+
document.documentElement.classList.add('dark');
36+
localStorage.setItem('theme', 'dark');
37+
} else {
38+
document.documentElement.classList.remove('dark');
39+
localStorage.setItem('theme', 'light');
40+
}
41+
};
42+
};
43+
44+
useEffect(() => {
45+
setAppTheme();
46+
}, []);
47+
48+
useEffect(() => {
49+
handleSystemThemeChange();
50+
}, []);
51+
52+
return (
53+
<div className="relative pb-24 overflow-hidden">
54+
<div className="flex flex-col items-center max-w-2xl w-full mx-auto">
55+
{children}
56+
</div>
57+
</div>
58+
);
59+
}

0 commit comments

Comments
 (0)