feat/improve-about-page #9
@@ -2,8 +2,8 @@ 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() {
|
||||
@@ -15,10 +15,10 @@ export default function AboutPage() {
|
||||
{/* Classification Header */}
|
||||
<div className="border-2 border-[rgb(var(--border-primary))] p-8 mb-10">
|
||||
<p className="text-[rgb(var(--text-muted))] font-mono text-xs uppercase tracking-widest mb-4">
|
||||
>> CLASSIFIED_DOC://PUBLIC_ACCESS
|
||||
>> _DOC://PUBLIC_ACCESS
|
||||
</p>
|
||||
<h1 className="text-4xl md:text-5xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] tracking-tight">
|
||||
DESPRE MINE_
|
||||
ABOUT ME_
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -28,111 +28,220 @@ export default function AboutPage() {
|
||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||
<div className="border-l-4 border-[var(--neon-cyan)] pl-6">
|
||||
<p className="font-mono text-base text-[rgb(var(--text-primary))] leading-relaxed mb-4">
|
||||
Bun venit pe blogul meu! Sunt un dezvoltator pasionat de tehnologie, specializat
|
||||
în dezvoltarea web modernă cu Next.js, React și TypeScript.
|
||||
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.
|
||||
</p>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider">
|
||||
STATUS: ACTIVE // LEVEL: SENIOR DEV
|
||||
STATUS: ACTIVE // ROLE: DAD + DEV + LIFE ENTHUSIAST
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Life & Values Section */}
|
||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||
> LIFE & VALUES
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="border-l-4 border-[var(--neon-pink)] pl-6">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-pink)] uppercase mb-2">
|
||||
[FAMILY FIRST]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-l-4 border-[var(--neon-cyan)] pl-6">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[ACTIVE LIFESTYLE]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-l-4 border-[var(--neon-green)] pl-6">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-green)] uppercase mb-2">
|
||||
[ENJOYING THE SIMPLE THINGS]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
<div className="border-l-4 border-[var(--neon-orange)] pl-6">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-orange)] uppercase mb-2">
|
||||
[TECH WITH PURPOSE]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Content Section */}
|
||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||
> CE VEI GĂSI AICI
|
||||
> WHAT YOU'LL FIND HERE
|
||||
</h2>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider mb-6">
|
||||
CONTENT SCOPE // EVERYTHING FROM TECH TO LIFE
|
||||
</p>
|
||||
<ul className="space-y-3">
|
||||
<li className="flex items-start gap-3">
|
||||
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
||||
<span className="text-[var(--neon-pink)] font-mono font-bold">></span>
|
||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Tutoriale despre dezvoltare web
|
||||
<strong>Thoughts & Opinions</strong> - My take on life, work, and everything in
|
||||
between
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-3">
|
||||
<span className="text-[var(--neon-pink)] font-mono font-bold">></span>
|
||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
<strong>Life & Family</strong> - Adventures in parenting, sports, and enjoying
|
||||
the simple things
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-3">
|
||||
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Ghiduri practice pentru Next.js și React
|
||||
<strong>Tech Research</strong> - When I dive into interesting technologies and
|
||||
experiments
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-3">
|
||||
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Sfaturi despre design și UX
|
||||
<strong>System Administration</strong> - Self-hosting, infrastructure, and
|
||||
DevOps adventures
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-3">
|
||||
<span className="text-[var(--neon-cyan)] font-mono font-bold">></span>
|
||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Experiențe din proiecte reale
|
||||
<strong>Development Insights</strong> - Lessons learned from building software
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex items-start gap-3">
|
||||
<span className="text-[var(--neon-green)] font-mono font-bold">></span>
|
||||
<span className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
<strong>Random Stuff</strong> - Because life doesn't fit into neat
|
||||
categories!
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* Tech Stack Section */}
|
||||
{/* Areas of Focus Section */}
|
||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||
> TEHNOLOGII FOLOSITE
|
||||
> AREAS OF FOCUS
|
||||
</h2>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider mb-6">
|
||||
SYSTEM STACK // VERSION 2.0
|
||||
</p>
|
||||
<div className="grid gap-4">
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[FRAMEWORK]
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-pink)] uppercase mb-2">
|
||||
[BEING A DAD]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))]">
|
||||
<strong>Next.js 16</strong> - Framework React pentru producție
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Playing with my boy, teaching moments, watching him grow, building memories
|
||||
together
|
||||
</p>
|
||||
</div>
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[LANGUAGE]
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[STAYING ACTIVE]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))]">
|
||||
<strong>TypeScript</strong> - Pentru type safety
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Gym sessions, sports, keeping fit, maintaining energy for life's demands
|
||||
</p>
|
||||
</div>
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[STYLING]
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-green)] uppercase mb-2">
|
||||
[TECHNOLOGY & SYSTEMS]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))]">
|
||||
<strong>Tailwind CSS</strong> - Pentru stilizare rapidă
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Software development, infrastructure, DevOps, self-hosting adventures
|
||||
</p>
|
||||
</div>
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-sm font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[CONTENT]
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-orange)] uppercase mb-2">
|
||||
[LIFE BALANCE]
|
||||
</h3>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))]">
|
||||
<strong>Markdown</strong> - Pentru conținut
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Relaxing with good company, enjoying downtime, appreciating the simple moments
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/* Tech Stack Section */}
|
||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||
> TECH STACK
|
||||
</h2>
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-muted))] uppercase tracking-wider mb-6">
|
||||
TOOLS I USE // WHEN NEEDED
|
||||
</p>
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[DEVELOPMENT]
|
||||
</h3>
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
.NET, Golang, TypeScript, Next.js, React
|
||||
</p>
|
||||
</div>
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[INFRASTRUCTURE]
|
||||
</h3>
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Windows Server, Linux, Docker, Hyper-V
|
||||
</p>
|
||||
</div>
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[DESIGN]
|
||||
</h3>
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Tailwind CSS, Markdown, Terminal aesthetics
|
||||
</p>
|
||||
</div>
|
||||
<div className="border border-[rgb(var(--border-primary))] p-4">
|
||||
<h3 className="font-mono text-xs font-bold text-[var(--neon-cyan)] uppercase mb-2">
|
||||
[SELF-HOSTING]
|
||||
</h3>
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-primary))] leading-relaxed">
|
||||
Home lab, privacy-focused services, full control, Git server
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Contact Section */}
|
||||
<section className="border-2 border-[rgb(var(--border-primary))] p-8">
|
||||
<h2 className="text-2xl font-mono font-bold uppercase text-[rgb(var(--text-primary))] mb-6 pb-3 border-b-2 border-[rgb(var(--border-primary))]">
|
||||
> CONTACT
|
||||
</h2>
|
||||
<div className="border-l-4 border-[var(--neon-pink)] pl-6">
|
||||
<p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed mb-4">
|
||||
Mă poți contacta pe{' '}
|
||||
{/* <p className="font-mono text-sm text-[rgb(var(--text-primary))] leading-relaxed mb-4">
|
||||
You can reach me at{' '}
|
||||
<a
|
||||
href="mailto:email@example.com"
|
||||
className="text-[var(--neon-cyan)] hover:text-[var(--neon-pink)] underline transition-colors"
|
||||
>
|
||||
email@example.com
|
||||
</a>{' '}
|
||||
sau mă poți găsi pe rețelele sociale.
|
||||
</p>
|
||||
<p className="font-mono text-xs text-[rgb(var(--text-muted))] uppercase tracking-wider">
|
||||
or find me on social media.
|
||||
</p> */}
|
||||
{/* <p className="font-mono text-xs text-[rgb(var(--text-muted))] uppercase tracking-wider">
|
||||
RESPONSE TIME: < 24H // STATUS: MONITORED
|
||||
</p>
|
||||
</p> */}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +91,7 @@ export default async function BlogPostPage({ params }: { params: Promise<{ slug:
|
||||
<div className="border-b border-[var(--neon-pink)] pb-4 mb-6 relative">
|
||||
<div className="flex items-center gap-3 mb-3 justify-end">
|
||||
<p className="font-mono text-xs text-[var(--neon-cyan)] uppercase tracking-widest">
|
||||
>> CLASSIFIED_DOC://PUBLIC_ACCESS
|
||||
>> _DOC://PUBLIC_ACCESS
|
||||
</p>
|
||||
<div className="flex gap-1.5">
|
||||
<div className="w-4 h-4 border border-[rgb(var(--border-primary))] hover:bg-red-500/10 cursor-pointer" />
|
||||
|
||||
@@ -437,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 {
|
||||
|
||||
@@ -49,7 +49,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
<div className="border-2 border-slate-300 dark:border-slate-800 p-6">
|
||||
<p className="text-center text-slate-500 dark:text-slate-500 font-mono text-xs uppercase tracking-wider">
|
||||
© 2025 <span style={{ color: 'var(--neon-cyan)' }}>//</span> BLOG &{' '}
|
||||
<span style={{ color: 'var(--neon-pink)' }}>PORTOFOLIU</span>{' '}
|
||||
<span style={{ color: 'var(--neon-pink)' }}>RANDOM THOUGHTS</span>{' '}
|
||||
<span style={{ color: 'var(--neon-cyan)' }}>//</span> ALL RIGHTS RESERVED
|
||||
</p>
|
||||
</div>
|
||||
|
||||
26
app/page.tsx
26
app/page.tsx
@@ -45,7 +45,7 @@ export default async function HomePage() {
|
||||
|
||||
<div className="border-l-4 border-cyan-700 dark:border-cyan-900 pl-6 mb-8">
|
||||
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
||||
DOCUMENT LEVEL-1 // CLASSIFIED
|
||||
DOCUMENT LEVEL-1 //
|
||||
</p>
|
||||
<h1 className="text-4xl md:text-6xl lg:text-7xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight mb-6">
|
||||
BUILD. WRITE.
|
||||
@@ -53,7 +53,7 @@ export default async function HomePage() {
|
||||
SHARE.
|
||||
</h1>
|
||||
<p className="text-base md:text-lg lg:text-xl text-slate-700 dark:text-slate-400 font-mono leading-relaxed max-w-2xl">
|
||||
> Explorează idei despre dezvoltare, design și tehnologie_
|
||||
> Explore ideas
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -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]
|
||||
</Link>
|
||||
<Link
|
||||
href="/about"
|
||||
className="px-6 md:px-8 py-3 md: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-xs md:text-sm tracking-wider hover:bg-slate-200 dark:hover:bg-slate-800 hover:border-slate-500 dark:hover:border-slate-600 rounded-none transition-colors duration-200"
|
||||
>
|
||||
[DESPRE MINE]
|
||||
[ABOUT ME]
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,7 +83,7 @@ export default async function HomePage() {
|
||||
ARCHIVE ACCESS // RECENT ENTRIES
|
||||
</p>
|
||||
<h2 className="text-3xl md:text-5xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight">
|
||||
> POSTĂRI RECENTE_
|
||||
> RECENT ENTRIES
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -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] >>
|
||||
</Link>
|
||||
)}
|
||||
<Link
|
||||
href="/tags"
|
||||
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 TAG-URILE] >>
|
||||
[SEE ALL TAGS] >>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Stats Section - from worktree-agent-1 */}
|
||||
<section className="py-24 bg-zinc-50 dark:bg-zinc-900 border-y-4 border-slate-300 dark:border-slate-800 transition-colors duration-300">
|
||||
{/* <section className="py-24 bg-zinc-50 dark:bg-zinc-900 border-y-4 border-slate-300 dark:border-slate-800 transition-colors duration-300">
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
<div className="border-l-4 border-teal-700 dark:border-teal-900 pl-6 mb-12">
|
||||
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
||||
SYSTEM STATISTICS // DATABASE METRICS
|
||||
</p>
|
||||
<h2 className="text-3xl md:text-5xl font-mono font-bold text-slate-900 dark:text-slate-100 uppercase tracking-tight">
|
||||
> METRICI_
|
||||
> METRICS
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
@@ -177,7 +177,7 @@ export default async function HomePage() {
|
||||
{allPosts.length}+
|
||||
</div>
|
||||
<p className="text-slate-600 dark:text-slate-400 font-mono text-sm uppercase tracking-wider border-t-2 border-slate-300 dark:border-slate-800 pt-4">
|
||||
ARTICOLE PUBLICATE
|
||||
PUBLISHED
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -200,10 +200,10 @@ export default async function HomePage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section> */}
|
||||
|
||||
{/* Newsletter CTA - from worktree-agent-1 */}
|
||||
<section className="py-24 bg-zinc-100 dark:bg-slate-900 border-t-4 border-slate-300 dark:border-slate-800 transition-colors duration-300">
|
||||
{/* <section className="py-24 bg-zinc-100 dark:bg-slate-900 border-t-4 border-slate-300 dark:border-slate-800 transition-colors duration-300">
|
||||
<div className="max-w-3xl mx-auto px-6">
|
||||
<div className="border-4 border-slate-300 dark:border-slate-700 bg-white dark:bg-zinc-900 p-12 transition-colors duration-300">
|
||||
<p className="font-mono text-xs text-slate-500 dark:text-slate-500 uppercase tracking-widest mb-2">
|
||||
@@ -233,7 +233,7 @@ export default async function HomePage() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section> */}
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,16 +27,15 @@ export function OptimizedImage({
|
||||
|
||||
if (hasError) {
|
||||
return (
|
||||
<div className="my-8 rounded-lg border border-zinc-800 bg-zinc-900/50 p-8 text-center">
|
||||
<p className="text-zinc-400">Failed to load image</p>
|
||||
{caption && <p className="mt-2 text-sm text-zinc-500">{caption}</p>}
|
||||
</div>
|
||||
<span className="block my-8 rounded-lg border border-zinc-800 bg-zinc-900/50 p-8 text-center">
|
||||
<span className="block text-zinc-400">Failed to load image</span>
|
||||
{caption && <span className="block mt-2 text-sm text-zinc-500">{caption}</span>}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<figure className={`my-8 ${className}`}>
|
||||
<div className="relative overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900/50">
|
||||
const imageElement = (
|
||||
<span className="block relative overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900/50">
|
||||
<Image
|
||||
src={src}
|
||||
alt={alt}
|
||||
@@ -51,14 +50,21 @@ export function OptimizedImage({
|
||||
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 && (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="h-8 w-8 animate-spin rounded-full border-2 border-emerald-500 border-t-transparent" />
|
||||
</div>
|
||||
<span className="absolute inset-0 flex items-center justify-center">
|
||||
<span className="block h-8 w-8 animate-spin rounded-full border-2 border-emerald-500 border-t-transparent" />
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</span>
|
||||
)
|
||||
|
||||
// Always use <span> to avoid invalid HTML nesting in <p> tags
|
||||
// This prevents hydration mismatches between server and client
|
||||
return (
|
||||
<span className={`block my-8 ${className}`}>
|
||||
{imageElement}
|
||||
{caption && (
|
||||
<figcaption className="mt-3 text-center text-sm text-zinc-400">{caption}</figcaption>
|
||||
<span className="block mt-3 text-center text-sm text-zinc-400">{caption}</span>
|
||||
)}
|
||||
</figure>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,17 +18,50 @@ export default function MarkdownRenderer({ content, className = '' }: MarkdownRe
|
||||
<div className={`prose prose-invert prose-zinc max-w-none ${className}`}>
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
rehypePlugins={[rehypeRaw, [rehypeSanitize, {
|
||||
tagNames: ['p', 'a', 'img', 'code', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
||||
'ul', 'ol', 'li', 'blockquote', 'table', 'thead', 'tbody', 'tr', 'th', 'td',
|
||||
'strong', 'em', 'del', 'br', 'hr', 'div', 'span'],
|
||||
rehypePlugins={[
|
||||
rehypeRaw,
|
||||
[
|
||||
rehypeSanitize,
|
||||
{
|
||||
tagNames: [
|
||||
'p',
|
||||
'a',
|
||||
'img',
|
||||
'code',
|
||||
'pre',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'ul',
|
||||
'ol',
|
||||
'li',
|
||||
'blockquote',
|
||||
'table',
|
||||
'thead',
|
||||
'tbody',
|
||||
'tr',
|
||||
'th',
|
||||
'td',
|
||||
'strong',
|
||||
'em',
|
||||
'del',
|
||||
'br',
|
||||
'hr',
|
||||
'div',
|
||||
'span',
|
||||
],
|
||||
attributes: {
|
||||
a: ['href', 'rel', 'target'],
|
||||
img: ['src', 'alt', 'title', 'width', 'height'],
|
||||
code: ['className'],
|
||||
'*': ['className', 'id']
|
||||
}
|
||||
}]]}
|
||||
'*': ['className', 'id'],
|
||||
},
|
||||
},
|
||||
],
|
||||
]}
|
||||
components={{
|
||||
img: ({ node, src, alt, title, ...props }) => {
|
||||
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 (
|
||||
<OptimizedImage
|
||||
src={cleanSrc}
|
||||
alt={altText || alt || ''}
|
||||
caption={caption}
|
||||
width={width}
|
||||
height={height}
|
||||
/>
|
||||
)
|
||||
const imageProps = {
|
||||
src: cleanSrc,
|
||||
alt: altText || alt || '',
|
||||
caption: caption,
|
||||
...(width && { width }),
|
||||
...(height && { height }),
|
||||
}
|
||||
|
||||
return <OptimizedImage {...imageProps} />
|
||||
},
|
||||
code: ({ node, className, children, ...props }) => {
|
||||
const inline = !className && typeof children === 'string' && !children.includes('\n')
|
||||
|
||||
@@ -51,6 +51,12 @@ export function Navbar() {
|
||||
className="font-mono text-sm text-zinc-400 dark:text-zinc-500 uppercase tracking-wider hover:text-cyan-400 dark:hover:text-cyan-300 transition-colors cursor-pointer"
|
||||
>
|
||||
[ABOUT]
|
||||
</Link>
|
||||
<Link
|
||||
href="/blog"
|
||||
className="font-mono text-sm text-zinc-400 dark:text-zinc-500 uppercase tracking-wider hover:text-cyan-400 dark:hover:text-cyan-300 transition-colors cursor-pointer"
|
||||
>
|
||||
[BLOG]
|
||||
</Link>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
|
||||
@@ -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 <h1>Hello, Next.js 15!</h1>
|
||||
}
|
||||
```
|
||||
|
||||
### Check out this article:
|
||||
|
||||
[Check this out](tech/articol-tehnic.md)
|
||||
|
||||
## Conclusion
|
||||
|
||||
Next.js 15 brings many improvements for building modern web applications.
|
||||
@@ -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:
|
||||
|
||||

|
||||
|
||||
## Content
|
||||
|
||||
You are reading the technical article that was linked from the example post.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 171 KiB |
@@ -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
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
41
content/blog/why-this-page.md
Normal file
41
content/blog/why-this-page.md
Normal file
@@ -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?
|
||||
|
||||

|
||||
|
||||
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.
|
||||
BIN
content/blog/whythispage/selfhostedrig.gif
Normal file
BIN
content/blog/whythispage/selfhostedrig.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 MiB |
46
lib/utils.ts
46
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 {
|
||||
|
||||
Reference in New Issue
Block a user