A Notebook as a Portfolio Service — build, preview, and export developer portfolios that look and behave exactly like Jupyter, Kaggle, or Google Colab notebooks.
NoteFolio turns the familiar notebook interface into a portfolio builder. Instead of a traditional résumé site, you compose your story in markdown and code cells — intro, skills, experience, projects, achievements, contact — then run cells to render interactive charts, timelines, and cards.
The result feels like a live notebook: execution counters, syntax-highlighted code, sidebar table of contents, and dark/light themes.
| Feature | Description |
|---|---|
| Three templates | Jupyter Notebook, Kaggle, and Google Colab aesthetics |
| Cell-based editor | Markdown intro + Python-style section cells with auto-fill snippets |
| Live preview | Full notebook preview with sidebar TOC before export |
| Rich outputs | Radar charts, experience timelines, project cards, achievement tables |
| Resume upload | Attach a PDF/Word résumé visible in preview and exports |
| Export | Download as interactive HTML (single file) or React (Vite zip) |
| Dark / light mode | Toggle in preview and in exported HTML — both themes included |
| Session persistence | Work saved in sessionStorage per template |
- Node.js 18+
- npm 9+
git clone https://github.com/your-username/notefolio.git
cd notefolio
npm install
npm run devOpen http://localhost:5173.
npm run build
npm run preview- Demo portfolio — The home page shows a sample notebook (Abhir Mirikar's portfolio).
- Build your NoteFolio — Click Build your NoteFolio 🚀 in the sidebar → choose a template.
- Compose cells — Add an Intro markdown cell, Define portfolio (JSON), then section cells (Skills, Experience, …).
- Run cells — Execute markdown and code cells; section code auto-inserts when you run matching headings.
- Preview — Use the Preview button once the portfolio object is defined.
- Export — From preview, Save as → HTML or React project.
Full walkthrough: Documentation (also at /docs in the app).
notefolio/
├── src/
│ ├── App.jsx # Main app — portfolio demo, editor, preview, routing
│ ├── DocsPage.jsx # In-app documentation (/docs)
│ ├── portfolioEngine.js # Rule engine, preview resolution, section detection
│ ├── portfolio-rules.json # Portfolio JSON schema rules
│ └── lib/
│ ├── portfolioOutputs.jsx # Chart & section output components
│ ├── portfolioExportLayout.jsx
│ ├── portfolioExportCapture.jsx
│ ├── portfolioSession.js # sessionStorage helpers
│ └── portfolioContext.js # Shared tokens & context
├── public/
├── index.html
├── package.json
└── README.md
| Template | URL prefix | Style |
|---|---|---|
| Jupyter | /create/jupyter |
Classic .ipynb — In/Out prompts, kernel bar |
| Kaggle | /create/kaggle |
Competition notebook — blue accent, right sidebar |
| Colab | /create/colab |
Google Colab — runtime connect flow, amber accent |
Preview URLs: /{template}/preview
Single .html file with embedded React bundle (via esm.sh). Includes sidebar, animations, Recharts, and a dark/light toggle. Requires internet on first open for CDN modules.
Vite project with snapshot.html and copied lib files — suitable for self-hosting or customization.
- React 18 + Vite 5
- Tailwind CSS 3
- Framer Motion — cell & chart animations
- Recharts — radar, bar, sparkline charts
- react-syntax-highlighter — code cells
- lucide-react — icons
- esbuild-wasm — single-file HTML bundling
- JSZip — React export packaging
NoteFolio includes a declarative rule engine that connects notebook code cells to portfolio data and visualizations. It lives in two files:
| File | Role |
|---|---|
src/portfolio-rules.json |
Schema, matching rules, and section templates |
src/portfolioEngine.js |
Parser, validator, matcher, and executor |
- Initialize — Parses JSON from the Define portfolio cell (
json.loads("""…""")) and stores it as the live portfolio object. - Match — When you run a code cell, regex patterns in
portfolio-rules.jsonidentify which visualization rule applies (skills radar, experience timeline, project cards, etc.). - Validate — Before rendering, required JSON fields are checked (e.g.
skillRadarmust have at least one entry withskill,proficiency,experience). - Execute — Returns a typed output (
skills,experience,projects, …) that React components inportfolioOutputs.jsxrender as charts and cards.
Section markdown headings (Skills, Experience, …) are detected separately via keywords in portfolio-rules.json → sections, which auto-inserts the matching default code snippet.
Step 1 — Define portfolio (required first)
import portfolio
import json
portfolio = json.loads("""
{
"name": "Your Name",
"skillRadar": [ { "skill": "Python", "proficiency": 90, "experience": 75 } ],
"experience": [ … ],
"projects": [ … ],
"achievements": [ … ],
"contact": { "email": "…", "linkedin": "…", "github": "…" }
}
""")Run this cell. The engine parses the JSON, validates structure, and unlocks preview/export.
Step 2 — Add section cells
Type a markdown heading and run the cell — e.g. ## Skills. NoteFolio inserts a code cell with the default snippet from sections:
skills = Portfolio.load_skills(domain="ML/AI")
skills.visualize(renderer="radar")Run the code cell. The engine matches rule skills_radar, validates skillRadar in your JSON, and renders the radar chart.
Step 3 — Swap visualizations
Change the code to match a different rule. Examples from portfolio-rules.json:
| Section | Example code | Output |
|---|---|---|
| Skills | skills.visualize(renderer="histogram") |
Bar chart |
| Skills | skills.visualize(renderer="pie") |
Pie chart |
| Experience | experience.plot_timeline() |
Timeline |
| Experience | experience.sunburst() |
Sunburst |
| Projects | projects.render_cards() |
Project cards |
| Projects | projects.render_treemap() |
Treemap |
| Achievements | achievements.head(10) |
Table + sparklines |
| Contact | Portfolio.connect(author="…") |
Contact row |
| Resume | resume = inputFile() |
Upload bar |
If validation fails, the cell output shows specific errors (e.g. Skills[0].proficiency is required).
To add a new visualization:
- Add a rule object to
portfolio-rules.json→ruleswithpatterns,action, andrequiredSections. - Implement the output component in
portfolioOutputs.jsxif theactiontype is new. - Optionally add a
sectionsentry withdefaultCodefor auto-insert.
Portfolio content is defined in a Define portfolio code cell as JSON (see PORTFOLIO_DEFINE_TEMPLATE in src/portfolioEngine.js). The rule engine validates structure against src/portfolio-rules.json.
Editor sessions are stored in sessionStorage under keys jp_editor_{template}.
The app is a static SPA. Deploy dist/ to Vercel, Netlify, or GitHub Pages.
vercel.json includes SPA rewrites so routes like /docs, /create, and /jupyter/preview work client-side.
Contributions welcome! Please open an issue or PR.
- Fork the repo
- Create a feature branch
- Commit your changes
- Open a pull request
MIT © Abhir Mirikar
Abhir Mirikar — GitHub · LinkedIn
Built with the idea that a portfolio should feel as explorable as a notebook you actually want to run.