├── .eslintrc.js
├── .eslintrc.json
├── .gitignore
├── .husky
└── pre-commit
├── .prettierignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── components
├── BlogPost.tsx
├── Divider.tsx
├── Footer.tsx
├── Header.tsx
├── Hero.tsx
├── Layout.tsx
├── NavItems.tsx
├── ProjectCard.tsx
├── SubscribeForm.tsx
├── TopBlogPost.tsx
├── TopTweets.tsx
└── index.ts
├── contentlayer.config.ts
├── data
├── menus.ts
├── posts
│ ├── encode-decode-string-golang.md
│ ├── next-js-resources.md
│ └── what-is-json-web-token.md
├── projects.ts
└── tweets.ts
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── pages
├── _app.tsx
├── _document.tsx
├── blog
│ ├── [slug].tsx
│ └── index.tsx
├── contact.tsx
├── index.tsx
├── projects.tsx
└── top-tweets.tsx
├── postcss.config.js
├── public
├── developer-avatar.png
├── favicon.ico
└── projects
│ └── project.png
├── styles
└── globals.css
├── tailwind.config.js
├── tsconfig.json
└── types.ts
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es2021: true,
5 | node: true,
6 | },
7 | extends: [
8 | "eslint:recommended",
9 | "plugin:@typescript-eslint/recommended",
10 | "prettier",
11 | "next/core-web-vitals",
12 | ],
13 | parser: "@typescript-eslint/parser",
14 | parserOptions: {
15 | ecmaFeatures: {
16 | jsx: true,
17 | },
18 | ecmaVersion: "latest",
19 | sourceType: "module",
20 | },
21 | plugins: ["react", "@typescript-eslint"],
22 | rules: {
23 | "@typescript-eslint/no-explicit-any": "off",
24 | "@typescript-eslint/no-var-requires": "off",
25 | },
26 | settings: {
27 | react: {
28 | version: "detect",
29 | },
30 | },
31 | overrides: [
32 | {
33 | files: ["*.js"],
34 | },
35 | ],
36 | };
37 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.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 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 |
37 |
38 | # Contentlayer
39 | .contentlayer
40 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | echo '🏗️👷 Styling, testing and building your project before committing'
5 |
6 | # Check Prettier standards
7 | npm run check-format ||
8 | (
9 | echo '🤢🤮🤢🤮 Its F**KING RAW - Your styling looks disgusting. 🤢🤮🤢🤮
10 | Prettier Check Failed. Run npm run format, add changes and try commit again.';
11 | false;
12 | )
13 |
14 | # Check ESLint Standards
15 | npm run check-lint ||
16 | (
17 | echo '😤🏀👋😤 Get that weak s**t out of here! 😤🏀👋😤
18 | ESLint Check Failed. Make the required changes listed above, add changes and try to commit again.'
19 | false;
20 | )
21 |
22 | # Check tsconfig standards
23 | npm run check-types ||
24 | (
25 | echo '🤡😂❌🤡 Failed Type check. 🤡😂❌🤡
26 | Are you seriously trying to write that? Make the changes required above.'
27 | false;
28 | )
29 |
30 | # If everything passes... Now we can commit
31 | echo '🤔🤔🤔🤔... Alright... Code looks good to me... 🤔🤔🤔🤔'
32 |
33 | # npm run build ||
34 | # (
35 | # echo '❌👷🔨❌ Better call Bob... Because your build failed ❌👷🔨❌
36 | # Next build failed: View the errors above to see why.
37 | # '
38 | # false;
39 | # )
40 |
41 | # If everything passes... Now we can commit
42 | echo '✅✅✅✅ You win this time... I am committing this now. ✅✅✅✅'
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .next
3 | public
4 | **/**/node_modules
5 | **/**/.next
6 | **/**/public
7 | npm/migration/**
8 |
9 | *.lock
10 | *.log
11 |
12 | .gitignore
13 | .npmignore
14 | .prettierignore
15 | .DS_Store
16 | .eslintignore
17 |
18 | out
19 |
20 | .contentlayer
21 |
22 | data/posts/*
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "endOfLine": "lf",
3 | "printWidth": 80,
4 | "tabWidth": 2,
5 | "trailingComma": "es5"
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Kiran K
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NextJS Blog Template for Developers
2 |
3 | This is a simple NextJS blog template for developers. Still in development. Feel free to contribute!
4 |
5 | ## Pages
6 |
7 | - [x] Home
8 | - [x] Projects
9 | - [x] Blog
10 | - [x] Contact form
11 | - [x] Subscribe to the email form
12 | - [x] Latest Articles & News
13 | - [x] Top Tweets
14 | - [ ] Open Source Contributions
15 | - [ ] Make the header mobile responsive
16 |
17 | ## Demo
18 |
19 | See the [demo](https://nextjs-blog-template-xi.vercel.app/)
20 |
21 | ## How to update the data (Posts, Projects, etc.)
22 |
23 | - Add new posts to the `data/posts` folder.
24 | - Add new projects to the `data/projects.ts` file.
25 | - Add new tweets to the `data/tweets.ts` file.
26 | - Add new menu items to the `data/menus.ts` file.
27 |
28 | ## Development
29 |
30 | First, run the development server:
31 |
32 | ```bash
33 | npm run dev
34 | ```
35 |
36 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
37 |
38 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
39 |
40 | ## Learn More
41 |
42 | To learn more about Next.js, take a look at the following resources:
43 |
44 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
45 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
46 |
47 | ## Deploy on Vercel
48 |
49 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
50 |
51 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
52 |
--------------------------------------------------------------------------------
/components/BlogPost.tsx:
--------------------------------------------------------------------------------
1 | import type { Post } from "contentlayer/generated";
2 | import Link from "next/link";
3 |
4 | const BlogPost = ({ post }: { post: Post }) => {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | {post.title}
12 |
13 |
14 | {post.description}
15 |
16 |
{post.publishedAt}
17 |
18 |
19 |
20 |
21 | );
22 | };
23 |
24 | export default BlogPost;
25 |
--------------------------------------------------------------------------------
/components/Divider.tsx:
--------------------------------------------------------------------------------
1 | const Divider = () => {
2 | return
;
3 | };
4 |
5 | export default Divider;
6 |
--------------------------------------------------------------------------------
/components/Footer.tsx:
--------------------------------------------------------------------------------
1 | const Footer = () => {
2 | return (
3 |
13 | );
14 | };
15 |
16 | export default Footer;
17 |
--------------------------------------------------------------------------------
/components/Header.tsx:
--------------------------------------------------------------------------------
1 | import NavItems from "./NavItems";
2 |
3 | const Header = () => {
4 | return (
5 |
6 |
Kiran K
7 |
8 |
9 | );
10 | };
11 |
12 | export default Header;
13 |
--------------------------------------------------------------------------------
/components/Hero.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 |
3 | const Hero = () => {
4 | return (
5 |
6 |
Kiran Krishnan
7 |
8 | Software Engineer (Open Source, Dev Tools) @ BoxyHQ
9 |
10 |
11 | Sharing my journey in tech. Open source contributor. I'm excited to
12 | learn new languages and contribute to OSS.
13 |
14 |
19 |
20 | );
21 | };
22 |
23 | export default Hero;
24 |
--------------------------------------------------------------------------------
/components/Layout.tsx:
--------------------------------------------------------------------------------
1 | import Header from "./Header";
2 | import Footer from "./Footer";
3 | import React from "react";
4 |
5 | const Layout = ({ children }: { children: React.ReactElement }) => {
6 | return (
7 |
8 |
9 |
{children}
10 |
11 |
12 | );
13 | };
14 |
15 | export default Layout;
16 |
--------------------------------------------------------------------------------
/components/NavItems.tsx:
--------------------------------------------------------------------------------
1 | import type { Menu } from "types";
2 | import Link from "next/link";
3 | import menus from "data/menus";
4 | import { useRouter } from "next/router";
5 |
6 | const Nav = () => {
7 | return (
8 |
9 |
10 | {menus.map((menu) => (
11 |
15 |
16 |
17 | ))}
18 |
19 |
20 | );
21 | };
22 |
23 | const NavItem = ({ menu }: { menu: Menu }) => {
24 | const router = useRouter();
25 |
26 | const { asPath } = router;
27 |
28 | return (
29 |
30 |
33 | {menu.title}
34 |
35 |
36 | );
37 | };
38 |
39 | export default Nav;
40 |
--------------------------------------------------------------------------------
/components/ProjectCard.tsx:
--------------------------------------------------------------------------------
1 | import type { Project } from "types";
2 | import Link from "next/link";
3 |
4 | const ProjectCard = ({ project }: { project: Project; key: string }) => {
5 | return (
6 |
21 | );
22 | };
23 |
24 | export default ProjectCard;
25 |
--------------------------------------------------------------------------------
/components/SubscribeForm.tsx:
--------------------------------------------------------------------------------
1 | const SubscribeForm = () => {
2 | return (
3 |
4 |
5 |
6 | Subscribe to the email newsletter
7 |
8 |
9 | Join 5,000+ others and never miss out on new tips, tutorials, and
10 | more.
11 |
12 |
24 |
25 |
26 | );
27 | };
28 |
29 | export default SubscribeForm;
30 |
--------------------------------------------------------------------------------
/components/TopBlogPost.tsx:
--------------------------------------------------------------------------------
1 | import { BlogPost } from "components";
2 | import type { Post } from "contentlayer/generated";
3 |
4 | const TopBlogPost = ({ posts }: { posts: Post[] | null }) => {
5 | return (
6 | <>
7 |
8 | Latest Articles & News
9 |
10 |
11 | {posts &&
12 | posts.map((post) => )}
13 |
14 | >
15 | );
16 | };
17 |
18 | export default TopBlogPost;
19 |
--------------------------------------------------------------------------------
/components/TopTweets.tsx:
--------------------------------------------------------------------------------
1 | import { TwitterTweetEmbed } from "react-twitter-embed";
2 | import tweets from "data/tweets";
3 |
4 | const TopTweets = () => {
5 | return (
6 | <>
7 |
8 | {tweets.map((tweetId) => (
9 |
10 | ))}
11 |
12 | >
13 | );
14 | };
15 |
16 | export default TopTweets;
17 |
--------------------------------------------------------------------------------
/components/index.ts:
--------------------------------------------------------------------------------
1 | export { default as BlogPost } from "./BlogPost";
2 | export { default as Footer } from "./Footer";
3 | export { default as Header } from "./Header";
4 | export { default as Hero } from "./Hero";
5 | export { default as Layout } from "./Layout";
6 | export { default as NavItems } from "./NavItems";
7 | export { default as ProjectCard } from "./ProjectCard";
8 | export { default as SubscribeForm } from "./SubscribeForm";
9 | export { default as TopTweets } from "./TopTweets";
10 | export { default as TopBlogPost } from "./TopBlogPost";
11 | export { default as Divider } from "./Divider";
12 |
--------------------------------------------------------------------------------
/contentlayer.config.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ComputedFields,
3 | defineDocumentType,
4 | makeSource,
5 | } from "contentlayer/source-files";
6 |
7 | const computedFields: ComputedFields = {
8 | slug: {
9 | type: "string",
10 | resolve: (doc) => doc._raw.sourceFileName.replace(/\.md$/, ""),
11 | },
12 | };
13 |
14 | const Post = defineDocumentType(() => ({
15 | name: "Post",
16 | filePathPattern: "**/*.md",
17 | contentType: "markdown",
18 | fields: {
19 | title: { type: "string", required: true },
20 | publishedAt: { type: "string", required: true },
21 | description: { type: "string", required: true },
22 | image: { type: "string", required: false },
23 | },
24 | computedFields,
25 | }));
26 |
27 | export default makeSource({
28 | contentDirPath: "data/posts",
29 | documentTypes: [Post],
30 | });
31 |
--------------------------------------------------------------------------------
/data/menus.ts:
--------------------------------------------------------------------------------
1 | const menus = [
2 | {
3 | title: "Home",
4 | path: "/",
5 | },
6 | {
7 | title: "Projects",
8 | path: "/projects",
9 | },
10 | {
11 | title: "Blog",
12 | path: "/blog",
13 | },
14 | {
15 | title: "Top Tweets",
16 | path: "/top-tweets",
17 | },
18 | {
19 | title: "Contact",
20 | path: "/contact",
21 | },
22 | ];
23 |
24 | export default menus;
25 |
--------------------------------------------------------------------------------
/data/posts/encode-decode-string-golang.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to Base64 encode and decode data in Golang
3 | publishedAt: '2022-03-03'
4 | description: In this article, I'll show you Base64 encoding and decoding in Golang.
5 | ---
6 |
7 | In this post, I'll show you Base64 encoding and decoding in Golang.
8 |
9 | Base64 encoding schemes are commonly used when there is a need to encode binary data that needs to be stored and transferred over media that are designed to deal with ASCII.
10 |
11 | This is to ensure that the data remain intact without modification during transport.
12 |
13 | Read more about the Base64 encoding scheme [here](https://developer.mozilla.org/en-US/docs/Glossary/Base64).
14 |
15 | Golang provides built-in support for base64 encoding and decoding with a package `encoding/base64`.
16 |
17 | Let's see the code for base64 encoding and decoding in Golang.
18 |
19 | Create a new folder called `base64-encode-decode`.
20 |
21 | ```bash
22 | mkdir base64-encode-decode
23 |
24 | cd base64-encode-decode
25 |
26 | touch main.go
27 | ```
28 |
29 | Open the `main.go` and import the necessary packages.
30 |
31 | ```go
32 | package main
33 |
34 | import (
35 | "encoding/base64"
36 | "fmt"
37 | )
38 | ```
39 |
40 | The package `encoding/base64` provides 2 functions for encoding and decoding data in Base64 format.
41 |
42 | `EncodeToString` encodes the passed data in Base64 format and returns the encoded data as a string.
43 |
44 | ```go
45 | func (enc *Encoding) EncodeToString(src []byte) string
46 | ```
47 |
48 | `DecodeString` decodes the passed data (string) and returns the decoded data as a byte slice.
49 |
50 | ```go
51 | func (enc *Encoding) DecodeString(s string) ([]byte, error)
52 | ```
53 |
54 | Let's add the code to encode and print the encoded data.
55 |
56 | ```go
57 | func main() {
58 | text := "Hello World - Go!"
59 |
60 | encodedText := base64.StdEncoding.EncodeToString([]byte(text));
61 |
62 | fmt.Printf("Encoded Text: %s\n", encodedText)
63 | }
64 | ```
65 |
66 | The above code will print the following output:
67 |
68 | ```go
69 | Encoded Text: SGVsbG8gV29ybGQgLSBHbyE=
70 | ```
71 |
72 | Now, let's add the code to decode the encoded data and print the decoded data.
73 |
74 | ```go
75 | decodedText, err := base64.StdEncoding.DecodeString(encodedText);
76 | if err != nil {
77 | panic(err)
78 | }
79 |
80 | fmt.Printf("Decoded Text: %s\n", decodedText)
81 | ```
82 |
83 | The above code will print the following output:
84 |
85 | ```
86 | Decoded Text: Hello World - Go!
87 | ```
88 |
89 | Here is the complete working code.
90 |
91 | ```go
92 | package main
93 |
94 | import (
95 | "encoding/base64"
96 | "fmt"
97 | )
98 |
99 | func main() {
100 | text := "Hello World - Go!"
101 |
102 | encodedText := base64.StdEncoding.EncodeToString([]byte(text));
103 |
104 | fmt.Printf("Encoded Text: %s\n", encodedText)
105 |
106 | decodedText, err := base64.StdEncoding.DecodeString(encodedText);
107 | if err != nil {
108 | panic(err)
109 | }
110 |
111 | fmt.Printf("Decoded Text: %s\n", decodedText)
112 | }
113 | ```
114 |
--------------------------------------------------------------------------------
/data/posts/next-js-resources.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 25 Resources to Learn Next.js in 2022
3 | publishedAt: '2022-03-04'
4 | description: I've curated 25 online resources to learn Next.js in 2022.
5 | ---
6 |
7 | I've curated 25 online resources to learn Next.js in 2022. I hope you find these resources useful and interesting. I'll keep updating the below list as I discover new resources.
8 |
9 | 1. [Next.js documentation](https://nextjs.org/docs)
10 |
11 | 2. [The Next.js Handbook](https://www.freecodecamp.org/news/the-next-js-handbook/)
12 |
13 | 3. [Awesome Next.js](https://awesomenextjs.com/)
14 |
15 | 4. [Complete Next.js Developer in 2022: Zero to Mastery](https://academy.zerotomastery.io/p/learn-next-js)
16 |
17 | 5. [Next.js Crash Course for Beginners 2021 - Learn NextJS from Scratch](https://www.youtube.com/watch?v=MFuwkrseXVE)
18 |
19 | 6. [Mastering Next.js](https://masteringnextjs.com/)
20 |
21 | 7. [Getting started with Next.js](https://flaviocopes.com/nextjs/)
22 |
23 | 8. [Explore all the official Next.js examples](https://nextexamples.vercel.app/)
24 |
25 | 9. [Complete Next.js with React & Node - Beautiful Portfolio App](https://academy.eincode.com/courses/complete-next-js-with-react-node-beautiful-portfolio-app)
26 |
27 | 10. [Universal React with Next.js - The Ultimate Guide](https://www.udemy.com/course/universal-react-with-nextjs-the-ultimate-guide/)
28 |
29 | 11. [Building Server-side Rendered React Apps for Beginners](https://www.pluralsight.com/courses/building-server-side-rendered-react-apps-beginners)
30 |
31 | 12. [Next.js - The ultimate way to build React apps](https://www.educative.io/courses/next-js-build-react-apps)
32 |
33 | 13. [This Mission: Next.js from the Ground Up](https://explorers.netlify.com/learn/nextjs)
34 |
35 | 14. [Learn Next.js 11 - Build Modern Next.js Applications](https://codedamn.com/learn/nextjs-fundamentals)
36 |
37 | 15. [Build a Fullstack App With Strapi and Next.js](https://www.digitalocean.com/community/tech_talks/build-a-fullstack-app-with-strapi-and-next-js)
38 |
39 | 16. [Next.js Crash Course](https://www.youtube.com/watch?v=mTz0GXj8NN0)
40 |
41 | 17. [Next.js Tutorial from The Net Ninja](https://youtube.com/playlist?list=PL4cUxeGkcC9g9gP2onazU5-2M-AzA8eBw)
42 |
43 | 18. [From Design to Development Crash Course - Full Stack Next.js Tutorial](https://www.youtube.com/watch?v=QjZIeA952jE&t=402s)
44 |
45 | 19. [Using Next.js - React Resources](https://reactresources.com/topics/nextjs)
46 |
47 | 20. [Next.js Tutorial - tutorialspoint.com](https://www.tutorialspoint.com/nextjs/index.htm)
48 |
49 | 21. [Production-Ready Next.js](https://frontendmasters.com/workshops/production-next-js/)
50 |
51 | 22. [Getting Started with Next.js](https://teacode.io/blog/getting-started-next-js)
52 |
53 | 23. [Next.js Conf 2020](https://www.youtube.com/playlist?list=PLBnKlKpPeagnT2Cmv4giCbosfrbKnuYTD)
54 |
55 | 24. [Next.js - egghead.io](https://egghead.io/q/next)
56 |
57 | 25. [Using NextJS With Wordpress Headless CMS](https://academind.com/tutorials/nextjs-wordpress-headless-cms)
58 |
--------------------------------------------------------------------------------
/data/posts/what-is-json-web-token.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: What is JSON Web Token?
3 | publishedAt: '2021-11-16'
4 | description: JWT or JSON Web Token is an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.
5 | ---
6 |
7 | JWT or **JSON Web Token** is an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.
8 |
9 | The main purpose of JWTs is to transfer claims between two parties.
10 |
11 | The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS) and/or encrypted using JSON Web Encryption (JWE).
12 |
13 | **JWS** - Signatures are useful to validate the data against tampering.
14 |
15 | **JWT** - Encryption is useful to protect the data from being read by third parties.
16 |
17 | Signed JWTs have 3 different parts. These three elements are separated by dots.
18 |
19 | 1. Header
20 |
21 | 2. Payload
22 |
23 | 3. Signature
24 |
25 | **Header**
26 |
27 | The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.
28 |
29 | 
30 |
31 | **Payload**
32 |
33 | The second part of the token is the payload, which contains the claims. As a developer, you can include information about the user in the payload.
34 |
35 | 
36 |
37 | **Signature**
38 |
39 | The signature will be created in the following way.
40 |
41 | 
42 |
43 | **Final JWT**
44 |
45 | The output is three Base64-URL strings separated by dots.
46 |
47 | [header].[payload].[signature]
48 |
49 | 
50 |
--------------------------------------------------------------------------------
/data/projects.ts:
--------------------------------------------------------------------------------
1 | const projects = [
2 | {
3 | name: "Supabase",
4 | description:
5 | "Supabase is an open source Firebase alternative. Start your project with a Postgres Database, Authentication, instant APIs, Realtime subscriptions and Storage.",
6 | image: "/projects/project.png",
7 | url: "http://localhost:3000/",
8 | },
9 | {
10 | name: "SAML Jackson",
11 | description:
12 | "A SAML SSO service designed as an OAuth 2.0 flow. Integrate SAML with just a few lines of code.",
13 | image: "/projects/project.png",
14 | url: "http://localhost:3000/",
15 | },
16 | {
17 | name: "Nhost",
18 | description:
19 | "Nhost is an open source Firebase alternative with GraphQL, built with the following things in mind: Open Source, GraphQL, SQL, Great Developer Experience.",
20 | image: "/projects/project.png",
21 | url: "http://localhost:3000/",
22 | },
23 | {
24 | name: "Jitsu",
25 | description:
26 | "Jitsu is a fully-scriptable data ingestion engine for modern data teams. Set-up a real-time data pipeline in minutes, not days.",
27 | image: "/projects/project.png",
28 | url: "http://localhost:3000/",
29 | },
30 | {
31 | name: "PostHog",
32 | description:
33 | "PostHog is the all-in-one platform for building better products - with product analytics, feature flags, session recordings, a/b testing, heatmaps.",
34 | image: "/projects/project.png",
35 | url: "http://localhost:3000/",
36 | },
37 | ];
38 |
39 | export default projects;
40 |
--------------------------------------------------------------------------------
/data/tweets.ts:
--------------------------------------------------------------------------------
1 | // Add the tweet id to the list of tweets
2 | const tweets = [
3 | "1477614047268802561",
4 | "1477614047268802561",
5 | "1477614047268802561",
6 | "1477614047268802561",
7 | ];
8 |
9 | export default tweets;
10 |
--------------------------------------------------------------------------------
/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | const { withContentlayer } = require("next-contentlayer");
2 |
3 | /**
4 | * @type {import('next').NextConfig}
5 | */
6 | module.exports = withContentlayer({
7 | swcMinify: true,
8 | reactStrictMode: true,
9 | images: {
10 | domains: [],
11 | },
12 | });
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nextjs-blog-template",
3 | "author": {
4 | "name": "Kiran K",
5 | "email": "kiran@boxyhq.com"
6 | },
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/devkiran/nextjs-blog-template"
10 | },
11 | "version": "1.0.0",
12 | "private": true,
13 | "scripts": {
14 | "dev": "next dev",
15 | "build": "next build",
16 | "start": "next start",
17 | "lint": "next lint",
18 | "check-types": "tsc --pretty --noEmit",
19 | "check-format": "prettier --check .",
20 | "check-lint": "eslint . --ext ts --ext tsx --ext js",
21 | "format": "prettier --write .",
22 | "test-all": "npm run check-format && npm run check-lint && npm run check-types && npm run build",
23 | "prepare": "husky install"
24 | },
25 | "dependencies": {
26 | "@heroicons/react": "^1.0.6",
27 | "contentlayer": "^0.2.6",
28 | "daisyui": "^2.19.0",
29 | "next": "12.2.2",
30 | "next-contentlayer": "^0.2.6",
31 | "next-seo": "^5.4.0",
32 | "react": "18.2.0",
33 | "react-dom": "18.2.0",
34 | "react-markdown": "^8.0.3",
35 | "react-twitter-embed": "^4.0.4",
36 | "rehype-highlight": "^5.0.2",
37 | "rehype-prism-plus": "^1.4.2"
38 | },
39 | "devDependencies": {
40 | "@tailwindcss/typography": "^0.5.4",
41 | "@types/node": "18.0.5",
42 | "@types/react": "18.0.15",
43 | "@types/react-dom": "18.0.6",
44 | "@typescript-eslint/eslint-plugin": "^5.30.6",
45 | "autoprefixer": "^10.4.7",
46 | "eslint": "^8.19.0",
47 | "eslint-config-next": "^12.2.2",
48 | "eslint-config-prettier": "^8.5.0",
49 | "eslint-plugin-react": "^7.30.1",
50 | "husky": "^8.0.1",
51 | "lint-staged": "^13.0.3",
52 | "postcss": "^8.4.14",
53 | "prettier": "^2.7.1",
54 | "prettier-plugin-tailwindcss": "^0.1.12",
55 | "tailwindcss": "^3.1.6",
56 | "typescript": "4.7.4"
57 | },
58 | "husky": {
59 | "hooks": {
60 | "pre-commit": "lint-staged"
61 | }
62 | },
63 | "lint-staged": {
64 | "*.{js,ts}": "eslint --cache --fix",
65 | "*.{js,ts,css,md}": "prettier --write"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import type { AppProps } from "next/app";
2 | import Head from "next/head";
3 |
4 | import "../styles/globals.css";
5 |
6 | function MyApp({ Component, pageProps }: AppProps) {
7 | return (
8 | <>
9 |
10 | Freelance Template
11 |
12 |
13 |
14 |
15 | >
16 | );
17 | }
18 |
19 | export default MyApp;
20 |
--------------------------------------------------------------------------------
/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Head, Html, Main, NextScript } from "next/document";
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/pages/blog/[slug].tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from "next";
2 | import type { Post } from "contentlayer/generated";
3 | import { allPosts } from "contentlayer/generated";
4 | import ReactMarkdown from "react-markdown";
5 | import rehypeHighlight from "rehype-highlight";
6 | import { Layout } from "components";
7 | import { NextSeo } from "next-seo";
8 |
9 | const Post: NextPage<{ post: Post }> = ({ post }) => {
10 | return (
11 |
12 | <>
13 |
14 |
15 |
{post.title}
16 |
20 | {post.body.raw}
21 |
22 |
23 | >
24 |
25 | );
26 | };
27 |
28 | export function getStaticPaths() {
29 | return {
30 | paths: allPosts.map((p) => ({ params: { slug: p.slug } })),
31 | fallback: false,
32 | };
33 | }
34 |
35 | export function getStaticProps({ params }: { params: { slug: string } }) {
36 | const post = allPosts.find((post) => post.slug === params?.slug);
37 |
38 | return { props: { post } };
39 | }
40 |
41 | export default Post;
42 |
--------------------------------------------------------------------------------
/pages/blog/index.tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from "next";
2 | import type { Post } from "contentlayer/generated";
3 | import { allPosts } from "contentlayer/generated";
4 | import { BlogPost, Layout } from "components";
5 | import { NextSeo } from "next-seo";
6 |
7 | const Posts: NextPage<{ posts: Post[] | null }> = ({ posts }) => {
8 | return (
9 |
10 | <>
11 |
12 |
13 |
All Posts
14 |
15 | Lorem Ipsum has been the industrys standard dummy text ever since
16 | the 1500s, when an unknown printer took a galley of type and
17 | scrambled it to make a type specimen book
18 |
19 |
20 | {posts &&
21 | posts.map((post) => )}
22 |
23 |
24 | >
25 |
26 | );
27 | };
28 |
29 | export function getStaticProps() {
30 | const posts = allPosts.map((post) => {
31 | return {
32 | title: post.title,
33 | description: post.description,
34 | content: post.body,
35 | publishedAt: post.publishedAt,
36 | slug: post.slug,
37 | };
38 | });
39 |
40 | return { props: { posts: posts } };
41 | }
42 |
43 | export default Posts;
44 |
--------------------------------------------------------------------------------
/pages/contact.tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from "next";
2 | import { Layout } from "components";
3 | import { NextSeo } from "next-seo";
4 |
5 | const Contact: NextPage = () => {
6 | return (
7 |
8 | <>
9 |
10 |
11 |
12 |
Get in touch
13 |
14 | Lorem Ipsum is simply dummy text of the printing and typesetting
15 | industry.
16 |
17 |
18 |
kiran@boxyhq.com
19 |
20 |
26 |
34 |
40 |
41 |
73 |
74 | >
75 |
76 | );
77 | };
78 |
79 | export default Contact;
80 |
--------------------------------------------------------------------------------
/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from "next";
2 | import type { Post } from "contentlayer/generated";
3 | import { Layout, Hero, SubscribeForm, TopBlogPost, Divider } from "components";
4 | import { NextSeo } from "next-seo";
5 | import { allPosts } from "contentlayer/generated";
6 |
7 | const Home: NextPage<{ posts: Post[] | null }> = ({ posts }) => {
8 | return (
9 |
10 | <>
11 |
12 |
13 |
14 |
15 |
16 |
17 | >
18 |
19 | );
20 | };
21 |
22 | export function getStaticProps() {
23 | const posts = allPosts.map((post) => {
24 | return {
25 | title: post.title,
26 | description: post.description,
27 | publishedAt: post.publishedAt,
28 | slug: post.slug,
29 | };
30 | });
31 |
32 | return { props: { posts: posts } };
33 | }
34 |
35 | export default Home;
36 |
--------------------------------------------------------------------------------
/pages/projects.tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from "next";
2 | import projects from "data/projects";
3 | import { ProjectCard, Layout } from "components";
4 | import { NextSeo } from "next-seo";
5 |
6 | const Projects: NextPage = () => {
7 | return (
8 |
9 | <>
10 |
11 |
12 |
Projects
13 |
14 | Lorem Ipsum has been the industrys standard dummy text ever since
15 | the 1500s, when an unknown printer took a galley of type and
16 | scrambled it to make a type specimen book
17 |
18 |
19 | {projects.map((project) => (
20 |
21 | ))}
22 |
23 |
24 | >
25 |
26 | );
27 | };
28 |
29 | export default Projects;
30 |
--------------------------------------------------------------------------------
/pages/top-tweets.tsx:
--------------------------------------------------------------------------------
1 | import type { NextPage } from "next";
2 | import { Layout, TopTweets } from "components";
3 | import { NextSeo } from "next-seo";
4 |
5 | const Posts: NextPage = () => {
6 | return (
7 |
8 | <>
9 |
10 |
11 |
12 |
Top Tweets
13 |
14 | Top tweets from the past week. Follow me on Twitter to hear more
15 | about what I share.
16 |
17 |
18 |
19 |
20 |
21 | >
22 |
23 | );
24 | };
25 |
26 | export default Posts;
27 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | };
7 |
--------------------------------------------------------------------------------
/public/developer-avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devkiran/nextjs-blog-template/e3295b3bd1c7e2a2fb6169a034c20b2033fd8b4d/public/developer-avatar.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devkiran/nextjs-blog-template/e3295b3bd1c7e2a2fb6169a034c20b2033fd8b4d/public/favicon.ico
--------------------------------------------------------------------------------
/public/projects/project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devkiran/nextjs-blog-template/e3295b3bd1c7e2a2fb6169a034c20b2033fd8b4d/public/projects/project.png
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | html,
6 | body {
7 | padding: 0;
8 | margin: 0;
9 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
10 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
11 | }
12 |
13 | a {
14 | color: inherit;
15 | text-decoration: none;
16 | }
17 |
18 | * {
19 | box-sizing: border-box;
20 | }
21 |
22 | .prose .anchor {
23 | @apply invisible absolute no-underline;
24 |
25 | margin-left: -1em;
26 | padding-right: 0.5em;
27 | width: 80%;
28 | max-width: 700px;
29 | cursor: pointer;
30 | }
31 |
32 | .anchor:hover {
33 | @apply visible;
34 | }
35 |
36 | .prose > :first-child {
37 | margin-top: 1.25em !important;
38 | margin-bottom: 1.25em !important;
39 | }
40 |
41 | .prose a {
42 | @apply text-cyan-500;
43 | }
44 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./pages/**/*.{js,ts,jsx,tsx}",
5 | "./components/**/*.{js,ts,jsx,tsx}",
6 | ],
7 | theme: {
8 | extend: {},
9 | },
10 | plugins: [require("daisyui"), require(`@tailwindcss/typography`)],
11 | };
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "baseUrl": ".",
18 | "paths": {
19 | "contentlayer/generated": ["./.contentlayer/generated"],
20 | "components/*": ["components/*"]
21 | }
22 | },
23 | "include": [
24 | "next-env.d.ts",
25 | "**/*.ts",
26 | "**/*.tsx",
27 | ".contentlayer/generated"
28 | ],
29 | "exclude": ["node_modules"]
30 | }
31 |
--------------------------------------------------------------------------------
/types.ts:
--------------------------------------------------------------------------------
1 | export type Project = {
2 | name: string;
3 | description: string;
4 | image: string;
5 | url: string;
6 | };
7 |
8 | export type Menu = {
9 | title: string;
10 | path: string;
11 | };
12 |
--------------------------------------------------------------------------------