Inspiration

As developers, we all need portfolios—but most are static HTML sites that require code changes for every content update. Want to add a new project? Edit HTML. Update your bio? Modify JSX. Fix a typo? Redeploy.

I wanted a solution that combines the speed of static sites with the flexibility of a CMS—without the overhead of a backend, database, or admin authentication. DynamicFolio CMS was born from this need: a fully dynamic portfolio that stores data in localStorage, making it perfect for single-user portfolios that need frequent updates.

The DevOne Hack theme ("Build Your Developer Portfolio") was the perfect catalyst to turn this idea into reality.

What it does

DynamicFolio CMS is a Next.js 16 portfolio website with a built-in admin dashboard that lets you:

✅ **Manage all content** (Hero, About, Projects, Skills, Blog, Resume, Testimonials) through an intuitive UI
✅ **Integrate real Medium blog posts** via RSS feeds (auto-fetches on page load)
✅ **Support 6 languages** (English, Spanish, French, Chinese, Arabic, Bengali) with RTL for Arabic
✅ **Generate print-optimized PDF resumes** with one click
✅ **Drag-and-drop reorder** projects, skills, and experiences
✅ **Preview changes in real-time** without page reloads
✅ **Store all data in localStorage**—no backend, no database, no authentication needed

The admin dashboard (/admin) provides a complete CMS experience with form validation, toast notifications, and persistent state management using Zustand.

How we built it

Tech Stack:

  • Next.js 16 (App Router + Turbopack) for ultra-fast builds
  • TypeScript 5.0 in strict mode for type safety
  • Zustand with localStorage persistence for state management
  • Tailwind CSS + Shadcn UI for beautiful, accessible components
  • Framer Motion for smooth animations
  • rss-parser for Medium RSS integration
  • @hello-pangea/dnd for drag-and-drop functionality

Architecture:

  • Server-first design: Default to Server Components, use "use client" only when needed
  • Co-located features: Each route has _components/, _hooks/, _services/ subfolders
  • Modular stores: Separate Zustand stores for hero, about, projects, skills, blog, resume, testimonials
  • Custom i18n system: Context-based translations with 600+ keys across 6 languages
  • Print optimization: Dedicated /resume/print route with inline CSS for PDF export

Key Technical Decisions:

  1. No Backend: localStorage persistence removes need for database, hosting, authentication
  2. Server-side RSS: Solved CORS issues by creating /api/blog/fetch-medium API route
  3. Auto-fetch logic: Blog page detects placeholder text and automatically refreshes Medium posts
  4. Hydration pattern: Custom useHydration() hook prevents SSR/client mismatches

Challenges we ran into

1. CORS Issues with Medium RSS

  • Problem: Direct fetch from Medium RSS failed due to CORS policy
  • Solution: Created server-side API route (/api/blog/fetch-medium) to proxy requests
  • Learning: Server-side fetching avoids browser CORS restrictions

2. SSR/Client Hydration Mismatches

  • Problem: Zustand loads localStorage data on client, causing "Hydration failed" errors
  • Solution: Built useHydration() hook that waits for client hydration before rendering
  • Learning: Always check if data is hydrated before accessing stores in Server Components

3. Auto-Fetch for External Blog Posts

  • Problem: Blog page showed placeholder until manual "Refresh Feeds" click
  • Solution: Added smart detection in use-blog-data.ts hook to auto-fetch on mount
  • Learning: Detect existing data to avoid unnecessary API calls

4. RTL Layout for Arabic

  • Problem: Arabic text broke layout, icons mirrored incorrectly
  • Solution: Used dir attribute from i18n context + Tailwind rtl: modifier
  • Learning: RTL support requires both HTML dir attribute and CSS logical properties

5. Print-Optimized Resume

  • Problem: Browser print dialog included navigation, footers, and broke pagination
  • Solution: Created dedicated /resume/print route with inline CSS and print-specific styles
  • Learning: Inline styles ensure consistent rendering across browsers

Accomplishments that we're proud of

✅ Built a **full-featured CMS without a single line of backend code**
✅ Integrated **real Medium RSS feeds** with automatic excerpt extraction from HTML
✅ Implemented **6-language support** including RTL (Arabic) with 600+ translation keys
✅ Achieved **0 TypeScript errors** in strict mode across 23 production routes
✅ Designed **intuitive drag-and-drop admin interface** with real-time preview
✅ Created **print-optimized resume route** that generates pixel-perfect PDFs
✅ Maintained **server-first architecture** with minimal client-side JavaScript
✅ Completed entire project from idea to deployment in hackathon timeline

What we learned

Technical Skills:

  • Next.js 16 App Router: Mastered server components, streaming, and route groups
  • State Management: Built complex Zustand stores with localStorage persistence
  • RSS Parsing: Learned XML parsing, HTML extraction, and graceful error handling
  • SSR Patterns: Solved hydration issues with custom hooks and client/server boundaries
  • Internationalization: Designed scalable i18n system supporting RTL languages
  • Performance: Implemented lazy loading, Suspense boundaries, and React Compiler optimizations

Product Design:

  • Importance of intuitive UX: Admin dashboard must be as simple as editing a Google Doc
  • Progressive disclosure: Show only what's needed; hide complexity behind smart defaults
  • Real-time feedback: Toast notifications and instant preview prevent user confusion

Engineering Process:

  • Start with Server Components by default, add "use client" only when needed
  • Co-locate features for maintainability (avoid giant /components folder)
  • Use barrel exports (index.ts) for clean imports
  • Separate data, types, and logic for loose coupling

What's next for DynamicFolio CMS

Short-term (Post-Hackathon):

  • Analytics dashboard to track portfolio views, project clicks, blog engagement
  • Contact form integration with SendGrid/Resend for email notifications
  • Image upload via Cloudinary/Uploadcare (currently uses static URLs)

Mid-term (1-3 months):

  • Export/import data as JSON for backup and migration
  • Theme customization: color picker for brand personalization
  • SEO enhancements: Open Graph images, structured data, dynamic sitemaps

Long-term (3+ months):

  • Optional Supabase backend for multi-user scenarios
  • PWA support with offline-first service workers
  • AI-powered content suggestions (e.g., "Improve your project descriptions")
  • Template marketplace: Share portfolio designs with community

Vision: Make DynamicFolio CMS the go-to solution for developers who want a professional portfolio without the complexity of WordPress or headless CMS platforms. Think "Notion for developer portfolios."

Built With

  • framer-motion
  • nextjs
  • rss-parser
  • shadcn-ui
  • typescript
  • zustand
Share this project:

Updates