Theme Creation Quick Start
What You Need to Know
A MintyFlask theme is a collection of templates and styles that define your site's appearance. Themes build on top of mixins (like blog, portfolio) to create a complete website.
Three key parts of a theme:
- Templates - Page layouts and structure (Jinja2)
- CSS - Visual styling (Tailwind + custom CSS)
- Configuration - Theme metadata (YAML)
Most themes start by using existing mixins and adding custom styling.
Your First Theme in 3 Steps
Step 1: Create Theme Directory
themes/
└── my-blog/ # Your theme name
├── config/
│ └── theme.yaml # Theme configuration
├── templates/
│ └── pages/ # Your page templates
│ └── homepage.html
└── static/
└── css/
└── src/
└── input.css # CSS entry point
Step 2: Configure Your Theme
# themes/my-blog/config/theme.yaml
name: "My Blog"
version: "1.0.0"
parent: "_core"
description: "A personal blog theme"
author: "Your Name"
dependencies:
templates:
- "_core/layouts/base.html"
css:
- "_core/foundations/typography.css"
js:
- "_core/components/theme-switcher.js"
features:
- blog-posts
- categories
- tags
Step 3: Create Your CSS Entry Point
/* themes/my-blog/static/css/src/input.css */
/* Import Tailwind */
@import "tailwindcss";
/* Define dark mode variant */
@custom-variant dark (&:where(.dark, .dark *));
/* Declare sources for Tailwind */
@source "../../../../../themes/_core/templates";
@source "../../../../../mixins/blog/templates";
@source "../../../templates";
/* CSS Layers */
@layer base {
/* Import core foundations */
@import "../../../../../themes/_core/static/css/foundations/index.css";
}
@layer components {
/* Import core components */
@import "../../../../../themes/_core/static/css/components/index.css";
/* Import blog mixin */
@import "../../../../../mixins/blog/static/css/blog.css";
}
@layer theme {
/* Your custom theme styles */
:root {
/* Override design tokens */
--color-primary: oklch(60% 0.15 250);
--color-secondary: oklch(65% 0.12 180);
}
}
That's it! You now have a functioning theme that uses the blog mixin.
Creating Your Homepage
{# themes/my-blog/templates/pages/homepage.html #}
{% extends "layouts/blog-home.html" %}
{# Customise the hero section #}
{% set hero_title = "Welcome to My Blog" %}
{% set hero_subtitle = "Thoughts on development and design" %}
{% set hero_cta_text = "Read Articles" %}
{# Configure recent posts section #}
{% set recent_posts_title = "Latest Posts" %}
{% set recent_posts_limit = 6 %}
Flask route:
@blog_bp.route('/')
def homepage():
posts = get_recent_posts(limit=10)
return render_template('pages/homepage.html', posts=posts)
Customising Mixin Styles
Add your custom styles in the theme layer:
/* themes/my-blog/static/css/src/input.css */
@layer theme {
/* Override blog post card */
.blog-post-card {
border-radius: 0; /* Square corners */
border-width: 2px;
}
/* Custom hero styling */
.hero-banner {
background: linear-gradient(
135deg,
var(--color-primary),
var(--color-secondary)
);
padding: 4rem 2rem;
text-align: centre;
}
}
Common Theme Patterns
Pattern 1: Using a Mixin Layout
{# themes/my-blog/templates/pages/category.html #}
{% extends "layouts/post-list.html" %}
{# Configure the layout #}
{% set page_title = "Category: " + category %}
{% set pagination_endpoint = 'blog_bp.category_view' %}
{% set pagination_params = {'category': category} %}
Pattern 2: Creating a Custom Page
{# themes/my-blog/templates/pages/about.html #}
{% extends resolve_base_template('base.html') %}
{% block content %}
<article class="prose prose-lg mx-auto py-12">
<h1>About Me</h1>
<p>I'm a developer who loves writing about code...</p>
</article>
{% endblock %}
Pattern 3: Custom Component
{# themes/my-blog/templates/pages/landing.html #}
{% extends resolve_base_template('base.html') %}
{% block content %}
<div class="hero-banner">
<h1 class="text-4xl font-bold mb-4">Welcome</h1>
<p class="text-xl mb-8">Start your journey here</p>
<a href="/blog" class="btn-base btn-intent-primary btn-size-lg">
Get Started
</a>
</div>
<div class="container mx-auto py-12">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
{% for feature in features %}
<div class="card-base card-intent-feature">
<div class="card-body text-centre">
<div class="text-4xl mb-4">{{ feature.icon }}</div>
<h3 class="card-title">{{ feature.title }}</h3>
<p class="card-description">{{ feature.description }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
Design Tokens
Customise your theme's appearance through tokens:
@layer theme {
:root {
/* Colours */
--color-primary: oklch(60% 0.15 250);
--color-secondary: oklch(65% 0.12 180);
/* Spacing (make everything more spacious) */
--spacing-md: 1.25rem;
--spacing-lg: 2rem;
--spacing-xl: 3rem;
/* Typography (larger text) */
--text-base: 1.125rem;
--text-lg: 1.25rem;
--text-xl: 1.5rem;
/* Border radius (rounder corners) */
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
}
}
Directory Structure
Complete theme structure:
themes/my-blog/
├── config/
│ └── theme.yaml # Theme metadata
├── templates/
│ ├── pages/ # Your page templates
│ │ ├── homepage.html
│ │ ├── about.html
│ │ └── contact.html
│ └── layouts/ # Custom layouts (optional)
│ └── custom-layout.html
└── static/
├── css/
│ ├── src/
│ │ └── input.css # CSS entry point
│ └── dist/
│ └── output.css # Built CSS
└── images/ # Theme images
└── logo.png
Using Multiple Mixins
Combine multiple mixins in one theme:
/* themes/agency/static/css/src/input.css */
@layer components {
/* Import multiple mixins */
@import "../../../../../mixins/blog/static/css/blog.css";
@import "../../../../../mixins/portfolio/static/css/portfolio.css";
@import "../../../../../mixins/team/static/css/team.css";
}
@layer theme {
/* Harmonise styling across all mixins */
.blog-post-card,
.portfolio-card-base,
.team-member-card {
border-radius: var(--radius-lg);
border: 2px solid var(--color-border);
}
}
Dark Mode Setup
Enable dark mode in your theme:
/* themes/my-blog/static/css/src/input.css */
@layer theme {
/* Light mode (default) */
:root {
--color-surface: oklch(98% 0 0);
--color-text-primary: oklch(20% 0 0);
}
/* Dark mode */
.dark {
--color-surface: oklch(20% 0 0);
--color-text-primary: oklch(95% 0 0);
}
}
Toggle button (add to base template):
<button id="theme-toggle" class="btn-base btn-intent-secondary btn-size-sm">
<span class="light-icon">🌞</span>
<span class="dark-icon">🌙</span>
</button>
<script>
const toggle = document.getElementById("theme-toggle");
const html = document.documentElement;
toggle.addEventListener("click", () => {
html.classList.toggle("dark");
localStorage.setItem(
"theme",
html.classList.contains("dark") ? "dark" : "light",
);
});
// Load preference
if (localStorage.getItem("theme") === "dark") {
html.classList.add("dark");
}
</script>
Building Your CSS
# Install Tailwind CLI
npm install -D tailwindcss
# Build CSS (development)
npx tailwindcss -i themes/my-blog/static/css/src/input.css \
-o themes/my-blog/static/css/dist/output.css \
--watch
# Build CSS (production)
npx tailwindcss -i themes/my-blog/static/css/src/input.css \
-o themes/my-blog/static/css/dist/output.css \
--minify
Quick Checklist
Theme setup:
- Create theme directory
- Add
theme.yamlconfiguration - Create
input.csswith layers - Create homepage template
- Build CSS
Customisation:
- Override design tokens
- Customise mixin components
- Add dark mode styles
- Test responsive design
- Add custom pages
Polish:
- Add theme logo/images
- Test with sample content
- Verify all links work
- Check accessibility
- Test dark mode
Common Issues
CSS not loading
Check:
- Did you build the CSS?
- Is the CSS path correct in your base template?
- Are imports in
input.csscorrect?
Template not found
Check:
- Is the template in the right directory?
- Are you using
resolve_base_template()correctly? - Is the template search path configured?
Styles not applying
Check:
- Are you using the correct layer (
@layer theme)? - Did you rebuild the CSS?
- Are class names spelled correctly?
Next Steps
You now know how to create a basic theme. For more details:
- Theme Creation User Guide - Advanced customisation patterns
- CSS Architecture Quick Start - Understanding layers
- Component Development - Creating custom components
Summary
Creating a theme:
- Set up structure - Directories and configuration
- Create input.css - Import core, mixins, add custom styles
- Build templates - Use mixin layouts or create custom
- Customise tokens - Override colours, spacing, typography
- Build CSS - Compile with Tailwind
- Test everything - Pages, responsive, dark mode
With these steps, you can create professional themes that leverage MintyFlask's mixin system.