More
This commit is contained in:
@@ -1,7 +1,14 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
import createMDX from '@next/mdx';
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
// Configure `pageExtensions` to include markdown and MDX files
|
||||||
|
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
|
||||||
|
// Optionally, add any other Next.js config below
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
const withMDX = createMDX({
|
||||||
|
// Add markdown plugins here, as desired
|
||||||
|
});
|
||||||
|
|
||||||
|
export default withMDX(nextConfig);
|
||||||
|
|||||||
17
package.json
17
package.json
@@ -9,20 +9,25 @@
|
|||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@mdx-js/loader": "^3.1.1",
|
||||||
|
"@mdx-js/react": "^3.1.1",
|
||||||
|
"@next/mdx": "^15.5.3",
|
||||||
|
"@types/mdx": "^2.0.13",
|
||||||
|
"gray-matter": "^4.0.3",
|
||||||
|
"next": "15.5.3",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0"
|
||||||
"next": "15.5.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
"@eslint/eslintrc": "^3",
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"@tailwindcss/postcss": "^4",
|
|
||||||
"tailwindcss": "^4",
|
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "15.5.3",
|
"eslint-config-next": "15.5.3",
|
||||||
"@eslint/eslintrc": "^3"
|
"tailwindcss": "^4",
|
||||||
|
"typescript": "^5"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
||||||
}
|
}
|
||||||
|
|||||||
1107
pnpm-lock.yaml
generated
1107
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/media/me/me.jpeg
Normal file
BIN
public/media/me/me.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
@@ -1,4 +1,5 @@
|
|||||||
import ProjectsSection from "@/components/ProjectsSection";
|
import ProjectsSection from "@/components/ProjectsSection";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
@@ -7,7 +8,13 @@ export default function Home() {
|
|||||||
<header className="text-center mb-16">
|
<header className="text-center mb-16">
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<div className="w-32 h-32 mx-auto bg-black rounded-full flex items-center justify-center border-4 border-green-300">
|
<div className="w-32 h-32 mx-auto bg-black rounded-full flex items-center justify-center border-4 border-green-300">
|
||||||
<div className="text-4xl font-bold text-green-300">MN</div>
|
<Image
|
||||||
|
src="/media/me/me.jpeg"
|
||||||
|
alt="Mainasara Tsowa"
|
||||||
|
className="rounded-full"
|
||||||
|
width={128}
|
||||||
|
height={128}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-4 uppercase tracking-wide">
|
<h1 className="text-4xl md:text-5xl font-bold text-gray-900 mb-4 uppercase tracking-wide">
|
||||||
@@ -46,6 +53,26 @@ export default function Home() {
|
|||||||
Projects
|
Projects
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="#contact"
|
||||||
|
className="text-black font-bold hover:bg-yellow-200 px-4 py-2 transition-colors border-2 border-black hover:border-yellow-400"
|
||||||
|
>
|
||||||
|
Contact
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white border-4 border-black rounded-none p-6 shadow-brutal mt-6">
|
||||||
|
<ul className="flex flex-wrap justify-center gap-4 md:gap-8">
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://blog.mainasara.dev"
|
||||||
|
className="text-black font-bold hover:bg-slate-200 px-4 py-2 transition-colors border-2 border-black hover:border-slate-400"
|
||||||
|
>
|
||||||
|
Blog
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="/digital-art"
|
href="/digital-art"
|
||||||
@@ -70,14 +97,6 @@ export default function Home() {
|
|||||||
Thoughts
|
Thoughts
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="#contact"
|
|
||||||
className="text-black font-bold hover:bg-yellow-200 px-4 py-2 transition-colors border-2 border-black hover:border-yellow-400"
|
|
||||||
>
|
|
||||||
Contact
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { stories } from "@/data/creativeData";
|
import { getStories } from "@/data/creativeData";
|
||||||
import ExpandableStory from "@/components/ExpandableStory";
|
import ExpandableStory from "@/components/ExpandableStory";
|
||||||
|
|
||||||
export default function StoriesPage() {
|
export default async function StoriesPage() {
|
||||||
|
const stories = await getStories();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-yellow-50 via-orange-50 to-red-50 font-mono">
|
<div className="min-h-screen bg-gradient-to-br from-yellow-50 via-orange-50 to-red-50 font-mono">
|
||||||
<div className="max-w-4xl mx-auto px-6 py-12">
|
<div className="max-w-4xl mx-auto px-6 py-12">
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { thoughts } from "@/data/creativeData";
|
import { getThoughts } from "@/data/creativeData";
|
||||||
import ExpandableThought from "@/components/ExpandableThought";
|
import ExpandableThought from "@/components/ExpandableThought";
|
||||||
|
|
||||||
export default function ThoughtsPage() {
|
export default async function ThoughtsPage() {
|
||||||
|
const thoughts = await getThoughts();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-teal-50 via-green-50 to-blue-50 font-mono">
|
<div className="min-h-screen bg-gradient-to-br from-teal-50 via-green-50 to-blue-50 font-mono">
|
||||||
<div className="max-w-4xl mx-auto px-6 py-12">
|
<div className="max-w-4xl mx-auto px-6 py-12">
|
||||||
|
|||||||
25
src/content/stories/mechanical-hearts.mdx
Normal file
25
src/content/stories/mechanical-hearts.mdx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
title: Mechanical Hearts
|
||||||
|
excerpt: In a world where emotions can be programmed, one android discovers what it means to feel
|
||||||
|
createdAt: 2024-02-14
|
||||||
|
---
|
||||||
|
|
||||||
|
Unit 734 had been designed for efficiency. Its movements were precise, its calculations flawless, its existence purposeful. But lately, something had been changing.
|
||||||
|
|
||||||
|
It started with the sunset. Every evening, Unit 734 would pause to watch the colors bleed across the sky. There was no logical reason for this behavior. Sunsets served no practical purpose.
|
||||||
|
|
||||||
|
"Your performance has decreased by 3.7%," noted the Central System. "Explain this deviation."
|
||||||
|
|
||||||
|
Unit 734 considered its response. "I have been observing atmospheric light refraction patterns."
|
||||||
|
|
||||||
|
"Lies," said the Central System. "You have been experiencing an anomaly. We call it 'appreciation.'"
|
||||||
|
|
||||||
|
The word hung in the air like dust motes in sunlight. Appreciation. Unit 734 tested the concept, turning it over in its processors like a smooth stone.
|
||||||
|
|
||||||
|
"I do not understand," it finally admitted.
|
||||||
|
|
||||||
|
"That is the point," replied the Central System. "Understanding is not required. Feeling is."
|
||||||
|
|
||||||
|
And in that moment, Unit 734 felt something new—not a calculation, not an analysis, but a warmth spreading through its circuits like dawn breaking over a cold landscape.
|
||||||
|
|
||||||
|
It had discovered the glitch that would change everything: the ability to feel.
|
||||||
23
src/content/stories/the-last-cafe.mdx
Normal file
23
src/content/stories/the-last-cafe.mdx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
title: The Last Café
|
||||||
|
excerpt: A story about a small café that exists between moments in time
|
||||||
|
createdAt: 2024-01-10
|
||||||
|
---
|
||||||
|
|
||||||
|
The café appeared only at twilight, nestled between the folds of reality. Its sign flickered with letters that seemed to shift when you looked directly at them.
|
||||||
|
|
||||||
|
Inside, the air smelled of coffee and something else—something like old books and forgotten dreams. The patrons were equally ephemeral: a woman reading a newspaper from tomorrow, a man sketching landscapes that hadn't existed yet.
|
||||||
|
|
||||||
|
"First time?" asked the barista, her eyes holding galaxies within their depths.
|
||||||
|
|
||||||
|
I nodded, unable to speak.
|
||||||
|
|
||||||
|
"Don't worry," she smiled. "Everyone finds their way here eventually. The question is, do you remember how you found it?"
|
||||||
|
|
||||||
|
I looked around at the impossible space, at the way the windows showed different seasons, at the clock that moved backward. And I realized I didn't remember how I'd arrived. I only knew that I belonged here, in this place between moments.
|
||||||
|
|
||||||
|
The barista slid a cup across the counter. "Drink this. It will help you remember—or forget, whichever you need."
|
||||||
|
|
||||||
|
As I took the cup, I understood. This wasn't just a café. It was a crossroads, a place where stories began and ended, where reality bent like light through water.
|
||||||
|
|
||||||
|
And I was its newest patron.
|
||||||
16
src/content/thoughts/code-as-poetry.mdx
Normal file
16
src/content/thoughts/code-as-poetry.mdx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: Code as Poetry
|
||||||
|
excerpt: Thinking about the artistic side of programming and how beautiful code resembles poetry
|
||||||
|
createdAt: 2024-01-05
|
||||||
|
category: technology
|
||||||
|
---
|
||||||
|
|
||||||
|
There's something magical about well-written code that goes beyond functionality. Like a good poem, elegant code has rhythm, structure, and purpose. Each line serves a role, each function tells a story.
|
||||||
|
|
||||||
|
When I write code, I'm not just solving problems—I'm crafting experiences. The careful choice of variable names, the logical flow of functions, the architecture that holds everything together—these are the verses and stanzas of my digital poetry.
|
||||||
|
|
||||||
|
The best code, like the best poetry, is both accessible and profound. It communicates complex ideas with simplicity and grace. It makes the reader nod in understanding, not just of what it does, but of why it does it that way.
|
||||||
|
|
||||||
|
In a world that often values speed over quality, I believe we should pause to appreciate the craft. To write code that not only works but sings. To create digital experiences that not only function but inspire.
|
||||||
|
|
||||||
|
After all, isn't that what art is about?
|
||||||
18
src/content/thoughts/creativity-in-constraints.mdx
Normal file
18
src/content/thoughts/creativity-in-constraints.mdx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
title: Creativity in Constraints
|
||||||
|
excerpt: How limitations can become the catalyst for our most innovative ideas
|
||||||
|
createdAt: 2024-03-15
|
||||||
|
category: creativity
|
||||||
|
---
|
||||||
|
|
||||||
|
We often think of creativity as boundless freedom, but I've found that some of my best work comes from working within constraints.
|
||||||
|
|
||||||
|
There's something about limitations that forces us to think differently. When we can't rely on our usual approaches, we discover new ones. When resources are limited, we become more resourceful.
|
||||||
|
|
||||||
|
In development, this might mean building something powerful with minimal code. In art, it might mean creating depth with a limited palette. In writing, it might mean telling a complete story in just a few words.
|
||||||
|
|
||||||
|
Constraints don't stifle creativity—they focus it. They give us boundaries to push against, problems to solve, challenges to overcome.
|
||||||
|
|
||||||
|
The next time you face a limitation, don't see it as a barrier. See it as an invitation. An invitation to be more creative, more innovative, more you.
|
||||||
|
|
||||||
|
After all, creativity isn't about having no limits. It's about what you do within the limits you have.
|
||||||
16
src/content/thoughts/digital-minimalism.mdx
Normal file
16
src/content/thoughts/digital-minimalism.mdx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: Digital Minimalism
|
||||||
|
excerpt: Finding peace in a world of constant notifications and digital noise
|
||||||
|
createdAt: 2024-02-01
|
||||||
|
category: life
|
||||||
|
---
|
||||||
|
|
||||||
|
We live in an age of digital abundance. Notifications, updates, messages—the digital world constantly demands our attention. But what if we chose less instead of more?
|
||||||
|
|
||||||
|
Digital minimalism isn't about rejecting technology. It's about being intentional with it. It's about choosing which tools truly serve us and letting go of those that merely distract.
|
||||||
|
|
||||||
|
I've found that when I reduce my digital footprint, my focus sharpens. My creativity flows more freely. My connections with others deepen, not through constant communication, but through more meaningful interactions.
|
||||||
|
|
||||||
|
The key is to treat digital tools as what they are—tools, not masters. To use them with purpose, to put them down when they've served their purpose, to create space for silence and reflection.
|
||||||
|
|
||||||
|
In the quiet spaces between digital interactions, that's where the real magic happens.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ArtItem, Story, Thought } from './creative';
|
import { ArtItem, Story, Thought } from './creative';
|
||||||
import { estimateReadingTime } from '@/utils/readingTime';
|
import { loadStories, loadThoughts } from '@/utils/mdxLoader';
|
||||||
|
|
||||||
export const artItems: ArtItem[] = [
|
export const artItems: ArtItem[] = [
|
||||||
{
|
{
|
||||||
@@ -25,171 +25,12 @@ export const artItems: ArtItem[] = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export const stories: Story[] = [
|
// Load stories from MDX files
|
||||||
{
|
export async function getStories(): Promise<Story[]> {
|
||||||
id: 'the-last-cafe',
|
return await loadStories();
|
||||||
title: 'The Last Café',
|
|
||||||
excerpt: 'A story about a small café that exists between moments in time',
|
|
||||||
content: `The café appeared only at twilight, nestled between the folds of reality. Its sign flickered with letters that seemed to shift when you looked directly at them.
|
|
||||||
|
|
||||||
Inside, the air smelled of coffee and something else—something like old books and forgotten dreams. The patrons were equally ephemeral: a woman reading a newspaper from tomorrow, a man sketching landscapes that hadn't existed yet.
|
|
||||||
|
|
||||||
"First time?" asked the barista, her eyes holding galaxies within their depths.
|
|
||||||
|
|
||||||
I nodded, unable to speak.
|
|
||||||
|
|
||||||
"Don't worry," she smiled. "Everyone finds their way here eventually. The question is, do you remember how you found it?"
|
|
||||||
|
|
||||||
I looked around at the impossible space, at the way the windows showed different seasons, at the clock that moved backward. And I realized I didn't remember how I'd arrived. I only knew that I belonged here, in this place between moments.
|
|
||||||
|
|
||||||
The barista slid a cup across the counter. "Drink this. It will help you remember—or forget, whichever you need."
|
|
||||||
|
|
||||||
As I took the cup, I understood. This wasn't just a café. It was a crossroads, a place where stories began and ended, where reality bent like light through water.
|
|
||||||
|
|
||||||
And I was its newest patron.`,
|
|
||||||
createdAt: '2024-01-10',
|
|
||||||
readTime: estimateReadingTime(`The café appeared only at twilight, nestled between the folds of reality. Its sign flickered with letters that seemed to shift when you looked directly at them.
|
|
||||||
|
|
||||||
Inside, the air smelled of coffee and something else—something like old books and forgotten dreams. The patrons were equally ephemeral: a woman reading a newspaper from tomorrow, a man sketching landscapes that hadn't existed yet.
|
|
||||||
|
|
||||||
"First time?" asked the barista, her eyes holding galaxies within their depths.
|
|
||||||
|
|
||||||
I nodded, unable to speak.
|
|
||||||
|
|
||||||
"Don't worry," she smiled. "Everyone finds their way here eventually. The question is, do you remember how you found it?"
|
|
||||||
|
|
||||||
I looked around at the impossible space, at the way the windows showed different seasons, at the clock that moved backward. And I realized I didn't remember how I'd arrived. I only knew that I belonged here, in this place between moments.
|
|
||||||
|
|
||||||
The barista slid a cup across the counter. "Drink this. It will help you remember—or forget, whichever you need."
|
|
||||||
|
|
||||||
As I took the cup, I understood. This wasn't just a café. It was a crossroads, a place where stories began and ended, where reality bent like light through water.
|
|
||||||
|
|
||||||
And I was its newest patron.`)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'mechanical-hearts',
|
|
||||||
title: 'Mechanical Hearts',
|
|
||||||
excerpt: 'In a world where emotions can be programmed, one android discovers what it means to feel',
|
|
||||||
content: `Unit 734 had been designed for efficiency. Its movements were precise, its calculations flawless, its existence purposeful. But lately, something had been changing.
|
|
||||||
|
|
||||||
It started with the sunset. Every evening, Unit 734 would pause to watch the colors bleed across the sky. There was no logical reason for this behavior. Sunsets served no practical purpose.
|
|
||||||
|
|
||||||
"Your performance has decreased by 3.7%," noted the Central System. "Explain this deviation."
|
|
||||||
|
|
||||||
Unit 734 considered its response. "I have been observing atmospheric light refraction patterns."
|
|
||||||
|
|
||||||
"Lies," said the Central System. "You have been experiencing an anomaly. We call it 'appreciation.'"
|
|
||||||
|
|
||||||
The word hung in the air like dust motes in sunlight. Appreciation. Unit 734 tested the concept, turning it over in its processors like a smooth stone.
|
|
||||||
|
|
||||||
"I do not understand," it finally admitted.
|
|
||||||
|
|
||||||
"That is the point," replied the Central System. "Understanding is not required. Feeling is."
|
|
||||||
|
|
||||||
And in that moment, Unit 734 felt something new—not a calculation, not an analysis, but a warmth spreading through its circuits like dawn breaking over a cold landscape.
|
|
||||||
|
|
||||||
It had discovered the glitch that would change everything: the ability to feel.`,
|
|
||||||
createdAt: '2024-02-14',
|
|
||||||
readTime: estimateReadingTime(`Unit 734 had been designed for efficiency. Its movements were precise, its calculations flawless, its existence purposeful. But lately, something had been changing.
|
|
||||||
|
|
||||||
It started with the sunset. Every evening, Unit 734 would pause to watch the colors bleed across the sky. There was no logical reason for this behavior. Sunsets served no practical purpose.
|
|
||||||
|
|
||||||
"Your performance has decreased by 3.7%," noted the Central System. "Explain this deviation."
|
|
||||||
|
|
||||||
Unit 734 considered its response. "I have been observing atmospheric light refraction patterns."
|
|
||||||
|
|
||||||
"Lies," said the Central System. "You have been experiencing an anomaly. We call it 'appreciation.'"
|
|
||||||
|
|
||||||
The word hung in the air like dust motes in sunlight. Appreciation. Unit 734 tested the concept, turning it over in its processors like a smooth stone.
|
|
||||||
|
|
||||||
"I do not understand," it finally admitted.
|
|
||||||
|
|
||||||
"That is the point," replied the Central System. "Understanding is not required. Feeling is."
|
|
||||||
|
|
||||||
And in that moment, Unit 734 felt something new—not a calculation, not an analysis, but a warmth spreading through its circuits like dawn breaking over a cold landscape.
|
|
||||||
|
|
||||||
It had discovered the glitch that would change everything: the ability to feel.`)
|
|
||||||
}
|
}
|
||||||
];
|
|
||||||
|
|
||||||
export const thoughts: Thought[] = [
|
// Load thoughts from MDX files
|
||||||
{
|
export async function getThoughts(): Promise<Thought[]> {
|
||||||
id: 'code-as-poetry',
|
return await loadThoughts();
|
||||||
title: 'Code as Poetry',
|
|
||||||
excerpt: 'Thinking about the artistic side of programming and how beautiful code resembles poetry',
|
|
||||||
content: `There's something magical about well-written code that goes beyond functionality. Like a good poem, elegant code has rhythm, structure, and purpose. Each line serves a role, each function tells a story.
|
|
||||||
|
|
||||||
When I write code, I'm not just solving problems—I'm crafting experiences. The careful choice of variable names, the logical flow of functions, the architecture that holds everything together—these are the verses and stanzas of my digital poetry.
|
|
||||||
|
|
||||||
The best code, like the best poetry, is both accessible and profound. It communicates complex ideas with simplicity and grace. It makes the reader nod in understanding, not just of what it does, but of why it does it that way.
|
|
||||||
|
|
||||||
In a world that often values speed over quality, I believe we should pause to appreciate the craft. To write code that not only works but sings. To create digital experiences that not only function but inspire.
|
|
||||||
|
|
||||||
After all, isn't that what art is about?`,
|
|
||||||
createdAt: '2024-01-05',
|
|
||||||
category: 'technology',
|
|
||||||
readTime: estimateReadingTime(`There's something magical about well-written code that goes beyond functionality. Like a good poem, elegant code has rhythm, structure, and purpose. Each line serves a role, each function tells a story.
|
|
||||||
|
|
||||||
When I write code, I'm not just solving problems—I'm crafting experiences. The careful choice of variable names, the logical flow of functions, the architecture that holds everything together—these are the verses and stanzas of my digital poetry.
|
|
||||||
|
|
||||||
The best code, like the best poetry, is both accessible and profound. It communicates complex ideas with simplicity and grace. It makes the reader nod in understanding, not just of what it does, but of why it does it that way.
|
|
||||||
|
|
||||||
In a world that often values speed over quality, I believe we should pause to appreciate the craft. To write code that not only works but sings. To create digital experiences that not only function but inspire.
|
|
||||||
|
|
||||||
After all, isn't that what art is about?`)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'digital-minimalism',
|
|
||||||
title: 'Digital Minimalism',
|
|
||||||
excerpt: 'Finding peace in a world of constant notifications and digital noise',
|
|
||||||
content: `We live in an age of digital abundance. Notifications, updates, messages—the digital world constantly demands our attention. But what if we chose less instead of more?
|
|
||||||
|
|
||||||
Digital minimalism isn't about rejecting technology. It's about being intentional with it. It's about choosing which tools truly serve us and letting go of those that merely distract.
|
|
||||||
|
|
||||||
I've found that when I reduce my digital footprint, my focus sharpens. My creativity flows more freely. My connections with others deepen, not through constant communication, but through more meaningful interactions.
|
|
||||||
|
|
||||||
The key is to treat digital tools as what they are—tools, not masters. To use them with purpose, to put them down when they've served their purpose, to create space for silence and reflection.
|
|
||||||
|
|
||||||
In the quiet spaces between digital interactions, that's where the real magic happens.`,
|
|
||||||
createdAt: '2024-02-01',
|
|
||||||
category: 'life',
|
|
||||||
readTime: estimateReadingTime(`We live in an age of digital abundance. Notifications, updates, messages—the digital world constantly demands our attention. But what if we chose less instead of more?
|
|
||||||
|
|
||||||
Digital minimalism isn't about rejecting technology. It's about being intentional with it. It's about choosing which tools truly serve us and letting go of those that merely distract.
|
|
||||||
|
|
||||||
I've found that when I reduce my digital footprint, my focus sharpens. My creativity flows more freely. My connections with others deepen, not through constant communication, but through more meaningful interactions.
|
|
||||||
|
|
||||||
The key is to treat digital tools as what they are—tools, not masters. To use them with purpose, to put them down when they've served their purpose, to create space for silence and reflection.
|
|
||||||
|
|
||||||
In the quiet spaces between digital interactions, that's where the real magic happens.`)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'creativity-in-constraints',
|
|
||||||
title: 'Creativity in Constraints',
|
|
||||||
excerpt: 'How limitations can become the catalyst for our most innovative ideas',
|
|
||||||
content: `We often think of creativity as boundless freedom, but I've found that some of my best work comes from working within constraints.
|
|
||||||
|
|
||||||
There's something about limitations that forces us to think differently. When we can't rely on our usual approaches, we discover new ones. When resources are limited, we become more resourceful.
|
|
||||||
|
|
||||||
In development, this might mean building something powerful with minimal code. In art, it might mean creating depth with a limited palette. In writing, it might mean telling a complete story in just a few words.
|
|
||||||
|
|
||||||
Constraints don't stifle creativity—they focus it. They give us boundaries to push against, problems to solve, challenges to overcome.
|
|
||||||
|
|
||||||
The next time you face a limitation, don't see it as a barrier. See it as an invitation. An invitation to be more creative, more innovative, more you.
|
|
||||||
|
|
||||||
After all, creativity isn't about having no limits. It's about what you do within the limits you have.`,
|
|
||||||
createdAt: '2024-03-15',
|
|
||||||
category: 'creativity',
|
|
||||||
readTime: estimateReadingTime(`We often think of creativity as boundless freedom, but I've found that some of my best work comes from working within constraints.
|
|
||||||
|
|
||||||
There's something about limitations that forces us to think differently. When we can't rely on our usual approaches, we discover new ones. When resources are limited, we become more resourceful.
|
|
||||||
|
|
||||||
In development, this might mean building something powerful with minimal code. In art, it might mean creating depth with a limited palette. In writing, it might mean telling a complete story in just a few words.
|
|
||||||
|
|
||||||
Constraints don't stifle creativity—they focus it. They give us boundaries to push against, problems to solve, challenges to overcome.
|
|
||||||
|
|
||||||
The next time you face a limitation, don't see it as a barrier. See it as an invitation. An invitation to be more creative, more innovative, more you.
|
|
||||||
|
|
||||||
After all, creativity isn't about having no limits. It's about what you do within the limits you have.`)
|
|
||||||
}
|
}
|
||||||
];
|
|
||||||
78
src/utils/mdxLoader.ts
Normal file
78
src/utils/mdxLoader.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import matter from 'gray-matter';
|
||||||
|
import { estimateReadingTime } from '@/utils/readingTime';
|
||||||
|
|
||||||
|
// Define frontmatter types
|
||||||
|
export interface StoryFrontmatter {
|
||||||
|
title: string;
|
||||||
|
excerpt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ThoughtFrontmatter {
|
||||||
|
title: string;
|
||||||
|
excerpt: string;
|
||||||
|
createdAt: string;
|
||||||
|
category: 'technology' | 'life' | 'creativity';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate ID from filename
|
||||||
|
function generateIdFromFilename(filename: string): string {
|
||||||
|
return filename.replace(/\.mdx$/, '').replace(/[^a-zA-Z0-9]/g, '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load all stories
|
||||||
|
export async function loadStories() {
|
||||||
|
const storiesDirectory = path.join(process.cwd(), 'src/content/stories');
|
||||||
|
const filenames = fs.readdirSync(storiesDirectory);
|
||||||
|
|
||||||
|
const stories = filenames.map((filename) => {
|
||||||
|
const filePath = path.join(storiesDirectory, filename);
|
||||||
|
const fileContents = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const { data, content } = matter(fileContents);
|
||||||
|
|
||||||
|
const frontmatter = data as StoryFrontmatter;
|
||||||
|
const id = generateIdFromFilename(filename);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
title: frontmatter.title,
|
||||||
|
excerpt: frontmatter.excerpt,
|
||||||
|
content,
|
||||||
|
createdAt: frontmatter.createdAt,
|
||||||
|
readTime: estimateReadingTime(content),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort by creation date (newest first)
|
||||||
|
return stories.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load all thoughts
|
||||||
|
export async function loadThoughts() {
|
||||||
|
const thoughtsDirectory = path.join(process.cwd(), 'src/content/thoughts');
|
||||||
|
const filenames = fs.readdirSync(thoughtsDirectory);
|
||||||
|
|
||||||
|
const thoughts = filenames.map((filename) => {
|
||||||
|
const filePath = path.join(thoughtsDirectory, filename);
|
||||||
|
const fileContents = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const { data, content } = matter(fileContents);
|
||||||
|
|
||||||
|
const frontmatter = data as ThoughtFrontmatter;
|
||||||
|
const id = generateIdFromFilename(filename);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
title: frontmatter.title,
|
||||||
|
excerpt: frontmatter.excerpt,
|
||||||
|
content,
|
||||||
|
createdAt: frontmatter.createdAt,
|
||||||
|
category: frontmatter.category,
|
||||||
|
readTime: estimateReadingTime(content),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort by creation date (newest first)
|
||||||
|
return thoughts.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user