diff --git a/modules/blox/layouts/events/page.html b/modules/blox/layouts/events/page.html
index ad177eec..4a5818be 100644
--- a/modules/blox/layouts/events/page.html
+++ b/modules/blox/layouts/events/page.html
@@ -282,7 +282,20 @@
{{end}}
{{/* Process featured image using utility with placement-specific constraints */}}
- {{ if ne $featured.MediaType.SubType "gif" }}
+ {{ if strings.Contains $featured.MediaType.SubType "svg" }}
+ {{/* SVGs cannot be processed by Hugo (Fit/Fill). Render directly. */}}
+
+
+

+ {{ with $image_params.caption }}
{{ . | markdownify | emojify }}{{ end }}
+
+
+ {{ else if ne $featured.MediaType.SubType "gif" }}
{{/* Pre-fit image to placement constraints, then apply responsive processing */}}
{{ $fitted_image := $featured }}
{{ if eq $placement 2}}
diff --git a/modules/blox/layouts/single.html b/modules/blox/layouts/single.html
index d317e5a5..fab49d43 100644
--- a/modules/blox/layouts/single.html
+++ b/modules/blox/layouts/single.html
@@ -179,7 +179,19 @@
{{end}}
{{/* Process featured image using utility with placement-specific constraints */}}
- {{ if ne $featured.MediaType.SubType "gif" }}
+ {{ if strings.Contains $featured.MediaType.SubType "svg" }}
+ {{/* SVGs cannot be processed by Hugo (Fit/Fill). Render directly. */}}
+
+
+

+ {{ with $image_params.caption }}
{{ . | markdownify | emojify }}{{ end }}
+
+
+ {{ else if ne $featured.MediaType.SubType "gif" }}
{{/* Pre-fit image to placement constraints, then apply responsive processing */}}
{{ $fitted_image := $featured }}
{{ if eq $placement 2}}
diff --git a/templates/dev-portfolio/.devcontainer/devcontainer.json b/templates/dev-portfolio/.devcontainer/devcontainer.json
new file mode 100644
index 00000000..cba4ea48
--- /dev/null
+++ b/templates/dev-portfolio/.devcontainer/devcontainer.json
@@ -0,0 +1,25 @@
+{
+ "name": "HugoBlox Codespace",
+ "image": "ghcr.io/HugoBlox/hugo-blox-dev:hugo0.154.2",
+ "updateContentCommand": "pnpm install --frozen-lockfile --prefer-offline",
+ "postCreateCommand": "pnpm --version && hugo version",
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "hugoblox.hugoblox-studio"
+ ]
+ }
+ },
+ "mounts": [
+ "source=pnpm-store,target=/home/vscode/.local/share/pnpm,type=volume"
+ ],
+ "remoteUser": "vscode",
+ "forwardPorts": [
+ 1313
+ ],
+ "portsAttributes": {
+ "1313": {
+ "label": "Hugo Server"
+ }
+ }
+}
diff --git a/templates/dev-portfolio/.github/FUNDING.yml b/templates/dev-portfolio/.github/FUNDING.yml
new file mode 100644
index 00000000..2ed14d29
--- /dev/null
+++ b/templates/dev-portfolio/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+github: gcushen
+custom: https://hugoblox.com/sponsor/
diff --git a/templates/dev-portfolio/.github/preview.png b/templates/dev-portfolio/.github/preview.png
new file mode 100644
index 00000000..36a29e9f
Binary files /dev/null and b/templates/dev-portfolio/.github/preview.png differ
diff --git a/templates/dev-portfolio/.github/workflows/deploy.yml b/templates/dev-portfolio/.github/workflows/deploy.yml
new file mode 100644
index 00000000..fc593765
--- /dev/null
+++ b/templates/dev-portfolio/.github/workflows/deploy.yml
@@ -0,0 +1,125 @@
+name: Deploy website to GitHub Pages
+
+env:
+ NODE_VERSION: '20'
+
+on:
+ # Trigger the workflow every time you push to the `main` branch
+ push:
+ branches: ['main']
+ # Allows you to run this workflow manually from the Actions tab on GitHub
+ workflow_dispatch:
+
+# Provide permission to clone the repo and deploy it to GitHub Pages
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: 'pages'
+ cancel-in-progress: false
+
+jobs:
+ # Build website
+ build:
+ if: github.repository_owner != 'HugoBlox'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ # Fetch history for Hugo's .GitInfo and .Lastmod
+ fetch-depth: 0
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ env.NODE_VERSION }}
+
+ - name: Setup pnpm
+ if: hashFiles('package.json') != ''
+ uses: pnpm/action-setup@v4
+
+ - name: Get Hugo Version
+ id: hugo-version
+ run: |
+ VERSION=$(grep "hugo_version" hugoblox.yaml | awk '{print $2}' | tr -d "'\"")
+ echo "HUGO_VERSION=$VERSION" >> $GITHUB_ENV
+
+ - name: Install dependencies
+ run: |
+ # Install Tailwind CLI if package.json exists
+ if [ -f "package.json" ]; then
+ echo "Installing Tailwind dependencies..."
+ pnpm install --no-frozen-lockfile || npm install
+ fi
+
+ - name: Setup Hugo
+ uses: peaceiris/actions-hugo@v3
+ with:
+ hugo-version: ${{ env.HUGO_VERSION }}
+ extended: true
+
+ # Cache dependencies (Go modules, node_modules) - stable, rarely changes
+ - uses: actions/cache@v4
+ with:
+ path: |
+ /tmp/hugo_cache_runner/
+ node_modules/
+ modules/*/node_modules/
+ key: ${{ runner.os }}-hugo-deps-${{ hashFiles('**/go.mod', '**/package-lock.json',
+ '**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-hugo-deps-
+
+ # Cache Hugo resources (processed images, CSS) - invalidates only when assets/config change
+ - uses: actions/cache@v4
+ with:
+ path: resources/
+ key: ${{ runner.os }}-hugo-resources-${{ hashFiles('assets/**/*', 'config/**/*',
+ 'hugo.yaml', 'package.json') }}
+ restore-keys: |
+ ${{ runner.os }}-hugo-resources-
+
+ - name: Setup Pages
+ id: pages
+ uses: actions/configure-pages@v5
+
+ - name: Build with Hugo
+ env:
+ HUGO_ENVIRONMENT: production
+ HUGO_BLOX_LICENSE: ${{ secrets.HUGO_BLOX_LICENSE }}
+ run: |
+ echo "Hugo Cache Dir: $(hugo config | grep cachedir)"
+ hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/"
+
+ - name: Generate Pagefind search index (if applicable)
+ run: |
+ # Check if site uses Pagefind search
+ if [ -f "package.json" ] && grep -q "pagefind" package.json; then
+ pnpm run pagefind || npx pagefind --site "public"
+ fi
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v4
+ with:
+ path: ./public
+
+ # Deploy website to GitHub Pages hosting
+ deploy:
+ if: github.repository_owner != 'HugoBlox'
+ needs: build
+ # Grant GITHUB_TOKEN the permissions required to make a Pages deployment
+ permissions:
+ pages: write # to deploy to Pages
+ id-token: write # to verify the deployment originates from an appropriate source
+ # Deploy to the github-pages environment
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/templates/dev-portfolio/.gitignore b/templates/dev-portfolio/.gitignore
new file mode 100644
index 00000000..5c572926
--- /dev/null
+++ b/templates/dev-portfolio/.gitignore
@@ -0,0 +1,69 @@
+# ============================================================================
+# Hugo Site .gitignore
+# ============================================================================
+
+# ============================================================================
+# Hugo Build Artifacts
+# ============================================================================
+
+# Generated site output
+public/
+
+# Hugo resources (processed assets)
+resources/
+
+# Hugo build lock
+.hugo_build.lock
+
+# Hugo stats
+hugo_stats.json
+
+# Auto-generated JS config
+**/assets/jsconfig.json
+
+# ============================================================================
+# Node.js & Package Managers
+# ============================================================================
+
+# Dependencies
+node_modules/
+
+# ============================================================================
+# Environment & Configuration
+# ============================================================================
+
+# Environment variables
+.env
+.env.local
+.env.*.local
+
+# ============================================================================
+# Generated Content
+# ============================================================================
+
+# Pagefind search index
+pagefind/
+static/pagefind/
+
+# ============================================================================
+# Operating System
+# ============================================================================
+
+# macOS
+.DS_Store
+.DS_Store?
+._*
+
+# Windows
+Thumbs.db
+Desktop.ini
+
+# Linux
+*~
+
+# ============================================================================
+# Logs & Temporary Files
+# ============================================================================
+
+*.log
+npm-debug.log*
diff --git a/templates/dev-portfolio/LICENSE.md b/templates/dev-portfolio/LICENSE.md
new file mode 100644
index 00000000..9da70cd3
--- /dev/null
+++ b/templates/dev-portfolio/LICENSE.md
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023-present George Cushen (https://neuralgeo.com/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/templates/dev-portfolio/README.md b/templates/dev-portfolio/README.md
new file mode 100644
index 00000000..3d5d6896
--- /dev/null
+++ b/templates/dev-portfolio/README.md
@@ -0,0 +1,124 @@
+# [Developer Portfolio (Free)](https://hugoblox.com/templates/dev-portfolio/start?utm_source=github&utm_medium=readme)
+
+[](https://hugoblox.com/templates/dev-portfolio/start?utm_source=github&utm_medium=readme)
+
+
The Dev Portfolio That Gets You Hired
+
+
+ Built for uni students, STEM grads, and software engineers.
+ Showcase real projects, ship a clean blog, and stand out with a modern dark-first design — without a fragile “black box” React app.
+
+
+
+ 🚀 Deploy in 60s (Free)
+ •
+ Live Demo
+ •
+ HugoBlox Studio (Visual Editor)
+
+
+
+
+
+
+
+
+
+
+
+---
+
+## Why this template?
+
+Most portfolios look the same — and most “quick” site builders produce slow sites you can’t maintain.
+
+- **⚡ Fast by default**: Hugo + Tailwind 4 + Hugo Modules → great Lighthouse scores without JS bloat.
+- **🧠 AI-ready content**: Your projects and posts live in clean Markdown/YAML — readable by humans and LLMs.
+- **🎯 Job-hunting optimized**: Projects, tech stack, experience timeline, and a blog layout that looks credible.
+- **🌙 Dark-first (but light-mode supported)**: Looks premium in dark mode, still works perfectly in light mode.
+- **🧩 Block-based**: Reorder/replace sections without rewriting templates.
+
+---
+
+## Who it’s for
+
+- **Students & grads** applying to internships / MSc / PhD / junior roles
+- **STEM professionals** (research, data, ML, bio, engineering) showcasing projects and writing
+- **Software engineers** building a portfolio that feels modern in 2026
+
+---
+
+## What you get (Free)
+
+- **Developer hero** with modern gradients + optional typewriter
+- **Filterable portfolio** (tags + smooth transitions)
+- **Tech stack** grid with icons
+- **Experience + education timeline**
+- **Blog section** (cards + featured images)
+- **Contact section** with social links + copy email
+
+---
+
+## Get started (recommended)
+
+### Option 1 — Online deployer (fastest)
+
+Deploy this template in ~60 seconds:
+
+- [Deploy in browser →](https://hugoblox.com/templates/dev-portfolio/start?utm_source=github&utm_medium=readme)
+
+### Option 2 — HugoBlox Studio (visual editor in VS Code)
+
+- [Studio guide →](https://docs.hugoblox.com/guides/studio/?utm_source=github&utm_medium=readme)
+- [Studio AI automation plans (Free/Plus/Pro) →](https://hugoblox.com/pricing/?utm_source=github&utm_medium=readme)
+
+### Option 3 — HugoBlox CLI (developer workflow)
+
+Install:
+
+```bash
+npm install -g hugoblox@latest
+```
+
+Create a site:
+
+```bash
+hugoblox create site --template dev-portfolio
+```
+
+[CLI docs →](https://docs.hugoblox.com/start/cli/?utm_source=github&utm_medium=readme)
+
+---
+
+## Customize in 10 minutes
+
+- **Your profile**: `data/authors/me.yaml`
+- **Homepage sections**: `content/_index.md`
+- **Projects**: `content/projects/
/index.md`
+- **Blog posts**: `content/blog//index.md`
+- **Theme + identity**: `config/_default/params.yaml`
+
+---
+
+## Want the Pro version? 💎
+
+If you want a version that feels meaningfully more premium (and helps fund open source + research):
+
+- [Premium template →](https://hugoblox.com/templates/dev-portfolio-pro/start?utm_source=github&utm_medium=readme)
+- [HugoBlox Pro / Studio →](https://hugoblox.com/pricing?utm_source=github&utm_medium=readme)
+
+---
+
+## Community & support
+
+- **Docs**: [docs.hugoblox.com →](https://docs.hugoblox.com/?utm_source=github&utm_medium=readme)
+- **Discord**: [Join Discord →](https://discord.gg/z8wNYzb)
+- **Issues**: [Open an issue →](https://github.com/HugoBlox/kit/issues)
+
+---
+
+MIT © 2016–Present [George Cushen](https://neuralgeo.com/?utm_source=github&utm_medium=readme)
diff --git a/templates/dev-portfolio/assets/media/authors/me.png b/templates/dev-portfolio/assets/media/authors/me.png
new file mode 100644
index 00000000..5ebc1f3b
Binary files /dev/null and b/templates/dev-portfolio/assets/media/authors/me.png differ
diff --git a/templates/dev-portfolio/assets/media/icons/custom/.gitkeep b/templates/dev-portfolio/assets/media/icons/custom/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/templates/dev-portfolio/config/_default/hugo.yaml b/templates/dev-portfolio/config/_default/hugo.yaml
new file mode 100644
index 00000000..16c633f1
--- /dev/null
+++ b/templates/dev-portfolio/config/_default/hugo.yaml
@@ -0,0 +1,55 @@
+# Configuration of Hugo
+# Guide: https://docs.hugoblox.com/tutorial/
+# Hugo Documentation: https://gohugo.io/getting-started/configuration/#all-configuration-settings
+# This file is formatted using YAML syntax - learn more at https://learnxinyminutes.com/docs/yaml/
+
+# Website name (set in params.yaml under hugoblox.branding.name)
+title: ''
+# Website URL
+baseURL: 'https://example.com/'
+
+############################
+## LANGUAGE
+############################
+
+defaultContentLanguage: en
+hasCJKLanguage: false
+defaultContentLanguageInSubdir: false
+removePathAccents: true
+
+############################
+## ADVANCED
+############################
+
+build:
+ writeStats: true
+enableGitInfo: false
+summaryLength: 30
+pagination:
+ pagerSize: 10
+enableEmoji: true
+enableRobotsTXT: true
+footnotereturnlinkcontents: ^
+ignoreFiles: [".ipynb_checkpoints$", "\\.Rmd$", "\\.Rmarkdown$", "_cache$"]
+disableAliases: true
+outputs:
+ home: [HTML, RSS, headers, redirects, backlinks]
+ section: [HTML, RSS]
+imaging:
+ resampleFilter: lanczos
+ quality: 90
+ anchor: smart
+ hint: picture
+timeout: 600000
+taxonomies:
+ author: authors
+ tag: tags
+ publication_type: publication_types
+markup:
+ _merge: deep
+ highlight:
+ lineNos: false
+security:
+ _merge: deep
+sitemap:
+ _merge: deep
diff --git a/templates/dev-portfolio/config/_default/languages.yaml b/templates/dev-portfolio/config/_default/languages.yaml
new file mode 100644
index 00000000..88fa733d
--- /dev/null
+++ b/templates/dev-portfolio/config/_default/languages.yaml
@@ -0,0 +1,22 @@
+# Languages
+# Create a section for each of your site's languages.
+# Documentation: https://docs.hugoblox.com/reference/language/
+
+# Default language
+en:
+ languageCode: en-us
+ # Uncomment for multi-lingual sites, and move English content into `en` sub-folder.
+ #contentDir: content/en
+
+# Uncomment the lines below to configure your website in a second language.
+#zh:
+# languageCode: zh-Hans
+# contentDir: content/zh
+# title: Chinese website title...
+# params:
+# description: Site description in Chinese...
+# menu:
+# main:
+# - name: 传
+# url: '#about'
+# weight: 1
diff --git a/templates/dev-portfolio/config/_default/menus.yaml b/templates/dev-portfolio/config/_default/menus.yaml
new file mode 100644
index 00000000..f0480744
--- /dev/null
+++ b/templates/dev-portfolio/config/_default/menus.yaml
@@ -0,0 +1,20 @@
+# Navigation Links
+# To link a homepage section, use a hash `#` followed by the section ID.
+# The weight parameter defines the order that the links appear.
+
+main:
+ - name: Projects
+ url: /#projects
+ weight: 10
+ - name: Skills
+ url: /#skills
+ weight: 20
+ - name: Experience
+ url: /#experience
+ weight: 30
+ - name: Blog
+ url: /#blog
+ weight: 40
+ - name: Contact
+ url: /#contact
+ weight: 50
diff --git a/templates/dev-portfolio/config/_default/module.yaml b/templates/dev-portfolio/config/_default/module.yaml
new file mode 100644
index 00000000..4101cd91
--- /dev/null
+++ b/templates/dev-portfolio/config/_default/module.yaml
@@ -0,0 +1,26 @@
+############################
+## HUGO MODULES
+## Install or uninstall themes and plugins here.
+## Docs: https://gohugo.io/hugo-modules/
+############################
+
+imports:
+ - path: github.com/HugoBlox/kit/modules/integrations/netlify
+ - path: github.com/HugoBlox/kit/modules/blox
+ - path: github.com/HugoBlox/kit/modules/slides
+
+# Install any Hugo Blox within the `hugo-blox/blox/` folder
+mounts:
+ - source: hugo-blox/blox/community
+ target: layouts/_partials/blox/community/
+ includeFiles: '**.html'
+ - source: hugo-blox/blox/all-access
+ target: layouts/_partials/blox/
+ includeFiles: '**.html'
+ - source: hugo-blox/blox
+ target: assets/dist/community/blox/
+ includeFiles: '**.css'
+ - source: layouts
+ target: layouts
+ - source: assets
+ target: assets
diff --git a/templates/dev-portfolio/config/_default/params.yaml b/templates/dev-portfolio/config/_default/params.yaml
new file mode 100644
index 00000000..66ee890f
--- /dev/null
+++ b/templates/dev-portfolio/config/_default/params.yaml
@@ -0,0 +1,291 @@
+# ══════════════════════════════════════════════════════════════════════════════
+# HUGO BLOX CONFIGURATION
+# Schema: hugoblox.com/schema/v2
+# Tutorial: https://docs.hugoblox.com/tutorial/
+# Documentation: https://docs.hugoblox.com/
+# ══════════════════════════════════════════════════════════════════════════════
+hugoblox:
+ schema: "2.0"
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # IDENTITY
+ # Site-level branding (for people/profiles, use the author system in content/authors/)
+ # ────────────────────────────────────────────────────────────────────────────
+ identity:
+ # Site name - shown in navbar, footer, copyright, and browser title by default
+ name: "Your Name"
+ # Legal entity for copyright notices (defaults to name if not set)
+ organization: ""
+ # Schema.org type for structured data
+ type: person # person | organization | local_business
+ # Short tagline displayed on your site
+ tagline: "Full-Stack Developer"
+ # Site meta description for search engines and social sharing
+ description: "Modern developer portfolio showcasing web development projects, technical blog posts, and open source contributions. Built with Hugo Blox."
+ # Social accounts (used for meta tags like Twitter Cards)
+ social:
+ twitter: "yourusername" # Twitter/X handle for Twitter Cards (without @)
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # THEME
+ # Color and visual design system
+ # ────────────────────────────────────────────────────────────────────────────
+ theme:
+ # Mode: 'light', 'dark', or 'system' (follows OS preference)
+ mode: dark
+ # Theme pack: name from data/themes/ or { light: "x", dark: "y" } for mix-and-match
+ pack: "default"
+ # Optional: Override theme pack colors
+ colors:
+ primary: "" # Tailwind palette name or hex (e.g., "indigo" or "#6366f1")
+ secondary: ""
+ neutral: "" # Affects gray utilities (text-gray-*, bg-gray-*)
+ # Optional: Mode-specific color overrides
+ colors_light: {}
+ colors_dark: {}
+ # Optional: Semantic surface color overrides
+ surfaces:
+ background: ""
+ foreground: ""
+ header:
+ background: ""
+ foreground: ""
+ footer:
+ background: ""
+ foreground: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # TYPOGRAPHY
+ # Font and text sizing
+ # ────────────────────────────────────────────────────────────────────────────
+ typography:
+ # Font: 'sans' (Inter), 'serif' (Roboto Slab), or 'native' (system fonts)
+ font: "sans"
+ # Size: 'sm', 'md', 'lg', or 'xl' (affects base font size and scale)
+ size: "md"
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # LAYOUT
+ # Spacing and shape tokens
+ # ────────────────────────────────────────────────────────────────────────────
+ layout:
+ # Border radius: 'none', 'sm', 'md', 'lg', or 'full'
+ radius: "md"
+ # Spacing density: 'compact', 'comfortable', or 'spacious'
+ spacing: "comfortable"
+ # Avatar shape in author profiles
+ avatar_shape: circle # circle | square | rounded
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # HEADER
+ # Site header and navigation bar
+ # ────────────────────────────────────────────────────────────────────────────
+ header:
+ enable: true
+ # Header style variant
+ style: navbar # navbar | navbar-simple | minimal
+ # Stick to top on scroll
+ sticky: true
+ # Menu alignment
+ align: center # left | center | right
+ # Feature toggles
+ search: true
+ theme_toggle: true
+ theme_picker: true
+ language_switcher: true
+ # Call-to-action button
+ cta:
+ enable: false
+ text: ""
+ url: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # FOOTER
+ # Site footer
+ # ────────────────────────────────────────────────────────────────────────────
+ footer:
+ # Footer style variant
+ style: minimal # minimal | columns | centered
+ language_switcher: true
+ # Custom footer text (HTML supported)
+ text: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # COPYRIGHT
+ # Legal notices and licensing
+ # ────────────────────────────────────────────────────────────────────────────
+ copyright:
+ # Copyright notice - supports {year}, {name}, {license} placeholders
+ notice: "© {year} {name}. This work is licensed under {license}"
+ license:
+ type: cc # cc | custom
+ allow_derivatives: false
+ share_alike: true
+ allow_commercial: false
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # SEO
+ # Search engine optimization - overrides and technical settings
+ # ────────────────────────────────────────────────────────────────────────────
+ seo:
+ # Browser tab title override (defaults to identity.name if not set)
+ title: ""
+ # For local_business identity type only
+ location:
+ address:
+ street: ""
+ city: ""
+ region: ""
+ postal_code: ""
+ country: ""
+ coordinates:
+ latitude: null
+ longitude: null
+ phone: ""
+ # AI/LLM crawler guidance (llms.txt)
+ ai:
+ allow:
+ - /
+ disallow: []
+ note: "Guidance for AI crawlers - customize to match your public content."
+ contact: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # CONTENT
+ # Content rendering and behavior
+ # ────────────────────────────────────────────────────────────────────────────
+ content:
+ # Math rendering
+ math:
+ enable: false
+ # Table of contents
+ toc:
+ enable: true
+ # Reading time estimates
+ reading_time:
+ enable: true
+ # Academic citations (disabled for developer portfolio)
+ citations:
+ style: apa # apa | mla | chicago | ieee
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # SEARCH
+ # Site search
+ # ────────────────────────────────────────────────────────────────────────────
+ search:
+ enable: true
+ # Trending/suggested search terms
+ suggestions: []
+ # Quick action shortcuts in search modal
+ quick_actions: []
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # COMMENTS
+ # User comments system
+ # ────────────────────────────────────────────────────────────────────────────
+ comments:
+ enable: false
+ provider: "" # giscus | disqus
+ giscus:
+ repo: ""
+ repo_id: ""
+ category: ""
+ category_id: ""
+ disqus:
+ shortname: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # ANALYTICS
+ # Traffic and behavior analytics
+ # ────────────────────────────────────────────────────────────────────────────
+ analytics:
+ google:
+ measurement_id: "" # Google Analytics 4: G-XXXXXXXXXX
+ google_tag_manager:
+ container_id: "" # GTM-XXXXXXX
+ plausible:
+ domain: ""
+ fathom:
+ site_id: ""
+ pirsch:
+ site_id: ""
+ clarity:
+ project_id: ""
+ baidu:
+ site_id: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # VERIFICATION
+ # Search engine site verification codes
+ # ────────────────────────────────────────────────────────────────────────────
+ verification:
+ google: ""
+ bing: ""
+ baidu: ""
+ yandex: ""
+ pinterest: ""
+ naver: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # REPOSITORY
+ # Source code repository for "Edit this page" links
+ # ────────────────────────────────────────────────────────────────────────────
+ repository:
+ enable: false
+ url: "" # e.g., https://github.com/username/repo
+ branch: main
+ content_dir: content
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # LOCALE
+ # Regional formatting preferences
+ # ────────────────────────────────────────────────────────────────────────────
+ locale:
+ date_format: "Jan 2, 2006" # Go time format
+ time_format: "3:04 PM"
+ address_format: en-us
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # SECURITY
+ # Security headers and policies (requires Netlify integration)
+ # ────────────────────────────────────────────────────────────────────────────
+ security:
+ csp:
+ policy: ""
+ report_only: false
+ frame_options: sameorigin # deny | sameorigin | allow - sameorigin allows slides embedding
+ permissions_policy: ""
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # PRIVACY
+ # Privacy and compliance features
+ # ────────────────────────────────────────────────────────────────────────────
+ privacy:
+ enable: false
+ anonymize_analytics: true
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # DEBUG
+ # Development and debugging (hidden in production)
+ # ────────────────────────────────────────────────────────────────────────────
+ debug:
+ enable: false
+ hud:
+ position: bottom-left # top-left | top-right | bottom-left | bottom-right
+ opacity: 1.0
+ export_logs: true
+
+ # ────────────────────────────────────────────────────────────────────────────
+ # PRO
+ # Pro subscription features and affiliate program
+ # ────────────────────────────────────────────────────────────────────────────
+ pro:
+ # Hide "Powered by HugoBlox" attribution
+ # Requires: Pro subscription to support HugoBlox via alternative means
+ # Note: Even with Pro, you can keep this false to support open source!
+ # Get Pro: https://hugoblox.com/pro
+ hide_attribution: false
+
+ # Affiliate referral code for rewards program
+ # Join affiliate program: https://hugoblox.com/affiliates
+ affiliate_code: ""
diff --git a/templates/dev-portfolio/content/_index.md b/templates/dev-portfolio/content/_index.md
new file mode 100644
index 00000000..a1d5b2e2
--- /dev/null
+++ b/templates/dev-portfolio/content/_index.md
@@ -0,0 +1,259 @@
+---
+# Leave the homepage title empty to use the site title
+title: ''
+summary: ''
+date: 2026-01-05
+type: landing
+
+design:
+ # Default section spacing
+ spacing: '0'
+
+sections:
+ # Developer Hero - Gradient background with name, role, social, and CTAs
+ - block: dev-hero
+ id: hero
+ content:
+ username: me
+ greeting: "Hi, I'm"
+ show_status: true
+ show_scroll_indicator: true
+ typewriter:
+ enable: true
+ prefix: "I build"
+ strings:
+ - "full-stack web apps"
+ - "scalable APIs"
+ - "beautiful UIs"
+ - "open source tools"
+ type_speed: 70
+ delete_speed: 40
+ pause_time: 2500
+ cta_buttons:
+ - text: View My Work
+ url: "#projects"
+ icon: arrow-down
+ - text: Get In Touch
+ url: "#contact"
+ icon: envelope
+ design:
+ style: centered
+ avatar_shape: circle
+ animations: true
+ background:
+ color:
+ light: "#fafafa"
+ dark: "#0a0a0f"
+ spacing:
+ padding: ["6rem", "0", "4rem", "0"]
+
+ # Filterable Portfolio - Alpine.js powered project filtering
+ - block: portfolio
+ id: projects
+ content:
+ title: "Featured Projects"
+ subtitle: "A selection of my recent work"
+ count: 6
+ filters:
+ folders:
+ - projects
+ buttons:
+ - name: All
+ tag: '*'
+ - name: Full-Stack
+ tag: Full-Stack
+ - name: Frontend
+ tag: Frontend
+ - name: Backend
+ tag: Backend
+ default_button_index: 0
+ # Archive link auto-shown if more projects exist than 'count' above
+ # archive:
+ # enable: false # Set to false to explicitly hide
+ # text: "Browse All" # Customize text
+ # link: "/work/" # Custom URL
+ design:
+ columns: 3
+ background:
+ color:
+ light: "#ffffff"
+ dark: "#0d0d12"
+ spacing:
+ padding: ["4rem", "0", "4rem", "0"]
+
+ # Visual Tech Stack - Icons organized by category
+ - block: tech-stack
+ id: skills
+ content:
+ title: "Tech Stack"
+ subtitle: "Technologies I use to build things"
+ categories:
+ - name: Languages
+ items:
+ - name: TypeScript
+ icon: devicon/typescript
+ - name: JavaScript
+ icon: devicon/javascript
+ - name: Python
+ icon: devicon/python
+ - name: Go
+ icon: devicon/go
+ - name: Frontend
+ items:
+ - name: React
+ icon: devicon/react
+ - name: Next.js
+ icon: devicon/nextjs
+ - name: Tailwind CSS
+ icon: devicon/tailwindcss
+ - name: Alpine.js
+ icon: devicon/alpinejs
+ - name: Backend
+ items:
+ - name: Node.js
+ icon: devicon/nodejs
+ - name: Express
+ icon: devicon/express
+ - name: PostgreSQL
+ icon: devicon/postgresql
+ - name: Redis
+ icon: devicon/redis
+ - name: DevOps
+ items:
+ - name: Docker
+ icon: devicon/docker
+ - name: AWS
+ icon: devicon/amazonwebservices-wordmark
+ - name: GitHub Actions
+ icon: brands/github
+ - name: Vercel
+ icon: devicon/vercel
+ design:
+ style: grid
+ show_levels: false
+ background:
+ color:
+ light: "#f5f5f5"
+ dark: "#08080c"
+ spacing:
+ padding: ["4rem", "0", "4rem", "0"]
+
+ # Experience Timeline
+ - block: resume-experience
+ id: experience
+ content:
+ title: Experience
+ date_format: Jan 2006
+ items:
+ - title: Senior Software Engineer
+ company: Tech Corp
+ company_url: ''
+ company_logo: ''
+ location: San Francisco, CA
+ date_start: '2023-01-01'
+ date_end: ''
+ description: |2-
+ * Lead development of microservices architecture serving 1M+ users
+ * Improved API response time by 40% through optimization
+ * Mentored team of 5 junior developers
+ * Tech stack: React, Node.js, PostgreSQL, AWS
+ - title: Full-Stack Developer
+ company: Startup Inc
+ company_url: ''
+ company_logo: ''
+ location: Remote
+ date_start: '2021-06-01'
+ date_end: '2022-12-31'
+ description: |2-
+ * Built and deployed 3 production applications from scratch
+ * Implemented CI/CD pipeline reducing deployment time by 60%
+ * Collaborated with design team on UI/UX improvements
+ * Tech stack: Next.js, Express, MongoDB, Docker
+ - title: Junior Developer
+ company: Web Agency
+ company_url: ''
+ company_logo: ''
+ location: New York, NY
+ date_start: '2020-01-01'
+ date_end: '2021-05-31'
+ description: |2-
+ * Developed client websites using modern web technologies
+ * Maintained and updated legacy codebases
+ * Participated in code reviews and agile ceremonies
+ * Tech stack: React, WordPress, PHP, MySQL
+ design:
+ columns: '1'
+ background:
+ color:
+ light: "#ffffff"
+ dark: "#0d0d12"
+ spacing:
+ padding: ["4rem", "0", "4rem", "0"]
+
+ # Recent Blog Posts
+ - block: collection
+ id: blog
+ content:
+ title: Recent Posts
+ subtitle: 'Thoughts on web development, tech, and more'
+ text: ''
+ filters:
+ folders:
+ - blog
+ exclude_featured: false
+ count: 3
+ order: desc
+ design:
+ view: card
+ columns: 3
+ background:
+ color:
+ light: "#f5f5f5"
+ dark: "#08080c"
+ spacing:
+ padding: ["4rem", "0", "4rem", "0"]
+
+ # Contact Section
+ - block: contact-info
+ id: contact
+ content:
+ title: Get In Touch
+ subtitle: "Let's build something amazing together"
+ text: |-
+ I'm always interested in hearing about new projects and opportunities.
+ Whether you're looking to hire, collaborate, or just want to say hi, feel free to reach out!
+ email: alex@example.com
+ autolink: true
+ design:
+ columns: '1'
+ background:
+ color:
+ light: "#ffffff"
+ dark: "#0d0d12"
+ spacing:
+ padding: ["4rem", "0", "4rem", "0"]
+
+ # CTA Card
+ - block: cta-card
+ content:
+ title: "Open to Opportunities"
+ text: |-
+ I'm currently looking for **senior engineering** or **tech lead** roles.
+
+ Let's connect and discuss how I can help your team.
+ button:
+ text: 'Download Resume'
+ url: uploads/resume.pdf
+ new_tab: true
+ design:
+ card:
+ # Light mode: soft pastel theme gradient | Dark mode: rich deep gradient
+ css_class: 'bg-gradient-to-br from-primary-200 via-primary-100 to-secondary-200 dark:from-primary-600 dark:via-primary-700 dark:to-secondary-700'
+ text_color: dark
+ background:
+ color:
+ light: "#f5f5f5"
+ dark: "#08080c"
+ spacing:
+ padding: ["4rem", "0", "6rem", "0"]
+---
diff --git a/templates/dev-portfolio/content/authors/_index.md b/templates/dev-portfolio/content/authors/_index.md
new file mode 100644
index 00000000..853f3eda
--- /dev/null
+++ b/templates/dev-portfolio/content/authors/_index.md
@@ -0,0 +1,9 @@
+---
+# To publish author profile pages, remove all the `build` and `cascade` settings below.
+build:
+ render: never
+cascade:
+ build:
+ render: never
+ list: always
+---
diff --git a/templates/dev-portfolio/content/blog/_index.md b/templates/dev-portfolio/content/blog/_index.md
new file mode 100644
index 00000000..c067352b
--- /dev/null
+++ b/templates/dev-portfolio/content/blog/_index.md
@@ -0,0 +1,4 @@
+---
+title: Blog
+view: article-grid
+---
diff --git a/templates/dev-portfolio/content/blog/building-rest-api/featured.png b/templates/dev-portfolio/content/blog/building-rest-api/featured.png
new file mode 100644
index 00000000..6e596845
Binary files /dev/null and b/templates/dev-portfolio/content/blog/building-rest-api/featured.png differ
diff --git a/templates/dev-portfolio/content/blog/building-rest-api/index.md b/templates/dev-portfolio/content/blog/building-rest-api/index.md
new file mode 100644
index 00000000..dc56495f
--- /dev/null
+++ b/templates/dev-portfolio/content/blog/building-rest-api/index.md
@@ -0,0 +1,455 @@
+---
+title: "Building a Production-Ready REST API with Node.js and Express"
+date: 2024-12-10
+summary: "A comprehensive guide to building scalable, secure REST APIs with proper error handling, validation, and documentation"
+tags:
+ - Node.js
+ - Express
+ - REST API
+ - Backend
+ - Tutorial
+authors:
+ - me
+featured: true
+---
+
+Building a REST API seems straightforward until you need to handle authentication, validation, error handling, and documentation. This guide covers best practices for production-ready APIs.
+
+## Table of Contents
+
+1. [Project Setup](#project-setup)
+2. [Folder Structure](#folder-structure)
+3. [Database Integration](#database)
+4. [Authentication & Authorization](#auth)
+5. [Error Handling](#errors)
+6. [Validation](#validation)
+7. [API Documentation](#docs)
+8. [Testing](#testing)
+
+## Project Setup {#project-setup}
+
+Start with a solid foundation:
+
+```bash
+mkdir my-api && cd my-api
+npm init -y
+npm install express dotenv cors helmet compression
+npm install -D typescript @types/node @types/express ts-node-dev
+```
+
+Create `tsconfig.json`:
+
+```json
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "commonjs",
+ "lib": ["ES2020"],
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true
+ }
+}
+```
+
+## Folder Structure {#folder-structure}
+
+Organize your code for maintainability:
+
+```
+src/
+├── config/ # Configuration files
+├── controllers/ # Route controllers
+├── middleware/ # Custom middleware
+├── models/ # Database models
+├── routes/ # API routes
+├── services/ # Business logic
+├── utils/ # Helper functions
+├── validators/ # Input validation
+└── app.ts # App setup
+```
+
+## Database Integration {#database}
+
+Using Prisma for type-safe database access:
+
+```typescript
+// prisma/schema.prisma
+model User {
+ id String @id @default(uuid())
+ email String @unique
+ name String
+ password String
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+```
+
+```typescript
+// src/config/database.ts
+import { PrismaClient } from '@prisma/client'
+
+const prisma = new PrismaClient({
+ log: process.env.NODE_ENV === 'development' ? ['query'] : []
+})
+
+export default prisma
+```
+
+## Authentication & Authorization {#auth}
+
+Implement JWT-based authentication:
+
+```typescript
+// src/middleware/auth.ts
+import jwt from 'jsonwebtoken'
+import { Request, Response, NextFunction } from 'express'
+
+interface JWTPayload {
+ userId: string
+ email: string
+}
+
+export const authenticate = async (
+ req: Request,
+ res: Response,
+ next: NextFunction
+) => {
+ try {
+ const token = req.headers.authorization?.split(' ')[1]
+
+ if (!token) {
+ return res.status(401).json({ error: 'Authentication required' })
+ }
+
+ const payload = jwt.verify(
+ token,
+ process.env.JWT_SECRET!
+ ) as JWTPayload
+
+ req.user = payload
+ next()
+ } catch (error) {
+ res.status(401).json({ error: 'Invalid or expired token' })
+ }
+}
+```
+
+## Error Handling {#errors}
+
+Centralized error handling:
+
+```typescript
+// src/middleware/errorHandler.ts
+import { Request, Response, NextFunction } from 'express'
+
+class AppError extends Error {
+ statusCode: number
+ isOperational: boolean
+
+ constructor(message: string, statusCode: number) {
+ super(message)
+ this.statusCode = statusCode
+ this.isOperational = true
+ Error.captureStackTrace(this, this.constructor)
+ }
+}
+
+export const errorHandler = (
+ err: Error,
+ req: Request,
+ res: Response,
+ next: NextFunction
+) => {
+ if (err instanceof AppError) {
+ return res.status(err.statusCode).json({
+ status: 'error',
+ message: err.message
+ })
+ }
+
+ // Log unexpected errors
+ console.error('Unexpected error:', err)
+
+ res.status(500).json({
+ status: 'error',
+ message: 'Internal server error'
+ })
+}
+
+export { AppError }
+```
+
+## Validation {#validation}
+
+Use Zod for runtime validation:
+
+```typescript
+// src/validators/userValidator.ts
+import { z } from 'zod'
+
+export const createUserSchema = z.object({
+ body: z.object({
+ email: z.string().email('Invalid email address'),
+ name: z.string().min(2, 'Name must be at least 2 characters'),
+ password: z.string().min(8, 'Password must be at least 8 characters')
+ })
+})
+
+export const validate = (schema: any) => {
+ return async (req: Request, res: Response, next: NextFunction) => {
+ try {
+ await schema.parseAsync({
+ body: req.body,
+ query: req.query,
+ params: req.params
+ })
+ next()
+ } catch (error) {
+ if (error instanceof z.ZodError) {
+ return res.status(400).json({
+ status: 'error',
+ errors: error.errors
+ })
+ }
+ next(error)
+ }
+ }
+}
+```
+
+## API Documentation {#docs}
+
+Auto-generate docs with Swagger:
+
+```typescript
+// src/config/swagger.ts
+import swaggerJsdoc from 'swagger-jsdoc'
+
+const options = {
+ definition: {
+ openapi: '3.0.0',
+ info: {
+ title: 'My API',
+ version: '1.0.0',
+ description: 'API documentation'
+ },
+ servers: [
+ {
+ url: 'http://localhost:3000',
+ description: 'Development server'
+ }
+ ]
+ },
+ apis: ['./src/routes/*.ts']
+}
+
+export const swaggerSpec = swaggerJsdoc(options)
+```
+
+Document endpoints in route files:
+
+```typescript
+/**
+ * @openapi
+ * /api/users:
+ * post:
+ * summary: Create a new user
+ * tags: [Users]
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * email:
+ * type: string
+ * name:
+ * type: string
+ * password:
+ * type: string
+ * responses:
+ * 201:
+ * description: User created successfully
+ */
+router.post('/users', validate(createUserSchema), createUser)
+```
+
+## Testing {#testing}
+
+Write tests with Jest and Supertest:
+
+```typescript
+// tests/users.test.ts
+import request from 'supertest'
+import app from '../src/app'
+import prisma from '../src/config/database'
+
+describe('User API', () => {
+ beforeEach(async () => {
+ await prisma.user.deleteMany()
+ })
+
+ afterAll(async () => {
+ await prisma.$disconnect()
+ })
+
+ describe('POST /api/users', () => {
+ it('should create a new user', async () => {
+ const res = await request(app)
+ .post('/api/users')
+ .send({
+ email: 'test@example.com',
+ name: 'Test User',
+ password: 'password123'
+ })
+ .expect(201)
+
+ expect(res.body).toHaveProperty('id')
+ expect(res.body.email).toBe('test@example.com')
+ })
+
+ it('should return 400 for invalid email', async () => {
+ const res = await request(app)
+ .post('/api/users')
+ .send({
+ email: 'invalid-email',
+ name: 'Test User',
+ password: 'password123'
+ })
+ .expect(400)
+
+ expect(res.body).toHaveProperty('errors')
+ })
+ })
+})
+```
+
+## Security Best Practices
+
+1. **Rate Limiting**
+ ```typescript
+ import rateLimit from 'express-rate-limit'
+
+ const limiter = rateLimit({
+ windowMs: 15 * 60 * 1000, // 15 minutes
+ max: 100 // limit each IP to 100 requests per windowMs
+ })
+
+ app.use('/api/', limiter)
+ ```
+
+2. **Helmet** for security headers
+ ```typescript
+ import helmet from 'helmet'
+ app.use(helmet())
+ ```
+
+3. **CORS** configuration
+ ```typescript
+ import cors from 'cors'
+ app.use(cors({
+ origin: process.env.ALLOWED_ORIGINS?.split(','),
+ credentials: true
+ }))
+ ```
+
+4. **Input Sanitization**
+ ```typescript
+ import mongoSanitize from 'express-mongo-sanitize'
+ app.use(mongoSanitize())
+ ```
+
+## Performance Optimization
+
+### 1. Response Compression
+```typescript
+import compression from 'compression'
+app.use(compression())
+```
+
+### 2. Caching
+```typescript
+import Redis from 'ioredis'
+const redis = new Redis(process.env.REDIS_URL)
+
+async function getCachedData(key: string) {
+ const cached = await redis.get(key)
+ if (cached) return JSON.parse(cached)
+
+ const data = await fetchFromDatabase()
+ await redis.setex(key, 3600, JSON.stringify(data))
+ return data
+}
+```
+
+### 3. Database Query Optimization
+```typescript
+// Use pagination
+const users = await prisma.user.findMany({
+ skip: (page - 1) * limit,
+ take: limit,
+ select: {
+ id: true,
+ email: true,
+ name: true
+ // Don't select sensitive fields like password
+ }
+})
+
+// Use indexes
+@@index([email])
+@@index([createdAt])
+```
+
+## Deployment Checklist
+
+- [ ] Environment variables configured
+- [ ] Database migrations run
+- [ ] SSL/TLS certificates installed
+- [ ] Rate limiting enabled
+- [ ] Logging configured (Winston, Morgan)
+- [ ] Error tracking (Sentry)
+- [ ] Health check endpoint
+- [ ] API documentation deployed
+- [ ] Load testing completed
+- [ ] Backup strategy implemented
+
+## Monitoring
+
+```typescript
+// Health check endpoint
+app.get('/health', async (req, res) => {
+ try {
+ await prisma.$queryRaw`SELECT 1`
+ res.status(200).json({ status: 'healthy', timestamp: new Date() })
+ } catch (error) {
+ res.status(503).json({ status: 'unhealthy', error: error.message })
+ }
+})
+```
+
+## Conclusion
+
+Building production-ready APIs requires attention to:
+- **Structure**: Organized code is maintainable code
+- **Security**: Authentication, validation, and rate limiting
+- **Errors**: Proper error handling and logging
+- **Testing**: Comprehensive test coverage
+- **Documentation**: Clear API docs for consumers
+- **Performance**: Caching and optimization
+
+The complete example code is available on [GitHub](https://github.com/alexjohnson/rest-api-guide).
+
+## Resources
+
+- [Express Best Practices](https://expressjs.com/en/advanced/best-practice-performance.html)
+- [Node.js Security Checklist](https://github.com/goldbergyoni/nodebestpractices#6-security-best-practices)
+- [Prisma Documentation](https://www.prisma.io/docs)
+
+---
+
+Questions? Leave a comment below or reach out on [Twitter](https://twitter.com/alexjohnson)!
diff --git a/templates/dev-portfolio/content/blog/docker-deployment/featured.png b/templates/dev-portfolio/content/blog/docker-deployment/featured.png
new file mode 100644
index 00000000..dc088cd3
Binary files /dev/null and b/templates/dev-portfolio/content/blog/docker-deployment/featured.png differ
diff --git a/templates/dev-portfolio/content/blog/docker-deployment/index.md b/templates/dev-portfolio/content/blog/docker-deployment/index.md
new file mode 100644
index 00000000..a1580f86
--- /dev/null
+++ b/templates/dev-portfolio/content/blog/docker-deployment/index.md
@@ -0,0 +1,526 @@
+---
+title: "Docker Deployment Guide: From Development to Production"
+date: 2024-10-15
+summary: "Learn how to containerize your applications with Docker, optimize images, and deploy to production with best practices"
+tags:
+ - Docker
+ - DevOps
+ - Deployment
+ - Tutorial
+authors:
+ - me
+featured: false
+---
+
+Docker simplifies deployment by packaging your application with all dependencies. This guide covers containerizing apps, optimizing images, and production deployment.
+
+## Why Docker?
+
+**Problems Docker solves**:
+- ❌ "Works on my machine" syndrome
+- ❌ Complex dependency management
+- ❌ Environment inconsistencies
+- ❌ Difficult scaling
+
+**Benefits**:
+- ✅ Consistent environments (dev = prod)
+- ✅ Easy scaling
+- ✅ Simplified deployment
+- ✅ Isolation and security
+
+## Basic Dockerfile
+
+For a Node.js application:
+
+```dockerfile
+# Use official Node image
+FROM node:18-alpine
+
+# Set working directory
+WORKDIR /app
+
+# Copy package files
+COPY package*.json ./
+
+# Install dependencies
+RUN npm ci --only=production
+
+# Copy application code
+COPY . .
+
+# Expose port
+EXPOSE 3000
+
+# Start application
+CMD ["node", "server.js"]
+```
+
+Build and run:
+
+```bash
+docker build -t my-app .
+docker run -p 3000:3000 my-app
+```
+
+## Multi-Stage Builds (Optimization)
+
+Reduce image size with multi-stage builds:
+
+```dockerfile
+# Stage 1: Build
+FROM node:18-alpine AS builder
+
+WORKDIR /app
+COPY package*.json ./
+RUN npm ci
+
+COPY . .
+RUN npm run build
+
+# Stage 2: Production
+FROM node:18-alpine
+
+WORKDIR /app
+
+# Copy only necessary files from builder
+COPY --from=builder /app/dist ./dist
+COPY --from=builder /app/node_modules ./node_modules
+COPY package*.json ./
+
+EXPOSE 3000
+CMD ["node", "dist/server.js"]
+```
+
+**Result**: Image size reduced from 800MB → 150MB!
+
+## Docker Compose for Local Development
+
+`docker-compose.yml`:
+
+```yaml
+version: '3.8'
+
+services:
+ app:
+ build: .
+ ports:
+ - "3000:3000"
+ environment:
+ - NODE_ENV=development
+ - DATABASE_URL=postgresql://user:pass@db:5432/mydb
+ volumes:
+ - .:/app
+ - /app/node_modules
+ depends_on:
+ - db
+ - redis
+
+ db:
+ image: postgres:15-alpine
+ environment:
+ - POSTGRES_USER=user
+ - POSTGRES_PASSWORD=pass
+ - POSTGRES_DB=mydb
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+ ports:
+ - "5432:5432"
+
+ redis:
+ image: redis:7-alpine
+ ports:
+ - "6379:6379"
+
+volumes:
+ postgres_data:
+```
+
+Start everything:
+
+```bash
+docker-compose up -d
+```
+
+## Environment Variables
+
+Never hardcode secrets! Use `.env` file:
+
+```env
+# .env (add to .gitignore!)
+DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
+JWT_SECRET=your-secret-key
+API_KEY=your-api-key
+```
+
+Reference in docker-compose:
+
+```yaml
+services:
+ app:
+ env_file:
+ - .env
+```
+
+## Production Dockerfile
+
+Optimized for production:
+
+```dockerfile
+FROM node:18-alpine AS builder
+
+WORKDIR /app
+
+# Copy package files
+COPY package*.json ./
+
+# Install all dependencies (including devDependencies)
+RUN npm ci
+
+# Copy source
+COPY . .
+
+# Build application
+RUN npm run build
+
+# Remove devDependencies
+RUN npm prune --production
+
+# Production stage
+FROM node:18-alpine
+
+# Add non-root user
+RUN addgroup -g 1001 -S nodejs && \
+ adduser -S nodejs -u 1001
+
+WORKDIR /app
+
+# Copy built app from builder
+COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
+COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
+COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
+
+# Use non-root user
+USER nodejs
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
+ CMD node healthcheck.js
+
+EXPOSE 3000
+
+CMD ["node", "dist/server.js"]
+```
+
+## Image Optimization Tips
+
+### 1. Use .dockerignore
+
+```
+node_modules
+npm-debug.log
+.git
+.env
+.DS_Store
+*.md
+.vscode
+coverage
+.github
+```
+
+### 2. Layer Caching
+
+```dockerfile
+# ❌ Bad: Changes to code invalidate ALL layers
+COPY . .
+RUN npm ci
+
+# ✅ Good: Package changes don't rebuild code
+COPY package*.json ./
+RUN npm ci
+COPY . .
+```
+
+### 3. Use Alpine Images
+
+```dockerfile
+# Large: node:18 (900MB)
+FROM node:18
+
+# Small: node:18-alpine (150MB)
+FROM node:18-alpine
+```
+
+### 4. Combine RUN Commands
+
+```dockerfile
+# ❌ Bad: Multiple layers
+RUN apt-get update
+RUN apt-get install -y curl
+RUN apt-get clean
+
+# ✅ Good: Single layer
+RUN apt-get update && \
+ apt-get install -y curl && \
+ apt-get clean && \
+ rm -rf /var/lib/apt/lists/*
+```
+
+## Deploying to AWS ECS
+
+### 1. Build and Push to ECR
+
+```bash
+# Authenticate Docker to ECR
+aws ecr get-login-password --region us-east-1 | \
+ docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
+
+# Build image
+docker build -t my-app .
+
+# Tag image
+docker tag my-app:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
+
+# Push to ECR
+docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
+```
+
+### 2. ECS Task Definition
+
+```json
+{
+ "family": "my-app",
+ "networkMode": "awsvpc",
+ "requiresCompatibilities": ["FARGATE"],
+ "cpu": "256",
+ "memory": "512",
+ "containerDefinitions": [
+ {
+ "name": "my-app",
+ "image": "123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest",
+ "portMappings": [
+ {
+ "containerPort": 3000,
+ "protocol": "tcp"
+ }
+ ],
+ "environment": [
+ {
+ "name": "NODE_ENV",
+ "value": "production"
+ }
+ ],
+ "secrets": [
+ {
+ "name": "DATABASE_URL",
+ "valueFrom": "arn:aws:secretsmanager:..."
+ }
+ ],
+ "logConfiguration": {
+ "logDriver": "awslogs",
+ "options": {
+ "awslogs-group": "/ecs/my-app",
+ "awslogs-region": "us-east-1",
+ "awslogs-stream-prefix": "ecs"
+ }
+ }
+ }
+ ]
+}
+```
+
+## Docker Security Best Practices
+
+### 1. Use Non-Root User
+
+```dockerfile
+# Add user
+RUN addgroup -g 1001 -S nodejs && \
+ adduser -S nodejs -u 1001
+
+# Switch to user
+USER nodejs
+```
+
+### 2. Scan for Vulnerabilities
+
+```bash
+# Using Trivy
+docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
+ aquasec/trivy image my-app:latest
+```
+
+### 3. Keep Base Images Updated
+
+```dockerfile
+# ✅ Pin specific version, update regularly
+FROM node:18.19.0-alpine
+
+# ❌ Avoid 'latest' tag
+FROM node:latest
+```
+
+### 4. Read-Only Filesystem
+
+```yaml
+services:
+ app:
+ read_only: true
+ tmpfs:
+ - /tmp
+```
+
+## Health Checks
+
+Simple health check endpoint:
+
+```javascript
+// healthcheck.js
+const http = require('http')
+
+const options = {
+ host: 'localhost',
+ port: 3000,
+ path: '/health',
+ timeout: 2000
+}
+
+const request = http.request(options, (res) => {
+ if (res.statusCode === 200) {
+ process.exit(0)
+ } else {
+ process.exit(1)
+ }
+})
+
+request.on('error', () => {
+ process.exit(1)
+})
+
+request.end()
+```
+
+## Monitoring & Logging
+
+### Container Logs
+
+```bash
+# View logs
+docker logs my-app
+
+# Follow logs
+docker logs -f my-app
+
+# Last 100 lines
+docker logs --tail 100 my-app
+```
+
+### Docker Stats
+
+```bash
+# View resource usage
+docker stats
+
+# Specific container
+docker stats my-app
+```
+
+## Common Issues & Solutions
+
+### Issue: Image Too Large
+
+**Solution**: Multi-stage builds, Alpine images, .dockerignore
+
+### Issue: Slow Builds
+
+**Solution**: Optimize layer caching, use BuildKit
+
+```bash
+DOCKER_BUILDKIT=1 docker build -t my-app .
+```
+
+### Issue: Container Won't Start
+
+**Solution**: Check logs, verify CMD/ENTRYPOINT
+
+```bash
+docker logs container-id
+docker inspect container-id
+```
+
+## CI/CD Pipeline Example (GitHub Actions)
+
+```yaml
+name: Deploy
+
+on:
+ push:
+ branches: [main]
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Configure AWS credentials
+ uses: aws-actions/configure-aws-credentials@v2
+ with:
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ aws-region: us-east-1
+
+ - name: Login to Amazon ECR
+ id: login-ecr
+ uses: aws-actions/amazon-ecr-login@v1
+
+ - name: Build and push image
+ env:
+ ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
+ ECR_REPOSITORY: my-app
+ IMAGE_TAG: ${{ github.sha }}
+ run: |
+ docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
+ docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
+
+ - name: Update ECS service
+ run: |
+ aws ecs update-service --cluster my-cluster \
+ --service my-app --force-new-deployment
+```
+
+## Best Practices Checklist
+
+- [ ] Use multi-stage builds
+- [ ] Use .dockerignore
+- [ ] Run as non-root user
+- [ ] Pin base image versions
+- [ ] Scan for vulnerabilities
+- [ ] Implement health checks
+- [ ] Use environment variables for config
+- [ ] Keep images small (<500MB)
+- [ ] Tag images properly (not just 'latest')
+- [ ] Set up logging and monitoring
+
+## Resources
+
+- [Docker Documentation](https://docs.docker.com/)
+- [Docker Best Practices](https://docs.docker.com/develop/dev-best-practices/)
+- [Dockerfile Reference](https://docs.docker.com/engine/reference/builder/)
+- [Docker Compose](https://docs.docker.com/compose/)
+
+## Conclusion
+
+Docker streamlines deployment by:
+1. Creating consistent environments
+2. Simplifying dependency management
+3. Enabling easy scaling
+4. Improving security through isolation
+
+Start small, optimize incrementally, and always test in staging before production!
+
+---
+
+**Example repo**: [github.com/alexjohnson/docker-guide](https://github.com/alexjohnson/docker-guide)
+
+Questions? Reach out on [Twitter](https://twitter.com/alexjohnson)!
diff --git a/templates/dev-portfolio/content/blog/react-performance/featured.png b/templates/dev-portfolio/content/blog/react-performance/featured.png
new file mode 100644
index 00000000..d0a17d39
Binary files /dev/null and b/templates/dev-portfolio/content/blog/react-performance/featured.png differ
diff --git a/templates/dev-portfolio/content/blog/react-performance/index.md b/templates/dev-portfolio/content/blog/react-performance/index.md
new file mode 100644
index 00000000..b63133cb
--- /dev/null
+++ b/templates/dev-portfolio/content/blog/react-performance/index.md
@@ -0,0 +1,397 @@
+---
+title: "React Performance Optimization: A Practical Guide"
+date: 2024-11-22
+summary: "Learn how to identify and fix performance bottlenecks in React applications with real-world examples and profiling techniques"
+tags:
+ - React
+ - Performance
+ - JavaScript
+ - Frontend
+ - Optimization
+authors:
+ - me
+featured: true
+---
+
+React apps can become slow as they grow. This guide covers practical techniques to identify bottlenecks and optimize performance, backed by real-world examples.
+
+## Common Performance Issues
+
+Before optimizing, measure. Use React DevTools Profiler to identify:
+- Unnecessary re-renders
+- Heavy computations
+- Large component trees
+- Inefficient list rendering
+
+## 1. Prevent Unnecessary Re-renders
+
+### Problem: Parent Re-renders Cascade
+
+```jsx
+// ❌ Bad: Child re-renders on every parent update
+function Parent() {
+ const [count, setCount] = useState(0)
+
+ return (
+
+
+ {/* Re-renders even though it doesn't use count! */}
+
+ )
+}
+```
+
+### Solution: React.memo
+
+```jsx
+// ✅ Good: Child only re-renders when props change
+const ExpensiveChild = React.memo(() => {
+ console.log('ExpensiveChild rendered')
+ return {/* expensive rendering */}
+})
+```
+
+**When to use**: Components that render often but rarely change props.
+
+## 2. Optimize Expensive Calculations
+
+### Problem: Recalculating on Every Render
+
+```jsx
+// ❌ Bad: filterItems runs on every render
+function ProductList({ products, searchTerm }) {
+ const filtered = products.filter(p =>
+ p.name.toLowerCase().includes(searchTerm.toLowerCase())
+ ) // Runs even when products/searchTerm haven't changed!
+
+ return {filtered.map(p => - {p.name}
)}
+}
+```
+
+### Solution: useMemo
+
+```jsx
+// ✅ Good: Only recalculates when dependencies change
+function ProductList({ products, searchTerm }) {
+ const filtered = useMemo(() =>
+ products.filter(p =>
+ p.name.toLowerCase().includes(searchTerm.toLowerCase())
+ ),
+ [products, searchTerm]
+ )
+
+ return {filtered.map(p => - {p.name}
)}
+}
+```
+
+**When to use**: Expensive calculations that don't need to run on every render.
+
+## 3. Stabilize Function References
+
+### Problem: New Function on Every Render
+
+```jsx
+// ❌ Bad: handleClick creates new function every render
+function Parent() {
+ const [count, setCount] = useState(0)
+
+ const handleClick = () => setCount(count + 1)
+
+ return // Child re-renders!
+}
+
+const Child = React.memo(({ onClick }) => {
+ return
+})
+```
+
+### Solution: useCallback
+
+```jsx
+// ✅ Good: handleClick reference stays stable
+function Parent() {
+ const [count, setCount] = useState(0)
+
+ const handleClick = useCallback(() => {
+ setCount(c => c + 1) // Use functional update!
+ }, []) // Empty deps because we use functional update
+
+ return
+}
+```
+
+**When to use**: Passing callbacks to memoized child components.
+
+## 4. Virtual Lists for Large Datasets
+
+### Problem: Rendering 10,000 Items
+
+```jsx
+// ❌ Bad: Renders all 10,000 items (slow!)
+function LargeList({ items }) {
+ return (
+
+ {items.map(item => (
+
{item.name}
+ ))}
+
+ )
+}
+```
+
+### Solution: react-window
+
+```jsx
+// ✅ Good: Only renders visible items
+import { FixedSizeList } from 'react-window'
+
+function LargeList({ items }) {
+ const Row = ({ index, style }) => (
+ {items[index].name}
+ )
+
+ return (
+
+ {Row}
+
+ )
+}
+```
+
+**Result**: 10,000 items render in <50ms instead of 2000ms!
+
+## 5. Code Splitting & Lazy Loading
+
+### Problem: Large Bundle Size
+
+```jsx
+// ❌ Bad: Everything loads upfront
+import AdminPanel from './AdminPanel' // 500KB!
+import UserDashboard from './UserDashboard'
+
+function App() {
+ return isAdmin ? :
+}
+```
+
+### Solution: React.lazy
+
+```jsx
+// ✅ Good: Load components on demand
+const AdminPanel = React.lazy(() => import('./AdminPanel'))
+const UserDashboard = React.lazy(() => import('./UserDashboard'))
+
+function App() {
+ return (
+ }>
+ {isAdmin ? : }
+
+ )
+}
+```
+
+**Result**: Initial bundle: 150KB instead of 650KB!
+
+## 6. Optimize Context Usage
+
+### Problem: Context Causes Mass Re-renders
+
+```jsx
+// ❌ Bad: Every consumer re-renders on any state change
+const AppContext = createContext()
+
+function AppProvider({ children }) {
+ const [user, setUser] = useState(null)
+ const [theme, setTheme] = useState('light')
+ const [notifications, setNotifications] = useState([])
+
+ return (
+
+ {children}
+
+ )
+}
+```
+
+### Solution: Split Contexts
+
+```jsx
+// ✅ Good: Separate contexts for different concerns
+const UserContext = createContext()
+const ThemeContext = createContext()
+const NotificationContext = createContext()
+
+function AppProvider({ children }) {
+ const [user, setUser] = useState(null)
+ const [theme, setTheme] = useState('light')
+ const [notifications, setNotifications] = useState([])
+
+ return (
+
+
+
+ {children}
+
+
+
+ )
+}
+```
+
+**Result**: Components only re-render when their specific context changes!
+
+## 7. Debounce Expensive Operations
+
+### Problem: Search Triggers on Every Keystroke
+
+```jsx
+// ❌ Bad: API call on every keystroke
+function SearchBox() {
+ const [query, setQuery] = useState('')
+
+ useEffect(() => {
+ searchAPI(query) // Called 10+ times as user types "javascript"!
+ }, [query])
+
+ return setQuery(e.target.value)} />
+}
+```
+
+### Solution: Custom Debounce Hook
+
+```jsx
+// ✅ Good: API call only after user stops typing
+function useDebounce(value, delay) {
+ const [debouncedValue, setDebouncedValue] = useState(value)
+
+ useEffect(() => {
+ const handler = setTimeout(() => setDebouncedValue(value), delay)
+ return () => clearTimeout(handler)
+ }, [value, delay])
+
+ return debouncedValue
+}
+
+function SearchBox() {
+ const [query, setQuery] = useState('')
+ const debouncedQuery = useDebounce(query, 300)
+
+ useEffect(() => {
+ if (debouncedQuery) {
+ searchAPI(debouncedQuery) // Called once after 300ms pause!
+ }
+ }, [debouncedQuery])
+
+ return setQuery(e.target.value)} />
+}
+```
+
+## 8. Key Props Matter
+
+### Problem: Poor Key Choices
+
+```jsx
+// ❌ Bad: Using index as key causes issues
+{items.map((item, index) => (
+ {item.name}
+))}
+
+// When items reorder, React thinks they're different components!
+```
+
+### Solution: Stable, Unique Keys
+
+```jsx
+// ✅ Good: Use stable IDs
+{items.map(item => (
+ {item.name}
+))}
+```
+
+## Real-World Example: Optimizing a Dashboard
+
+**Before**: Dashboard with 20 widgets, each fetching data, all re-rendering on any state change.
+
+**After optimization**:
+1. Split into separate contexts for user, theme, data
+2. Memoized individual widgets with React.memo
+3. Used useMemo for data transformations
+4. Lazy loaded heavy charts
+5. Debounced filter inputs
+
+**Result**:
+- Initial render: 3000ms → 800ms
+- Interactions: 200ms → 50ms
+- Bundle size: 800KB → 250KB (initial) + 550KB (lazy)
+
+## Profiling Workflow
+
+1. **React DevTools Profiler**
+ - Record interaction
+ - Identify components taking longest
+ - Check why they rendered (props change? parent render?)
+
+2. **Chrome DevTools Performance**
+ - Record performance
+ - Look for long tasks (>50ms)
+ - Check FPS during animations
+
+3. **Lighthouse**
+ - Run audit
+ - Focus on "Time to Interactive"
+ - Check bundle sizes
+
+## Common Pitfalls
+
+❌ **Don't** optimize prematurely
+✅ **Do** measure first, optimize bottlenecks
+
+❌ **Don't** memo everything
+✅ **Do** memo expensive components
+
+❌ **Don't** use useMemo for simple calculations
+✅ **Do** use for actual performance issues
+
+❌ **Don't** forget dependency arrays
+✅ **Do** include all dependencies (or use ESLint plugin)
+
+## Performance Checklist
+
+- [ ] Use React DevTools Profiler to identify issues
+- [ ] Memoize expensive child components
+- [ ] Use useMemo for heavy calculations
+- [ ] Use useCallback for callbacks to memoized children
+- [ ] Implement code splitting for large components
+- [ ] Use virtual lists for large datasets
+- [ ] Debounce expensive operations (search, API calls)
+- [ ] Use proper key props for lists
+- [ ] Split contexts to minimize re-renders
+- [ ] Optimize bundle size (tree shaking, minification)
+
+## Tools & Resources
+
+- [React DevTools](https://chrome.google.com/webstore/detail/react-developer-tools)
+- [react-window](https://react-window.vercel.app/)
+- [Bundle Analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer)
+- [Why Did You Render](https://github.com/welldone-software/why-did-you-render)
+
+## Conclusion
+
+Performance optimization is about:
+1. **Measuring** before optimizing
+2. **Identifying** actual bottlenecks
+3. **Applying** targeted fixes
+4. **Verifying** improvements
+
+Don't optimize blindly—profile, fix, measure, repeat!
+
+---
+
+**Want to dive deeper?** Check out my [React Performance Workshop](https://github.com/alexjohnson/react-perf-workshop).
+
+Questions? Reach out on [Twitter](https://twitter.com/alexjohnson)!
diff --git a/templates/dev-portfolio/content/projects/_index.md b/templates/dev-portfolio/content/projects/_index.md
new file mode 100644
index 00000000..45fba71f
--- /dev/null
+++ b/templates/dev-portfolio/content/projects/_index.md
@@ -0,0 +1,26 @@
+---
+title: 'Projects'
+date: 2024-05-19
+type: landing
+
+design:
+ # Section spacing
+ spacing: '5rem'
+
+# Page sections
+sections:
+ - block: collection
+ content:
+ title: Selected Projects
+ text: I enjoy making things. Here are a selection of projects that I have worked on over the years.
+ filters:
+ folders:
+ - projects
+ design:
+ view: article-grid
+ fill_image: false
+ columns: 3
+ show_date: false
+ show_read_time: false
+ show_read_more: false
+---
diff --git a/templates/dev-portfolio/content/projects/ecommerce-platform/featured.png b/templates/dev-portfolio/content/projects/ecommerce-platform/featured.png
new file mode 100644
index 00000000..5485fa8f
Binary files /dev/null and b/templates/dev-portfolio/content/projects/ecommerce-platform/featured.png differ
diff --git a/templates/dev-portfolio/content/projects/ecommerce-platform/index.md b/templates/dev-portfolio/content/projects/ecommerce-platform/index.md
new file mode 100644
index 00000000..c30d7b05
--- /dev/null
+++ b/templates/dev-portfolio/content/projects/ecommerce-platform/index.md
@@ -0,0 +1,167 @@
+---
+title: "E-Commerce Platform"
+date: 2024-11-15
+summary: "E-commerce API backend with Stripe payments, inventory management, and real-time webhooks"
+tags:
+ - Backend
+ - Node.js
+ - API
+ - E-Commerce
+tech_stack:
+ - React
+ - TypeScript
+ - Node.js
+ - Express
+ - PostgreSQL
+ - Stripe
+ - Redis
+ - Docker
+links:
+ - type: github
+ url: https://github.com/alexjohnson/ecommerce-platform
+ label: Code
+ - type: live
+ url: https://shop-demo.example.com
+ label: Demo
+featured: true
+status: "Live"
+role: "Lead Developer"
+duration: "4 months"
+team_size: 2
+highlights:
+ - "Handles 10k+ concurrent users"
+ - "99.9% uptime SLA"
+ - "Processing $50k+ monthly transactions"
+ - "60% faster page load vs competitors"
+---
+
+A modern, scalable e-commerce platform built from scratch with performance and user experience as top priorities.
+
+## Overview
+
+Built a complete e-commerce solution for a mid-sized retail company looking to expand online. The platform handles everything from product catalog management to payment processing and order fulfillment.
+
+## Key Features
+
+### Customer-Facing
+- **Product Catalog** - Dynamic filtering, sorting, and search with instant results
+- **Shopping Cart** - Real-time inventory checking and price calculations
+- **Checkout** - Secure payment processing via Stripe with Apple Pay/Google Pay support
+- **Order Tracking** - Real-time order status updates with email notifications
+- **User Accounts** - Profile management, order history, and saved addresses
+
+### Admin Dashboard
+- **Inventory Management** - Real-time stock tracking and low-stock alerts
+- **Order Management** - Bulk order processing and fulfillment workflow
+- **Analytics** - Sales dashboards, customer insights, and revenue reporting
+- **Product Management** - Easy product creation with image uploads and variants
+
+## Technical Highlights
+
+### Performance Optimization
+- Implemented Redis caching reducing database queries by 70%
+- Optimized images with WebP format and lazy loading
+- Server-side rendering for critical pages improving SEO and load times
+- CDN integration for global content delivery
+
+### Scalability
+- Microservices architecture allowing independent scaling
+- Horizontal scaling with load balancing
+- Database read replicas for improved query performance
+- Message queues for async processing (order emails, inventory updates)
+
+### Security
+- JWT authentication with refresh tokens
+- Rate limiting to prevent abuse
+- Input validation and sanitization
+- PCI-compliant payment processing via Stripe
+
+## Architecture
+
+```
+┌─────────────┐ ┌──────────────┐ ┌─────────────┐
+│ React SPA │────▶│ REST API │────▶│ PostgreSQL │
+└─────────────┘ │ (Express) │ └─────────────┘
+ └──────┬───────┘
+ │
+ ┌──────▼───────┐
+ │ Redis │
+ │ (Cache) │
+ └──────────────┘
+```
+
+## Challenges & Solutions
+
+### Challenge 1: Inventory Sync
+**Problem**: Multiple users buying same product simultaneously causing overselling
+
+**Solution**: Implemented optimistic locking with Redis to ensure inventory accuracy during concurrent purchases
+
+### Challenge 2: Payment Processing
+**Problem**: Handling payment failures gracefully while maintaining order integrity
+
+**Solution**: Built robust state machine for order processing with automatic retry logic and customer notifications
+
+### Challenge 3: Performance at Scale
+**Problem**: Slow page loads during traffic spikes
+
+**Solution**: Implemented multi-layer caching strategy (CDN, Redis, in-memory) and database query optimization
+
+## Results
+
+- **Performance**: 60% faster page load times compared to previous platform
+- **Conversion**: 25% increase in conversion rate due to improved UX
+- **Uptime**: 99.9% uptime over 6 months in production
+- **Scale**: Successfully handled Black Friday with 10k concurrent users
+- **Revenue**: Processing over $50k in monthly transactions
+
+## Tech Stack Details
+
+**Frontend**
+- React 18 with TypeScript
+- Tailwind CSS for styling
+- React Query for data fetching
+- React Hook Form for forms
+
+**Backend**
+- Node.js with Express
+- PostgreSQL with Prisma ORM
+- Redis for caching and sessions
+- Bull for job queues
+
+**Infrastructure**
+- Docker containers
+- AWS EC2 for hosting
+- AWS S3 for image storage
+- Cloudflare CDN
+- GitHub Actions for CI/CD
+
+**Payment & Services**
+- Stripe for payments
+- SendGrid for emails
+- Sentry for error tracking
+
+## Future Improvements
+
+- [ ] Mobile app (React Native)
+- [ ] Multi-language support
+- [ ] Wishlist and product recommendations
+- [ ] Live chat support
+- [ ] Advanced analytics dashboard
+
+## Screenshots
+
+*(Screenshots would go here in production)*
+
+## Lessons Learned
+
+1. **Start with Performance**: Built with performance in mind from day one rather than optimizing later
+2. **Testing Matters**: Comprehensive test suite caught critical bugs before production
+3. **Monitor Everything**: Proper logging and monitoring essential for maintaining uptime
+4. **User Feedback**: Regular user testing revealed UX issues we wouldn't have found otherwise
+
+---
+
+**Project Status**: ✅ Live in Production
+**GitHub**: [View Source Code](https://github.com/alexjohnson/ecommerce-platform)
+**Demo**: [Try it Live](https://shop-demo.example.com)
diff --git a/templates/dev-portfolio/content/projects/task-manager/featured.png b/templates/dev-portfolio/content/projects/task-manager/featured.png
new file mode 100644
index 00000000..6aeea1c4
Binary files /dev/null and b/templates/dev-portfolio/content/projects/task-manager/featured.png differ
diff --git a/templates/dev-portfolio/content/projects/task-manager/index.md b/templates/dev-portfolio/content/projects/task-manager/index.md
new file mode 100644
index 00000000..96e72598
--- /dev/null
+++ b/templates/dev-portfolio/content/projects/task-manager/index.md
@@ -0,0 +1,170 @@
+---
+title: "TaskFlow - Project Management Tool"
+date: 2024-09-20
+summary: "Real-time collaborative task management application with drag-and-drop Kanban boards and team features"
+tags:
+ - Full-Stack
+ - Next.js
+ - Real-Time
+ - Productivity
+tech_stack:
+ - Next.js
+ - TypeScript
+ - Prisma
+ - PostgreSQL
+ - WebSockets
+ - Tailwind CSS
+links:
+ - type: github
+ url: https://github.com/alexjohnson/taskflow
+ label: Code
+ - type: live
+ url: https://taskflow-demo.example.com
+ label: Demo
+featured: true
+status: "Live"
+role: "Solo Developer"
+duration: "2 months"
+team_size: 1
+highlights:
+ - "Real-time collaboration with WebSockets"
+ - "2000+ active users"
+ - "Featured on Product Hunt"
+---
+
+A modern, intuitive task management tool built for remote teams. Features real-time collaboration, customizable workflows, and beautiful UI.
+
+## Overview
+
+TaskFlow was born out of frustration with existing project management tools being either too complex or lacking essential features. I built a solution that's powerful yet simple to use.
+
+## Key Features
+
+### Core Functionality
+- **Kanban Boards** - Drag-and-drop interface for visual task management
+- **Real-Time Sync** - See changes instantly as team members update tasks
+- **Multiple Views** - Switch between Kanban, List, and Calendar views
+- **Task Details** - Rich descriptions, attachments, comments, and checklists
+- **Labels & Filters** - Organize and find tasks quickly
+
+### Collaboration
+- **Team Workspaces** - Separate spaces for different projects/teams
+- **@Mentions** - Tag team members in comments for notifications
+- **Activity Feed** - Track all changes and updates
+- **Permissions** - Role-based access control (admin, member, viewer)
+
+### Productivity
+- **Keyboard Shortcuts** - Power user features for faster navigation
+- **Templates** - Reusable board templates for common workflows
+- **Due Dates & Reminders** - Never miss a deadline
+- **Time Tracking** - Built-in timer for task duration tracking
+
+## Technical Implementation
+
+### Real-Time Features
+Used WebSockets (Socket.io) for instant updates across all connected clients. Implemented optimistic UI updates for snappy user experience even before server confirmation.
+
+### Drag & Drop
+Built custom drag-and-drop using react-beautiful-dnd with smooth animations and mobile touch support.
+
+### Performance
+- Implemented virtual scrolling for boards with 1000+ tasks
+- Optimized database queries with proper indexing
+- Used Redis for session storage and caching
+- Image optimization with Next.js Image component
+
+### Authentication
+- Secure auth with NextAuth.js
+- Support for email/password and OAuth (Google, GitHub)
+- JWT tokens with automatic refresh
+
+## Architecture
+
+Built as a modern monolith with Next.js API routes:
+
+```
+┌─────────────┐ ┌──────────────┐ ┌─────────────┐
+│ Next.js │────▶│ API Routes │────▶│ PostgreSQL │
+│ (React) │ │ (REST/WS) │ │ + Prisma │
+└─────────────┘ └──────────────┘ └─────────────┘
+ │ │
+ │ ┌──────▼───────┐
+ └────────────▶│ Socket.io │
+ │ (Real-Time) │
+ └──────────────┘
+```
+
+## Challenges Solved
+
+### Real-Time Conflicts
+**Problem**: Multiple users editing same task simultaneously
+
+**Solution**: Implemented operational transformation (OT) for conflict resolution and last-write-wins strategy with conflict notifications
+
+### Mobile Performance
+**Problem**: Drag-and-drop laggy on mobile devices
+
+**Solution**: Optimized touch handlers and reduced re-renders using React.memo and useMemo
+
+### Scale
+**Problem**: Growing user base causing performance issues
+
+**Solution**: Added Redis caching layer and optimized database queries, reducing response time by 65%
+
+## Results
+
+- 📈 **Users**: 2000+ active users within 3 months
+- ⭐ **Product Hunt**: Featured and received 200+ upvotes
+- 🚀 **Performance**: Sub-100ms API response times
+- 💯 **Uptime**: 99.8% uptime since launch
+- 📱 **Mobile**: 40% of traffic from mobile devices
+
+## Tech Stack
+
+**Frontend**
+- Next.js 14 (App Router)
+- TypeScript
+- Tailwind CSS
+- Framer Motion (animations)
+- React Beautiful DnD
+
+**Backend**
+- Next.js API Routes
+- Prisma ORM
+- PostgreSQL
+- Socket.io for WebSockets
+- NextAuth.js for authentication
+
+**Infrastructure**
+- Vercel for hosting
+- Supabase for PostgreSQL
+- Redis Cloud for caching
+- AWS S3 for file storage
+
+## User Feedback
+
+> "Finally, a task manager that doesn't get in my way. The real-time updates are magical!" - Sarah K., Product Manager
+
+> "We switched from Trello and haven't looked back. TaskFlow is faster and more intuitive." - Mike R., Engineering Lead
+
+## Open Source
+
+TaskFlow is open source! Contributions welcome.
+
+**License**: MIT
+**GitHub**: [alexjohnson/taskflow](https://github.com/alexjohnson/taskflow)
+**Demo**: [Try it live](https://taskflow-demo.example.com)
+
+## What's Next
+
+Currently working on:
+- [ ] Mobile apps (iOS & Android)
+- [ ] Gantt chart view
+- [ ] Advanced reporting and analytics
+- [ ] API for third-party integrations
+- [ ] Offline mode support
+
+---
+
+**Status**: ✅ Live & Actively Maintained
+**Try it**: [taskflow-demo.example.com](https://taskflow-demo.example.com)
diff --git a/templates/dev-portfolio/content/projects/weather-app/featured.png b/templates/dev-portfolio/content/projects/weather-app/featured.png
new file mode 100644
index 00000000..8a059e80
Binary files /dev/null and b/templates/dev-portfolio/content/projects/weather-app/featured.png differ
diff --git a/templates/dev-portfolio/content/projects/weather-app/index.md b/templates/dev-portfolio/content/projects/weather-app/index.md
new file mode 100644
index 00000000..713bed0d
--- /dev/null
+++ b/templates/dev-portfolio/content/projects/weather-app/index.md
@@ -0,0 +1,179 @@
+---
+title: "WeatherNow - Real-Time Weather App"
+date: 2024-06-10
+summary: "Beautiful weather application with real-time data, 7-day forecasts, and interactive maps"
+tags:
+ - Frontend
+ - React
+ - API Integration
+ - PWA
+tech_stack:
+ - React
+ - TypeScript
+ - OpenWeather API
+ - Mapbox
+ - Tailwind CSS
+ - Vite
+links:
+ - type: github
+ url: https://github.com/alexjohnson/weather-now
+ label: Code
+ - type: live
+ url: https://weathernow-demo.netlify.app
+ label: Demo
+featured: false
+status: "Live"
+role: "Solo Developer"
+duration: "3 weeks"
+team_size: 1
+highlights:
+ - "PWA with offline support"
+ - "5000+ monthly active users"
+ - "Lighthouse score: 100"
+---
+
+A fast, beautiful weather application that provides real-time weather data, forecasts, and interactive maps. Built as a Progressive Web App with offline support.
+
+## Overview
+
+WeatherNow started as a weekend project to learn PWA development. It evolved into a fully-featured weather app used by thousands of people daily.
+
+## Features
+
+### Weather Data
+- **Current Conditions** - Real-time weather for any location
+- **7-Day Forecast** - Detailed daily forecasts with hourly breakdown
+- **Weather Alerts** - Severe weather notifications
+- **Historical Data** - Past weather data and trends
+
+### User Experience
+- **Location Detection** - Automatic location based on GPS or IP
+- **Search** - Find weather for any city worldwide
+- **Favorites** - Save frequently checked locations
+- **Units** - Toggle between metric and imperial
+- **Dark Mode** - Automatic or manual theme switching
+
+### Progressive Web App
+- **Offline Support** - Access cached data without internet
+- **Install** - Add to home screen like a native app
+- **Fast** - Optimized for performance (Lighthouse 100)
+- **Responsive** - Perfect on any device
+
+## Technical Highlights
+
+### Performance
+- Achieved **100/100 Lighthouse score** across all categories
+- Implemented service workers for offline functionality
+- Optimized bundle size: < 150KB gzipped
+- Lazy loading for images and components
+- Prefetching for instant navigation
+
+### Data Management
+- Smart caching strategy with stale-while-revalidate
+- Background sync for updated forecasts
+- Efficient API usage with request batching
+- Local storage for user preferences
+
+### UI/UX
+- Smooth animations with Framer Motion
+- Interactive weather map with Mapbox
+- Weather icons that match current conditions
+- Accessible (WCAG AA compliant)
+
+## API Integration
+
+Integrated multiple weather APIs for comprehensive data:
+
+```typescript
+// Example: Fetching weather data
+const fetchWeather = async (lat: number, lon: number) => {
+ const response = await fetch(
+ `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}`
+ )
+ return response.json()
+}
+```
+
+## Architecture
+
+```
+┌─────────────┐ ┌──────────────┐
+│ React App │────▶│ OpenWeather │
+│ (Vite) │ │ API │
+└──────┬──────┘ └──────────────┘
+ │
+ │ ┌──────────────┐
+ └───────────▶│ Mapbox │
+ │ API │
+ └──────────────┘
+```
+
+## Challenges
+
+### Challenge: API Rate Limits
+**Solution**: Implemented intelligent caching and request batching to stay within free tier limits while maintaining data freshness
+
+### Challenge: Offline Experience
+**Solution**: Service workers with cache-first strategy for UI, network-first for data with graceful fallbacks
+
+### Challenge: Performance on Slow Networks
+**Solution**: Image optimization, code splitting, and Progressive rendering for instant perceived performance
+
+## Results
+
+- 📈 **Users**: 5000+ monthly active users
+- ⚡ **Performance**: 100 Lighthouse score
+- 📱 **PWA**: 40% of users installed as app
+- 🌍 **Global**: Users from 50+ countries
+- ⭐ **Rating**: 4.8/5 average user rating
+
+## Tech Stack
+
+**Frontend**
+- React 18
+- TypeScript
+- Tailwind CSS
+- Framer Motion
+- Vite (build tool)
+
+**APIs**
+- OpenWeather API
+- Mapbox GL JS
+- IP Geolocation API
+
+**Tools**
+- Workbox (PWA)
+- React Query (data fetching)
+- Zustand (state management)
+
+**Hosting**
+- Netlify
+- Cloudflare CDN
+
+## Open Source
+
+This project is open source and welcomes contributions!
+
+**License**: MIT
+**GitHub**: [alexjohnson/weather-now](https://github.com/alexjohnson/weather-now)
+
+## Lessons Learned
+
+1. **PWAs are powerful**: Service workers enable app-like experiences on the web
+2. **Performance matters**: Users notice and appreciate fast apps
+3. **Caching strategy**: Critical for offline support and API cost management
+4. **Simplicity wins**: Started with core features, added more based on user feedback
+
+## Future Plans
+
+- [ ] Weather widgets for websites
+- [ ] Social features (share weather conditions)
+- [ ] Weather photography integration
+- [ ] Apple Watch & Android Wear apps
+- [ ] Premium features (ad-free, extended forecasts)
+
+---
+
+**Status**: ✅ Live & Maintained
+**Try it**: [weathernow-demo.netlify.app](https://weathernow-demo.netlify.app)
+**GitHub**: [@alexjohnson/weather-now](https://github.com/alexjohnson/weather-now)
diff --git a/templates/dev-portfolio/data/authors/me.yaml b/templates/dev-portfolio/data/authors/me.yaml
new file mode 100644
index 00000000..17478ba8
--- /dev/null
+++ b/templates/dev-portfolio/data/authors/me.yaml
@@ -0,0 +1,100 @@
+schema: hugoblox/author/v1
+slug: me
+is_owner: true
+name:
+ display: Alex Johnson
+ given: Alex
+ family: Johnson
+postnominals: []
+status:
+ icon: "💻" # Emoji shown on avatar badge: 💻 developer, 🎨 designer, 🚀 startup, 🔬 researcher, 🎓 student
+role: Full-Stack Developer
+email: alex@example.com
+bio: |
+ Full-stack developer with 5+ years of experience building scalable web applications.
+ Passionate about modern JavaScript, cloud architecture, and creating delightful user experiences.
+
+affiliations:
+ - name: Tech Corp
+ url: https://techcorp.example.com
+
+links:
+ - icon: at-symbol
+ url: mailto:alex@example.com
+ label: E-mail Me
+ - icon: brands/github
+ url: https://github.com/alexjohnson
+ - icon: brands/linkedin
+ url: https://www.linkedin.com/in/alexjohnson/
+ - icon: brands/x
+ url: https://x.com/alexjohnson
+
+interests:
+ - Web Development
+ - Cloud Architecture
+ - Open Source
+ - Developer Experience
+
+education:
+ - degree: B.S. Computer Science
+ institution: State University
+ start: 2015-09-01
+ end: 2019-05-31
+ summary: |
+ Focus on software engineering and distributed systems.
+ Senior project on distributed caching systems.
+ button:
+ text: View Project
+ url: https://github.com/alexjohnson/senior-project
+ icon: brands/github
+
+experience:
+ - role: Senior Software Engineer
+ org: Tech Corp
+ start: 2023-01-01
+ summary: |
+ Lead development of microservices architecture serving 1M+ users.
+ Improved API response time by 40% through optimization.
+ Mentored team of 5 junior developers.
+ - role: Full-Stack Developer
+ org: Startup Inc
+ start: 2021-06-01
+ end: 2022-12-31
+ summary: |
+ Built and deployed 3 production applications from scratch.
+ Implemented CI/CD pipeline reducing deployment time by 60%.
+ Led migration from monolith to microservices architecture.
+ - role: Junior Developer
+ org: Web Agency
+ start: 2020-01-01
+ end: 2021-05-31
+ summary: |
+ Developed client websites using React and modern web technologies.
+ Participated in code reviews and agile ceremonies.
+
+skills:
+ - name: Development
+ items:
+ - label: TypeScript
+ level: 5
+ - label: React
+ level: 5
+ - label: Node.js
+ level: 5
+ - label: Python
+ level: 4
+ - name: DevOps
+ items:
+ - label: Docker
+ level: 4
+ - label: AWS
+ level: 4
+ - label: CI/CD
+ level: 5
+
+languages:
+ - name: English
+ level: 5
+ label: Native
+
+awards: []
diff --git a/templates/dev-portfolio/go.mod b/templates/dev-portfolio/go.mod
new file mode 100644
index 00000000..41fbe9cf
--- /dev/null
+++ b/templates/dev-portfolio/go.mod
@@ -0,0 +1,8 @@
+module github.com/HugoBlox/kit/templates/dev-portfolio-free
+
+go 1.19
+
+require (
+ github.com/HugoBlox/kit/modules/integrations/netlify v0.0.0-20260102210655-66cba27dc652
+ github.com/HugoBlox/kit/modules/blox v0.0.0-20260102211810-cdaf97afb270
+)
diff --git a/templates/dev-portfolio/hugoblox.yaml b/templates/dev-portfolio/hugoblox.yaml
new file mode 100644
index 00000000..9fb28766
--- /dev/null
+++ b/templates/dev-portfolio/hugoblox.yaml
@@ -0,0 +1,5 @@
+build:
+ hugo_version: '0.154.2'
+template:
+ id: "dev-portfolio"
+ name: "Developer Portfolio"
diff --git a/templates/dev-portfolio/netlify.toml b/templates/dev-portfolio/netlify.toml
new file mode 100644
index 00000000..1d11f881
--- /dev/null
+++ b/templates/dev-portfolio/netlify.toml
@@ -0,0 +1,61 @@
+[build]
+ command = """
+ set -e
+ echo "=== Starting Blog build process ==="
+ echo "Node version: $(node --version)"
+ echo "pnpm version: $(pnpm --version)"
+ echo "Hugo version: $(hugo version)"
+ echo "Go version: $(go version || echo 'Go not available')"
+
+ echo "=== Installing dependencies ==="
+ pnpm install --verbose --no-frozen-lockfile
+
+ echo "=== Running Hugo build ==="
+ hugo --gc --minify -b $URL --logLevel debug --printI18nWarnings --printPathWarnings
+
+ echo "=== Running Pagefind indexing ==="
+ pnpm run pagefind
+
+ echo "=== Build completed successfully ==="
+ """
+ publish = "public"
+
+[build.environment]
+ HUGO_VERSION = "0.154.2"
+ GO_VERSION = "1.21.5"
+ NODE_VERSION = "22"
+ # Netlify runs an implicit install step; ensure it never enforces frozen lockfiles
+ PNPM_FLAGS = "--no-frozen-lockfile"
+ HUGO_ENABLEGITINFO = "true"
+ HUGO_LOG_I18N_WARNINGS = "true"
+ HUGO_LOG_WARNINGS = "true"
+ FORCE_COLOR = "1"
+ PNPM_LOG_LEVEL = "debug"
+
+[context.production.environment]
+ HUGO_ENV = "production"
+
+[context.deploy-preview]
+ command = """
+ set -e
+ echo "=== Deploy Preview Build ==="
+ echo "Deploy URL: $DEPLOY_PRIME_URL"
+ pnpm install --verbose --no-frozen-lockfile
+ hugo --gc --minify --buildFuture -b $DEPLOY_PRIME_URL --logLevel debug --printI18nWarnings --printPathWarnings
+ pnpm run pagefind
+ """
+
+[context.branch-deploy]
+ command = """
+ set -e
+ echo "=== Branch Deploy Build ==="
+ echo "Deploy URL: $DEPLOY_PRIME_URL"
+ pnpm install --verbose --no-frozen-lockfile
+ hugo --gc --minify -b $DEPLOY_PRIME_URL --logLevel debug --printI18nWarnings --printPathWarnings
+ pnpm run pagefind
+ """
+
+[[plugins]]
+ package = "netlify-plugin-hugo-cache-resources"
+ [plugins.inputs]
+ debug = true
diff --git a/templates/dev-portfolio/package.json b/templates/dev-portfolio/package.json
new file mode 100644
index 00000000..a154de2c
--- /dev/null
+++ b/templates/dev-portfolio/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "hugo-blox-dev-portfolio-free",
+ "version": "1.0.0",
+ "private": true,
+ "packageManager": "pnpm@10.14.0",
+ "description": "Modern developer portfolio template for Hugo Blox with Tailwind CSS v4 - Free version",
+ "scripts": {
+ "dev": "hugo server --disableFastRender",
+ "build": "hugo --minify && pnpm run pagefind",
+ "pagefind": "pagefind --site public"
+ },
+ "dependencies": {
+ "@tailwindcss/cli": "^4.1.12",
+ "@tailwindcss/typography": "^0.5.10",
+ "pagefind": "^1.4.0",
+ "preact": "^10.27.2",
+ "tailwindcss": "^4.1.12"
+ }
+}
diff --git a/templates/dev-portfolio/pnpm-lock.yaml b/templates/dev-portfolio/pnpm-lock.yaml
new file mode 100644
index 00000000..2049b436
--- /dev/null
+++ b/templates/dev-portfolio/pnpm-lock.yaml
@@ -0,0 +1,714 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@tailwindcss/cli':
+ specifier: ^4.1.12
+ version: 4.1.18
+ '@tailwindcss/typography':
+ specifier: ^0.5.10
+ version: 0.5.19(tailwindcss@4.1.18)
+ pagefind:
+ specifier: ^1.4.0
+ version: 1.4.0
+ preact:
+ specifier: ^10.27.2
+ version: 10.28.1
+ tailwindcss:
+ specifier: ^4.1.12
+ version: 4.1.18
+
+packages:
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/remapping@2.3.5':
+ resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
+
+ '@pagefind/darwin-arm64@1.4.0':
+ resolution: {integrity: sha512-2vMqkbv3lbx1Awea90gTaBsvpzgRs7MuSgKDxW0m9oV1GPZCZbZBJg/qL83GIUEN2BFlY46dtUZi54pwH+/pTQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@pagefind/darwin-x64@1.4.0':
+ resolution: {integrity: sha512-e7JPIS6L9/cJfow+/IAqknsGqEPjJnVXGjpGm25bnq+NPdoD3c/7fAwr1OXkG4Ocjx6ZGSCijXEV4ryMcH2E3A==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@pagefind/freebsd-x64@1.4.0':
+ resolution: {integrity: sha512-WcJVypXSZ+9HpiqZjFXMUobfFfZZ6NzIYtkhQ9eOhZrQpeY5uQFqNWLCk7w9RkMUwBv1HAMDW3YJQl/8OqsV0Q==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@pagefind/linux-arm64@1.4.0':
+ resolution: {integrity: sha512-PIt8dkqt4W06KGmQjONw7EZbhDF+uXI7i0XtRLN1vjCUxM9vGPdtJc2mUyVPevjomrGz5M86M8bqTr6cgDp1Uw==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@pagefind/linux-x64@1.4.0':
+ resolution: {integrity: sha512-z4oddcWwQ0UHrTHR8psLnVlz6USGJ/eOlDPTDYZ4cI8TK8PgwRUPQZp9D2iJPNIPcS6Qx/E4TebjuGJOyK8Mmg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@pagefind/windows-x64@1.4.0':
+ resolution: {integrity: sha512-NkT+YAdgS2FPCn8mIA9bQhiBs+xmniMGq1LFPDhcFn0+2yIUEiIG06t7bsZlhdjknEQRTSdT7YitP6fC5qwP0g==}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.1':
+ resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+ engines: {node: '>= 10.0.0'}
+
+ '@tailwindcss/cli@4.1.18':
+ resolution: {integrity: sha512-sMZ+lZbDyxwjD2E0L7oRUjJ01Ffjtme5OtjvvnC+cV4CEDcbqzbp25TCpxHj6kWLU9+DlqJOiNgSOgctC2aZmg==}
+ hasBin: true
+
+ '@tailwindcss/node@4.1.18':
+ resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==}
+
+ '@tailwindcss/oxide-android-arm64@4.1.18':
+ resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [android]
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.18':
+ resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-darwin-x64@4.1.18':
+ resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.18':
+ resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
+ resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==}
+ engines: {node: '>= 10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
+ resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
+ resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
+ resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.18':
+ resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.18':
+ resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+ bundledDependencies:
+ - '@napi-rs/wasm-runtime'
+ - '@emnapi/core'
+ - '@emnapi/runtime'
+ - '@tybys/wasm-util'
+ - '@emnapi/wasi-threads'
+ - tslib
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
+ resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==}
+ engines: {node: '>= 10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
+ resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==}
+ engines: {node: '>= 10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@tailwindcss/oxide@4.1.18':
+ resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==}
+ engines: {node: '>= 10'}
+
+ '@tailwindcss/typography@0.5.19':
+ resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==}
+ peerDependencies:
+ tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ cssesc@3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ detect-libc@1.0.3:
+ resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
+ detect-libc@2.1.2:
+ resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
+ engines: {node: '>=8'}
+
+ enhanced-resolve@5.18.4:
+ resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==}
+ engines: {node: '>=10.13.0'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ graceful-fs@4.2.11:
+ resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ jiti@2.6.1:
+ resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
+ hasBin: true
+
+ lightningcss-android-arm64@1.30.2:
+ resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.30.2:
+ resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.30.2:
+ resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.30.2:
+ resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.30.2:
+ resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.30.2:
+ resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.30.2:
+ resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.30.2:
+ resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.30.2:
+ resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.30.2:
+ resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.30.2:
+ resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.30.2:
+ resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==}
+ engines: {node: '>= 12.0.0'}
+
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ mri@1.2.0:
+ resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
+ engines: {node: '>=4'}
+
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
+ pagefind@1.4.0:
+ resolution: {integrity: sha512-z2kY1mQlL4J8q5EIsQkLzQjilovKzfNVhX8De6oyE6uHpfFtyBaqUpcl/XzJC/4fjD8vBDyh1zolimIcVrCn9g==}
+ hasBin: true
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ postcss-selector-parser@6.0.10:
+ resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
+ engines: {node: '>=4'}
+
+ preact@10.28.1:
+ resolution: {integrity: sha512-u1/ixq/lVQI0CakKNvLDEcW5zfCjUQfZdK9qqWuIJtsezuyG6pk9TWj75GMuI/EzRSZB/VAE43sNWWZfiy8psw==}
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ tailwindcss@4.1.18:
+ resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==}
+
+ tapable@2.3.0:
+ resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==}
+ engines: {node: '>=6'}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ util-deprecate@1.0.2:
+ resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+snapshots:
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/remapping@2.3.5':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.31':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@pagefind/darwin-arm64@1.4.0':
+ optional: true
+
+ '@pagefind/darwin-x64@1.4.0':
+ optional: true
+
+ '@pagefind/freebsd-x64@1.4.0':
+ optional: true
+
+ '@pagefind/linux-arm64@1.4.0':
+ optional: true
+
+ '@pagefind/linux-x64@1.4.0':
+ optional: true
+
+ '@pagefind/windows-x64@1.4.0':
+ optional: true
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher@2.5.1':
+ dependencies:
+ detect-libc: 1.0.3
+ is-glob: 4.0.3
+ micromatch: 4.0.8
+ node-addon-api: 7.1.1
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.1
+ '@parcel/watcher-darwin-arm64': 2.5.1
+ '@parcel/watcher-darwin-x64': 2.5.1
+ '@parcel/watcher-freebsd-x64': 2.5.1
+ '@parcel/watcher-linux-arm-glibc': 2.5.1
+ '@parcel/watcher-linux-arm-musl': 2.5.1
+ '@parcel/watcher-linux-arm64-glibc': 2.5.1
+ '@parcel/watcher-linux-arm64-musl': 2.5.1
+ '@parcel/watcher-linux-x64-glibc': 2.5.1
+ '@parcel/watcher-linux-x64-musl': 2.5.1
+ '@parcel/watcher-win32-arm64': 2.5.1
+ '@parcel/watcher-win32-ia32': 2.5.1
+ '@parcel/watcher-win32-x64': 2.5.1
+
+ '@tailwindcss/cli@4.1.18':
+ dependencies:
+ '@parcel/watcher': 2.5.1
+ '@tailwindcss/node': 4.1.18
+ '@tailwindcss/oxide': 4.1.18
+ enhanced-resolve: 5.18.4
+ mri: 1.2.0
+ picocolors: 1.1.1
+ tailwindcss: 4.1.18
+
+ '@tailwindcss/node@4.1.18':
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ enhanced-resolve: 5.18.4
+ jiti: 2.6.1
+ lightningcss: 1.30.2
+ magic-string: 0.30.21
+ source-map-js: 1.2.1
+ tailwindcss: 4.1.18
+
+ '@tailwindcss/oxide-android-arm64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-arm64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-darwin-x64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-freebsd-x64@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-gnu@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-arm64-musl@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-gnu@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-linux-x64-musl@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-wasm32-wasi@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-win32-arm64-msvc@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide-win32-x64-msvc@4.1.18':
+ optional: true
+
+ '@tailwindcss/oxide@4.1.18':
+ optionalDependencies:
+ '@tailwindcss/oxide-android-arm64': 4.1.18
+ '@tailwindcss/oxide-darwin-arm64': 4.1.18
+ '@tailwindcss/oxide-darwin-x64': 4.1.18
+ '@tailwindcss/oxide-freebsd-x64': 4.1.18
+ '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18
+ '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18
+ '@tailwindcss/oxide-linux-arm64-musl': 4.1.18
+ '@tailwindcss/oxide-linux-x64-gnu': 4.1.18
+ '@tailwindcss/oxide-linux-x64-musl': 4.1.18
+ '@tailwindcss/oxide-wasm32-wasi': 4.1.18
+ '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18
+ '@tailwindcss/oxide-win32-x64-msvc': 4.1.18
+
+ '@tailwindcss/typography@0.5.19(tailwindcss@4.1.18)':
+ dependencies:
+ postcss-selector-parser: 6.0.10
+ tailwindcss: 4.1.18
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ cssesc@3.0.0: {}
+
+ detect-libc@1.0.3: {}
+
+ detect-libc@2.1.2: {}
+
+ enhanced-resolve@5.18.4:
+ dependencies:
+ graceful-fs: 4.2.11
+ tapable: 2.3.0
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ graceful-fs@4.2.11: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-number@7.0.0: {}
+
+ jiti@2.6.1: {}
+
+ lightningcss-android-arm64@1.30.2:
+ optional: true
+
+ lightningcss-darwin-arm64@1.30.2:
+ optional: true
+
+ lightningcss-darwin-x64@1.30.2:
+ optional: true
+
+ lightningcss-freebsd-x64@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.30.2:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.30.2:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.30.2:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.30.2:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.30.2:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.30.2:
+ optional: true
+
+ lightningcss@1.30.2:
+ dependencies:
+ detect-libc: 2.1.2
+ optionalDependencies:
+ lightningcss-android-arm64: 1.30.2
+ lightningcss-darwin-arm64: 1.30.2
+ lightningcss-darwin-x64: 1.30.2
+ lightningcss-freebsd-x64: 1.30.2
+ lightningcss-linux-arm-gnueabihf: 1.30.2
+ lightningcss-linux-arm64-gnu: 1.30.2
+ lightningcss-linux-arm64-musl: 1.30.2
+ lightningcss-linux-x64-gnu: 1.30.2
+ lightningcss-linux-x64-musl: 1.30.2
+ lightningcss-win32-arm64-msvc: 1.30.2
+ lightningcss-win32-x64-msvc: 1.30.2
+
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ mri@1.2.0: {}
+
+ node-addon-api@7.1.1: {}
+
+ pagefind@1.4.0:
+ optionalDependencies:
+ '@pagefind/darwin-arm64': 1.4.0
+ '@pagefind/darwin-x64': 1.4.0
+ '@pagefind/freebsd-x64': 1.4.0
+ '@pagefind/linux-arm64': 1.4.0
+ '@pagefind/linux-x64': 1.4.0
+ '@pagefind/windows-x64': 1.4.0
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ postcss-selector-parser@6.0.10:
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+
+ preact@10.28.1: {}
+
+ source-map-js@1.2.1: {}
+
+ tailwindcss@4.1.18: {}
+
+ tapable@2.3.0: {}
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ util-deprecate@1.0.2: {}
diff --git a/templates/dev-portfolio/static/uploads/resume.pdf b/templates/dev-portfolio/static/uploads/resume.pdf
new file mode 100644
index 00000000..d0489a3a
Binary files /dev/null and b/templates/dev-portfolio/static/uploads/resume.pdf differ