Implement complete web interface for the Gear entity: - Add GearView model with category badges and formatted display - Create GearTemplate and GearListTemplate for Askama rendering - Build main gear page with collapsible add form (Datastar-powered) - Implement gear list table with sortable columns and pagination - Use trash icon for delete actions matching roasts table design - Add Gear navigation link in main menu between Bags and Timeline - Integrate gear events into timeline view with proper labels and links The web UI follows the established patterns from other entities with Datastar for reactive fragment updates and proper authentication gating. Apply code formatting fixes across all gear-related modules.
104 lines
3.6 KiB
HTML
104 lines
3.6 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Brewlog · Gear{% endblock %}
|
|
{% block content %}
|
|
<section data-signals:show-form="false" data-signals:is-submitting="false">
|
|
<header class="flex flex-wrap items-start justify-between gap-4">
|
|
<div class="flex flex-col gap-2">
|
|
<h1 class="text-3xl font-semibold">Gear</h1>
|
|
<p class="max-w-2xl text-sm text-stone-600">Track your brewing equipment.</p>
|
|
</div>
|
|
{% if is_authenticated %}
|
|
<button
|
|
type="button"
|
|
class="flex h-10 w-10 items-center justify-center rounded-full border border-amber-500 text-2xl font-semibold text-amber-700 transition hover:border-amber-400 hover:text-amber-600"
|
|
data-class:hidden="$showForm"
|
|
data-on:click="$showForm = true"
|
|
aria-label="Add new gear"
|
|
>
|
|
<span aria-hidden="true">+</span>
|
|
</button>
|
|
{% endif %}
|
|
</header>
|
|
|
|
{% if is_authenticated %}
|
|
<div
|
|
class="mt-6 rounded-lg border border-amber-300 bg-amber-100/80 p-5 shadow-sm"
|
|
data-show="$showForm"
|
|
style="display: none"
|
|
>
|
|
<div>
|
|
<h2 class="text-lg font-semibold text-amber-700">New Gear</h2>
|
|
<p class="mt-1 text-sm text-stone-600">
|
|
Add brewing equipment to your collection.
|
|
</p>
|
|
</div>
|
|
<form
|
|
method="post"
|
|
action="/api/v1/gear"
|
|
class="mt-4 flex flex-col gap-4"
|
|
data-on:submit="$isSubmitting = true; @post('/api/v1/gear?{{ navigator.query_for_page(1) }}', {contentType: 'form', responseOverrides: {selector: '#gear-list', mode: 'replace'}})"
|
|
data-ref="form"
|
|
data-on:datastar-fetch="evt.detail.type === 'finished' && $isSubmitting && ($showForm = false, $form && $form.reset(), $isSubmitting = false)"
|
|
>
|
|
<div class="grid gap-4 sm:grid-cols-2">
|
|
<label class="flex flex-col gap-1 text-sm">
|
|
<span class="text-stone-700">Category *</span>
|
|
<select name="category" required class="input-field">
|
|
<option value="">Select a category</option>
|
|
<option value="grinder">Grinder</option>
|
|
<option value="brewer">Brewer</option>
|
|
</select>
|
|
</label>
|
|
<label class="flex flex-col gap-1 text-sm">
|
|
<span class="text-stone-700">Make *</span>
|
|
<input
|
|
type="text"
|
|
name="make"
|
|
required
|
|
class="input-field"
|
|
placeholder="Baratza"
|
|
/>
|
|
</label>
|
|
<label class="flex flex-col gap-1 text-sm">
|
|
<span class="text-stone-700">Model *</span>
|
|
<input
|
|
type="text"
|
|
name="model"
|
|
required
|
|
class="input-field"
|
|
placeholder="Encore"
|
|
/>
|
|
</label>
|
|
<label class="flex flex-col gap-1 text-sm sm:col-span-2">
|
|
<span class="text-stone-700">Notes</span>
|
|
<textarea
|
|
name="notes"
|
|
rows="3"
|
|
class="input-field"
|
|
placeholder="Additional notes about this equipment..."
|
|
></textarea>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="flex justify-end gap-3">
|
|
<button
|
|
type="button"
|
|
class="rounded-md px-4 py-2 text-sm font-medium text-stone-600 hover:bg-stone-200/50"
|
|
data-on:click="$showForm = false"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
class="rounded-md bg-amber-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-amber-700 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-2"
|
|
>
|
|
Save Gear
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="mt-8">{% include "partials/gear_list.html" %}</div>
|
|
</section>
|
|
{% endblock %}
|