brewlog/templates/pages/roaster.html
Jon Seager 958c8de6cc
feat(detail): add roaster, cafe, and gear detail pages
- Add detail page routes, templates, and view models for roasters, cafes,
  and gear, following the existing pattern from bags/brews/cups
- Add map_with_legend_1 macro for single-country detail maps
- Redirect to detail page after entity creation instead of list page
- Check referer in create handlers to return list fragment only from data page
- Update bag delete button to use red background style
- Update datastar tests to include referer header for create assertions
2026-02-08 17:20:46 +00:00

74 lines
2.8 KiB
HTML

{% extends "base.html" %}
{% import "partials/detail_cards.html" as detail %}
{% import "partials/icons.html" as icons %}
{% block title %}Brewlog · {{ roaster.name }}{% endblock %}
{% block og_title %}{{ roaster.name }} — Brewlog{% endblock %}
{% block og_description %}{{ roaster.name }} — {{ roaster.country_flag }} {{ roaster.country }}{% if let Some(c) = roaster.city %}, {{ c }}{% endif %}{% endblock %}
{% block head %}<meta property="og:image" content="{{ base_url }}/og-image.png" />{% endblock %}
{% block content %}
<header class="flex items-start justify-between gap-4">
<div class="flex flex-col gap-2">
<h1 class="text-3xl font-semibold">{{ roaster.name }}</h1>
<p class="text-sm text-text-secondary">
{{ roaster.country_flag }} {{ roaster.country }}{% if let Some(c) = roaster.city %} · {{ c }}{% endif %} · Added {{ roaster.created_date }}
</p>
</div>
{{ detail::share_button() }}
</header>
{{ detail::share_script() }}
<div class="grid gap-6 md:grid-cols-2">
<div class="rounded-lg border bg-surface p-5">
<h2 class="text-lg font-semibold text-text mb-4">Details</h2>
<dl class="grid grid-cols-2 gap-x-4 gap-y-3 text-sm">
<div>
<dt class="text-text-muted">Country</dt>
<dd class="font-medium text-text">
{% if !roaster.country_flag.is_empty() %}{{ roaster.country_flag }} {% endif %}{{ roaster.country }}
</dd>
</div>
{% if let Some(c) = roaster.city %}
<div>
<dt class="text-text-muted">City</dt>
<dd class="font-medium text-text">{{ c }}</dd>
</div>
{% endif %}
{% if let Some(url) = roaster.homepage %}
<div>
<dt class="text-text-muted">Website</dt>
<dd class="font-medium">
<a href="{{ url }}" target="_blank" rel="noreferrer noopener" class="text-accent hover:text-accent-hover transition">Visit Website</a>
</dd>
</div>
{% endif %}
</dl>
</div>
{{ detail::map_with_legend_1(roaster.map_countries, roaster.map_max, "Roaster", "") }}
</div>
{% if is_authenticated %}
<div class="rounded-lg border bg-surface p-5 flex items-center gap-2">
<button type="button" onclick="deleteRoaster('{{ roaster.id }}')"
class="inline-flex items-center gap-2 rounded-md bg-red-600 px-4 py-2 text-sm font-medium text-white transition hover:bg-red-700">
{{ icons::delete("h-4 w-4") }} Delete
</button>
</div>
<script>
const deleteRoaster = async (id) => {
if (!confirm('Delete this roaster? This cannot be undone.')) return;
try {
const resp = await fetch(`/api/v1/roasters/${id}`, {
method: 'DELETE',
credentials: 'same-origin',
});
if (!resp.ok) throw new Error(`Server returned ${resp.status}`);
window.location.href = '/data?type=roasters';
} catch (e) {
alert(`Failed to delete roaster: ${e.message}`);
}
};
</script>
{% endif %}
{% endblock %}