# TailwindCSS Migration Implementation Plan
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Replace the ~1000 lines of custom CSS with TailwindCSS utility classes, while preserving the existing design and dark mode support.
**Architecture:**
1. Install TailwindCSS as a dev dependency with PostCSS
2. Create a minimal `tailwind.config.js` that extends the default theme with the existing color palette
3. Keep a small `base.css` for critical custom styles that can't be replaced (e.g., CodeMirror overrides, Milkdown-specific styles)
4. Replace HTML class names with Tailwind utility classes in templates
5. Use `@apply` for complex patterns that appear multiple times
**Tech Stack:** TailwindCSS 4.x, PostCSS, existing esbuild for CSS bundling
---
## Current CSS Inventory
| File | Lines | Purpose |
|------|-------|---------|
| `static/css/style.css` | 427 | Base styles, navbar, cards, buttons, forms, alerts |
| `static/css/editor.css` | 419 | Editor layout, toolbar, modals, split pane |
| `static/css/markdown.css` | 84 | Markdown preview rendering |
| `static/css/diff.css` | 60 | Diff view styling |
| **Total** | **990** | |
---
## Chunk 1: Setup TailwindCSS
**Files:**
- Modify: `/Users/johnluther/projects/diffdown/package.json`
- Create: `/Users/johnluther/projects/diffdown/tailwind.config.js`
- Create: `/Users/johnluther/projects/diffdown/postcss.config.js`
- Create: `/Users/johnluther/projects/diffdown/src/styles/input.css`
- [ ] **Step 1: Install TailwindCSS and dependencies**
Run: `npm install -D tailwindcss postcss autoprefixer`
- [ ] **Step 2: Initialize Tailwind config**
```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./templates/**/*.html",
"./static/**/*.js",
],
darkMode: 'class', // Use data-theme attribute for dark mode
theme: {
extend: {
colors: {
bg: 'var(--bg)',
'bg-card': 'var(--bg-card)',
text: 'var(--text)',
'text-muted': 'var(--text-muted)',
border: 'var(--border)',
primary: 'var(--primary)',
'primary-hover': 'var(--primary-hover)',
danger: 'var(--danger)',
success: 'var(--success)',
'code-bg': 'var(--code-bg)',
'alert-error-bg': 'var(--alert-error-bg)',
'alert-error-border': 'var(--alert-error-border)',
},
fontFamily: {
sans: ['"Barlow"', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', 'sans-serif'],
heading: ['"Lexend"', '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', 'sans-serif'],
mono: ['"JetBrains Mono"', '"Fira Code"', '"Cascadia Code"', 'monospace'],
},
borderRadius: {
DEFAULT: '6px',
},
},
},
plugins: [],
}
```
- [ ] **Step 3: Create PostCSS config**
```javascript
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
```
- [ ] **Step 4: Create input.css for Tailwind directives**
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Keep custom font import */
@import url(https://fonts.bunny.net/css?family=barlow:100,200,300,400,500,600|lexend:100,200,300,400,500,600,700,800,900);
/* CSS variables - kept for backward compatibility */
:root {
--bg: #fafafa;
--bg-card: #fff;
--text: #1a1a2e;
--text-muted: #6b7280;
--border: #e5e7eb;
--primary: #2563eb;
--primary-hover: #1d4ed8;
--danger: #dc2626;
--success: #16a34a;
--code-bg: #f3f4f6;
--alert-error-bg: #fef2f2;
--alert-error-border: #fecaca;
}
[data-theme="dark"] {
--bg: #0d1117;
--bg-card: #161b22;
--text: #e6edf3;
--text-muted: #ededed;
--text-secondary: #d4d4d4;
--border: #30363d;
--code-bg: #1f2428;
--primary: #388bfd;
--primary-hover: #58a6ff;
--danger: #f85149;
--success: #3fb950;
--alert-error-bg: #1c0608;
--alert-error-border: #6e1c20;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg: #0d1117;
--bg-card: #161b22;
--text: #e6edf3;
--text-muted: #ededed;
--text-secondary: #d4d4d4;
--border: #30363d;
--code-bg: #1f2428;
--primary: #388bfd;
--primary-hover: #58a6ff;
--danger: #f85149;
--success: #3fb950;
--alert-error-bg: #1c0608;
--alert-error-border: #6e1c20;
}
}
```
- [ ] **Step 5: Add build script to package.json**
```json
"scripts": {
"build:css": "npx tailwindcss -i ./src/styles/input.css -o ./static/css/tailwind.css",
"build:collab": "npx esbuild node_modules/prosemirror-collab/dist/index.js --bundle --format=esm --outfile=static/vendor/collab.js",
"build": "npm run build:css && npm run build:collab"
}
```
- [ ] **Step 6: Build TailwindCSS**
Run: `npm run build:css`
Expected: Creates `static/css/tailwind.css` with Tailwind utilities
- [ ] **Step 7: Commit**
```bash
git add package.json tailwind.config.js postcss.config.js src/styles/input.css static/css/tailwind.css
git commit -m "feat: add TailwindCSS setup"
```
---
## Chunk 2: Replace CSS in base.html
**Files:**
- Modify: `/Users/johnluther/projects/diffdown/templates/base.html`
- [ ] **Step 1: Replace navbar styles with Tailwind classes**
Old:
```html
```
New:
```html
```
- [ ] **Step 2: Replace main and alert styles**
Old:
```html
{{if .Error}}
{{.Error}}
{{end}}
{{block "content" .}}{{end}}
```
New:
```html
{{if .Error}}
{{.Error}}
{{end}}
{{block "content" .}}{{end}}
```
- [ ] **Step 3: Update base.html to link tailwind.css instead of style.css**
Old:
```html
```
New (keep style.css for now, we'll remove later):
```html
```
- [ ] **Step 4: Test locally**
Run: `make run`
Open: `http://127.0.0.1:8080`
Verify: Navbar, main content, and dark mode still work
- [ ] **Step 5: Commit**
```bash
git add templates/base.html
git commit -m "refactor: convert base.html to TailwindCSS classes"
```
---
## Chunk 3: Replace style.css (base styles)
**Files:**
- Modify: `/Users/johnluther/projects/diffdown/templates/landing.html`
- Modify: `/Users/johnluther/projects/diffdown/templates/documents.html`
- Modify: `/Users/johnluther/projects/diffdown/templates/register.html`
- Modify: `/Users/johnluther/projects/diffdown/templates/login.html`
- [ ] **Step 1: Review style.css for reusable patterns**
Run: `cat static/css/style.css`
Identify patterns to convert:
- `.btn`, `.btn-sm`, `.btn-outline` → Tailwind utility classes
- `.alert`, `.alert-error` → Already handled in base.html
- `.card` → Tailwind card styles
- `.form-group`, `.form-label`, `.form-input` → Tailwind form styles
- [ ] **Step 2: Convert landing.html**
Read and convert elements to use Tailwind classes inline instead of custom CSS classes.
- [ ] **Step 3: Convert documents.html**
Same approach for the documents dashboard page.
- [ ] **Step 4: Convert auth pages (register, login)**
Convert form elements to use Tailwind classes.
- [ ] **Step 5: Test all pages**
Run: `make run`
Verify: Landing, documents, login, register pages render correctly with dark mode
- [ ] **Step 6: Commit**
```bash
git add templates/
git commit -m "refactor: convert auth and dashboard pages to TailwindCSS"
```
---
## Chunk 4: Replace editor.css (complex layout)
**Files:**
- Modify: `/Users/johnluther/projects/diffdown/templates/document_edit.html`
- Modify: `/Users/johnluther/projects/diffdown/templates/document_view.html`
- [ ] **Step 1: Review editor.css**
Key patterns:
- `.editor-page` → Full height flex container
- `.editor-toolbar` → Sticky top toolbar with flex layout
- `.editor-rich` → Rich text editor container
- `.editor-split` → Split pane layout (editor + preview)
- `.invite-modal` → Modal overlay and box
- [ ] **Step 2: Convert document_edit.html toolbar**
```html
```
- [ ] **Step 3: Convert editor containers**
- [ ] **Step 4: Convert modal components**
- [ ] **Step 5: Test editor functionality**
Run: `make run`
Create/edit a document
Verify: Rich mode, source mode, preview, toolbar all work
- [ ] **Step 6: Commit**
```bash
git add templates/document_edit.html templates/document_view.html
git commit -m "refactor: convert editor pages to TailwindCSS classes"
```
---
## Chunk 5: Replace markdown.css and diff.css
**Files:**
- Modify: `/Users/johnluther/projects/diffdown/templates/document_view.html`
- Modify: `/Users/johnluther/projects/diffdown/templates/landing.html`
- Create: Keep minimal overrides in a new file if needed
- [ ] **Step 1: Review markdown.css**
Mostly Markdown rendering styles - can keep as-is for now with minimal overrides.
- [ ] **Step 2: Review diff.css**
Diff view styles - can keep as-is.
- [ ] **Step 3: Link tailwind.css in view templates**
Add `` to templates that don't have it.
- [ ] **Step 4: Test view pages**
Run: `make run`
View a document
Verify: Markdown renders correctly with dark mode
- [ ] **Step 5: Commit**
```bash
git add templates/
git commit -m "refactor: add TailwindCSS to view pages"
```
---
## Chunk 6: Cleanup and final integration
**Files:**
- Delete: `/Users/johnluther/projects/diffdown/static/css/style.css` (after verifying no missing styles)
- Delete: `/Users/johnluther/projects/diffdown/static/css/editor.css` (after verifying no missing styles)
- Modify: `/Users/johnluther/projects/diffdown/templates/base.html`
- Modify: `/Users/johnluther/projects/diffdown/package.json`
- [ ] **Step 1: Check for any remaining custom CSS references**
Run: `grep -r 'class="' templates/ | grep -E '\.(btn|alert|card|form)' | head -20`
- [ ] **Step 2: Remove unused CSS files one by one**
Start with style.css - comment out the link in base.html, test thoroughly, then delete.
- [ ] **Step 3: Keep minimal base.css for CodeMirror/Milkdown overrides**
Create `static/css/base.css` for:
- CodeMirror theme overrides
- Milkdown-specific styles
- Any other third-party library styles
- [ ] **Step 4: Update base.html to remove old CSS links**
```html
```
- [ ] **Step 5: Add CSS build to existing build command**
```json
"scripts": {
"build": "npm run build:css && npm run build:collab",
"build:css": "npx tailwindcss -i ./src/styles/input.css -o ./static/css/tailwind.css --minify",
"build:collab": "npx esbuild node_modules/prosemirror-collab/dist/index.js --bundle --format=esm --outfile=static/vendor/collab.js"
}
```
- [ ] **Step 6: Final testing**
Run: `make build && make run`
Test all pages:
- Landing page
- Login/register
- Documents list
- Document edit (rich + source mode)
- Document view
- About page
- Dark mode toggle
- [ ] **Step 7: Commit final cleanup**
```bash
git add -A
git commit -m "refactor: complete TailwindCSS migration, remove legacy CSS"
```
---
## Testing Checklist
- [ ] Landing page displays correctly (logged out)
- [ ] Login page renders with proper styling
- [ ] Register page renders with proper styling
- [ ] Dashboard shows document list with cards
- [ ] Dark mode toggle works on all pages
- [ ] Document editor loads in rich mode
- [ ] Document editor toggles to source mode
- [ ] Preview pane renders Markdown
- [ ] Invite modal opens/closes properly
- [ ] Document view renders Markdown
- [ ] About page displays correctly
- [ ] Navbar shows correct links for logged in/out users
---
## Rollback Plan
If issues arise:
1. Keep old CSS files in a `static/css/legacy/` folder
2. Restore old link in base.html: ``
3. Test before committing deletions
---
## Notes
- TailwindCSS 4.x uses a different configuration approach - verify which version is installed
- The `data-theme` attribute approach is already implemented, Tailwind's `darkMode: 'class'` should work with it
- CodeMirror and Milkdown may need specific overrides in a separate CSS file
- Consider using `@layer components` in input.css for complex custom patterns