This Flask app now uses Tailwind CSS with the @ianlintner/theme preset for a modern, responsive interface with built-in dark mode support.
- Tailwind CSS 3.3+ - Utility-first CSS framework
- @ianlintner/theme - Custom theme preset with semantic colors and components
- Vanilla JavaScript - No frontend framework dependencies
flask_app/
├── templates/
│ ├── base.html # Main layout with header, footer, modal
│ ├── index.html # Dashboard with search and filtering
│ └── [other pages...]
├── static/
│ ├── input.css # Entry point (imports theme styles & Tailwind)
│ ├── output.css # Generated Tailwind CSS (built via npm)
│ └── [other assets...]
- Input:
flask_app/static/input.cssimports theme styles and Tailwind directives - Build Tool: Tailwind CSS CLI
- Output:
flask_app/static/output.css(loaded by Flask templates)
# Install npm dependencies
npm install
# Build CSS (generates flask_app/static/output.css)
npm run build:cssWatch mode (auto-rebuild on file changes):
npm run watch:cssManual build:
npm run build:cssThe templates reference the built CSS:
<link rel="stylesheet" href="{{ url_for('static', filename='output.css') }}">The theme provides semantic color tokens (via CSS variables) that work in light and dark modes:
- Primary: Blue (default brand color)
- Destructive: Red (alerts, errors)
- Muted: Gray (secondary text, disabled states)
- Accent: System accent color
Dark mode is automatically applied based on:
- localStorage preference (
themekey) - System preference (
prefers-color-scheme) - Default: Dark mode
Toggle via the theme selector in the header:
// Theme toggle (in base.html)
document.documentElement.classList.toggle('dark', theme === 'dark');All components use Tailwind's responsive prefixes:
sm:,md:,lg:breakpoints for mobile-first design- Grid layouts adapt from 1 → 2 → 3 columns
Edit tailwind.config.js:
const config = {
presets: [themePreset],
theme: {
extend: {
colors: {
// Add custom colors
brand: '#0066cc',
},
spacing: {
// Add custom spacing
},
},
},
};In flask_app/static/input.css:
@layer components {
.my-card {
@apply bg-white dark:bg-slate-900 rounded-lg shadow-md p-4;
}
}The theme uses CSS variables defined by @ianlintner/theme. Override them in your input.css:
:root {
--primary: 200 100% 50%; /* HSL format */
--secondary: 280 100% 50%;
}
[data-theme="light"] {
--background: 0 0% 100%;
--foreground: 0 0% 0%;
}<article class="demo-card">
<div class="demo-card-title">Card Title</div>
<p class="demo-card-description">Description text</p>
<button class="px-3 py-2 bg-blue-600 text-white rounded-lg">Action</button>
</article>The demo modal uses vanilla JavaScript:
openModal(title); // Show modal
closeModal(); // Hide modal
runDemo(id, title); // Run and display demo output<span class="badge-info">Info badge</span>
<span class="badge-warning">Warning badge</span>- Tailwind CSS: ~32 KB (gzipped)
- Theme Styles: Included in Tailwind output
- JavaScript: ~2 KB (modal & search logic)
- Unused CSS automatically removed (Tailwind purge)
- Template paths configured in
tailwind.config.js - Dark mode using CSS class (no extra HTTP requests)
# Clear and rebuild
rm flask_app/static/output.css
npm run build:css- Verify
output.cssis being served: Check Flask logs - Clear browser cache (Ctrl+Shift+Del or Cmd+Shift+Delete)
- Verify
darkclass is on<html>element
# Reinstall all packages
rm -rf node_modules package-lock.json
npm install
npm run build:css# Build CSS for production
npm run build:cssThe generated flask_app/static/output.css is all that's needed—Node.js is not required at runtime.
npm install
npm run build:css
python -m pip install -e ".[dev]"
pytest -q