We will be undergoing planned maintenance on January 16th, 2026 at 1:00pm UTC. Please make sure to save your work.

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