@@ -36,9 +36,8 @@ export default function LanguageSwitcher() {
className={`
w-full text-left px-4 py-2 font-mono uppercase text-xs
border-b border-slate-700 last:border-b-0
- ${locale === loc
- ? 'bg-cyan-900 text-cyan-300'
- : 'text-slate-400 hover:bg-slate-800'
+ ${
+ locale === loc ? 'bg-cyan-900 text-cyan-300' : 'text-slate-400 hover:bg-slate-800'
}
`}
>
@@ -48,12 +47,7 @@ export default function LanguageSwitcher() {
)}
- {isOpen && (
- setIsOpen(false)}
- />
- )}
+ {isOpen &&
setIsOpen(false)} />}
- );
+ )
}
diff --git a/content/blog/en/why-this-page.md b/content/blog/en/why-this-page.md
index dc12dff..ba3fbb5 100644
--- a/content/blog/en/why-this-page.md
+++ b/content/blog/en/why-this-page.md
@@ -1,5 +1,5 @@
---
-title: 'Why I created this page'
+title: 'First post'
description: 'First post'
date: '2025-12-02'
author: 'Rares'
@@ -24,7 +24,7 @@ Well, yes, there are. But I believe that sharing some of my opinions and experie
## Why self-host?
-
+
Now, let's talk about why I chose to self-host this blog. In a nutshell, self-hosting gave me:
diff --git a/content/blog/ro/why-this-page.md b/content/blog/ro/why-this-page.md
index c040ebd..23ed5df 100644
--- a/content/blog/ro/why-this-page.md
+++ b/content/blog/ro/why-this-page.md
@@ -1,6 +1,6 @@
---
-title: 'Why I created this page'
-description: 'First post'
+title: 'Primul post'
+description: 'Primul post'
date: '2025-12-02'
author: 'Rares'
category: 'Opinion'
@@ -23,7 +23,7 @@ Dacă te gândești de ce să mai creezi inca un blog cand sunt atea pe net, pai
## De ce selfhost?
-
+
Am inceput sa fac hosting acasa din cateva motive:
diff --git a/docs/ENV_CONFIG_GUIDE.md b/docs/ENV_CONFIG_GUIDE.md
index d21b057..ebc26ea 100644
--- a/docs/ENV_CONFIG_GUIDE.md
+++ b/docs/ENV_CONFIG_GUIDE.md
@@ -5,6 +5,7 @@
This guide documents the configuration for build-time environment variables in the Next.js CI/CD pipeline.
**Problem Solved:** Next.js 16 requires `NEXT_PUBLIC_*` variables available during `npm run build` for:
+
- SEO metadata (`metadataBase`)
- Sitemap generation
- OpenGraph URLs
@@ -19,6 +20,7 @@ This guide documents the configuration for build-time environment variables in t
### 1. `.gitea/workflows/main.yml`
**Changes:**
+
- Added step to create `.env` from Gitea secrets (after checkout)
- Added cleanup step to remove `.env` after Docker push
@@ -34,7 +36,7 @@ This guide documents the configuration for build-time environment variables in t
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1
EOF
-
+
echo "✅ .env file created successfully"
echo "Preview (secrets masked):"
cat .env | sed 's/=.*/=***MASKED***/g'
@@ -44,7 +46,7 @@ This guide documents the configuration for build-time environment variables in t
- name: 🚀 Push Docker image to registry
run: |
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
-
+
# Clean up sensitive files
rm -f .env
echo "✅ Cleaned up .env file"
@@ -55,6 +57,7 @@ This guide documents the configuration for build-time environment variables in t
### 2. `Dockerfile.nextjs`
**Changes:**
+
- Added `COPY .env* ./` in builder stage (after copying node_modules, before copying source code)
**Added Section:**
@@ -73,6 +76,7 @@ COPY .env* ./
### 3. `.dockerignore`
**Changes:**
+
- Modified to allow `.env` file (created by CI/CD) while excluding other `.env*` files
**Updated Section:**
@@ -85,6 +89,7 @@ COPY .env* ./
```
**Explanation:**
+
- `.env*` excludes all environment files
- `!.env` creates exception for main `.env` (from CI/CD)
- `.env.local`, `.env.development`, `.env.production.local` remain excluded
@@ -99,11 +104,12 @@ Navigate to: **Repository Settings → Secrets**
Add the following secret:
-| Secret Name | Value | Type | Description |
-|------------|-------|------|-------------|
+| Secret Name | Value | Type | Description |
+| ---------------------- | ------------------------ | ------------------ | ------------------- |
| `NEXT_PUBLIC_SITE_URL` | `https://yourdomain.com` | Secret or Variable | Production site URL |
**Notes:**
+
- Can be configured as **Secret** (masked in logs) or **Variable** (visible in logs)
- Recommended: Use **Variable** since it's a public URL
- For sensitive values (API keys), always use **Secret**
@@ -113,12 +119,14 @@ Add the following secret:
To add more build-time variables:
1. **Add to Gitea Secrets/Variables:**
+
```
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
NEXT_PUBLIC_API_URL=https://api.example.com
```
2. **Update workflow `.env` creation step:**
+
```yaml
cat > .env << EOF
NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }}
@@ -138,6 +146,7 @@ To add more build-time variables:
### Local Testing
1. **Create test `.env` file:**
+
```bash
cat > .env << EOF
NEXT_PUBLIC_SITE_URL=http://localhost:3030
@@ -147,24 +156,27 @@ To add more build-time variables:
```
2. **Build Docker image:**
+
```bash
docker build -t mypage:test -f Dockerfile.nextjs .
```
3. **Verify variable is embedded (should show "NOT FOUND" - correct behavior):**
+
```bash
docker run --rm mypage:test node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL || 'NOT FOUND')"
```
-
+
**Expected Output:** `NOT FOUND`
-
+
**Why?** `NEXT_PUBLIC_*` variables are embedded in JavaScript bundle during build, NOT available as runtime environment variables.
4. **Test application starts:**
+
```bash
docker run --rm -p 3030:3030 mypage:test
```
-
+
Visit `http://localhost:3030` to verify.
5. **Cleanup:**
@@ -214,10 +226,10 @@ To add more build-time variables:
### 🔒 Sensitive Data Guidelines
-| Type | Use For | Access |
-|------|---------|--------|
-| `NEXT_PUBLIC_*` | Client-side config (URLs, feature flags) | Public (embedded in JS bundle) |
-| `SECRET_*` | Server-side secrets (API keys, DB passwords) | Private (runtime only) |
+| Type | Use For | Access |
+| --------------- | -------------------------------------------- | ------------------------------ |
+| `NEXT_PUBLIC_*` | Client-side config (URLs, feature flags) | Public (embedded in JS bundle) |
+| `SECRET_*` | Server-side secrets (API keys, DB passwords) | Private (runtime only) |
---
@@ -226,10 +238,12 @@ To add more build-time variables:
### Issue: Variables not available during build
**Symptoms:**
+
- Next.js build errors about missing `NEXT_PUBLIC_SITE_URL`
- Metadata/sitemap generation fails
**Solution:**
+
- Verify `NEXT_PUBLIC_SITE_URL` secret exists in Gitea
- Check workflow logs for `.env` creation step
- Ensure `.env` file is created BEFORE Docker build
@@ -237,9 +251,11 @@ To add more build-time variables:
### Issue: Variables not working in application
**Symptoms:**
+
- URLs show as `undefined` or `null` in production
**Diagnosis:**
+
```bash
# Check if variable is in bundle (should work):
curl https://yourdomain.com | grep -o 'NEXT_PUBLIC_SITE_URL'
@@ -249,6 +265,7 @@ docker exec mypage-prod node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL)"
```
**Solution:**
+
- Verify `.env` was copied during Docker build
- Check Dockerfile logs for `COPY .env* ./` step
- Rebuild with `--no-cache` if needed
@@ -256,9 +273,11 @@ docker exec mypage-prod node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL)"
### Issue: `.env` file not found during Docker build
**Symptoms:**
+
- Docker build warning: `COPY .env* ./` - no files matched
**Solution:**
+
- Check `.dockerignore` allows `.env` file
- Verify workflow creates `.env` BEFORE Docker build
- Check file exists: `ls -la .env` in workflow
@@ -289,6 +308,7 @@ After deploying changes:
## Support
For issues or questions:
+
1. Check workflow logs in Gitea Actions
2. Review Docker build logs
3. Verify Gitea secrets configuration
diff --git a/docs/OPTIMIZATION_REPORT.md b/docs/OPTIMIZATION_REPORT.md
index 0699a86..412db3a 100644
--- a/docs/OPTIMIZATION_REPORT.md
+++ b/docs/OPTIMIZATION_REPORT.md
@@ -1,4 +1,5 @@
# Production Optimizations Report
+
Date: 2025-11-24
Branch: feat/production-improvements
@@ -7,6 +8,7 @@ Branch: feat/production-improvements
Successfully implemented 7 categories of production optimizations for Next.js 16 blog application.
### Build Status: SUCCESS
+
- Build Time: ~3.9s compilation + ~1.5s static generation
- Static Pages Generated: 19 pages
- Bundle Size: 1.2MB (static assets)
@@ -17,10 +19,12 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
## 1. Bundle Size Optimization - Remove Unused Dependencies
### Actions Taken:
+
- Removed `react-syntax-highlighter` (11 packages eliminated)
- Removed `@types/react-syntax-highlighter`
### Impact:
+
- **11 packages removed** from dependency tree
- Cleaner bundle, faster npm installs
- All remaining dependencies verified as actively used
@@ -30,11 +34,13 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
## 2. Lazy Loading for Heavy Components
### Status:
+
- Attempted to implement dynamic imports for CodeBlock component
- Tool limitations prevented full implementation
- Benefit would be minimal (CodeBlock already client-side rendered)
### Recommendation:
+
- Consider manual lazy loading in future if CodeBlock becomes heavier
- Current implementation is already performant
@@ -45,16 +51,19 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Security Enhancements Applied:
**Dockerfile.nextjs:**
+
- Remove SUID/SGID binaries (prevent privilege escalation)
- Remove apk package manager after dependencies installed
- Create proper permissions for /tmp, /.next/cache, /app/logs directories
**docker-compose.prod.yml:**
+
- Added `security_opt: no-new-privileges:true`
- Added commented read-only filesystem option (optional hardening)
- Documented tmpfs mounts for extra security
### Security Posture:
+
- Minimal attack surface in production container
- Non-root user execution enforced
- Package manager unavailable at runtime
@@ -66,22 +75,26 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Files Created:
**app/sitemap.ts:**
+
- Dynamic sitemap generation from markdown posts
- Static pages included (/, /blog, /about)
- Posts include lastModified date from frontmatter
- Priority and changeFrequency configured
**app/robots.ts:**
+
- Allows all search engines
-- Disallows /api/, /_next/, /admin/
+- Disallows /api/, /\_next/, /admin/
- References sitemap.xml
**app/feed.xml/route.ts:**
+
- RSS 2.0 feed for latest 20 posts
- Includes title, description, author, pubDate
- Proper content-type and cache headers
### SEO Impact:
+
- Search engines can discover all content via sitemap
- RSS feed for blog subscribers
- Proper robots.txt prevents indexing of internal routes
@@ -93,16 +106,19 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Configuration Updates:
**Sharp:**
+
- Already installed (production-grade image optimizer)
- Faster than default Next.js image optimizer
**next.config.js - Image Settings:**
+
- Cache optimized images for 30 days (`minimumCacheTTL`)
- Support AVIF and WebP formats
- SVG rendering enabled with security CSP
- Responsive image sizes configured (640px to 3840px)
### Performance Impact:
+
- Faster image processing during builds
- Smaller image file sizes (AVIF/WebP)
- Better Core Web Vitals (LCP, CLS)
@@ -113,21 +129,25 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Cache Headers Added:
-**Static Assets (/_next/static/*):**
+**Static Assets (/\_next/static/\*):**
+
- `Cache-Control: public, max-age=31536000, immutable`
- 1 year cache for versioned assets
-**Images (/images/*):**
+**Images (/images/\*):**
+
- `Cache-Control: public, max-age=31536000, immutable`
### Experimental Features Enabled:
**next.config.js - experimental:**
+
- `staleTimes.dynamic: 30s` (client-side cache for dynamic pages)
- `staleTimes.static: 180s` (client-side cache for static pages)
- `optimizePackageImports` for react-markdown ecosystem
### Performance Impact:
+
- Reduced bandwidth usage
- Faster repeat visits (cached assets)
- Improved navigation speed (stale-while-revalidate)
@@ -137,18 +157,22 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
## 7. Bundle Analyzer Setup
### Tools Installed:
+
- `@next/bundle-analyzer` (16.0.3)
### NPM Scripts Added:
+
- `npm run analyze` - Full bundle analysis
- `npm run analyze:server` - Server bundle only
- `npm run analyze:browser` - Browser bundle only
### Configuration:
+
- `next.config.analyzer.js` created
- Enabled with `ANALYZE=true` environment variable
### Usage:
+
```bash
npm run analyze
# Opens browser with bundle visualization
@@ -160,6 +184,7 @@ npm run analyze
## Bundle Size Analysis
### Static Assets:
+
```
Total Static: 1.2MB
- Largest chunks:
@@ -170,10 +195,12 @@ Total Static: 1.2MB
```
### Standalone Output:
+
- Total: 44MB (includes Node.js runtime, dependencies, server)
- Expected Docker image size: ~150MB (Alpine + Node.js + app)
### Bundle Composition:
+
- React + React-DOM: Largest dependencies
- react-markdown ecosystem: Second largest
- Next.js framework: Optimized with tree-shaking
@@ -183,6 +210,7 @@ Total Static: 1.2MB
## Build Verification
### Build Output:
+
```
Creating an optimized production build ...
✓ Compiled successfully in 3.9s
@@ -200,6 +228,7 @@ Route (app)
```
### Pre-rendered Pages:
+
- 19 static pages generated
- 3 blog posts
- 7 tag pages
@@ -210,6 +239,7 @@ Route (app)
## Files Modified/Created
### Modified:
+
- `Dockerfile.nextjs` (security hardening)
- `docker-compose.prod.yml` (security options)
- `next.config.js` (image optimization, caching headers)
@@ -217,6 +247,7 @@ Route (app)
- `package-lock.json` (dependency updates)
### Created:
+
- `app/sitemap.ts` (dynamic sitemap)
- `app/robots.ts` (robots.txt)
- `app/feed.xml/route.ts` (RSS feed)
@@ -227,6 +258,7 @@ Route (app)
## Performance Recommendations
### Implemented:
+
1. Bundle size reduced (11 packages removed)
2. Security hardened (Docker + CSP)
3. SEO optimized (sitemap + robots + RSS)
@@ -235,7 +267,8 @@ Route (app)
6. Bundle analyzer ready for monitoring
### Future Optimizations:
-1. Consider CDN for static assets (/images, /_next/static)
+
+1. Consider CDN for static assets (/images, /\_next/static)
2. Monitor bundle sizes with `npm run analyze` on each release
3. Add bundle size limits in CI/CD (fail if > threshold)
4. Consider Edge deployment for global performance
@@ -246,6 +279,7 @@ Route (app)
## Production Deployment Checklist
Before deploying:
+
- [ ] Set `NEXT_PUBLIC_SITE_URL` in production environment
- [ ] Verify Caddy reverse proxy configuration
- [ ] Test Docker build: `npm run docker:build`
diff --git a/eslint.config.mjs b/eslint.config.mjs
index b239007..7b0e754 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -12,7 +12,7 @@ export default [
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
- { argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
+ { argsIgnorePattern: '^_|node', varsIgnorePattern: '^_' },
],
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
@@ -26,6 +26,7 @@ export default [
'dist/',
'.cache/',
'*.config.js',
+ 'next.config.analyzer.js',
'public/',
'coverage/',
],
diff --git a/fix.js b/fix.js
deleted file mode 100644
index 9bc554e..0000000
--- a/fix.js
+++ /dev/null
@@ -1,11 +0,0 @@
-const fs = require('fs')
-let content = fs.readFileSync('lib/remark-copy-images.ts', 'utf8')
-const lines = content.split('\n')
-for (let i = 0; i < lines.length; i++) {
- if (lines[i].includes('replace')) {
- console.log(`Line ${i + 1}:`, JSON.stringify(lines[i]))
- lines[i] = lines[i].replace(/replace\(\/\\/g / g, 'replace(/\\/g')
- console.log(`Fixed:`, JSON.stringify(lines[i]))
- }
-}
-fs.writeFileSync('lib/remark-copy-images.ts', lines.join('\n'))
diff --git a/lib/env-validation.ts b/lib/env-validation.ts
index 86219c2..42cd42c 100644
--- a/lib/env-validation.ts
+++ b/lib/env-validation.ts
@@ -3,16 +3,9 @@
* Ensures all required environment variables are set before deployment
*/
-const requiredEnvVars = [
- 'NEXT_PUBLIC_SITE_URL',
- 'NODE_ENV',
-] as const
+const requiredEnvVars = ['NEXT_PUBLIC_SITE_URL', 'NODE_ENV'] as const
-const optionalEnvVars = [
- 'PORT',
- 'HOSTNAME',
- 'NEXT_PUBLIC_GA_ID',
-] as const
+const _optionalEnvVars = ['PORT', 'HOSTNAME', 'NEXT_PUBLIC_GA_ID'] as const
export function validateEnvironment() {
const missingVars: string[] = []
diff --git a/lib/remark-copy-images.ts b/lib/remark-copy-images.ts
index 6fc273c..b08ea8b 100644
--- a/lib/remark-copy-images.ts
+++ b/lib/remark-copy-images.ts
@@ -85,7 +85,7 @@ async function copyAndRewritePath(node: ImageNode, options: Options): Promise
{
+export async function getRelatedTags(
+ tagSlug: string,
+ locale: string = 'en',
+ limit = 5
+): Promise {
const posts = await getPostsByTag(tagSlug, locale)
const relatedTagMap = new Map()
@@ -107,7 +111,9 @@ export function validateTags(tags: any): string[] {
return validTags
}
-export async function getTagCloud(locale: string = 'en'): Promise> {
+export async function getTagCloud(
+ locale: string = 'en'
+): Promise> {
const tags = await getAllTags(locale)
if (tags.length === 0) return []
diff --git a/messages/en.json b/messages/en.json
index af3d382..a585bd5 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -18,6 +18,21 @@
"about": "About"
},
+ "Home": {
+ "terminalVersion": "TERMINAL:// V2.0",
+ "documentLevel": "DOCUMENT LEVEL-1 //",
+ "heroTitle": "BUILD. WRITE. SHARE.",
+ "heroSubtitle": "> Explore ideas",
+ "checkPostsButton": "[CHECK POSTS]",
+ "aboutMeButton": "[ABOUT ME]",
+ "recentEntriesLabel": "ARCHIVE ACCESS // RECENT ENTRIES",
+ "recentEntriesTitle": "> RECENT ENTRIES",
+ "fileLabel": "FILE#{number} // {category}",
+ "accessButton": "[ACCESS] >>",
+ "seePostsButton": "[SEE POSTS] >>",
+ "seeAllTagsButton": "[SEE ALL TAGS] >>"
+ },
+
"BlogListing": {
"title": "Blog",
"subtitle": "Latest articles and thoughts",
@@ -29,7 +44,9 @@
"filterByTag": "Filter by tag",
"clearFilters": "Clear filters",
"foundPosts": "Found {count} posts",
- "noPosts": "No posts found"
+ "noPosts": "No posts found",
+ "prev": "< PREV",
+ "next": "NEXT >"
},
"BlogPost": {
@@ -53,7 +70,54 @@
"About": {
"title": "About",
- "subtitle": "Learn more about me"
+ "subtitle": "Learn more about me",
+ "classificationHeader": ">> _DOC://PUBLIC_ACCESS",
+ "mainTitle": "ABOUT ME_",
+ "introLabel": "STATUS: ACTIVE // ROLE: DAD + DEV",
+ "introParagraph1": "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.",
+ "lifeValuesTitle": "> LIFE & VALUES",
+ "familyFirstTitle": "[FAMILY FIRST]",
+ "familyFirstText": "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.",
+ "activeLifestyleTitle": "[ACTIVE LIFESTYLE]",
+ "activeLifestyleText": "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.",
+ "simpleThingsTitle": "[ENJOYING THE SIMPLE THINGS]",
+ "simpleThingsText": "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.",
+ "techPurposeTitle": "[TECH WITH PURPOSE]",
+ "techPurposeText": "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.",
+ "contentTitle": "> WHAT YOU'LL FIND HERE",
+ "contentSubtitle": "CONTENT SCOPE // EVERYTHING FROM TECH TO LIFE",
+ "contentThoughts": "Thoughts & Opinions",
+ "contentThoughtsDesc": "My take on life, work, and everything in between",
+ "contentLifeFamily": "Life & Family",
+ "contentLifeFamilyDesc": "Adventures in parenting, sports, and enjoying the simple things",
+ "contentTechResearch": "Tech Research",
+ "contentTechResearchDesc": "When I dive into interesting technologies and experiments",
+ "contentSysAdmin": "System Administration",
+ "contentSysAdminDesc": "Self-hosting, infrastructure, and DevOps adventures",
+ "contentDevelopment": "Development Insights",
+ "contentDevelopmentDesc": "Lessons learned from building software",
+ "contentRandom": "Random Stuff",
+ "contentRandomDesc": "Because life doesn't fit into neat categories!",
+ "focusTitle": "> AREAS OF FOCUS",
+ "focusBeingDadTitle": "[BEING A DAD]",
+ "focusBeingDadText": "Playing with my boy, teaching moments, watching him grow, building memories together",
+ "focusStayingActiveTitle": "[STAYING ACTIVE]",
+ "focusStayingActiveText": "Gym sessions, sports, keeping fit, maintaining energy for life's demands",
+ "focusTechnologyTitle": "[TECHNOLOGY & SYSTEMS]",
+ "focusTechnologyText": "Software development, infrastructure, DevOps, self-hosting adventures",
+ "focusLifeBalanceTitle": "[LIFE BALANCE]",
+ "focusLifeBalanceText": "Relaxing with good company, enjoying downtime, appreciating the simple moments",
+ "techStackTitle": "> TECH STACK",
+ "techStackSubtitle": "TOOLS I USE // WHEN NEEDED",
+ "techStackDevelopmentTitle": "[DEVELOPMENT]",
+ "techStackDevelopmentText": ".NET, Golang, TypeScript, Next.js, React",
+ "techStackInfrastructureTitle": "[INFRASTRUCTURE]",
+ "techStackInfrastructureText": "Windows Server, Linux, Docker, Hyper-V",
+ "techStackDesignTitle": "[DESIGN]",
+ "techStackDesignText": "Tailwind CSS, Markdown, Terminal aesthetics",
+ "techStackSelfHostingTitle": "[SELF-HOSTING]",
+ "techStackSelfHostingText": "Home lab, privacy-focused services, full control, Git server",
+ "contactTitle": "> CONTACT"
},
"NotFound": {
diff --git a/messages/ro.json b/messages/ro.json
index d0077f2..5f7f57a 100644
--- a/messages/ro.json
+++ b/messages/ro.json
@@ -3,21 +3,32 @@
"siteTitle": "Blog Personal",
"siteDescription": "Gânduri despre tehnologie și dezvoltare"
},
-
"Navigation": {
"home": "Acasă",
"blog": "Blog",
"tags": "Etichete",
"about": "Despre"
},
-
"Breadcrumbs": {
"home": "Acasă",
"blog": "Blog",
"tags": "Etichete",
"about": "Despre"
},
-
+ "Home": {
+ "terminalVersion": "TERMINAL:// V2.0",
+ "documentLevel": "DOCUMENT LEVEL-1 //",
+ "heroTitle": "BUILD. WRITE. SHARE.",
+ "heroSubtitle": "> Explore ideas",
+ "checkPostsButton": "[CHECK POSTS]",
+ "aboutMeButton": "[ABOUT ME]",
+ "recentEntriesLabel": "ARCHIVE ACCESS // RECENT ENTRIES",
+ "recentEntriesTitle": "> RECENT ENTRIES",
+ "fileLabel": "FILE#{number} // {category}",
+ "accessButton": "[ACCESS] >>",
+ "seePostsButton": "[SEE POSTS] >>",
+ "seeAllTagsButton": "[SEE ALL TAGS] >>"
+ },
"BlogListing": {
"title": "Blog",
"subtitle": "Ultimele articole și gânduri",
@@ -29,9 +40,10 @@
"filterByTag": "Filtrează după etichetă",
"clearFilters": "Șterge filtrele",
"foundPosts": "{count} articole găsite",
- "noPosts": "Niciun articol găsit"
+ "noPosts": "Niciun articol găsit",
+ "prev": "< PREV",
+ "next": "NEXT >"
},
-
"BlogPost": {
"readMore": "Citește mai mult",
"readingTime": "{minutes} min citire",
@@ -41,7 +53,6 @@
"relatedPosts": "Articole similare",
"sharePost": "Distribuie acest articol"
},
-
"Tags": {
"title": "Etichete",
"subtitle": "Navighează după subiect",
@@ -50,18 +61,62 @@
"relatedTags": "Etichete similare",
"quickNav": "Navigare rapidă"
},
-
"About": {
"title": "Despre",
- "subtitle": "Află mai multe despre mine"
+ "subtitle": "Află mai multe despre mine",
+ "classificationHeader": ">> _DOC://PUBLIC_ACCESS",
+ "mainTitle": "DESPRE_",
+ "introLabel": "STATUS: ACTIV // ROL: TATĂ + DEV",
+ "introParagraph1": "Mi-am făcut un colțișor pe internet unde pot să împărtășesc cam tot ce vreau. O să găsești aici și tech, și viață, și haosul de zi cu zi.",
+ "lifeValuesTitle": "> VIAȚĂ & VALORI",
+ "familyFirstTitle": "[FAMILIA PE PRIMUL LOC]",
+ "familyFirstText": "Să fiu tată pentru un puști genial e cel mai important rol al meu. Timpul cu familia e sfânt – fie că construim turnuri din cuburi, explorăm parcuri sau doar trăim frumos haosul de zi cu zi. Tech-ul poate să aștepte, momentele astea nu.",
+ "activeLifestyleTitle": "[STIL DE VIAȚĂ ACTIV]",
+ "activeLifestyleText": "Încerc să-mi țin corpul în mișcare. Sală, sport, orice mă scoate din scaun. Mă ajută să fiu mai clar la minte, mai echilibrat și pregătit de ce aruncă viața în mine.",
+ "simpleThingsTitle": "[BUCURIA LUCRURILOR SIMPLE]",
+ "simpleThingsText": "Viața e prea scurtă să n-o savurezi. O băutură bună, o seară liniștită după o zi grea sau pur și simplu să nu faci nimic și să lași aburii să iasă… și e perfect așa.",
+ "techPurposeTitle": "[TECH CU SENS]",
+ "techPurposeText": "Da, îmi place tehnologia – self-hosting, privacy, joacă cu hardware. Dar pentru mine e o unealtă, nu un stil de viață. Tech-ul ar trebui să lucreze pentru tine, nu tu pentru el.",
+ "contentTitle": "> CE GĂSEȘTI AICI",
+ "contentSubtitle": "CONTENT SCOPE // DE LA TECH LA VIAȚĂ",
+ "contentThoughts": "Gânduri & Opinii",
+ "contentThoughtsDesc": "Cum văd eu viața, munca și tot ce e între ele",
+ "contentLifeFamily": "Viață & Familie",
+ "contentLifeFamilyDesc": "Aventuri de părinte, sport și bucuria lucrurilor mici",
+ "contentTechResearch": "Experimente Tech",
+ "contentTechResearchDesc": "Când mă afund în tehnologii interesante și experimente ciudate",
+ "contentSysAdmin": "Administrare Sisteme",
+ "contentSysAdminDesc": "Self-hosting, infrastructură și aventuri de tip DevOps",
+ "contentDevelopment": "Development Insights",
+ "contentDevelopmentDesc": "Lecții învățate din proiectele pe care le construiesc",
+ "contentRandom": "Chestii Random",
+ "contentRandomDesc": "Pentru că viața nu intră mereu frumos pe categorii!",
+ "focusTitle": "> ZONE DE FOCUS",
+ "focusBeingDadTitle": "[TATĂ ÎN PRIMUL RÂND]",
+ "focusBeingDadText": "Joacă cu băiatul meu, momente de învățat, să-l văd cum crește și să strângem amintiri împreună",
+ "focusStayingActiveTitle": "[SĂ RĂMÂN ACTIV]",
+ "focusStayingActiveText": "Sesiuni la sală, sport, să mă țin în formă și cu energie pentru tot ce am de dus",
+ "focusTechnologyTitle": "[TECH & SISTEME]",
+ "focusTechnologyText": "Dezvoltare software, infrastructură, DevOps, aventuri de self-hosting",
+ "focusLifeBalanceTitle": "[ECHILIBRU ÎN VIAȚĂ]",
+ "focusLifeBalanceText": "Relax cu prietenii, timp de respiro, apreciat momentele simple",
+ "techStackTitle": "> TECH STACK",
+ "techStackSubtitle": "UNELTELE PE CARE LE FOLOSESC // CÂND TREBUIE",
+ "techStackDevelopmentTitle": "[DEVELOPMENT]",
+ "techStackDevelopmentText": ".NET, Golang, TypeScript, Next.js, React",
+ "techStackInfrastructureTitle": "[INFRASTRUCTURĂ]",
+ "techStackInfrastructureText": "Windows Server, Linux, Docker, Hyper-V",
+ "techStackDesignTitle": "[DESIGN]",
+ "techStackDesignText": "Tailwind CSS, Markdown",
+ "techStackSelfHostingTitle": "[SELF-HOSTING]",
+ "techStackSelfHostingText": "Home lab, servicii cu focus pe privacy, control total, server Git",
+ "contactTitle": "> CONTACT"
},
-
"NotFound": {
"title": "Pagina nu a fost găsită",
"description": "Pagina pe care o cauți nu există",
"goHome": "Mergi la pagina principală"
},
-
"LanguageSwitcher": {
"switchLanguage": "Schimbă limba",
"currentLanguage": "Limba curentă"
diff --git a/middleware.ts b/middleware.ts
index 5d0d195..6ed5c63 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -1,5 +1,5 @@
-import createMiddleware from 'next-intl/middleware';
-import {routing} from './src/i18n/routing';
+import createMiddleware from 'next-intl/middleware'
+import { routing } from './src/i18n/routing'
export default createMiddleware({
...routing,
@@ -7,14 +7,10 @@ export default createMiddleware({
localeCookie: {
name: 'NEXT_LOCALE',
maxAge: 60 * 60 * 24 * 365,
- sameSite: 'lax'
- }
-});
+ sameSite: 'lax',
+ },
+})
export const config = {
- matcher: [
- '/',
- '/(en|ro)/:path*',
- '/((?!api|_next|_vercel|.*\\..*).*)'
- ]
-};
+ matcher: ['/', '/(en|ro)/:path*', '/((?!api|_next|_vercel|.*\\..*).*)'],
+}
diff --git a/next-env.d.ts b/next-env.d.ts
index c4b7818..9edff1c 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/dev/types/routes.d.ts";
+import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/next.config.js b/next.config.js
index 492484c..28f0760 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,4 +1,4 @@
-const withNextIntl = require('next-intl/plugin')();
+const withNextIntl = require('next-intl/plugin')()
/** @type {import('next').NextConfig} */
// ============================================
@@ -8,7 +8,6 @@ const withNextIntl = require('next-intl/plugin')();
// Deprecated options have been removed (swcMinify, reactStrictMode)
// SWC minification is now default in Next.js 16
-
// Production-ready Next.js configuration with standalone output
// This configuration is optimized for Docker deployment with minimal image size
//
@@ -123,12 +122,7 @@ const nextConfig = {
},
// Optimize package imports for smaller bundles
- optimizePackageImports: [
- 'react-markdown',
- 'rehype-raw',
- 'rehype-sanitize',
- 'remark-gfm',
- ],
+ optimizePackageImports: ['react-markdown', 'rehype-raw', 'rehype-sanitize', 'remark-gfm'],
// Enable PPR (Partial Prerendering) - Next.js 16 feature
// Uncomment to enable (currently in beta)
diff --git a/src/i18n/navigation.ts b/src/i18n/navigation.ts
index 8f5a5e2..a045d71 100644
--- a/src/i18n/navigation.ts
+++ b/src/i18n/navigation.ts
@@ -1,5 +1,4 @@
-import {createNavigation} from 'next-intl/navigation';
-import {routing} from './routing';
+import { createNavigation } from 'next-intl/navigation'
+import { routing } from './routing'
-export const {Link, redirect, usePathname, useRouter} =
- createNavigation(routing);
+export const { Link, redirect, usePathname, useRouter } = createNavigation(routing)
diff --git a/src/i18n/request.ts b/src/i18n/request.ts
index d00e5cb..0d5af21 100644
--- a/src/i18n/request.ts
+++ b/src/i18n/request.ts
@@ -1,15 +1,15 @@
-import {getRequestConfig} from 'next-intl/server';
-import {routing} from './routing';
-
-export default getRequestConfig(async ({requestLocale}) => {
- let locale = await requestLocale;
-
+import { getRequestConfig } from 'next-intl/server'
+import { routing } from './routing'
+
+export default getRequestConfig(async ({ requestLocale }) => {
+ let locale = await requestLocale
+
if (!locale || !routing.locales.includes(locale as any)) {
- locale = routing.defaultLocale;
+ locale = routing.defaultLocale
}
-
+
return {
locale,
- messages: (await import(`../../messages/${locale}.json`)).default
- };
-});
+ messages: (await import(`../../messages/${locale}.json`)).default,
+ }
+})
diff --git a/src/i18n/routing.ts b/src/i18n/routing.ts
index 9d21ecb..1b94c0a 100644
--- a/src/i18n/routing.ts
+++ b/src/i18n/routing.ts
@@ -1,4 +1,4 @@
-import {defineRouting} from 'next-intl/routing';
+import { defineRouting } from 'next-intl/routing'
export const routing = defineRouting({
locales: ['en', 'ro'],
@@ -6,8 +6,8 @@ export const routing = defineRouting({
localePrefix: 'always',
localeNames: {
en: 'English',
- ro: 'Română'
- }
-} as any);
+ ro: 'Română',
+ },
+} as any)
-export type Locale = (typeof routing.locales)[number];
+export type Locale = (typeof routing.locales)[number]
diff --git a/tsconfig.json b/tsconfig.json
index 3900e3a..4441b4c 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,11 +1,7 @@
{
"compilerOptions": {
"target": "ES2020",
- "lib": [
- "dom",
- "dom.iterable",
- "esnext"
- ],
+ "lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -23,12 +19,8 @@
}
],
"paths": {
- "@/*": [
- "./*"
- ],
- "@/i18n/*": [
- "./src/i18n/*"
- ]
+ "@/*": ["./*"],
+ "@/i18n/*": ["./src/i18n/*"]
}
},
"include": [
@@ -38,7 +30,5 @@
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
- "exclude": [
- "node_modules"
- ]
-}
\ No newline at end of file
+ "exclude": ["node_modules"]
+}
diff --git a/types/translations.d.ts b/types/translations.d.ts
index fc4e94f..277982e 100644
--- a/types/translations.d.ts
+++ b/types/translations.d.ts
@@ -1,5 +1,6 @@
-type Messages = typeof import('../messages/en.json');
+type Messages = typeof import('../messages/en.json')
declare global {
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
interface IntlMessages extends Messages {}
}