Magic Portfolio is a simple, clean, beginner-friendly portfolio template. It supports an MDX-based content system for projects and blog posts, an about / CV page and a gallery.
View the demo here.
1. Clone the repository
git clone https://github.com/once-ui-system/magic-portfolio.git
2. Install dependencies
npm install
3. Run dev server
npm run dev
4. Edit config
src/resources/once-ui.config.js
5. Edit content
src/resources/content.js
6. Create blog posts / projects
Add a new .mdx file to src/app/blog/posts or src/app/work/projects
Magic Portfolio was built with Once UI for Next.js. It requires Node.js v18.17+.
Magic Portfolio uses the Next.js App Router. Each route maps to a folder inside src/app/, and the page displayed for that route is defined by the page.tsx file in the folder.
src/app/
├── layout.tsx # Root layout (header, footer, route guard, global styles)
├── page.tsx # Home page (/)
├── not-found.tsx # 404 page
├── about/
│ └── page.tsx # /about
├── work/
│ ├── page.tsx # /work (project listing)
│ ├── [slug]/
│ │ └── page.tsx # /work/:slug (individual project)
│ └── projects/ # MDX files for project content
├── blog/
│ ├── page.tsx # /blog (blog listing)
│ ├── [slug]/
│ │ └── page.tsx # /blog/:slug (individual blog post)
│ └── posts/ # MDX files for blog post content
├── gallery/
│ └── page.tsx # /gallery
├── robots.ts # robots.txt generation
├── sitemap.ts # sitemap.xml generation
└── api/ # API routes (authentication, RSS, OG images)
Routes are enabled or disabled in src/resources/once-ui.config.ts through the routes object:
const routes: RoutesConfig = {
"/": true,
"/about": true,
"/work": true,
"/blog": true,
"/gallery": true,
};Setting a route to false hides it from the navigation header and renders a 404 when visited. The RouteGuard component in src/components/RouteGuard.tsx enforces this at runtime.
Individual routes can be password-protected via the protectedRoutes object in the same config file. The password is set through an environment variable (see .env.example). Authentication is handled by the /api/authenticate and /api/check-auth API routes.
Blog posts and work projects use dynamic segments ([slug]). Each MDX file placed in src/app/blog/posts/ or src/app/work/projects/ automatically becomes a page. The slug is derived from the MDX filename, and generateStaticParams() in each dynamic page file pre-renders all slugs at build time.
Page content—titles, descriptions, bios, social links, and more—is centralized in src/resources/content.tsx. Every page imports from this file, so most text changes only require editing a single place.
Docs available at: docs.once-ui.com
- All tokens, components & features of Once UI
- Automatic open-graph and X image generation with next/og
- Automatic schema and metadata generation based on the content file
- Responsive layout optimized for all screen sizes
- Timeless design without heavy animations and motion
- Endless customization options through data attributes
- Render sections conditionally based on the content file
- Enable or disable pages for blog, work, gallery and about / CV
- Generate and display social links automatically
- Set up password protection for URLs
- A localized, earlier version of Magic Portfolio is available with the next-intl library
- To use localization, switch to the 'i18n' branch
Lorant One: Threads / LinkedIn
- Join the Design Engineers Club on Discord and share your project with us!
- Deployed your docs? Share it on the Once UI Hub too! We feature our favorite apps on our landing page.
Distributed under the CC BY-NC 4.0 License.
- Attribution is required.
- Commercial usage is not allowed.
- You can extend the license to Dopler CC by purchasing a Once UI Pro license.
See LICENSE.txt for more information.
