diff --git a/app/about/page.tsx b/app/about/page.tsx index 9870ec7..0fc8e30 100644 --- a/app/about/page.tsx +++ b/app/about/page.tsx @@ -1,55 +1,252 @@ import { Metadata } from 'next' +import { Navbar } from '@/components/blog/navbar' export const metadata: Metadata = { - title: 'Despre', - description: 'Află mai multe despre mine și acest blog', + title: 'About', + description: 'Learn more about me and this blog', } export default function AboutPage() { return ( -
-

Despre Mine

+ <> + +
+
+ {/* Classification Header */} +
+

+ >> _DOC://PUBLIC_ACCESS +

+

+ ABOUT ME_ +

+
-
-

- Bun venit pe blogul meu! Sunt un dezvoltator pasionat de tehnologie, specializat în - dezvoltarea web modernă cu Next.js, React și TypeScript. -

+ {/* Main Content */} +
+ {/* Introduction Section */} +
+
+

+ Welcome to my corner of the internet! This is where I share my thoughts, opinions, + and experiences - from tech adventures to life as a family man. Yes, I love + technology, but there's so much more to life than just code and servers. +

+

+ STATUS: ACTIVE // ROLE: DAD + DEV + LIFE ENTHUSIAST +

+
+
-

Ce vei găsi aici

-
    -
  • Tutoriale despre dezvoltare web
  • -
  • Ghiduri practice pentru Next.js și React
  • -
  • Sfaturi despre design și UX
  • -
  • Experiențe din proiecte reale
  • -
+ {/* Life & Values Section */} +
+

+ > LIFE & VALUES +

+
+
+

+ [FAMILY FIRST] +

+

+ Being a dad to an amazing toddler is my most important role. Family time is + sacred - whether it's building block towers, exploring parks, or just + enjoying the chaos of everyday life together. Tech can wait; these moments + can't. +

+
+
+

+ [ACTIVE LIFESTYLE] +

+

+ I believe in keeping the body active. Whether it's hitting the gym, playing + sports, or just staying on the move - physical activity keeps me sharp, + balanced, and ready for whatever life throws my way. +

+
+
+

+ [ENJOYING THE SIMPLE THINGS] +

+

+ Life's too short not to enjoy it. A good drink, a relaxing + evening after a long day, or just not doing anything a blowing some steam off. +

+
+
+

+ [TECH WITH PURPOSE] +

+

+ Yes, I love tech - self-hosting, privacy, tinkering with hardware. But it's + a tool, not a lifestyle. Tech should serve life, not the other way around. +

+
+
+
-

Tehnologii folosite

-

Acest blog este construit cu:

-
    -
  • - Next.js 15 - Framework React pentru producție -
  • -
  • - TypeScript - Pentru type safety -
  • -
  • - Tailwind CSS - Pentru stilizare rapidă -
  • -
  • - Markdown - Pentru conținut -
  • -
+ {/* Content Section */} +
+

+ > WHAT YOU'LL FIND HERE +

+

+ CONTENT SCOPE // EVERYTHING FROM TECH TO LIFE +

+
    +
  • + > + + Thoughts & Opinions - My take on life, work, and everything in + between + +
  • +
  • + > + + Life & Family - Adventures in parenting, sports, and enjoying + the simple things + +
  • +
  • + > + + Tech Research - When I dive into interesting technologies and + experiments + +
  • +
  • + > + + System Administration - Self-hosting, infrastructure, and + DevOps adventures + +
  • +
  • + > + + Development Insights - Lessons learned from building software + +
  • +
  • + > + + Random Stuff - Because life doesn't fit into neat + categories! + +
  • +
+
-

Contact

-

- Mă poți contacta pe{' '} - - email@example.com - {' '} - sau mă poți găsi pe rețelele sociale. -

+ {/* Areas of Focus Section */} +
+

+ > AREAS OF FOCUS +

+
+
+

+ [BEING A DAD] +

+

+ Playing with my boy, teaching moments, watching him grow, building memories + together +

+
+
+

+ [STAYING ACTIVE] +

+

+ Gym sessions, sports, keeping fit, maintaining energy for life's demands +

+
+
+

+ [TECHNOLOGY & SYSTEMS] +

+

+ Software development, infrastructure, DevOps, self-hosting adventures +

+
+
+

+ [LIFE BALANCE] +

+

+ Relaxing with good company, enjoying downtime, appreciating the simple moments +

+
+
+
+ {/* Tech Stack Section */} +
+

+ > TECH STACK +

+

+ TOOLS I USE // WHEN NEEDED +

+
+
+

+ [DEVELOPMENT] +

+

+ .NET, Golang, TypeScript, Next.js, React +

+
+
+

+ [INFRASTRUCTURE] +

+

+ Windows Server, Linux, Docker, Hyper-V +

+
+
+

+ [DESIGN] +

+

+ Tailwind CSS, Markdown, Terminal aesthetics +

+
+
+

+ [SELF-HOSTING] +

+

+ Home lab, privacy-focused services, full control, Git server +

+
+
+
+ {/* Contact Section */} +
+

+ > CONTACT +

+
+ {/*

+ You can reach me at{' '} + + email@example.com + {' '} + or find me on social media. +

*/} + {/*

+ RESPONSE TIME: < 24H // STATUS: MONITORED +

*/} +
+
+
+
-
+ ) } diff --git a/app/blog/[...slug]/page.tsx b/app/blog/[...slug]/page.tsx index 89ad1be..7373e0f 100644 --- a/app/blog/[...slug]/page.tsx +++ b/app/blog/[...slug]/page.tsx @@ -91,7 +91,7 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:

- >> CLASSIFIED_DOC://PUBLIC_ACCESS + >> _DOC://PUBLIC_ACCESS

diff --git a/app/globals.css b/app/globals.css index 3d22f01..8e92fc5 100644 --- a/app/globals.css +++ b/app/globals.css @@ -45,6 +45,7 @@ } @layer utilities { + /* Scrollbar hiding utility */ .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; @@ -129,6 +130,7 @@ opacity: 0.8; } + /* Consolidated keyframes to avoid duplication */ @keyframes glitch-1 { 0%, 100% { @@ -211,46 +213,6 @@ clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%); } - @keyframes glitch-1 { - 0%, - 100% { - transform: translate(0, 0); - clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%); - } - 25% { - transform: translate(-3px, 2px); - clip-path: polygon(0 10%, 100% 10%, 100% 45%, 0 45%); - } - 50% { - transform: translate(3px, -2px); - clip-path: polygon(0 20%, 100% 20%, 100% 55%, 0 55%); - } - 75% { - transform: translate(-2px, -1px); - clip-path: polygon(0 5%, 100% 5%, 100% 40%, 0 40%); - } - } - - @keyframes glitch-2 { - 0%, - 100% { - transform: translate(0, 0); - clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%); - } - 25% { - transform: translate(3px, -2px); - clip-path: polygon(0 55%, 100% 55%, 100% 90%, 0 90%); - } - 50% { - transform: translate(-3px, 2px); - clip-path: polygon(0 45%, 100% 45%, 100% 80%, 0 80%); - } - 75% { - transform: translate(2px, 1px); - clip-path: polygon(0 60%, 100% 60%, 100% 95%, 0 95%); - } - } - /* Border Pulse Animation */ .border-pulse { animation: pulse-border 2s ease-in-out infinite; @@ -475,10 +437,9 @@ } .cyberpunk-prose img { - margin-top: 2rem; - margin-bottom: 2rem; - border: 4px solid var(--neon-pink); - box-shadow: 0 0 20px rgba(155, 90, 110, 0.5); + margin: 2rem; + /* border: 4px solid var(--neon-pink); */ + box-shadow: 0 0 2px rgba(155, 90, 110, 0.5); } .cyberpunk-prose hr { diff --git a/app/layout.tsx b/app/layout.tsx index 9787000..1712019 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -49,7 +49,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })

© 2025 // BLOG &{' '} - PORTOFOLIU{' '} + RANDOM THOUGHTS{' '} // ALL RIGHTS RESERVED

diff --git a/app/page.tsx b/app/page.tsx index acbe903..4bb3d7a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -45,7 +45,7 @@ export default async function HomePage() {

- DOCUMENT LEVEL-1 // CLASSIFIED + DOCUMENT LEVEL-1 //

BUILD. WRITE. @@ -53,7 +53,7 @@ export default async function HomePage() { SHARE.

- > Explorează idei despre dezvoltare, design și tehnologie_ + > Explore ideas

@@ -62,13 +62,13 @@ export default async function HomePage() { href="/blog" className="px-6 md:px-8 py-3 md:py-4 bg-cyan-700 dark:bg-cyan-900 text-white dark:text-slate-100 border-2 border-cyan-600 dark:border-cyan-700 font-mono font-bold uppercase text-xs md:text-sm tracking-wider hover:bg-cyan-600 dark:hover:bg-cyan-800 hover:border-cyan-500 dark:hover:border-cyan-600 rounded-none transition-colors duration-200" > - [EXPLOREAZĂ BLOG] + [CHECK POSTS] - [DESPRE MINE] + [ABOUT ME]
@@ -83,7 +83,7 @@ export default async function HomePage() { ARCHIVE ACCESS // RECENT ENTRIES

- > POSTĂRI RECENTE_ + > RECENT ENTRIES

@@ -146,28 +146,28 @@ export default async function HomePage() { href="/blog" className="inline-flex items-center px-8 py-4 bg-transparent text-slate-700 dark:text-slate-300 border-2 border-slate-400 dark:border-slate-700 font-mono font-bold uppercase text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 transition-colors duration-200" > - [VEZI TOATE ARTICOLELE] >> + [SEE POSTS] >> )} - [VEZI TOATE TAG-URILE] >> + [SEE ALL TAGS] >>
{/* Stats Section - from worktree-agent-1 */} -
+ {/*

SYSTEM STATISTICS // DATABASE METRICS

- > METRICI_ + > METRICS

@@ -177,7 +177,7 @@ export default async function HomePage() { {allPosts.length}+

- ARTICOLE PUBLICATE + PUBLISHED

@@ -200,10 +200,10 @@ export default async function HomePage() { -
+
*/} {/* Newsletter CTA - from worktree-agent-1 */} -
+ {/*

@@ -233,7 +233,7 @@ export default async function HomePage() {

-
+
*/} ) } diff --git a/components/blog/OptimizedImage.tsx b/components/blog/OptimizedImage.tsx index 5c97eed..500ab57 100644 --- a/components/blog/OptimizedImage.tsx +++ b/components/blog/OptimizedImage.tsx @@ -27,38 +27,44 @@ export function OptimizedImage({ if (hasError) { return ( -
-

Failed to load image

- {caption &&

{caption}

} -
+ + Failed to load image + {caption && {caption}} + ) } - return ( -
-
- {alt} setIsLoading(false)} - onError={() => setHasError(true)} - placeholder="blur" - blurDataURL="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300'%3E%3Crect width='400' height='300' fill='%2318181b'/%3E%3C/svg%3E" - /> - {isLoading && ( -
-
-
- )} -
- {caption && ( -
{caption}
+ const imageElement = ( + + {alt} setIsLoading(false)} + onError={() => setHasError(true)} + placeholder="blur" + blurDataURL="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='300'%3E%3Crect width='400' height='300' fill='%2318181b'/%3E%3C/svg%3E" + /> + {isLoading && ( + + + )} -
+ + ) + + // Always use to avoid invalid HTML nesting in

tags + // This prevents hydration mismatches between server and client + return ( + + {imageElement} + {caption && ( + {caption} + )} + ) } diff --git a/components/blog/markdown-renderer.tsx b/components/blog/markdown-renderer.tsx index 07be1ac..9254205 100644 --- a/components/blog/markdown-renderer.tsx +++ b/components/blog/markdown-renderer.tsx @@ -18,17 +18,50 @@ export default function MarkdownRenderer({ content, className = '' }: MarkdownRe

{ if (!src || typeof src !== 'string') return null @@ -55,19 +88,19 @@ export default function MarkdownRenderer({ content, className = '' }: MarkdownRe : [alt, undefined] const url = new URL(absoluteSrc, 'http://localhost') - const width = url.searchParams.get('w') ? parseInt(url.searchParams.get('w')!) : 800 - const height = url.searchParams.get('h') ? parseInt(url.searchParams.get('h')!) : 600 + const width = url.searchParams.get('w') ? parseInt(url.searchParams.get('w')!) : null + const height = url.searchParams.get('h') ? parseInt(url.searchParams.get('h')!) : null const cleanSrc = absoluteSrc.split('?')[0] - return ( - - ) + const imageProps = { + src: cleanSrc, + alt: altText || alt || '', + caption: caption, + ...(width && { width }), + ...(height && { height }), + } + + return }, code: ({ node, className, children, ...props }) => { const inline = !className && typeof children === 'string' && !children.includes('\n') diff --git a/components/blog/navbar.tsx b/components/blog/navbar.tsx index 9f77ee4..a0dd5df 100644 --- a/components/blog/navbar.tsx +++ b/components/blog/navbar.tsx @@ -52,7 +52,13 @@ export function Navbar() { > [ABOUT] - + + [BLOG] + +
diff --git a/content/blog/example.md b/content/blog/example.md deleted file mode 100644 index fc2666f..0000000 --- a/content/blog/example.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: 'Getting Started with Next.js 15' -description: 'Learn how to build modern web applications with Next.js 15 and TypeScript.' -date: '2025-01-07' -author: 'John Doe' -category: 'Tutorial' -tags: ['nextjs', 'typescript', 'tutorial'] ---- - -# Getting Started with Next.js 15 - -Welcome to this example blog post! This post demonstrates how markdown content is rendered. - -## Features - -- Server Components by default -- Improved performance -- Better TypeScript support - -## Code Example - -```typescript -export default function Page() { - return

Hello, Next.js 15!

-} -``` - -### Check out this article: - -[Check this out](tech/articol-tehnic.md) - -## Conclusion - -Next.js 15 brings many improvements for building modern web applications. diff --git a/content/blog/tech/articol-tehnic.md b/content/blog/tech/articol-tehnic.md deleted file mode 100644 index 5d509a7..0000000 --- a/content/blog/tech/articol-tehnic.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: 'Technical Article' -description: 'A technical article to test internal links' -date: '2025-01-10' -author: 'John Doe' -category: 'Tech' -tags: ['tech', 'test'] ---- - -# Technical Article - -This is a test article for internal blog post linking. - -Imagine cooler: - -![Cooler image:](./cooler.jpg) - -## Content - -You are reading the technical article that was linked from the example post. diff --git a/content/blog/tech/cooler.jpg b/content/blog/tech/cooler.jpg deleted file mode 100644 index a30a210..0000000 Binary files a/content/blog/tech/cooler.jpg and /dev/null differ diff --git a/content/blog/test-complet.md b/content/blog/test-complet.md deleted file mode 100644 index 5dbad7d..0000000 --- a/content/blog/test-complet.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: 'Test Complet Markdown' -description: 'Un articol de test care demonstrează toate elementele markdown suportate' -date: '2025-01-15' -author: 'Test Author' -category: 'Tutorial' -tags: ['markdown', 'test', 'demo'] -image: '/38636.jpg' -draft: false ---- - -# Heading 1 - -Acesta este un paragraf normal cu **text bold** și _text italic_. Putem combina **_bold și italic_**. - -## Heading 2 - -### Heading 3 - -#### Heading 4 - -##### Heading 5 - -###### Heading 6 - -## Liste - -### Listă neordonată - -- Item 1 -- Item 2 - - Subitem 2.1 - - Subitem 2.2 -- Item 3 - -### Listă ordonată - -1. Primul item -2. Al doilea item -3. Al treilea item - -## Cod - -Cod inline: `const x = 42;` - -Bloc de cod JavaScript: - -```javascript -function greet(name) { - console.log(`Hello, ${name}!`) - return true -} - -greet('World') -``` - -Bloc de cod Python: - -```python -def calculate_sum(a, b): - """Calculate sum of two numbers""" - return a + b - -result = calculate_sum(5, 10) -print(f"Result: {result}") -``` - -## Blockquote - -> Acesta este un blockquote. -> Poate avea multiple linii. -> -> Și paragrafe separate. - -## Link-uri - -[Link intern](/blog/alt-articol) - -[Link extern](https://example.com) - -## Imagini - -![Alt text pentru imagine](./tech/cooler.jpg) - -## Tabele - -| Coloana 1 | Coloana 2 | Coloana 3 | -| --------- | --------- | --------- | -| Celula 1 | Celula 2 | Celula 3 | -| Date 1 | Date 2 | Date 3 | -| Info 1 | Info 2 | Info 3 | - -## Linie orizontală - ---- - -## Task List (GFM) - -- [x] Task completat -- [ ] Task incomplet -- [ ] Alt task - -## Strikethrough - -~~Text șters~~ - -## Concluzie - -Acesta este sfârșitul articolului de test. diff --git a/content/blog/why-this-page.md b/content/blog/why-this-page.md new file mode 100644 index 0000000..dc12dff --- /dev/null +++ b/content/blog/why-this-page.md @@ -0,0 +1,41 @@ +--- +title: 'Why I created this page' +description: 'First post' +date: '2025-12-02' +author: 'Rares' +category: 'Opinion' +tags: ['opinion'] +image: '' +draft: false +--- + +# Why I Created This Blog & Why It's Not Just About Tech + +Hi there! Welcome to my blog. If you're wondering why I created this space, it's because I wanted to share more than just technical tutorials or how-to guides – though you'll find those here too. This blog is a reflection of me and my journey through the world of technology, self-hosting, and beyond. + +## Why a blog? + +You might be thinking, "Why create another tech blog? There are plenty out there." +Well, yes, there are. But I believe that sharing some of my opinions and experiences will eventually act out as a journal: + +1. **Personal touch**: Even though i've been working corporate all my career, this webpage won't contain that sugar coated language 😅. It's a place where you'll get to know me – my thoughts, my mistakes, and my victories. I believe that this personal touch makes the content more engaging and relatable. +2. **Beyond tech**: While I'll be writing about technology, I also want to explore other topics that interest me, such as mental health, productivity and so on.... I think a well-rounded approach can help create a more engaging and informative space. +3. **Self-hosting adventure**: As you might have guessed from the title, this blog is self-hosted. This was an exciting journey for me, and I'll be sharing my experiences, challenges, and learnings along the way. If you're interested in self-hosting or just want to understand what it's all about, you might find what worked for me or didn't. + +## Why self-host? + +![Selfhosting rig](./whythispage/selfhostedrig.gif?w=400 "My self-hosting setup | A look at the hardware running this blog") + +Now, let's talk about why I chose to self-host this blog. In a nutshell, self-hosting gave me: + +- **Full control**: By hosting my own website, I have complete control over my content and how it's displayed. No more compromises or limitations imposed by third-party platforms. +- **Owning my data**: It's just, that I can have control over my data without others snooping around. +- **It's fun**: Started looking into sysadmin/devops for a long time, after a burnout I stepped into selfhosting more convincingly. + +## What to expect + +As I mentioned earlier, this blog will be a mix of tech tutorials, personal thoughts, and everything in between. Here's what you can look forward to: + +- **Tech how-tos**: Step-by-step guides on various topics, from setting up your own development environment to configuring your server. +- **Self-hosting adventures**: My experiences, learnings, and tips on self-hosting, including challenges faced and solutions implemented. +- **Random musings**: Thoughts on productivity, mental health, and other interests of mine that might not be directly related to tech. diff --git a/content/blog/whythispage/selfhostedrig.gif b/content/blog/whythispage/selfhostedrig.gif new file mode 100644 index 0000000..7022e0c Binary files /dev/null and b/content/blog/whythispage/selfhostedrig.gif differ diff --git a/ENV_CONFIG_GUIDE.md b/docs/ENV_CONFIG_GUIDE.md similarity index 100% rename from ENV_CONFIG_GUIDE.md rename to docs/ENV_CONFIG_GUIDE.md diff --git a/OPTIMIZATION_REPORT.md b/docs/OPTIMIZATION_REPORT.md similarity index 100% rename from OPTIMIZATION_REPORT.md rename to docs/OPTIMIZATION_REPORT.md diff --git a/lib/utils.ts b/lib/utils.ts index b2c279e..e2a1692 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,18 +1,18 @@ export function formatDate(dateString: string): string { const date = new Date(dateString) const months = [ - 'ianuarie', - 'februarie', - 'martie', - 'aprilie', - 'mai', - 'iunie', - 'iulie', - 'august', - 'septembrie', - 'octombrie', - 'noiembrie', - 'decembrie', + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', ] return `${date.getDate()} ${months[date.getMonth()]} ${date.getFullYear()}` @@ -24,12 +24,22 @@ export function formatRelativeDate(dateString: string): string { const diffTime = Math.abs(now.getTime() - date.getTime()) const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) - if (diffDays === 0) return 'astăzi' - if (diffDays === 1) return 'ieri' - if (diffDays < 7) return `acum ${diffDays} zile` - if (diffDays < 30) return `acum ${Math.floor(diffDays / 7)} săptămâni` - if (diffDays < 365) return `acum ${Math.floor(diffDays / 30)} luni` - return `acum ${Math.floor(diffDays / 365)} ani` + if (diffDays === 0) return 'today' + if (diffDays === 1) return 'yesterday' + if (diffDays < 7) { + const days = diffDays + return `${days} day${days > 1 ? 's' : ''} ago` + } + if (diffDays < 30) { + const weeks = Math.floor(diffDays / 7) + return `${weeks} week${weeks > 1 ? 's' : ''} ago` + } + if (diffDays < 365) { + const months = Math.floor(diffDays / 30) + return `${months} month${months > 1 ? 's' : ''} ago` + } + const years = Math.floor(diffDays / 365) + return `${years} year${years > 1 ? 's' : ''} ago` } export function generateExcerpt(content: string, maxLength = 160): string { diff --git a/next.config.js b/next.config.js index a761ea8..220d49d 100644 --- a/next.config.js +++ b/next.config.js @@ -70,7 +70,6 @@ const nextConfig = { // Performance Optimization // ============================================ - // Compress static pages (reduces bandwidth) compress: true,