feat(ui): page templates for the new layout, logo in the zero hero
Rebuild index.html, month.html, month_create.html, and every partial against the new stylesheet: * Drop the old Quartermaster / Household budget header block. * Zero hero carries the logo on the left column with flanking Applied / Planned on the month page, and a Budget / Planning-for split on the budget page. Colophon tagline at the foot of every page. * month_nav switches to a single horizontal line: prev / title / next / state badge / lifecycle button, with the month picker wrapping below when present. * Entry rows render through the new table.entries grid (name, planned, applied, actions) with the notes row tucked underneath and hidden when empty via :has(input:placeholder-shown). * Primary Debt Target card uses the target-section styling with the burgundy left bar. * Back to Budget / Back to Configuration link justified right under each month nav. Refs #17 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
368a4d0741
commit
59ccb4db3c
8 changed files with 111 additions and 53 deletions
|
|
@ -1,10 +1,9 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="budget">
|
||||
<nav class="month-nav budget-nav">
|
||||
<span class="month-label">Budget configuration</span>
|
||||
<span class="spacer"></span>
|
||||
<a class="nav-link" href="/month/{{ current_year_month }}">This month ({{ current_year_month }})</a>
|
||||
<div class="page">
|
||||
<nav class="budget-nav">
|
||||
<span class="month-label">Budget <span class="year">MMXXVI</span></span>
|
||||
<a class="nav-link" href="/month/{{ current_year_month }}">This month ({{ current_year_month }}) →</a>
|
||||
{% if all_months %}
|
||||
<select
|
||||
class="month-picker"
|
||||
|
|
@ -18,13 +17,15 @@
|
|||
</select>
|
||||
{% endif %}
|
||||
</nav>
|
||||
|
||||
{% include "partials/budget_zero.html" %}
|
||||
|
||||
{% for g in groups %}
|
||||
<details class="group" id="group-{{ g.group.value }}"{% if g.default_open %} open{% endif %}>
|
||||
<summary class="group-header">
|
||||
<summary>
|
||||
<span class="chevron" aria-hidden="true"></span>
|
||||
<span class="group-name">{{ g.label }}</span>
|
||||
<span class="group-total" id="group-total-{{ g.group.value }}">${{ '%.2f' | format(g.total) }}</span>
|
||||
<span class="group-total" id="group-total-{{ g.group.value }}">${{ '{:,.2f}'.format(g.total) }}</span>
|
||||
</summary>
|
||||
{% for section in g.sections %}
|
||||
{% include "partials/section.html" %}
|
||||
|
|
@ -34,5 +35,10 @@
|
|||
{% endfor %}
|
||||
</details>
|
||||
{% endfor %}
|
||||
|
||||
<footer class="colophon">
|
||||
the art of giving every dollar a job
|
||||
<div class="signoff">Quartermaster</div>
|
||||
</footer>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="budget">
|
||||
<div class="page">
|
||||
{% include "partials/month_nav.html" %}
|
||||
<div class="back-link-row">
|
||||
<a class="back-link" href="/">Back to Budget ›</a>
|
||||
</div>
|
||||
|
||||
{% include "partials/month_zero.html" %}
|
||||
|
||||
{% for g in groups %}
|
||||
<details class="group" id="group-{{ g.group.value }}"{% if g.default_open %} open{% endif %}>
|
||||
<summary class="group-header">
|
||||
<summary>
|
||||
<span class="chevron" aria-hidden="true"></span>
|
||||
<span class="group-name">{{ g.label }}</span>
|
||||
<span class="group-total" id="group-total-{{ g.group.value }}">
|
||||
<span class="applied">${{ '%.2f' | format(g.total_applied) }}</span>
|
||||
<span class="applied">${{ '{:,.2f}'.format(g.total_applied) }}</span>
|
||||
<span class="divider">/</span>
|
||||
<span class="planned">${{ '%.2f' | format(g.total_planned) }}</span>
|
||||
<span class="planned">${{ '{:,.2f}'.format(g.total_planned) }}</span>
|
||||
</span>
|
||||
</summary>
|
||||
{% for section in g.sections %}
|
||||
|
|
@ -22,5 +27,10 @@
|
|||
{% endfor %}
|
||||
</details>
|
||||
{% endfor %}
|
||||
|
||||
<footer class="colophon">
|
||||
the art of giving every dollar a job
|
||||
<div class="signoff">Quartermaster · {{ year_month }}</div>
|
||||
</footer>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="budget">
|
||||
<div class="page">
|
||||
{% include "partials/month_nav.html" %}
|
||||
<section class="section month-missing">
|
||||
<div class="section-header">
|
||||
<h2>No snapshot yet</h2>
|
||||
<div class="back-link-row">
|
||||
<a class="back-link" href="/">Back to Budget ›</a>
|
||||
</div>
|
||||
|
||||
<section class="month-missing">
|
||||
<h2>No snapshot yet</h2>
|
||||
<p class="month-missing-body">
|
||||
This month has not been created. Creating it will snapshot the current
|
||||
budget: every entry, its planned amount, and the current Primary Debt
|
||||
Target. Applied amounts start at $0.00.
|
||||
budget: every entry, its planned amount, notes, and the current Primary
|
||||
Debt Target. Applied amounts start at $0.00.
|
||||
</p>
|
||||
<form
|
||||
hx-post="/month/{{ year_month }}/create"
|
||||
|
|
@ -19,5 +21,10 @@
|
|||
<button type="submit">Create {{ year_month }}</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<footer class="colophon">
|
||||
the art of giving every dollar a job
|
||||
<div class="signoff">Quartermaster</div>
|
||||
</footer>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,22 @@
|
|||
<section class="zero-widget" id="zero-widget" hx-swap-oob="outerHTML">
|
||||
<div class="zero-label">Zero Amount</div>
|
||||
<div class="zero-value tone-{{ tone }}">${{ '%.2f' | format(zero) }}</div>
|
||||
<div class="zero-brand">
|
||||
<img src="{{ url_for('static', path='brand/logo-full.png') }}" alt="Quartermaster">
|
||||
</div>
|
||||
<div class="zero-side left">
|
||||
<div class="zero-sublabel">Budget balance</div>
|
||||
<div class="zero-subvalue">{% if zero >= 0 %}unassigned{% else %}over-allocated{% endif %}</div>
|
||||
</div>
|
||||
<div class="zero-center">
|
||||
<p class="zero-label">Zero Amount</p>
|
||||
<h2 class="zero-value tone-{{ tone }}">
|
||||
<span class="dollar">$</span>{{ '{:,.2f}'.format(zero).split('.')[0] }}<span class="cent">.{{ '{:,.2f}'.format(zero).split('.')[1] }}</span>
|
||||
</h2>
|
||||
<p class="zero-caption">
|
||||
{% if tone == 'zero' %}every dollar has a home{% elif tone == 'positive' %}unassigned income remains{% else %}over-allocated, plan exceeds income{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="zero-side right">
|
||||
<div class="zero-sublabel">Planning for</div>
|
||||
<div class="zero-subvalue">{{ current_year_month }}</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,27 @@
|
|||
<nav class="month-nav">
|
||||
<a class="nav-link" href="/month/{{ prev_year_month }}" aria-label="Previous month">← {{ prev_year_month }}</a>
|
||||
<span class="month-label">{{ year_month }}</span>
|
||||
<a class="nav-link" href="/month/{{ next_year_month }}" aria-label="Next month">{{ next_year_month }} →</a>
|
||||
<nav class="month-line">
|
||||
<a class="nav-month prev" href="/month/{{ prev_year_month }}" aria-label="Previous month">
|
||||
<span class="chev">←</span> <em>{{ pretty_prev or prev_year_month }}</em>
|
||||
</a>
|
||||
<h2 class="month-title">{{ pretty_year_month or year_month }}</h2>
|
||||
<a class="nav-month next" href="/month/{{ next_year_month }}" aria-label="Next month">
|
||||
<em>{{ pretty_next or next_year_month }}</em> <span class="chev">→</span>
|
||||
</a>
|
||||
{% if state %}
|
||||
<span class="state-badge state-{{ state }}">
|
||||
{% if state == 'closed' and month.closed_at %}
|
||||
{% if state == 'closed' and month and month.closed_at %}
|
||||
Closed {{ month.closed_at.strftime('%Y-%m-%d') }}
|
||||
{% else %}
|
||||
{{ state | capitalize }}
|
||||
{{ state }}
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if state == 'planning' %}
|
||||
<form class="lifecycle-form" hx-post="/month/{{ year_month }}/activate" hx-swap="none">
|
||||
<button type="submit" class="primary">Activate</button>
|
||||
<button type="submit">Activate</button>
|
||||
</form>
|
||||
{% elif state == 'active' %}
|
||||
<form class="lifecycle-form" hx-post="/month/{{ year_month }}/close" hx-swap="none">
|
||||
<button
|
||||
type="submit"
|
||||
class="primary"
|
||||
{% if not can_close %}disabled title="Applied balance must equal $0.00 to close"{% endif %}
|
||||
>Close</button>
|
||||
</form>
|
||||
|
|
@ -27,13 +30,16 @@
|
|||
<button type="submit" class="secondary">Reopen</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span></span>
|
||||
<span></span>
|
||||
{% endif %}
|
||||
<span class="spacer"></span>
|
||||
{% if all_months %}
|
||||
{% if all_months and all_months|length > 1 %}
|
||||
<select
|
||||
class="month-picker"
|
||||
onchange="if(this.value){window.location=this.value}"
|
||||
aria-label="Jump to month"
|
||||
style="grid-column: 1 / -1; justify-self: end; margin-top: 0.3rem;"
|
||||
>
|
||||
<option value="">Jump to...</option>
|
||||
{% for m in all_months %}
|
||||
|
|
@ -44,5 +50,4 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
{% endif %}
|
||||
<a class="nav-link" href="/">Budget config</a>
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,22 @@
|
|||
<section class="zero-widget zero-widget-pair" id="zero-widget" hx-swap-oob="outerHTML">
|
||||
<div class="zero-label">Zero Amount</div>
|
||||
<div class="zero-values">
|
||||
<div class="zero-cell">
|
||||
<div class="zero-sublabel">Planned</div>
|
||||
<div class="zero-value tone-{{ planned_tone }}">${{ '%.2f' | format(zero.planned) }}</div>
|
||||
<section class="zero-widget" id="zero-widget" hx-swap-oob="outerHTML">
|
||||
<div class="zero-brand">
|
||||
<img src="{{ url_for('static', path='brand/logo-full.png') }}" alt="Quartermaster">
|
||||
</div>
|
||||
<div class="zero-cell">
|
||||
<div class="zero-side left">
|
||||
<div class="zero-sublabel">Applied</div>
|
||||
<div class="zero-value tone-{{ applied_tone }}">${{ '%.2f' | format(zero.applied) }}</div>
|
||||
<div class="zero-subvalue">${{ '{:,.2f}'.format(zero.applied).split('.')[0] }}<span class="cent">.{{ '{:,.2f}'.format(zero.applied).split('.')[1] }}</span></div>
|
||||
</div>
|
||||
<div class="zero-center">
|
||||
<p class="zero-label">Zero Amount</p>
|
||||
<h2 class="zero-value tone-{{ applied_tone }}">
|
||||
<span class="dollar">$</span>{{ '{:,.2f}'.format(zero.applied).split('.')[0] }}<span class="cent">.{{ '{:,.2f}'.format(zero.applied).split('.')[1] }}</span>
|
||||
</h2>
|
||||
<p class="zero-caption">
|
||||
{% if applied_tone == 'zero' %}the month balances{% elif applied_tone == 'positive' %}unassigned income remains{% else %}applied exceeds income{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="zero-side right">
|
||||
<div class="zero-sublabel">Planned</div>
|
||||
<div class="zero-subvalue">${{ '{:,.2f}'.format(zero.planned).split('.')[0] }}<span class="cent">.{{ '{:,.2f}'.format(zero.planned).split('.')[1] }}</span></div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@
|
|||
<div class="section-header">
|
||||
<h2>{{ section.label }}</h2>
|
||||
<span class="total" data-testid="total-{{ section.section.value }}">
|
||||
${{ '%.2f' | format(section.total) }}
|
||||
${{ '{:,.2f}'.format(section.total) }}
|
||||
</span>
|
||||
</div>
|
||||
<table class="entries">
|
||||
<tbody>
|
||||
{% for entry in section.entries %}
|
||||
<tr class="entry">
|
||||
<tr class="entry state-unchanged" style="--ratio: 1">
|
||||
<td class="entry-name">{{ entry.name }}</td>
|
||||
<td class="entry-amount">${{ '%.2f' | format(entry.amount) }}</td>
|
||||
<td class="entry-amount">${{ '{:,.2f}'.format(entry.amount) }}</td>
|
||||
<td class="entry-amount"></td>
|
||||
<td class="entry-actions">
|
||||
<button
|
||||
class="delete"
|
||||
|
|
@ -23,7 +24,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr class="entry-notes-row">
|
||||
<td colspan="3">
|
||||
<td colspan="4">
|
||||
<input
|
||||
class="notes-input"
|
||||
type="text"
|
||||
|
|
@ -39,10 +40,10 @@
|
|||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr class="empty"><td colspan="3">No entries yet.</td></tr>
|
||||
<tr class="empty"><td colspan="4">No entries yet.</td></tr>
|
||||
{% endfor %}
|
||||
<tr class="add-row">
|
||||
<td colspan="3">
|
||||
<td colspan="4">
|
||||
<form
|
||||
class="add-form"
|
||||
hx-post="/sections/{{ section.section.value }}/entries"
|
||||
|
|
|
|||
|
|
@ -2,35 +2,37 @@
|
|||
<div class="section-header">
|
||||
<h2>Primary Debt Target</h2>
|
||||
{% if target.entry %}
|
||||
<span class="total">${{ '%.2f' | format(target.entry.amount) }}</span>
|
||||
<span class="total">${{ '{:,.2f}'.format(target.entry.amount) }}</span>
|
||||
{% else %}
|
||||
<span class="total empty">$0.00</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<table class="entries">
|
||||
<tbody>
|
||||
<tr class="entry">
|
||||
<tr class="entry" style="--ratio: 1">
|
||||
<td class="entry-name">
|
||||
{% if target.entry %}{{ target.entry.name }}{% else %}<span class="muted">No target selected.</span>{% endif %}
|
||||
</td>
|
||||
<td class="entry-amount"></td>
|
||||
<td class="entry-amount"></td>
|
||||
<td class="entry-actions"></td>
|
||||
</tr>
|
||||
<tr class="add-row">
|
||||
<td colspan="3">
|
||||
<td colspan="4">
|
||||
<form
|
||||
class="target-form"
|
||||
hx-post="/debt-target"
|
||||
hx-target="#section-debt_target"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<select name="debt_minimum_id">
|
||||
<label for="debt-target-select">Choose from Debt Minimums</label>
|
||||
<select id="debt-target-select" name="debt_minimum_id">
|
||||
<option value="">(none)</option>
|
||||
{% for dm in debt_minimums %}
|
||||
<option
|
||||
value="{{ dm.id }}"
|
||||
{% if target.debt_minimum_id == dm.id %}selected{% endif %}
|
||||
>{{ dm.name }}: ${{ '%.2f' | format(dm.amount) }}</option>
|
||||
>{{ dm.name }}: ${{ '{:,.2f}'.format(dm.amount) }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit">Set</button>
|
||||
|
|
|
|||
Loading…
Reference in a new issue