├── .eslintrc.json ├── .gitignore ├── README.md ├── app ├── [slug] │ └── page.tsx ├── favicon.ico ├── globals.css ├── layout.tsx └── page.tsx ├── articles ├── art-of-side-hustle.md ├── how-stoicism-helps.md ├── how-to-write-clean-code.md ├── lessons-from-steve-jobs.md ├── merchant-of-venice.md ├── shoe-dog.md ├── why-you-should-start-a-business.md └── year-review-2023.md ├── components └── ArticleListItem.tsx ├── lib └── articles.ts ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── merchant.jpeg ├── next.svg └── vercel.svg ├── tailwind.config.ts ├── tsconfig.json └── types └── index.ts /.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | 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. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /app/[slug]/page.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link" 2 | import { ArrowLeftIcon } from "@heroicons/react/24/solid" 3 | import { getArticleData } from "@/lib/articles" 4 | 5 | const Article = async ({ params }: { params: { slug: string } }) => { 6 | const articleData = await getArticleData(params.slug) 7 | 8 | return ( 9 |
10 |
11 | 12 | 13 |

back to home

14 | 15 |

{articleData.date.toString()}

16 |
17 |
21 |
22 | ) 23 | } 24 | 25 | export default Article 26 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixfwa/nextjs-blog/a14a9e879b8e848d45de75a28b02f228460d8a50/app/favicon.ico -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .article { 6 | @apply flex flex-col gap-3 font-poppins text-lg tracking-wide mb-20; 7 | } 8 | 9 | .article > h1 { 10 | @apply font-cormorantGaramond text-4xl text-center tracking-tight; 11 | } 12 | 13 | .article > h2 { 14 | @apply font-cormorantGaramond text-3xl tracking-tight; 15 | } 16 | 17 | .article > ol { 18 | @apply list-decimal flex flex-col mx-10 gap-2; 19 | } 20 | 21 | .article > ul { 22 | @apply list-disc flex flex-col mx-10 gap-2; 23 | } 24 | 25 | .article > pre { 26 | @apply bg-neutral-950 text-neutral-50 p-5 overflow-scroll; 27 | } 28 | 29 | .article > blockquote { 30 | @apply pl-5 italic border-l-2 border-neutral-600 border-opacity-40; 31 | } 32 | 33 | .article > p > img { 34 | @apply w-1/2 mx-auto; 35 | } 36 | -------------------------------------------------------------------------------- /app/layout.tsx: -------------------------------------------------------------------------------- 1 | import type { Metadata } from "next" 2 | import { Cormorant_Garamond, Poppins } from "next/font/google" 3 | import "./globals.css" 4 | 5 | const cormorantGaramond = Cormorant_Garamond({ 6 | subsets: ["latin"], 7 | variable: "--font-cormorant-garamond", 8 | weight: ["400"], 9 | }) 10 | 11 | const poppins = Poppins({ 12 | subsets: ["latin"], 13 | variable: "--font-poppins", 14 | weight: ["400", "600"], 15 | }) 16 | 17 | export const metadata: Metadata = { 18 | title: "Create Next App", 19 | description: "Generated by create next app", 20 | } 21 | 22 | export default function RootLayout({ 23 | children, 24 | }: { 25 | children: React.ReactNode 26 | }) { 27 | return ( 28 | 29 | 32 | {children} 33 | 34 | 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | import ArticleItemList from "@/components/ArticleListItem" 2 | import { getCategorisedArticles } from "@/lib/articles" 3 | 4 | const HomePage = () => { 5 | const articles = getCategorisedArticles() 6 | 7 | console.log(articles) 8 | return ( 9 |
10 |
11 |

minimal blog

12 |
13 |
14 | {articles !== null && 15 | Object.keys(articles).map((article) => ( 16 | 21 | ))} 22 |
23 |
24 | ) 25 | } 26 | 27 | export default HomePage 28 | -------------------------------------------------------------------------------- /articles/art-of-side-hustle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The art of the side hustle" 3 | category: "business" 4 | date: "02-02-2023" 5 | --- 6 | 7 | # The Art of the Side Hustle 8 | -------------------------------------------------------------------------------- /articles/how-stoicism-helps.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "How Stoicism can help" 3 | category: "thoughts" 4 | date: "06-04-2023" 5 | --- 6 | 7 | # How Stoicism can help 8 | -------------------------------------------------------------------------------- /articles/how-to-write-clean-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "How to write clean code" 3 | category: "software engineering" 4 | date: "01-01-2023" 5 | --- 6 | 7 | # How to Write Clean Code 8 | 9 | Writing clean code is an essential skill for any developer. It not only makes your code more readable and maintainable but also makes it easier for others (and future you) to understand and modify. Here are some key principles to follow. 10 | 11 | ## Understandable and Consistent Naming 12 | 13 | Good naming is crucial for readability. 14 | 15 | - **Variables**: Choose names that clearly describe their purpose. 16 | - **Functions**: Name them based on what they do. If a function retrieves a user, name it `getUser`. 17 | 18 | > "Choosing good names takes time but saves more than it takes." - _Robert C. Martin_ 19 | 20 | ## Keep Functions Small and Focused 21 | 22 | A function should do one thing and do it well. 23 | 24 | 1. Limit the length of functions. Aim for 10-20 lines. 25 | 2. Avoid side effects. A function should not modify any hidden states. 26 | 27 | ## Comment Wisely 28 | 29 | Comments should explain _why_, not _what_. Code should speak for itself. 30 | 31 | - Use comments for clarification of complex code. 32 | - Avoid redundant comments. 33 | 34 | ## Refactoring 35 | 36 | Regularly refactor your code to make it cleaner. 37 | 38 | - Remove duplicate code. 39 | - Simplify complex logic. 40 | - Break large functions into smaller ones. 41 | 42 | ## Consistent Formatting 43 | 44 | Consistency is key. 45 | 46 | - Stick to one coding style. 47 | - Use linters and formatters like ESLint or Prettier. 48 | 49 | ## Avoid Deep Nesting 50 | 51 | Deep nesting makes code harder to read and maintain. 52 | 53 | ```javascript 54 | // Bad 55 | if (condition) { 56 | if (anotherCondition) { 57 | // ... 58 | } 59 | } 60 | 61 | // Good 62 | if (condition && anotherCondition) { 63 | // ... 64 | } 65 | ``` 66 | 67 | ## Error Handling 68 | 69 | Don't ignore errors. Handle them gracefully. 70 | 71 | - Use try-catch for error-prone code. 72 | - Validate inputs to prevent errors. 73 | 74 | ## Stay DRY (Don't Repeat Yourself) 75 | 76 | Avoid repetition. Use functions, classes, and modules. 77 | 78 | ## Readable Code over Clever Code 79 | 80 | Readable code is always better than clever, tricky code. 81 | 82 | > "Any fool can write code that a computer can understand. Good programmers write code that humans can understand." - _Martin Fowler_ 83 | 84 | ## Continuous Learning 85 | 86 | Stay updated with best practices and constantly improve your skills. 87 | 88 | Writing clean code is a practice that develops over time with experience and constant learning. Always be open to new ideas and improvements! 89 | -------------------------------------------------------------------------------- /articles/lessons-from-steve-jobs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Lessons from Steve Jobs" 3 | category: "business" 4 | date: "10-01-2023" 5 | --- 6 | 7 | # Lessons from Steve Jobs 8 | 9 | Steve Jobs, the iconic co-founder of Apple Inc., left an indelible mark on the tech industry and the world. His visionary approach to business, technology, and design revolutionized several industries. Here are some key lessons we can learn from his extraordinary life and career. 10 | 11 | ## Pursue Your Passion 12 | 13 | Steve Jobs once said, "The only way to do great work is to love what you do." His passion for perfection and innovation was evident in every Apple product. This lesson is vital: find what you love, and don't settle until you find it. Passion is the fuel that drives excellence. 14 | 15 | ## Connect the Dots 16 | 17 | Jobs believed in connecting the dots in life – looking back and understanding how different experiences shape your future. He dropped out of college but continued to audit classes that interested him, like calligraphy. This knowledge later played a crucial role in the development of the Macintosh computer. The takeaway is to remain curious and open to diverse experiences; they often lead to unexpected and innovative outcomes. 18 | 19 | ## Embrace Setbacks 20 | 21 | Jobs faced many setbacks, including being ousted from Apple, the company he co-founded. However, he saw these moments as opportunities for reflection and growth. He later returned to Apple and led it to new heights. Embracing setbacks and learning from failures are crucial for growth and eventual success. 22 | 23 | ## Simplify 24 | 25 | One of Jobs' most famous design principles was simplicity. Apple's products are known for their clean, simple, and intuitive design. The lesson here is to focus on simplicity in your work and life. Remove the unnecessary, and focus on what's truly important. 26 | 27 | ## Focus on the User Experience 28 | 29 | Jobs was obsessive about creating an exceptional user experience. He believed that technology should be intuitive, engaging, and accessible. This user-centered approach can be applied to any field – always think from the perspective of the end-user or customer. 30 | 31 | ## Lead by Example 32 | 33 | Jobs was not just a visionary; he was a leader who led by example. He was deeply involved in every aspect of Apple's product development, from design to marketing. Leadership is about taking responsibility and being fully committed to your vision. 34 | 35 | ## The Power of Storytelling 36 | 37 | Jobs was a master storyteller, whether he was introducing a new product or sharing his vision. He knew how to engage his audience and communicate his ideas compellingly. Effective storytelling is a powerful tool for connecting with people and inspiring action. 38 | 39 | ## Stay Hungry, Stay Foolish 40 | 41 | These words, borrowed from the Whole Earth Catalog, were part of Jobs' famous Stanford commencement speech. They reflect his philosophy of life – a continuous quest for knowledge and an openness to new adventures. Never settle, and always keep looking for what is next. 42 | -------------------------------------------------------------------------------- /articles/merchant-of-venice.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Merchant of Venice" 3 | category: "books" 4 | date: "02-04-2023" 5 | --- 6 | 7 | # The Merchant of Venice 8 | 9 | ![Art](/merchant.jpeg) 10 | 11 | William Shakespeare's 'The Merchant of Venice' is a play that has captivated audiences and readers for centuries. This complex work intertwines themes of mercy, justice, and prejudice, making it a subject of continual study and interpretation. 12 | 13 | ## Plot Overview 14 | 15 | 'The Merchant of Venice' tells the story of Antonio, a Venetian merchant, who borrows money from the Jewish moneylender Shylock to help his friend Bassanio court the wealthy heiress Portia. The contract between Antonio and Shylock states that if Antonio fails to repay the loan on time, Shylock is entitled to a pound of Antonio’s flesh. The play unfolds with themes of love, law, and prejudice intermingling, leading to a dramatic courtroom showdown. 16 | 17 | ## Key Themes 18 | 19 | ### The Nature of Mercy 20 | 21 | Portia's famous speech in the courtroom scene, "The quality of mercy is not strained," underscores the play's exploration of mercy as a divine attribute and its juxtaposition against the rigid application of the law. 22 | 23 | ### Prejudice and Tolerance 24 | 25 | The play is known for its exploration of anti-Semitism through the character of Shylock. Shakespeare presents Shylock as both a victim and a villain, prompting audiences to reflect on the nature of prejudice and tolerance. 26 | 27 | ### The Law and Justice 28 | 29 | Shakespeare examines the legal system of Venice, portraying it as a mechanism that can be manipulated, raising questions about the true nature of justice. 30 | 31 | ## Character Analysis 32 | 33 | ### Shylock: A Complex Villain 34 | 35 | Shylock is one of Shakespeare's most enigmatic characters. He is portrayed with both sympathetic and villainous qualities, challenging the audience to understand his motivations and the societal prejudices he faces. 36 | 37 | ### Portia: More Than a Mere Heiress 38 | 39 | Portia, while initially appearing as a typical romantic heroine, reveals herself to be intelligent, witty, and capable, particularly in the courtroom scene where she disguises herself as a young male lawyer. 40 | 41 | ## Modern Relevance 42 | 43 | The play's themes of mercy, justice, and prejudice remain relevant in today's society. The character of Shylock, in particular, has been the subject of extensive critical debate, especially in modern interpretations that consider historical and contemporary perspectives on anti-Semitism. 44 | 45 | ## Conclusion 46 | 47 | 'The Merchant of Venice' remains a powerful and provocative play. It continues to challenge and engage audiences with its complex characters and themes, making it a timeless piece of literature that resonates with contemporary issues of justice, tolerance, and human rights. 48 | 49 | --- 50 | 51 | This article provides an overview of Shakespeare's 'The Merchant of Venice', covering key themes, character analysis, and its relevance today. The markdown format includes headings, subheadings, and paragraphs to structure the content effectively. 52 | -------------------------------------------------------------------------------- /articles/shoe-dog.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Shoe Dog" 3 | category: "books" 4 | date: "02-05-2023" 5 | --- 6 | 7 | # The Shoe Dog 8 | -------------------------------------------------------------------------------- /articles/why-you-should-start-a-business.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Why you should start a business" 3 | category: "business" 4 | date: "31-01-2023" 5 | --- 6 | 7 | # Why you should start a business 8 | -------------------------------------------------------------------------------- /articles/year-review-2023.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Year in Review 2023" 3 | category: "thoughts" 4 | date: "31-12-2023" 5 | --- 6 | 7 | # Year in Review 2023 8 | -------------------------------------------------------------------------------- /components/ArticleListItem.tsx: -------------------------------------------------------------------------------- 1 | import Link from "next/link" 2 | import type { ArticleItem } from "@/types" 3 | 4 | interface Props { 5 | category: string 6 | articles: ArticleItem[] 7 | } 8 | 9 | const ArticleItemList = ({ category, articles }: Props) => { 10 | return ( 11 |
12 |

{category}

13 |
14 | {articles.map((article, id) => ( 15 | 20 | {article.title} 21 | 22 | ))} 23 |
24 |
25 | ) 26 | } 27 | 28 | export default ArticleItemList 29 | -------------------------------------------------------------------------------- /lib/articles.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs" 2 | import matter from "gray-matter" 3 | import path from "path" 4 | import moment from "moment" 5 | import { remark } from "remark" 6 | import html from "remark-html" 7 | 8 | import type { ArticleItem } from "@/types" 9 | 10 | const articlesDirectory = path.join(process.cwd(), "articles") 11 | 12 | const getSortedArticles = (): ArticleItem[] => { 13 | const fileNames = fs.readdirSync(articlesDirectory) 14 | 15 | const allArticlesData = fileNames.map((fileName) => { 16 | const id = fileName.replace(/\.md$/, "") 17 | 18 | const fullPath = path.join(articlesDirectory, fileName) 19 | const fileContents = fs.readFileSync(fullPath, "utf-8") 20 | 21 | const matterResult = matter(fileContents) 22 | 23 | return { 24 | id, 25 | title: matterResult.data.title, 26 | date: matterResult.data.date, 27 | category: matterResult.data.category, 28 | } 29 | }) 30 | 31 | return allArticlesData.sort((a, b) => { 32 | const format = "DD-MM-YYYY" 33 | const dateOne = moment(a.date, format) 34 | const dateTwo = moment(b.date, format) 35 | if (dateOne.isBefore(dateTwo)) { 36 | return -1 37 | } else if (dateTwo.isAfter(dateOne)) { 38 | return 1 39 | } else { 40 | 0 41 | } 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minimal-blog", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@heroicons/react": "^2.1.1", 13 | "gray-matter": "^4.0.3", 14 | "moment": "^2.30.1", 15 | "next": "14.0.4", 16 | "react": "^18", 17 | "react-dom": "^18", 18 | "remark": "^15.0.1", 19 | "remark-html": "^16.0.1" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "^20", 23 | "@types/react": "^18", 24 | "@types/react-dom": "^18", 25 | "autoprefixer": "^10.0.1", 26 | "eslint": "^8", 27 | "eslint-config-next": "14.0.4", 28 | "postcss": "^8", 29 | "tailwindcss": "^3.3.0", 30 | "typescript": "^5" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/merchant.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixfwa/nextjs-blog/a14a9e879b8e848d45de75a28b02f228460d8a50/public/merchant.jpeg -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss" 2 | 3 | const config: Config = { 4 | content: [ 5 | "./pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | fontFamily: { 12 | cormorantGaramond: ["var(--font-cormorant-garamond)", "serif"], 13 | poppins: ["var(--font-poppins)", "sans-serif"], 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | } 19 | export default config 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /types/index.ts: -------------------------------------------------------------------------------- 1 | export type ArticleItem = { 2 | id: string 3 | title: string 4 | date: string 5 | category: string 6 | } 7 | --------------------------------------------------------------------------------