Skip to content

Commit

Permalink
Add initial blog structure with routing, navigation, and components
Browse files Browse the repository at this point in the history
  • Loading branch information
lucaprotelli committed Nov 9, 2024
1 parent ce45107 commit 9f0a25f
Show file tree
Hide file tree
Showing 22 changed files with 2,673 additions and 0 deletions.
37 changes: 37 additions & 0 deletions blog/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem
.vscode

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files
.env

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
98 changes: 98 additions & 0 deletions blog/app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { notFound } from 'next/navigation'
import { CustomMDX } from 'app/components/mdx'
import { formatDate, getBlogPosts } from 'app/blog/utils'
import { baseUrl } from 'app/sitemap'

export async function generateStaticParams() {
let posts = getBlogPosts()

return posts.map((post) => ({
slug: post.slug,
}))
}

export function generateMetadata({ params }) {
let post = getBlogPosts().find((post) => post.slug === params.slug)
if (!post) {
return
}

let {
title,
publishedAt: publishedTime,
summary: description,
image,
} = post.metadata
let ogImage = image
? image
: `${baseUrl}/og?title=${encodeURIComponent(title)}`

return {
title,
description,
openGraph: {
title,
description,
type: 'article',
publishedTime,
url: `${baseUrl}/blog/${post.slug}`,
images: [
{
url: ogImage,
},
],
},
twitter: {
card: 'summary_large_image',
title,
description,
images: [ogImage],
},
}
}

export default function Blog({ params }) {
let post = getBlogPosts().find((post) => post.slug === params.slug)

if (!post) {
notFound()
}

return (
<section>
<script
type="application/ld+json"
suppressHydrationWarning
dangerouslySetInnerHTML={{
__html: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.metadata.title,
datePublished: post.metadata.publishedAt,
dateModified: post.metadata.publishedAt,
description: post.metadata.summary,
image: post.metadata.image
? `${baseUrl}${post.metadata.image}`
: `/og?title=${encodeURIComponent(post.metadata.title)}`,
url: `${baseUrl}/blog/${post.slug}`,
author: {
'@type': 'Person',
name: 'My Portfolio',
},
}),
}}
/>
<h1 className="title font-semibold text-2xl tracking-tighter">
{post.metadata.title}
</h1>
<div className="flex justify-between items-center mt-2 mb-8 text-sm">
<p className="text-sm text-neutral-600 dark:text-neutral-400">
{formatDate(post.metadata.publishedAt)}
</p>
</div>
<article className="prose">
<CustomMDX source={post.content} />
</article>
</section>
)
}
17 changes: 17 additions & 0 deletions blog/app/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { BlogPosts } from "app/components/posts"

export const metadata = {
title: "Blog",
description: "Read my blog.",
}

export default function Page() {
return (
<section>
<h1 className="font-semibold text-2xl mb-8 tracking-tighter">
Luca Protelli
</h1>
<BlogPosts />
</section>
)
}
31 changes: 31 additions & 0 deletions blog/app/blog/posts/spaces-vs-tabs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: 'Spaces vs. Tabs: The Indentation Debate Continues'
publishedAt: '2024-04-08'
summary: 'Explore the enduring debate between using spaces and tabs for code indentation, and why this choice matters more than you might think.'
---

The debate between using spaces and tabs for indentation in coding may seem trivial to the uninitiated, but it is a topic that continues to inspire passionate discussions among developers. This seemingly minor choice can affect code readability, maintenance, and even team dynamics.

Let's delve into the arguments for both sides and consider why this debate remains relevant in the software development world.

## The Case for Spaces

Advocates for using spaces argue that it ensures consistent code appearance across different editors, tools, and platforms. Because a space is a universally recognized character with a consistent width, code indented with spaces will look the same no matter where it's viewed. This consistency is crucial for maintaining readability and avoiding formatting issues when code is shared between team members or published online.

Additionally, some programming languages and style guides explicitly recommend spaces for indentation, suggesting a certain number of spaces (often two or four) per indentation level. Adhering to these recommendations can be essential for projects that aim for best practices in code quality and readability.

## The Case for Tabs

On the other side of the debate, proponents of tabs highlight the flexibility that tabs offer. Because the width of a tab can be adjusted in most text editors, individual developers can choose how much indentation they prefer to see, making the code more accessible and comfortable to read on a personal level. This adaptability can be particularly beneficial in teams with diverse preferences regarding code layout.

Tabs also have the advantage of semantic meaning. A tab is explicitly meant to represent indentation, whereas a space is used for many purposes within code. This distinction can make automated parsing and manipulation of code simpler, as tools can more easily recognize and adjust indentation levels without confusing them with spaces used for alignment.

## Hybrid Approaches and Team Dynamics

The debate often extends into discussions about hybrid approaches, where teams might use tabs for indentation and spaces for alignment within lines, attempting to combine the best of both worlds. However, such strategies require clear team agreements and disciplined adherence to coding standards to prevent formatting chaos.

Ultimately, the choice between spaces and tabs often comes down to team consensus and project guidelines. In environments where collaboration and code sharing are common, agreeing on a standard that everyone follows is more important than the individual preferences of spaces versus tabs. Modern development tools and linters can help enforce these standards, making the choice less about technical limitations and more about team dynamics and coding philosophy.

## Conclusion

While the spaces vs. tabs debate might not have a one-size-fits-all answer, it underscores the importance of consistency, readability, and team collaboration in software development. Whether a team chooses spaces, tabs, or a hybrid approach, the key is to make a conscious choice that serves the project's needs and to adhere to it throughout the codebase. As with many aspects of coding, communication and agreement among team members are paramount to navigating this classic programming debate.
90 changes: 90 additions & 0 deletions blog/app/blog/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import fs from 'fs'
import path from 'path'

type Metadata = {
title: string
publishedAt: string
summary: string
image?: string
}

function parseFrontmatter(fileContent: string) {
let frontmatterRegex = /---\s*([\s\S]*?)\s*---/
let match = frontmatterRegex.exec(fileContent)
let frontMatterBlock = match![1]
let content = fileContent.replace(frontmatterRegex, '').trim()
let frontMatterLines = frontMatterBlock.trim().split('\n')
let metadata: Partial<Metadata> = {}

frontMatterLines.forEach((line) => {
let [key, ...valueArr] = line.split(': ')
let value = valueArr.join(': ').trim()
value = value.replace(/^['"](.*)['"]$/, '$1') // Remove quotes
metadata[key.trim() as keyof Metadata] = value
})

return { metadata: metadata as Metadata, content }
}

function getMDXFiles(dir) {
return fs.readdirSync(dir).filter((file) => path.extname(file) === '.mdx')
}

function readMDXFile(filePath) {
let rawContent = fs.readFileSync(filePath, 'utf-8')
return parseFrontmatter(rawContent)
}

function getMDXData(dir) {
let mdxFiles = getMDXFiles(dir)
return mdxFiles.map((file) => {
let { metadata, content } = readMDXFile(path.join(dir, file))
let slug = path.basename(file, path.extname(file))

return {
metadata,
slug,
content,
}
})
}

export function getBlogPosts() {
return getMDXData(path.join(process.cwd(), 'app', 'blog', 'posts'))
}

export function formatDate(date: string, includeRelative = false) {
let currentDate = new Date()
if (!date.includes('T')) {
date = `${date}T00:00:00`
}
let targetDate = new Date(date)

let yearsAgo = currentDate.getFullYear() - targetDate.getFullYear()
let monthsAgo = currentDate.getMonth() - targetDate.getMonth()
let daysAgo = currentDate.getDate() - targetDate.getDate()

let formattedDate = ''

if (yearsAgo > 0) {
formattedDate = `${yearsAgo}y ago`
} else if (monthsAgo > 0) {
formattedDate = `${monthsAgo}mo ago`
} else if (daysAgo > 0) {
formattedDate = `${daysAgo}d ago`
} else {
formattedDate = 'Today'
}

let fullDate = targetDate.toLocaleString('en-us', {
month: 'long',
day: 'numeric',
year: 'numeric',
})

if (!includeRelative) {
return fullDate
}

return `${fullDate} (${formattedDate})`
}
61 changes: 61 additions & 0 deletions blog/app/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
function ArrowIcon() {
return (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.07102 11.3494L0.963068 10.2415L9.2017 1.98864H2.83807L2.85227 0.454545H11.8438V9.46023H10.2955L10.3097 3.09659L2.07102 11.3494Z"
fill="currentColor"
/>
</svg>
)
}

export default function Footer() {
return (
<footer className="mb-16">
<ul className="font-sm mt-8 flex flex-col space-x-0 space-y-2 text-neutral-600 md:flex-row md:space-x-4 md:space-y-0 dark:text-neutral-300">
<li>
<a
className="flex items-center transition-all hover:text-neutral-800 dark:hover:text-neutral-100"
rel="noopener noreferrer"
target="_blank"
href="/rss"
>
<ArrowIcon />
<p className="ml-2 h-7">rss</p>
</a>
</li>
<li>
<a
className="flex items-center transition-all hover:text-neutral-800 dark:hover:text-neutral-100"
rel="noopener noreferrer"
target="_blank"
href="https://github.com/lucaprotelli"
>
<ArrowIcon />
<p className="ml-2 h-7">github</p>
</a>
</li>
<li>
<a
className="flex items-center transition-all hover:text-neutral-800 dark:hover:text-neutral-100"
rel="noopener noreferrer"
target="_blank"
href="https://github.com/lucaprotelli/portfolio"
>
<ArrowIcon />
<p className="ml-2 h-7">view source</p>
</a>
</li>
</ul>
<p className="mt-8 text-neutral-600 dark:text-neutral-300">
© {new Date().getFullYear()} MIT Licensed
</p>
</footer>
)
}
Loading

0 comments on commit 9f0a25f

Please sign in to comment.