first commit

This commit is contained in:
2025-11-24 23:10:55 -06:00
commit 8315fa51c9
279 changed files with 74600 additions and 0 deletions

View File

@@ -0,0 +1,431 @@
# 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