# Template Structure and Conventions - Public Web Frontend

**Last Updated:** November 18, 2025

---

## Overview

This document outlines the template structure, naming conventions, and best practices for Jinja2 templates in the Code of Conquest web frontend.

**Template Philosophy:**
- Clean, semantic HTML
- Separation of concerns (templates, styles, scripts)
- Reusable components via includes and macros
- Responsive design patterns
- Accessibility-first

---

## Directory Structure

```
templates/
├── base.html                    # Base template (all pages extend this)
├── errors/                      # Error pages
│   ├── 404.html
│   ├── 500.html
│   └── 403.html
├── auth/                        # Authentication pages
│   ├── login.html
│   ├── register.html
│   └── forgot_password.html
├── dashboard/                   # User dashboard
│   └── index.html
├── characters/                  # Character management
│   ├── list.html
│   ├── create.html
│   ├── view.html
│   └── edit.html
├── sessions/                    # Game sessions
│   ├── create.html
│   ├── active.html
│   ├── history.html
│   └── view.html
├── multiplayer/                 # Multiplayer sessions
│   ├── create.html
│   ├── lobby.html
│   ├── session.html
│   └── complete.html
├── partials/                    # Reusable partial templates
│   ├── navigation.html
│   ├── footer.html
│   ├── character_card.html
│   ├── combat_ui.html
│   └── session_summary.html
├── components/                  # Reusable UI components (macros)
│   ├── forms.html
│   ├── buttons.html
│   ├── alerts.html
│   └── modals.html
└── macros/                      # Jinja2 macros
    ├── form_fields.html
    └── ui_elements.html
```

---

## Base Template

**File:** `templates/base.html`

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Code of Conquest{% endblock %}</title>

    <!-- CSS -->
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
    {% block extra_css %}{% endblock %}

    <!-- HTMX -->
    <script src="https://unpkg.com/htmx.org@1.9.10"></script>

    <!-- Appwrite SDK (for realtime) -->
    <script src="https://cdn.jsdelivr.net/npm/appwrite@latest"></script>

    {% block extra_head %}{% endblock %}
</head>
<body>
    {% include 'partials/navigation.html' %}

    <main class="container">
        {% block flash_messages %}
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}
            <div class="alerts">
                {% for category, message in messages %}
                <div class="alert alert-{{ category }}">
                    {{ message }}
                </div>
                {% endfor %}
            </div>
            {% endif %}
        {% endwith %}
        {% endblock %}

        {% block content %}
        <!-- Page content goes here -->
        {% endblock %}
    </main>

    {% include 'partials/footer.html' %}

    <!-- JavaScript -->
    <script src="{{ url_for('static', filename='js/main.js') }}"></script>
    {% block extra_js %}{% endblock %}
</body>
</html>
```

---

## Template Naming Conventions

### File Names
- Use lowercase with underscores: `character_list.html`, `session_create.html`
- Partial templates prefix with underscore: `_card.html`, `_form.html` (optional)
- Component files describe what they contain: `forms.html`, `buttons.html`

### Template Variables
- Use snake_case: `character`, `session_data`, `user_info`
- Prefix collections with descriptive names: `characters_list`, `sessions_active`
- Boolean flags use `is_` or `has_` prefix: `is_authenticated`, `has_premium`

### Block Names
- Use descriptive names: `{% block sidebar %}`, `{% block page_header %}`
- Common blocks:
  - `title` - Page title
  - `content` - Main content area
  - `extra_css` - Additional CSS files
  - `extra_js` - Additional JavaScript files
  - `extra_head` - Additional head elements

---

## Template Patterns

### Extending Base Template

```html
{% extends "base.html" %}

{% block title %}Character List - Code of Conquest{% endblock %}

{% block content %}
<div class="character-list">
    <h1>Your Characters</h1>
    <!-- Content -->
</div>
{% endblock %}

{% block extra_js %}
<script src="{{ url_for('static', filename='js/characters.js') }}"></script>
{% endblock %}
```

### Including Partial Templates

```html
{% include 'partials/character_card.html' with character=char %}
```

**Or without context:**
```html
{% include 'partials/navigation.html' %}
```

### Using Macros

**Define macro** in `templates/macros/form_fields.html`:

```html
{% macro text_input(name, label, value="", required=False, placeholder="") %}
<div class="form-group">
    <label for="{{ name }}">{{ label }}{% if required %} <span class="required">*</span>{% endif %}</label>
    <input type="text"
           id="{{ name }}"
           name="{{ name }}"
           value="{{ value }}"
           placeholder="{{ placeholder }}"
           {% if required %}required{% endif %}>
</div>
{% endmacro %}
```

**Use macro:**
```html
{% from 'macros/form_fields.html' import text_input %}

<form>
    {{ text_input('character_name', 'Character Name', required=True, placeholder='Enter name') }}
</form>
```

### Conditional Rendering

```html
{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}!</p>
{% else %}
    <a href="{{ url_for('auth.login') }}">Login</a>
{% endif %}
```

### Loops

```html
<div class="character-grid">
    {% for character in characters %}
    <div class="character-card">
        <h3>{{ character.name }}</h3>
        <p>Level {{ character.level }} {{ character.player_class.name }}</p>
    </div>
    {% else %}
    <p>No characters found. <a href="{{ url_for('characters.create') }}">Create one</a>?</p>
    {% endfor %}
</div>
```

---

## HTMX Integration in Templates

### Basic HTMX Attributes

```html
<!-- Form submission via HTMX -->
<form hx-post="{{ url_for('characters.create') }}"
      hx-target="#character-list"
      hx-swap="beforeend">
    <!-- form fields -->
    <button type="submit">Create Character</button>
</form>
```

### HTMX with Confirmation

```html
<button hx-delete="{{ url_for('characters.delete', character_id=char.character_id) }}"
        hx-confirm="Are you sure you want to delete this character?"
        hx-target="closest .character-card"
        hx-swap="outerHTML">
    Delete
</button>
```

### HTMX Polling

```html
<div hx-get="{{ url_for('sessions.status', session_id=session.session_id) }}"
     hx-trigger="every 5s"
     hx-target="#session-status">
    Loading...
</div>
```

---

## Component Patterns

### Character Card Component

**File:** `templates/partials/character_card.html`

```html
<div class="character-card" data-character-id="{{ character.character_id }}">
    <div class="card-header">
        <h3>{{ character.name }}</h3>
        <span class="level-badge">Lvl {{ character.level }}</span>
    </div>
    <div class="card-body">
        <p class="class">{{ character.player_class.name }}</p>
        <p class="stats">
            HP: {{ character.current_hp }}/{{ character.max_hp }} |
            Gold: {{ character.gold }}
        </p>
    </div>
    <div class="card-actions">
        <a href="{{ url_for('characters.view', character_id=character.character_id) }}" class="btn btn-primary">View</a>
        <a href="{{ url_for('sessions.create', character_id=character.character_id) }}" class="btn btn-secondary">Play</a>
    </div>
</div>
```

**Usage:**
```html
{% for character in characters %}
    {% include 'partials/character_card.html' with character=character %}
{% endfor %}
```

### Alert Component Macro

**File:** `templates/components/alerts.html`

```html
{% macro alert(message, category='info', dismissible=True) %}
<div class="alert alert-{{ category }}{% if dismissible %} alert-dismissible{% endif %}" role="alert">
    {{ message }}
    {% if dismissible %}
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
        <span aria-hidden="true">&times;</span>
    </button>
    {% endif %}
</div>
{% endmacro %}
```

**Usage:**
```html
{% from 'components/alerts.html' import alert %}

{{ alert('Character created successfully!', 'success') }}
{{ alert('Invalid character name', 'error') }}
```

---

## Accessibility Guidelines

### Semantic HTML
- Use proper heading hierarchy (`<h1>`, `<h2>`, etc.)
- Use `<nav>`, `<main>`, `<article>`, `<section>` elements
- Use `<button>` for actions, `<a>` for navigation

### ARIA Labels
```html
<button aria-label="Delete character">
    <span class="icon icon-trash"></span>
</button>

<nav aria-label="Main navigation">
    <!-- navigation links -->
</nav>
```

### Form Labels
```html
<label for="character-name">Character Name</label>
<input type="text" id="character-name" name="character_name">
```

### Focus Management
```html
<button class="btn" autofocus>Primary Action</button>
```

---

## Best Practices

### 1. Keep Templates DRY (Don't Repeat Yourself)
- Use includes for repeated sections
- Create macros for reusable components
- Extend base template consistently

### 2. Separate Logic from Presentation
- Avoid complex Python logic in templates
- Use template filters instead of inline calculations
- Pass fully-formed data from views

### 3. Use Template Comments
```html
{# This is a Jinja2 comment, not rendered in HTML #}

<!-- This is an HTML comment, visible in source -->
```

### 4. Whitespace Control
```html
{% for item in items -%}
    <li>{{ item }}</li>
{%- endfor %}
```

### 5. Template Inheritance Hierarchy
```
base.html
├── dashboard/base.html (extends base.html)
│   ├── dashboard/index.html
│   └── dashboard/profile.html
└── sessions/base.html (extends base.html)
    ├── sessions/create.html
    └── sessions/active.html
```

---

## Testing Templates

### Manual Checklist
- [ ] Templates extend base.html correctly
- [ ] All blocks are properly closed
- [ ] Variables are defined before use
- [ ] Forms have CSRF protection
- [ ] Links use `url_for()` instead of hardcoded paths
- [ ] Images have alt text
- [ ] Buttons have descriptive text or aria-labels
- [ ] Mobile responsive (test at 320px, 768px, 1024px)

### Template Linting
- Use `djLint` for Jinja2 template linting
- Ensure consistent indentation (2 or 4 spaces)
- Validate HTML with W3C validator

---

## Related Documentation

- **[HTMX_PATTERNS.md](HTMX_PATTERNS.md)** - HTMX integration patterns
- **[TESTING.md](TESTING.md)** - Manual testing guide
- **[/api/docs/API_REFERENCE.md](../../api/docs/API_REFERENCE.md)** - API endpoints for HTMX calls

---

**Document Version:** 1.0
**Created:** November 18, 2025
**Last Updated:** November 18, 2025
