# AgentForms Template Refactoring Plan
## Goal
Convert all user-facing pages to extend `base.html` instead of manually including `nav.html`. This ensures the nav bar appears consistently on every page and eliminates duplicated code (CSP event delegation, cookie banner, nav HTML, footer, shared CSS).
## Current State Analysis
### base.html (the new single source of truth)
- Includes `_shared.css.html` (413 lines of shared CSS)
- Includes `nav.html` (self-contained nav with styles + HTML + hamburger JS)
- Has `<div class="container">{% block content %}</div>`
- Has cookie consent banner (duplicated in many templates)
- Has CSP event delegation script (duplicated in many templates via `_dashboard_base.html`)
- Has closing `</body></html>` tags
### _dashboard_base.html (should be eliminated/consolidated)
- Includes `_shared.css.html` (redundant — base.html already has it)
- Has card/badge/table styles (some should go to `_shared.css.html`)
- Has CSP event delegation script (redundant — base.html already has it)
### _shared.css.html
- 413 lines of shared CSS (variables, buttons, forms, sections, features, FAQ, pricing, footer, mobile)
- Included by `_dashboard_base.html` and many templates directly
## Files Already Correct (DO NOT TOUCH)
These already extend `base.html`:
- `dashboard.html`, `admin_users.html`, `referral.html`, `site_added.html`, `sites.html`
- `teams/list.html`, `teams/create.html`, `teams/analytics.html`, `invites/accept.html`
## Files to Exclude (DO NOT MODIFY)
- `hosted_form.html` — client-facing form, should have NO nav
- `_shared.css.html`, `favicon.html`, `field_advanced.html` — partials
- `admin_login.html`, `admin_templates.html` — admin pages, separate design
- `_dashboard_base.html` — will be deprecated (see Phase 2)
## Files to Convert: 30 Total
### Phase 1: Simple Marketing Pages (8 files)
These use `base.html` structure with minimal page-specific styles. Straightforward conversion.
1. **pricing.html** (214 lines)
- Has: OG/Twitter meta, canonical link, `_shared.css.html`, `nav.html`, inline footer
- Page-specific: NONE (uses only `_shared.css.html` styles)
- Remove: nav include, inline footer, `</body></html>`, `_shared.css.html` include
2. **features.html** (130 lines)
- Has: `_shared.css.html`, `nav.html`, inline footer
- Page-specific: NONE
- Remove: nav include, inline footer, `</body></html>`, `_shared.css.html` include
3. **faq.html** (81 lines)
- Has: OG/Twitter meta, canonical link, `_shared.css.html`, `nav.html`, inline footer
- Page-specific: NONE
- Remove: nav include, inline footer, `</body></html>`, `_shared.css.html` include
4. **changelog.html** (93 lines)
- Has: OG/Twitter meta, canonical link, `_shared.css.html`, `nav.html`, inline footer
- Page-specific: NONE
- Remove: nav include, inline footer, `</body></html>`, `_shared.css.html` include
5. **privacy.html** (123 lines)
- Has: OG/Twitter meta, canonical link, `_shared.css.html`, `nav.html`, inline footer
- Page-specific: `main` padding, h1/h2/p/ul styles, max-width override, mobile responsive
- Convert `<style>` to `{% block head_extra %}`
6. **terms.html** (123 lines)
- Same pattern as privacy.html
- Page-specific: `main` padding, h1/h2/p/ul styles, max-width override, mobile responsive
7. **index.html** (672 lines) — LARGEST
- Has: OG/Twitter meta, JSON-LD structured data, canonical link, favicon
- Page-specific: Full custom CSS (~600 lines) with hero, steps, features, CTA, mobile
- Remove: `nav.html` include, inline footer, `</body></html>`, `_shared.css.html` include (if present)
- Convert: ALL inline CSS to `{% block head_extra %}`
- Preserve: JSON-LD script, OG meta, Twitter meta, canonical link
8. **api_docs.html** (652 lines)
- Has: OG/Twitter meta, canonical link, `_shared.css.html`, `nav.html`, inline footer
- Page-specific: API docs sidebar, code blocks, search, tabs, responsive
- Convert: inline CSS to `{% block head_extra %}`, inline JS to `{% block scripts %}`
### Phase 2: Auth Pages (2 files)
These have centered auth layout. Preserve `.auth-page` CSS.
9. **login.html** (301 lines)
- Has: `_shared.css.html`, `nav.html`, inline cookie banner, CSP script
- Page-specific: `.auth-page` centering layout, auth card styles, social login buttons, Google Recaptcha, mobile responsive
- Remove: `nav.html` include, duplicate cookie banner, duplicate CSP script, `</body></html>`
- Convert: `<style>` to `{% block head_extra %}`
- Preserve: ALL `data-onclick` handlers, `nonce="{{ csp_nonce }}"` attributes
10. **register.html** (200 lines)
- Same pattern as login.html
- Page-specific: `.auth-page` centering, auth card, social login, Recaptcha, mobile
- Same removals/conversions as login.html
### Phase 3: Error Pages (4 files)
Small, simple, consistent pattern.
11. **error_403.html** (65 lines)
12. **error_404.html** (65 lines)
13. **error_500.html** (65 lines)
14. **form_404.html** (69 lines)
All share the same pattern:
- Has: `_shared.css.html`, `nav.html`, inline footer
- Page-specific: `.error-page` flex layout, error code display, back button
- Remove: `nav.html`, inline footer, `</body></html>`, `_shared.css.html` include
### Phase 4: User Dashboard Pages (10 files)
These include `_dashboard_base.html` instead of `_shared.css.html`. Need to extract page-specific styles and drop `_dashboard_base.html` include.
15. **user_dashboard.html** (440 lines)
- Has: `_dashboard_base.html`, `nav.html`, inline cookie banner, inline footer
- Page-specific: tier badge colors, quick-action grid, stats grid, recent submissions table, site list, mobile responsive, `data-onclick` handlers
- Remove: `_dashboard_base.html` include, `nav.html` include, duplicate cookie banner, inline footer, `</body></html>`
- Convert: page-specific `<style>` to `{% block head_extra %}`, page-specific `<script>` to `{% block scripts %}`
- Preserve: ALL `data-onclick` handlers, `nonce` attributes, flash messages
16. **user_sites.html** (172 lines)
- Has: `_dashboard_base.html`, `nav.html`, inline cookie banner, inline footer
- Page-specific: `.btn-danger`, `.badge-ai`, `.warning`, `.token`, `.header-row`, inline styles
- Same removal/conversion pattern
17. **site_submissions.html** (134 lines)
- Has: `_dashboard_base.html`-like styles, `nav.html`, inline cookie banner
- Page-specific: card styles, table, submission display, field types, mobile responsive
- Same removal/conversion pattern
18. **site_analytics.html** (529 lines)
- Has: `_dashboard_base.html`, `nav.html`, inline cookie banner, inline footer
- Page-specific: Analytics charts (canvas), period selector, stats grid, traffic table, device/geo breakdown, mobile responsive
- Same removal/conversion pattern
- Preserve: `data-onclick` handlers for period switching
19. **documents_dashboard.html** (922 lines) — VERY LARGE
- Has: `_dashboard_base.html`, `nav.html`, inline cookie banner
- Page-specific: Tab bar, status chips, document table, template cards, modals, form elements, line items, PDF preview, toast notifications, mobile responsive (~600 lines of CSS, ~300 lines of JS)
- Same removal/conversion pattern
- Preserve: ALL `data-onclick` handlers, inline JS functions, modal logic
20. **settings.html** (496 lines)
- Has: `_shared.css.html`, `nav.html`, inline cookie banner, inline footer
- Page-specific: Settings header, settings grid, profile section, password form, site list, delete account, mobile responsive
- Same removal/conversion pattern
- Preserve: `data-onclick` handlers, flash messages
21. **user_settings_api_keys.html** (196 lines)
- Has: `_dashboard_base.html`-like styles, `nav.html`, inline cookie banner
- Page-specific: API key list, key generation form, usage stats, mobile responsive
- Same removal/conversion pattern
22. **edit_site.html** (3716 lines) — LARGEST FILE
- Has: `_shared.css.html`, Google Fonts, `nav.html`, inline cookie banner
- Page-specific: Full site editor with field management, document templates, conditional logic, AI generation, custom CSS editor, multi-step forms, tabs, modals (~3000+ lines of CSS + JS)
- Same removal/conversion pattern
- Preserve: Google Fonts preload links, ALL `data-onclick` handlers, ALL inline JS, CSP nonce attributes
- NOTE: Has `* { margin: 0; padding: 0; box-sizing: border-box; }` reset — remove as redundant with `_shared.css.html`
23. **upgrade.html** (116 lines)
- Has: Full custom CSS reset (NOT using `_shared.css.html` or `_dashboard_base.html`)
- Page-specific: Custom reset, nav background, card, btn, badge, pricing cards, mobile responsive
- Remove: Full CSS reset, nav background style (`nav { background: #1a1a2e; color: white; }`), `nav.html` include, `</body></html>`
- Convert: Page-specific CSS to `{% block head_extra %}`
- Preserve: Stripe integration, tier rendering, flash messages
24. **add_site_user.html** (116 lines)
- Has: Full custom CSS reset, `nav.html`, inline cookie banner
- Page-specific: Custom reset, nav, card, btn, badge, form, mobile responsive
- Same removal/conversion pattern as upgrade.html
### Phase 5: Misc Pages (2 files)
25. **templates_browser.html** (545 lines)
- Has: Full custom CSS reset, `nav.html`, inline cookie banner, inline footer
- Page-specific: Template grid, search/filter, category tabs, template cards, modal, mobile responsive
- Same removal/conversion pattern
- Preserve: ALL `data-onclick` handlers, inline JS
26. **signup.html** (72 lines)
- Has: Google Fonts, full custom CSS (dark theme), NO nav include
- Page-specific: Dark theme, success card, email confirmation
- NOTE: Does NOT include `nav.html` — but should probably extend base.html for consistency
- Convert to extend base.html, preserve dark theme in `{% block head_extra %}`
27. **verify_email.html** (142 lines)
- Has: Full custom CSS reset, NO nav include
- Page-specific: Verification card, check/✗ icons, mobile responsive
- NOTE: Does NOT include `nav.html` — but should probably extend base.html
- Convert to extend base.html
## Conversion Template Pattern
Every converted file follows this structure:
```jinja2
{% extends 'base.html' %}
{% block title %}Page Title — AgentForms{% endblock %}
{% block head_extra %}
<!-- Page-specific meta tags (OG, Twitter, canonical, JSON-LD) -->
<!-- Page-specific external links (Google Fonts, etc.) -->
<style nonce="{{ csp_nonce }}">
/* Page-specific CSS ONLY — no resets, no nav styles, no shared CSS */
</style>
{% endblock %}
{% block content %}
<!-- Page content only — NO nav include, NO footer, NO cookie banner -->
{% endblock %}
{% block scripts %}
<!-- Page-specific JS only — NO CSP event delegation -->
<script nonce="{{ csp_nonce }}">
// Page-specific JavaScript
</script>
{% endblock %}
```
## What to Remove from Each File
| Element | Reason |
|---------|--------|
| `<!DOCTYPE html>` | Provided by base.html |
| `<html>`, `<head>`, `<body>` | Provided by base.html |
| `<meta charset="UTF-8">` | Provided by base.html |
| `<meta name="viewport" ...>` | Provided by base.html |
| `<link rel="icon" ...>` | Provided by base.html |
| `{% include '_shared.css.html' %}` | Provided by base.html |
| `{% include '_dashboard_base.html' %}` | Provided by base.html (shared CSS + CSP script) |
| `{% include 'nav.html' %}` | Provided by base.html |
| `</body></html>` | Provided by base.html |
| Cookie consent banner | Provided by base.html |
| CSP event delegation script | Provided by base.html |
| `* { margin: 0; padding: 0; box-sizing: border-box; }` | Already in `_shared.css.html` |
| `nav { background: #1a1a2e; color: white; }` | Already in `nav.html` |
| `body { font-family: system-ui, ...; background: #f5f5f5; color: #333; }` | Already in `_shared.css.html` |
| `.container { max-width: ...; }` | Already in `_shared.css.html` |
| Inline `<footer>` blocks | Remove — pages don't need custom footers; use base.html container |
## What to Preserve in Each File
| Element | Location |
|---------|----------|
| Page-specific meta (OG, Twitter, canonical) | `{% block head_extra %}` |
| JSON-LD structured data | `{% block head_extra %}` |
| Google Fonts links | `{% block head_extra %}` |
| Page-specific CSS | `<style nonce="{{ csp_nonce }}">` inside `{% block head_extra %}` |
| `data-onclick`, `data-onsubmit`, etc. | In page content — untouched |
| `nonce="{{ csp_nonce }}"` attributes | On all style/script tags |
| Flash messages (`get_flashed_messages`) | In page content — untouched |
| Page-specific JavaScript | `{% block scripts %}` or inline in content |
| Form actions, CSRF tokens | In page content — untouched |
| Session checks (`session.get('user_id')`) | In page content — untouched |
## Priority of Removal for Duplicated CSS
When converting, these CSS rules are guaranteed duplicates and MUST be removed:
1. `* { margin: 0; padding: 0; box-sizing: border-box; }` — in `_shared.css.html`
2. `body { font-family: system-ui, ... }` — in `_shared.css.html`
3. `nav { background: #1a1a2e; color: white; }` — in `nav.html`
4. `.container { max-width: ...; margin: 0 auto; padding: ... }` — in `_shared.css.html`
5. `.card { background: white; border-radius: 8px; padding: ... }` — in `_dashboard_base.html`
6. `.btn { display: inline-block; padding: 8px 16px; ... }` — in `_shared.css.html`
7. `.badge { display: inline-block; padding: 2px 8px; ... }` — in `_dashboard_base.html`
8. `.error { background: #f8d7da; ... }` — in `_dashboard_base.html`
9. `.success { background: #d4edda; ... }` — in `_dashboard_base.html`
10. `table { width: 100%; border-collapse: collapse; }` — in `_dashboard_base.html`
11. `footer { ... }` — in `_shared.css.html`
12. `.footer-inner { ... }` — in `_shared.css.html`
13. `.footer-copy { ... }` — in `_shared.css.html`
14. `.footer-links { ... }` — in `_shared.css.html`
## Execution Order
1. **Phase 1** (pricing, features, faq, changelog, privacy, terms) — simplest, lowest risk
2. **Phase 2** (login, register) — auth pages, moderate complexity
3. **Phase 3** (error_403, error_404, error_500, form_404) — small, consistent pattern
4. **Phase 4** (user_dashboard, user_sites, site_*, settings, edit_site, upgrade, add_site_user, documents_dashboard, templates_browser, api_docs) — complex, needs careful testing
5. **Phase 5** (index.html, signup, verify_email) — index is largest, signup/verify_email have no nav
6. **Cleanup** — deprecate `_dashboard_base.html` if no templates use it
## Post-Conversion Cleanup
After all conversions:
1. Verify `_dashboard_base.html` is unused — if so, delete it
2. Verify no template still has `{% include 'nav.html' %}` (except base.html)
3. Verify no template has duplicate cookie banner
4. Verify no template has duplicate CSP event delegation script
5. Verify no template has `<!DOCTYPE html>` (except base.html)
6. Test each page in browser to confirm nav renders correctly
7. Test each page on mobile to confirm responsive design works
8. Test CSP compliance — verify no inline event handlers break
## Risk Assessment
| Risk | Mitigation |
|------|------------|
| CSS conflicts between shared and page-specific | Remove duplicate rules systematically (see "Priority of Removal") |
| `data-onclick` handlers stop working | CSP script in base.html handles these — no change needed |
| Missing `_shared.css.html` styles | base.html includes it — all styles available |
| Auth pages lose centered layout | `.auth-page` CSS preserved in `{% block head_extra %}` |
| Error pages lose styling | `.error-page` CSS preserved in `{% block head_extra %}` |
| Footer content differs per page | All footers are identical — safe to consolidate |
| Google Fonts on edit_site.html | Preserve preload/link in `{% block head_extra %}` |
| JSON-LD on index.html | Preserve in `{% block head_extra %}` |
| Dark theme on signup.html | Preserve ALL dark theme CSS in `{% block head_extra %}` |
## Summary Statistics
| Category | Files | Lines |
|----------|-------|-------|
| Already correct | 9 | — |
| Exceptions (no change) | 6 | — |
| Simple marketing | 8 | ~1,466 |
| Auth pages | 2 | ~501 |
| Error pages | 4 | ~264 |
| User dashboard | 10 | ~7,105 |
| Misc | 2 | ~216 |
| **Total to convert** | **26** | **~9,552** |