build(deps): bump askama from 0.12.1 to 0.15.4 (#7)
* build(deps): bump askama from 0.12.1 to 0.15.4 Bumps [askama](https://github.com/askama-rs/askama) from 0.12.1 to 0.15.4. - [Release notes](https://github.com/askama-rs/askama/releases) - [Commits](https://github.com/askama-rs/askama/compare/0.12.1...v0.15.4) --- updated-dependencies: - dependency-name: askama dependency-version: 0.15.4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * fix(deps): adapt templates and tests for askama 0.15 - Migrate macro calls from {% call %} to {{ }} expression syntax (134 occurrences) - Update test assertion for askama 0.15's numeric HTML entity encoding (& vs &) --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jon Seager <jon@sgrs.uk>
This commit is contained in:
parent
5bba529936
commit
ea4093b699
23 changed files with 166 additions and 174 deletions
74
Cargo.lock
generated
74
Cargo.lock
generated
|
|
@ -103,46 +103,54 @@ checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
|||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.12.1"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
|
||||
checksum = "08e1676b346cadfec169374f949d7490fd80a24193d37d2afce0c047cf695e57"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"askama_escape",
|
||||
"humansize",
|
||||
"num-traits",
|
||||
"askama_macros",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.12.5"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
|
||||
checksum = "7661ff56517787343f376f75db037426facd7c8d3049cef8911f1e75016f3a37"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_escape"
|
||||
version = "0.10.3"
|
||||
name = "askama_macros"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
|
||||
checksum = "713ee4dbfd1eb719c2dab859465b01fa1d21cb566684614a713a6b7a99a4e47b"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.2.1"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
|
||||
checksum = "1d62d674238a526418b30c0def480d5beadb9d8964e7f38d635b03bf639c704c"
|
||||
dependencies = [
|
||||
"nom",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"unicode-ident",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1149,15 +1157,6 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humansize"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.8.1"
|
||||
|
|
@ -1543,16 +1542,6 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
|
|
@ -3096,12 +3085,6 @@ version = "1.19.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.18"
|
||||
|
|
@ -3724,6 +3707,15 @@ version = "0.53.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wiremock"
|
||||
version = "0.6.5"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ edition = "2024"
|
|||
anyhow = "1.0"
|
||||
async-trait = "0.1"
|
||||
axum = { version = "0.7", features = ["macros"] }
|
||||
askama = "0.12"
|
||||
askama = "0.15"
|
||||
base64 = "0.22"
|
||||
chrono = { version = "0.4", features = ["serde", "clock"] }
|
||||
clap = { version = "4.5", features = ["derive", "env"] }
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
{% for passkey in passkeys %}
|
||||
<div class="flex items-center justify-between gap-4 rounded-md bg-surface-alt px-4 py-3">
|
||||
<div class="flex items-center gap-3 min-w-0">
|
||||
{% call icons::key("h-4 w-4 text-accent shrink-0") %}
|
||||
{{ icons::key("h-4 w-4 text-accent shrink-0") }}
|
||||
<div class="min-w-0">
|
||||
<span class="block text-sm font-semibold text-text">{{ passkey.name }}</span>
|
||||
<span class="block text-xs text-text-muted">
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
onclick="deletePasskey({{ passkey.id }}, '{{ passkey.name }}')"
|
||||
aria-label="Delete passkey"
|
||||
>
|
||||
{% call icons::delete("h-4 w-4") %}
|
||||
{{ icons::delete("h-4 w-4") }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -80,7 +80,7 @@
|
|||
</button>
|
||||
</div>
|
||||
<div id="add-passkey-loading" class="mt-3 hidden flex items-center gap-3 text-sm text-accent">
|
||||
{% call icons::spinner("h-5 w-5") %}
|
||||
{{ icons::spinner("h-5 w-5") }}
|
||||
Follow the prompts from your browser or device...
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
onclick="revokeToken({{ token.id }}, '{{ token.name }}')"
|
||||
aria-label="Revoke token"
|
||||
>
|
||||
{% call icons::delete("h-4 w-4") %}
|
||||
{{ icons::delete("h-4 w-4") }}
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{% block head %}
|
||||
<script>
|
||||
{% call location::location_search_js() %}
|
||||
{{ location::location_search_js() }}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
data-on:submit="$_extracting = true; $_extractError = ''; @post('/api/v1/extract-bag-scan', {contentType: 'form'})"
|
||||
data-on:datastar-fetch="if (!$_extracting) return; if (evt.detail.type === 'finished') { $_extracting = false; $_scanExtracted = true; document.getElementById('scan-extract-form').reset() } else if (evt.detail.type === 'error') { $_extracting = false; $_extractError = 'Extraction failed. Please try again.' }"
|
||||
>
|
||||
{% call scan::scan_input("scan-extract-form", "scan-image", "$_extracting", "$_extractError", "Describe the coffee bag…", "Waiting for response…") %}
|
||||
{{ scan::scan_input("scan-extract-form", "scan-image", "$_extracting", "$_extractError", "Describe the coffee bag…", "Waiting for response…") }}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
|
@ -427,14 +427,14 @@
|
|||
|
||||
<!-- Location search -->
|
||||
<div class="mt-4 border-b pb-4" data-show="!$_reviewingCafe">
|
||||
{% call location::location_search("$_cafeError") %}
|
||||
{{ location::location_search("$_cafeError") }}
|
||||
<p data-show="$_cafeError" data-text="$_cafeError" style="display:none" class="mt-2 text-sm text-red-600"></p>
|
||||
</div>
|
||||
|
||||
<!-- Selected cafe indicator -->
|
||||
<div class="mt-4 border-b pb-4 flex items-center justify-between" data-show="$_reviewingCafe" style="display:none">
|
||||
<div class="flex items-center gap-2">
|
||||
{% call icons::location("h-4 w-4 text-accent shrink-0") %}
|
||||
{{ icons::location("h-4 w-4 text-accent shrink-0") }}
|
||||
<span class="text-sm font-medium text-text" data-text="$_cafeName"></span>
|
||||
<span class="text-xs text-text-muted" data-show="$_cafeCity" data-text="$_cafeCity" style="display:none"></span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{% block head %}
|
||||
<script>
|
||||
{% call location::location_search_js() %}
|
||||
{{ location::location_search_js() }}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
style="display: none"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
{% call icons::location("h-4 w-4 text-accent shrink-0") %}
|
||||
{{ icons::location("h-4 w-4 text-accent shrink-0") }}
|
||||
<span class="font-medium text-text" data-text="$_cafeName"></span>
|
||||
<span class="text-xs text-text-muted" data-show="$_cafeCity" data-text="$_cafeCity" style="display: none"></span>
|
||||
</div>
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
style="display: none"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
{% call icons::bag("h-4 w-4 text-accent shrink-0") %}
|
||||
{{ icons::bag("h-4 w-4 text-accent shrink-0") }}
|
||||
<span class="font-medium text-text" data-text="$_roastName"></span>
|
||||
<span class="text-xs text-text-muted" data-show="$_roasterName" data-text="$_roasterName" style="display: none"></span>
|
||||
</div>
|
||||
|
|
@ -129,7 +129,7 @@
|
|||
<div class="mt-4" data-show="$_step === 1" style="display: none">
|
||||
<div class="rounded-lg border bg-surface p-5">
|
||||
<div data-show="!$_reviewingCafe">
|
||||
{% call location::location_search("$_error") %}
|
||||
{{ location::location_search("$_error") }}
|
||||
</div>
|
||||
|
||||
<!-- Review form for new cafe from Foursquare -->
|
||||
|
|
@ -208,7 +208,7 @@
|
|||
data-on:submit="$_extracting = true; $_extractError = ''; @post('/api/v1/scan', {contentType: 'form'})"
|
||||
data-on:datastar-fetch="if (!$_extracting) return; if (evt.detail.type === 'finished') { $_extracting = false; $_roastName = $_scanSuccess; $_step = 3 } else if (evt.detail.type === 'error') { $_extracting = false; $_extractError = 'Scan failed. Please try again.' }"
|
||||
>
|
||||
{% call scan::scan_input("checkin-scan-form", "checkin-image", "$_extracting", "$_extractError", "Describe the coffee…", "Scanning…") %}
|
||||
{{ scan::scan_input("checkin-scan-form", "checkin-image", "$_extracting", "$_extractError", "Describe the coffee…", "Scanning…") }}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<div class="rounded-lg border bg-surface p-6">
|
||||
{% if token.is_some() %}
|
||||
<div class="flex flex-col items-center text-center gap-3">
|
||||
{% call icons::check_circle("h-10 w-10 text-emerald-600 dark:text-emerald-400") %}
|
||||
{{ icons::check_circle("h-10 w-10 text-emerald-600 dark:text-emerald-400") }}
|
||||
<h1 class="text-2xl font-semibold text-accent">CLI Authenticated</h1>
|
||||
<p class="text-sm text-text-secondary">
|
||||
Your CLI has been authenticated successfully. You can close this window and return to the terminal.
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
{% else if error.is_some() %}
|
||||
<div class="flex flex-col items-center text-center gap-3">
|
||||
{% call icons::x_circle("h-10 w-10 text-red-600 dark:text-red-400") %}
|
||||
{{ icons::x_circle("h-10 w-10 text-red-600 dark:text-red-400") }}
|
||||
<h1 class="text-2xl font-semibold text-accent">Authentication Failed</h1>
|
||||
<div class="w-full rounded-md bg-red-100 border border-red-300 p-3 text-sm text-red-800 dark:bg-red-950/40 dark:border-red-800 dark:text-red-300">
|
||||
{{ error.as_ref().unwrap() }}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
{% else %}
|
||||
<div class="flex flex-col items-center text-center gap-3">
|
||||
{% call icons::spinner("h-10 w-10") %}
|
||||
{{ icons::spinner("h-10 w-10") }}
|
||||
<h1 class="text-2xl font-semibold text-accent">CLI Authentication</h1>
|
||||
<p class="text-sm text-text-secondary">
|
||||
Processing authentication…
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
href="/add?type={{ active_type }}"
|
||||
class="inline-flex items-center gap-2 rounded-md bg-accent px-4 py-2.5 text-sm font-semibold text-accent-text transition hover:bg-accent-hover"
|
||||
>
|
||||
{% call icons::plus_circle("h-4 w-4") %}
|
||||
{{ icons::plus_circle("h-4 w-4") }}
|
||||
Add
|
||||
</a>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
data-on:submit="$_extracting = true; $_extractError = ''; @post('/api/v1/extract-bag-scan', {contentType: 'form'})"
|
||||
data-on:datastar-fetch="if (!$_extracting) return; if (evt.detail.type === 'finished') { $_extracting = false; $_scanExtracted = true; document.getElementById('scan-extract-form').reset() } else if (evt.detail.type === 'error') { $_extracting = false; $_extractError = 'Extraction failed. Please try again.' }"
|
||||
>
|
||||
{% call scan::scan_input("scan-extract-form", "scan-image", "$_extracting", "$_extractError", "Describe the coffee bag…", "Waiting for response…") %}
|
||||
{{ scan::scan_input("scan-extract-form", "scan-image", "$_extracting", "$_extractError", "Describe the coffee bag…", "Waiting for response…") }}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
|
@ -128,7 +128,7 @@
|
|||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-accent transition hover:text-accent-hover hover:bg-surface-alt"
|
||||
title="Brew Again"
|
||||
>
|
||||
{% call icons::refresh("h-4 w-4") %}
|
||||
{{ icons::refresh("h-4 w-4") }}
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
|
@ -148,7 +148,7 @@
|
|||
</div>
|
||||
<div id="open-bags-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{% for bag in open_bags %}
|
||||
{% call bag_card::card(bag, is_authenticated) %}
|
||||
{{ bag_card::card(bag, is_authenticated) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -182,37 +182,37 @@
|
|||
</div>
|
||||
<div class="grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-7">
|
||||
<a href="/data?type=brews" class="group flex flex-col items-center gap-1 rounded-lg border bg-surface p-4 transition hover:bg-surface-alt">
|
||||
{% call icons::beaker("h-6 w-6 text-accent") %}
|
||||
{{ icons::beaker("h-6 w-6 text-accent") }}
|
||||
<span class="text-lg font-bold text-text group-hover:text-accent">{{ stats.brews }}</span>
|
||||
<span class="text-xs text-text-muted">Brews</span>
|
||||
</a>
|
||||
<a href="/data?type=roasts" class="group flex flex-col items-center gap-1 rounded-lg border bg-surface p-4 transition hover:bg-surface-alt">
|
||||
{% call icons::fire("h-6 w-6 text-accent") %}
|
||||
{{ icons::fire("h-6 w-6 text-accent") }}
|
||||
<span class="text-lg font-bold text-text group-hover:text-accent">{{ stats.roasts }}</span>
|
||||
<span class="text-xs text-text-muted">Roasts</span>
|
||||
</a>
|
||||
<a href="/data?type=roasters" class="group flex flex-col items-center gap-1 rounded-lg border bg-surface p-4 transition hover:bg-surface-alt">
|
||||
{% call icons::building("h-6 w-6 text-accent") %}
|
||||
{{ icons::building("h-6 w-6 text-accent") }}
|
||||
<span class="text-lg font-bold text-text group-hover:text-accent">{{ stats.roasters }}</span>
|
||||
<span class="text-xs text-text-muted">Roasters</span>
|
||||
</a>
|
||||
<a href="/data?type=bags" class="group flex flex-col items-center gap-1 rounded-lg border bg-surface p-4 transition hover:bg-surface-alt">
|
||||
{% call icons::bag("h-6 w-6 text-accent") %}
|
||||
{{ icons::bag("h-6 w-6 text-accent") }}
|
||||
<span class="text-lg font-bold text-text group-hover:text-accent">{{ stats.bags }}</span>
|
||||
<span class="text-xs text-text-muted">Bags</span>
|
||||
</a>
|
||||
<a href="/data?type=cups" class="group flex flex-col items-center gap-1 rounded-lg border bg-surface p-4 transition hover:bg-surface-alt">
|
||||
{% call icons::cup("h-6 w-6 text-accent") %}
|
||||
{{ icons::cup("h-6 w-6 text-accent") }}
|
||||
<span class="text-lg font-bold text-text group-hover:text-accent">{{ stats.cups }}</span>
|
||||
<span class="text-xs text-text-muted">Cups</span>
|
||||
</a>
|
||||
<a href="/data?type=cafes" class="group flex flex-col items-center gap-1 rounded-lg border bg-surface p-4 transition hover:bg-surface-alt">
|
||||
{% call icons::location("h-6 w-6 text-accent") %}
|
||||
{{ icons::location("h-6 w-6 text-accent") }}
|
||||
<span class="text-lg font-bold text-text group-hover:text-accent">{{ stats.cafes }}</span>
|
||||
<span class="text-xs text-text-muted">Cafes</span>
|
||||
</a>
|
||||
<a href="/data?type=gear" class="group flex flex-col items-center gap-1 rounded-lg border bg-surface p-4 transition hover:bg-surface-alt">
|
||||
{% call icons::wrench("h-6 w-6 text-accent") %}
|
||||
{{ icons::wrench("h-6 w-6 text-accent") }}
|
||||
<span class="text-lg font-bold text-text group-hover:text-accent">{{ stats.gear }}</span>
|
||||
<span class="text-xs text-text-muted">Gear</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
{% if is_authenticated %}
|
||||
<div class="mt-3 pt-3 border-t flex gap-3">
|
||||
<a href="/add?type=brew&bag_id={{ bag.id }}" class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover">
|
||||
{% call icons::plus_circle("h-4 w-4") %}
|
||||
{{ icons::plus_circle("h-4 w-4") }}
|
||||
Brew
|
||||
</a>
|
||||
<button
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-text"
|
||||
onclick="closeBag('{{ bag.id }}', document.getElementById('bag-card-{{ bag.id }}'))"
|
||||
>
|
||||
{% call icons::x_circle("h-4 w-4") %}
|
||||
{{ icons::x_circle("h-4 w-4") }}
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<h3 class="text-base font-semibold text-text">Roaster</h3>
|
||||
<div class="mt-2 rounded-lg border bg-surface px-4 py-3 flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
{% call icons::fire("h-4 w-4 text-accent shrink-0") %}
|
||||
{{ icons::fire("h-4 w-4 text-accent shrink-0") }}
|
||||
<span class="font-medium text-text" data-text="$_roasterName"></span>
|
||||
<span class="text-xs text-text-muted" data-show="$_roasterCountry" data-text="$_roasterCountry" style="display:none"></span>
|
||||
</div>
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
<h3 class="text-base font-semibold text-text">Roast</h3>
|
||||
<div class="mt-2 rounded-lg border bg-surface px-4 py-3 flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
{% call icons::bag("h-4 w-4 text-accent shrink-0") %}
|
||||
{{ icons::bag("h-4 w-4 text-accent shrink-0") }}
|
||||
<span class="font-medium text-text" data-text="$_roastName"></span>
|
||||
<span class="text-xs text-text-muted" data-show="$_origin" data-text="$_origin" style="display:none"></span>
|
||||
</div>
|
||||
|
|
@ -107,7 +107,7 @@
|
|||
</div>
|
||||
<p data-show="$_scanError" data-text="$_scanError" style="display:none" class="text-sm text-red-600"></p>
|
||||
<div data-show="$_scanSubmitting" style="display:none" class="flex items-center gap-3 text-sm text-accent">
|
||||
{% call icons::spinner("h-5 w-5") %}
|
||||
{{ icons::spinner("h-5 w-5") }}
|
||||
Saving…
|
||||
</div>
|
||||
<div data-show="!$_scanSubmitting" class="flex items-center justify-end gap-2">
|
||||
|
|
|
|||
|
|
@ -18,16 +18,16 @@
|
|||
<section class="rounded-lg border bg-surface"
|
||||
{% if bags.has_next() %}data-infinite-scroll data-next-url="{{ navigator.fragment_page_href(bags.next_page().unwrap())|safe }}" data-target="#bag-list"{% endif %}
|
||||
>
|
||||
{% call table::search_header(navigator, "#bag-list") %}
|
||||
{{ table::search_header(navigator, "#bag-list") }}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="responsive-table min-w-full divide-y text-left text-sm text-text">
|
||||
<thead class="bg-surface-alt text-xs font-semibold tracking-wide text-text">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#bag-list") %}
|
||||
{% call table::sortable_header("Roaster", "roaster", navigator, "#bag-list") %}
|
||||
{% call table::sortable_header("Roast", "roast", navigator, "#bag-list") %}
|
||||
{% call table::sortable_header("Status", "status", navigator, "#bag-list") %}
|
||||
{% call table::sortable_header("Finished", "finished-at", navigator, "#bag-list") %}
|
||||
{{ table::sortable_header("Added", "created-at", navigator, "#bag-list") }}
|
||||
{{ table::sortable_header("Roaster", "roaster", navigator, "#bag-list") }}
|
||||
{{ table::sortable_header("Roast", "roast", navigator, "#bag-list") }}
|
||||
{{ table::sortable_header("Status", "status", navigator, "#bag-list") }}
|
||||
{{ table::sortable_header("Finished", "finished-at", navigator, "#bag-list") }}
|
||||
{% if is_authenticated %}
|
||||
<th scope="col" class="actions-col px-4 py-3 text-right">Actions</th>
|
||||
{% endif %}
|
||||
|
|
@ -83,13 +83,13 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
data-on:click="confirm('Close this bag? This will mark it as finished.') && @put('/api/v1/bags/{{ bag.id }}?closed=true&{{ navigator.query() }}', {responseOverrides: {selector: '#bag-list', mode: 'replace'}})">
|
||||
{% call icons::x_circle("h-4 w-4") %} Close bag
|
||||
{{ icons::x_circle("h-4 w-4") }} Close bag
|
||||
</button>
|
||||
{% endif %}
|
||||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this bag?') && @delete('/api/v1/bags/{{ bag.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#bag-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -103,8 +103,8 @@
|
|||
<button type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-text-muted transition hover:text-accent hover:bg-surface-alt"
|
||||
title="Actions">
|
||||
<span class="icon-expand">{% call icons::ellipsis_vertical("h-5 w-5") %}</span>
|
||||
<span class="icon-collapse hidden">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span class="icon-expand">{{ icons::ellipsis_vertical("h-5 w-5") }}</span>
|
||||
<span class="icon-collapse hidden">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -118,13 +118,13 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
data-on:click="confirm('Close this bag? This will mark it as finished.') && @put('/api/v1/bags/{{ bag.id }}?closed=true&{{ navigator.query() }}', {responseOverrides: {selector: '#bag-list', mode: 'replace'}})">
|
||||
{% call icons::x_circle("h-4 w-4") %} Close bag
|
||||
{{ icons::x_circle("h-4 w-4") }} Close bag
|
||||
</button>
|
||||
{% endif %}
|
||||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this bag?') && @delete('/api/v1/bags/{{ bag.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#bag-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -137,7 +137,7 @@
|
|||
{% if bags.items.is_empty() %}
|
||||
<div class="p-8 text-center text-text-muted">No bags match your search.</div>
|
||||
{% endif %}
|
||||
{% call table::pagination_header(bags, navigator, "#bag-list") %}
|
||||
{{ table::pagination_header(bags, navigator, "#bag-list") }}
|
||||
{% if bags.has_next() %}
|
||||
<div class="infinite-scroll-sentinel h-4 md:hidden" aria-hidden="true"></div>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@
|
|||
<input type="hidden" name="quick_notes" value="{{ brew.quick_notes_raw }}" />
|
||||
<button type="submit"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover">
|
||||
{% call icons::plus_circle("h-4 w-4") %} Brew Again
|
||||
{{ icons::plus_circle("h-4 w-4") }} Brew Again
|
||||
</button>
|
||||
</form>
|
||||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this brew?') && @delete('/api/v1/brews/{{ brew.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#brew-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
|
@ -45,13 +45,13 @@
|
|||
<section class="rounded-lg border bg-surface"
|
||||
{% if brews.has_next() %}data-infinite-scroll data-next-url="{{ navigator.fragment_page_href(brews.next_page().unwrap())|safe }}" data-target="#brew-list"{% endif %}
|
||||
>
|
||||
{% call table::search_header(navigator, "#brew-list") %}
|
||||
{{ table::search_header(navigator, "#brew-list") }}
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="responsive-table min-w-full divide-y text-left text-sm text-text">
|
||||
<thead class="bg-surface-alt text-xs font-semibold tracking-wide text-text">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#brew-list") %}
|
||||
{{ table::sortable_header("Added", "created-at", navigator, "#brew-list") }}
|
||||
<th scope="col" class="px-4 py-3">Coffee</th>
|
||||
<th scope="col" class="px-4 py-3">Grind</th>
|
||||
<th scope="col" class="px-4 py-3">Recipe</th>
|
||||
|
|
@ -109,14 +109,14 @@
|
|||
</td>
|
||||
{% if is_authenticated %}
|
||||
<td data-label="" class="card-detail hidden">
|
||||
{% call brew_actions(brew, navigator) %}
|
||||
{{ brew_actions(brew, navigator) }}
|
||||
</td>
|
||||
<td data-label="" class="card-actions px-4 py-3 text-right">
|
||||
<button type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-text-muted transition hover:text-accent hover:bg-surface-alt"
|
||||
title="Actions">
|
||||
<span class="icon-expand">{% call icons::ellipsis_vertical("h-5 w-5") %}</span>
|
||||
<span class="icon-collapse hidden">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span class="icon-expand">{{ icons::ellipsis_vertical("h-5 w-5") }}</span>
|
||||
<span class="icon-collapse hidden">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
|
@ -124,7 +124,7 @@
|
|||
{% if is_authenticated %}
|
||||
<tr class="hidden detail-row">
|
||||
<td colspan="7" class="bg-surface-alt px-4 py-2">
|
||||
{% call brew_actions(brew, navigator) %}
|
||||
{{ brew_actions(brew, navigator) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% call table::pagination_header(brews, navigator, "#brew-list") %}
|
||||
{{ table::pagination_header(brews, navigator, "#brew-list") }}
|
||||
|
||||
{% if brews.has_next() %}
|
||||
<div class="infinite-scroll-sentinel h-4 md:hidden" aria-hidden="true"></div>
|
||||
|
|
|
|||
|
|
@ -18,15 +18,15 @@
|
|||
<section class="rounded-lg border bg-surface"
|
||||
{% if cafes.has_next() %}data-infinite-scroll data-next-url="{{ navigator.fragment_page_href(cafes.next_page().unwrap())|safe }}" data-target="#cafe-list"{% endif %}
|
||||
>
|
||||
{% call table::search_header(navigator, "#cafe-list") %}
|
||||
{{ table::search_header(navigator, "#cafe-list") }}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="responsive-table min-w-full divide-y text-left text-sm text-text">
|
||||
<thead class="bg-surface-alt text-xs font-semibold tracking-wide text-text">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#cafe-list") %}
|
||||
{% call table::sortable_header("Name", "name", navigator, "#cafe-list") %}
|
||||
{% call table::sortable_header("City", "city", navigator, "#cafe-list") %}
|
||||
{% call table::sortable_header("Country", "country", navigator, "#cafe-list") %}
|
||||
{{ table::sortable_header("Added", "created-at", navigator, "#cafe-list") }}
|
||||
{{ table::sortable_header("Name", "name", navigator, "#cafe-list") }}
|
||||
{{ table::sortable_header("City", "city", navigator, "#cafe-list") }}
|
||||
{{ table::sortable_header("Country", "country", navigator, "#cafe-list") }}
|
||||
<th scope="col" class="actions-col px-4 py-3 text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -56,19 +56,19 @@
|
|||
<div class="flex items-center gap-4">
|
||||
<a class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
href="{{ cafe.map_url }}" target="_blank" rel="noreferrer noopener">
|
||||
{% call icons::location("h-4 w-4") %} View Map
|
||||
{{ icons::location("h-4 w-4") }} View Map
|
||||
</a>
|
||||
{% if cafe.has_website %}
|
||||
<a class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
href="{{ cafe.website_url }}" target="_blank" rel="noreferrer noopener">
|
||||
{% call icons::external_link("h-4 w-4") %} Homepage
|
||||
{{ icons::external_link("h-4 w-4") }} Homepage
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if is_authenticated %}
|
||||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this cafe?') && @delete('/api/v1/cafes/{{ cafe.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#cafe-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -77,8 +77,8 @@
|
|||
<button type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-text-muted transition hover:text-accent hover:bg-surface-alt"
|
||||
title="Actions">
|
||||
<span class="icon-expand">{% call icons::ellipsis_vertical("h-5 w-5") %}</span>
|
||||
<span class="icon-collapse hidden">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span class="icon-expand">{{ icons::ellipsis_vertical("h-5 w-5") }}</span>
|
||||
<span class="icon-collapse hidden">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -87,19 +87,19 @@
|
|||
<div class="flex items-center gap-4">
|
||||
<a class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
href="{{ cafe.map_url }}" target="_blank" rel="noreferrer noopener">
|
||||
{% call icons::location("h-4 w-4") %} View Map
|
||||
{{ icons::location("h-4 w-4") }} View Map
|
||||
</a>
|
||||
{% if cafe.has_website %}
|
||||
<a class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
href="{{ cafe.website_url }}" target="_blank" rel="noreferrer noopener">
|
||||
{% call icons::external_link("h-4 w-4") %} Homepage
|
||||
{{ icons::external_link("h-4 w-4") }} Homepage
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if is_authenticated %}
|
||||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this cafe?') && @delete('/api/v1/cafes/{{ cafe.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#cafe-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
{% if cafes.items.is_empty() %}
|
||||
<div class="p-8 text-center text-text-muted">No cafes match your search.</div>
|
||||
{% endif %}
|
||||
{% call table::pagination_header(cafes, navigator, "#cafe-list") %}
|
||||
{{ table::pagination_header(cafes, navigator, "#cafe-list") }}
|
||||
{% if cafes.has_next() %}
|
||||
<div class="infinite-scroll-sentinel h-4 md:hidden" aria-hidden="true"></div>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -18,16 +18,16 @@
|
|||
<section class="rounded-lg border bg-surface"
|
||||
{% if cups.has_next() %}data-infinite-scroll data-next-url="{{ navigator.fragment_page_href(cups.next_page().unwrap())|safe }}" data-target="#cup-list"{% endif %}
|
||||
>
|
||||
{% call table::search_header(navigator, "#cup-list") %}
|
||||
{{ table::search_header(navigator, "#cup-list") }}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="responsive-table min-w-full divide-y text-left text-sm text-text">
|
||||
<thead class="bg-surface-alt text-xs font-semibold tracking-wide text-text">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#cup-list") %}
|
||||
{% call table::sortable_header("Roast", "roast", navigator, "#cup-list") %}
|
||||
{% call table::sortable_header("Roaster", "roaster", navigator, "#cup-list") %}
|
||||
{% call table::sortable_header("Cafe", "cafe", navigator, "#cup-list") %}
|
||||
{% call table::sortable_header("City", "city", navigator, "#cup-list") %}
|
||||
{{ table::sortable_header("Added", "created-at", navigator, "#cup-list") }}
|
||||
{{ table::sortable_header("Roast", "roast", navigator, "#cup-list") }}
|
||||
{{ table::sortable_header("Roaster", "roaster", navigator, "#cup-list") }}
|
||||
{{ table::sortable_header("Cafe", "cafe", navigator, "#cup-list") }}
|
||||
{{ table::sortable_header("City", "city", navigator, "#cup-list") }}
|
||||
{% if is_authenticated %}
|
||||
<th scope="col" class="actions-col px-4 py-3 text-right">Actions</th>
|
||||
{% endif %}
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this cup?') && @delete('/api/v1/cups/{{ cup.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#cup-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -69,8 +69,8 @@
|
|||
<button type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-text-muted transition hover:text-accent hover:bg-surface-alt"
|
||||
title="Actions">
|
||||
<span class="icon-expand">{% call icons::ellipsis_vertical("h-5 w-5") %}</span>
|
||||
<span class="icon-collapse hidden">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span class="icon-expand">{{ icons::ellipsis_vertical("h-5 w-5") }}</span>
|
||||
<span class="icon-collapse hidden">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this cup?') && @delete('/api/v1/cups/{{ cup.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#cup-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
{% if cups.items.is_empty() %}
|
||||
<div class="p-8 text-center text-text-muted">No cups match your search.</div>
|
||||
{% endif %}
|
||||
{% call table::pagination_header(cups, navigator, "#cup-list") %}
|
||||
{{ table::pagination_header(cups, navigator, "#cup-list") }}
|
||||
{% if cups.has_next() %}
|
||||
<div class="infinite-scroll-sentinel h-4 md:hidden" aria-hidden="true"></div>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -18,16 +18,16 @@
|
|||
<section class="rounded-lg border bg-surface"
|
||||
{% if gear.has_next() %}data-infinite-scroll data-next-url="{{ navigator.fragment_page_href(gear.next_page().unwrap())|safe }}" data-target="#gear-list"{% endif %}
|
||||
>
|
||||
{% call table::search_header(navigator, "#gear-list") %}
|
||||
{{ table::search_header(navigator, "#gear-list") }}
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="responsive-table min-w-full divide-y text-left text-sm text-text">
|
||||
<thead class="bg-surface-alt text-xs font-semibold tracking-wide text-text">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#gear-list") %}
|
||||
{% call table::sortable_header("Category", "category", navigator, "#gear-list") %}
|
||||
{% call table::sortable_header("Make", "make", navigator, "#gear-list") %}
|
||||
{% call table::sortable_header("Model", "model", navigator, "#gear-list") %}
|
||||
{{ table::sortable_header("Added", "created-at", navigator, "#gear-list") }}
|
||||
{{ table::sortable_header("Category", "category", navigator, "#gear-list") }}
|
||||
{{ table::sortable_header("Make", "make", navigator, "#gear-list") }}
|
||||
{{ table::sortable_header("Model", "model", navigator, "#gear-list") }}
|
||||
{% if is_authenticated %}
|
||||
<th scope="col" class="actions-col px-4 py-3 text-right">Actions</th>
|
||||
{% endif %}
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this gear?') && @delete('/api/v1/gear/{{ item.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#gear-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -66,8 +66,8 @@
|
|||
<button type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-text-muted transition hover:text-accent hover:bg-surface-alt"
|
||||
title="Actions">
|
||||
<span class="icon-expand">{% call icons::ellipsis_vertical("h-5 w-5") %}</span>
|
||||
<span class="icon-collapse hidden">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span class="icon-expand">{{ icons::ellipsis_vertical("h-5 w-5") }}</span>
|
||||
<span class="icon-collapse hidden">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this gear?') && @delete('/api/v1/gear/{{ item.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#gear-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
{% if gear.items.is_empty() %}
|
||||
<div class="p-8 text-center text-text-muted">No gear matches your search.</div>
|
||||
{% endif %}
|
||||
{% call table::pagination_header(gear, navigator, "#gear-list") %}
|
||||
{{ table::pagination_header(gear, navigator, "#gear-list") }}
|
||||
{% if gear.has_next() %}
|
||||
<div class="infinite-scroll-sentinel h-4 md:hidden" aria-hidden="true"></div>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@
|
|||
<section class="rounded-lg border bg-surface"
|
||||
{% if roasts.has_next() %}data-infinite-scroll data-next-url="{{ navigator.fragment_page_href(roasts.next_page().unwrap())|safe }}" data-target="#roast-list"{% endif %}
|
||||
>
|
||||
{% call table::search_header(navigator, "#roast-list") %}
|
||||
{{ table::search_header(navigator, "#roast-list") }}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="responsive-table min-w-full divide-y text-left text-sm text-text">
|
||||
<thead class="bg-surface-alt text-xs font-semibold tracking-wide text-text">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#roast-list") %}
|
||||
{% call table::sortable_header("Roast", "name", navigator, "#roast-list") %}
|
||||
{% call table::sortable_header("Origin", "origin", navigator, "#roast-list") %}
|
||||
{{ table::sortable_header("Added", "created-at", navigator, "#roast-list") }}
|
||||
{{ table::sortable_header("Roast", "name", navigator, "#roast-list") }}
|
||||
{{ table::sortable_header("Origin", "origin", navigator, "#roast-list") }}
|
||||
<th scope="col" class="px-4 py-3">Tasting Notes</th>
|
||||
{% if is_authenticated %}
|
||||
<th scope="col" class="actions-col px-4 py-3 text-right">Actions</th>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this roast?') && @delete('/api/v1/roasts/{{ roast.full_id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#roast-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -87,8 +87,8 @@
|
|||
<button type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-text-muted transition hover:text-accent hover:bg-surface-alt"
|
||||
title="Actions">
|
||||
<span class="icon-expand">{% call icons::ellipsis_vertical("h-5 w-5") %}</span>
|
||||
<span class="icon-collapse hidden">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span class="icon-expand">{{ icons::ellipsis_vertical("h-5 w-5") }}</span>
|
||||
<span class="icon-collapse hidden">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
|
@ -100,7 +100,7 @@
|
|||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this roast?') && @delete('/api/v1/roasts/{{ roast.full_id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#roast-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
{% if roasts.items.is_empty() %}
|
||||
<div class="p-8 text-center text-text-muted">No roasts match your search.</div>
|
||||
{% endif %}
|
||||
{% call table::pagination_header(roasts, navigator, "#roast-list") %}
|
||||
{{ table::pagination_header(roasts, navigator, "#roast-list") }}
|
||||
{% if roasts.has_next() %}
|
||||
<div class="infinite-scroll-sentinel h-4 md:hidden" aria-hidden="true"></div>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -18,15 +18,15 @@
|
|||
<section class="rounded-lg border bg-surface"
|
||||
{% if roasters.has_next() %}data-infinite-scroll data-next-url="{{ navigator.fragment_page_href(roasters.next_page().unwrap())|safe }}" data-target="#roaster-list"{% endif %}
|
||||
>
|
||||
{% call table::search_header(navigator, "#roaster-list") %}
|
||||
{{ table::search_header(navigator, "#roaster-list") }}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="responsive-table min-w-full divide-y text-left text-sm text-text">
|
||||
<thead class="bg-surface-alt text-xs font-semibold tracking-wide text-text">
|
||||
<tr>
|
||||
{% call table::sortable_header("Added", "created-at", navigator, "#roaster-list") %}
|
||||
{% call table::sortable_header("Name", "name", navigator, "#roaster-list") %}
|
||||
{% call table::sortable_header("Country", "country", navigator, "#roaster-list") %}
|
||||
{% call table::sortable_header("City", "city", navigator, "#roaster-list") %}
|
||||
{{ table::sortable_header("Added", "created-at", navigator, "#roaster-list") }}
|
||||
{{ table::sortable_header("Name", "name", navigator, "#roaster-list") }}
|
||||
{{ table::sortable_header("Country", "country", navigator, "#roaster-list") }}
|
||||
{{ table::sortable_header("City", "city", navigator, "#roaster-list") }}
|
||||
<th scope="col" class="actions-col px-4 py-3 text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -60,14 +60,14 @@
|
|||
{% if roaster.has_homepage %}
|
||||
<a class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
href="{{ roaster.homepage_url }}" target="_blank" rel="noreferrer noopener">
|
||||
{% call icons::external_link("h-4 w-4") %} Homepage
|
||||
{{ icons::external_link("h-4 w-4") }} Homepage
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if is_authenticated %}
|
||||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this roaster?') && @delete('/api/v1/roasters/{{ roaster.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#roaster-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -78,8 +78,8 @@
|
|||
<button type="button"
|
||||
class="inline-flex h-8 w-8 items-center justify-center rounded-md text-text-muted transition hover:text-accent hover:bg-surface-alt"
|
||||
title="Actions">
|
||||
<span class="icon-expand">{% call icons::ellipsis_vertical("h-5 w-5") %}</span>
|
||||
<span class="icon-collapse hidden">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span class="icon-expand">{{ icons::ellipsis_vertical("h-5 w-5") }}</span>
|
||||
<span class="icon-collapse hidden">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
|
@ -91,14 +91,14 @@
|
|||
{% if roaster.has_homepage %}
|
||||
<a class="inline-flex items-center gap-1 text-sm font-medium text-accent hover:text-accent-hover"
|
||||
href="{{ roaster.homepage_url }}" target="_blank" rel="noreferrer noopener">
|
||||
{% call icons::external_link("h-4 w-4") %} Homepage
|
||||
{{ icons::external_link("h-4 w-4") }} Homepage
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if is_authenticated %}
|
||||
<button type="button"
|
||||
class="inline-flex items-center gap-1 text-sm font-medium text-text-muted hover:text-red-600"
|
||||
data-on:click="confirm('Delete this roaster?') && @delete('/api/v1/roasters/{{ roaster.id }}?{{ navigator.query() }}', {responseOverrides: {selector: '#roaster-list', mode: 'replace'}})">
|
||||
{% call icons::delete("h-4 w-4") %} Delete
|
||||
{{ icons::delete("h-4 w-4") }} Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
{% if roasters.items.is_empty() %}
|
||||
<div class="p-8 text-center text-text-muted">No roasters match your search.</div>
|
||||
{% endif %}
|
||||
{% call table::pagination_header(roasters, navigator, "#roaster-list") %}
|
||||
{{ table::pagination_header(roasters, navigator, "#roaster-list") }}
|
||||
{% if roasters.has_next() %}
|
||||
<div class="infinite-scroll-sentinel h-4 md:hidden" aria-hidden="true"></div>
|
||||
{% endif %}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ const locateUser = (triggerEl) => {
|
|||
data-attr:disabled="$_locating || $_locationFound"
|
||||
aria-label="Use my location"
|
||||
>
|
||||
<span data-show="!$_locating">{% call icons::location("h-5 w-5") %}</span>
|
||||
<span data-show="$_locating" style="display: none">{% call icons::spinner("h-5 w-5") %}</span>
|
||||
<span data-show="!$_locating">{{ icons::location("h-5 w-5") }}</span>
|
||||
<span data-show="$_locating" style="display: none">{{ icons::spinner("h-5 w-5") }}</span>
|
||||
</button>
|
||||
<input type="text" data-bind:_city-name
|
||||
class="input-field w-full text-sm"
|
||||
|
|
|
|||
|
|
@ -4,41 +4,41 @@
|
|||
<div class="font-semibold uppercase tracking-[0.25em] text-accent"><a href="/">B{rew}log</a></div>
|
||||
<div class="relative flex items-center gap-1">
|
||||
<a class="rounded-md p-1.5 transition {% if nav_active == "home" %}text-accent{% else %}text-text-muted hover:text-text-secondary{% endif %}" href="/" title="Home" aria-label="Home">
|
||||
{% call icons::home("h-5 w-5") %}
|
||||
{{ icons::home("h-5 w-5") }}
|
||||
</a>
|
||||
<button type="button" class="rounded-md p-1.5 text-text-muted transition hover:text-text-secondary" title="Toggle theme" aria-label="Toggle theme" onclick="toggleTheme()">
|
||||
<span class="theme-icon-light">{% call icons::sun("h-5 w-5") %}</span>
|
||||
<span class="theme-icon-dark hidden">{% call icons::moon("h-5 w-5") %}</span>
|
||||
<span class="theme-icon-light">{{ icons::sun("h-5 w-5") }}</span>
|
||||
<span class="theme-icon-dark hidden">{{ icons::moon("h-5 w-5") }}</span>
|
||||
</button>
|
||||
<button class="rounded-md p-1.5 text-text-muted transition hover:text-text-secondary" data-on:click="$_navOpen = !$_navOpen" title="Menu" aria-label="Toggle menu">
|
||||
<span data-show="!$_navOpen">{% call icons::hamburger("h-5 w-5") %}</span>
|
||||
<span data-show="$_navOpen" style="display:none">{% call icons::close("h-5 w-5") %}</span>
|
||||
<span data-show="!$_navOpen">{{ icons::hamburger("h-5 w-5") }}</span>
|
||||
<span data-show="$_navOpen" style="display:none">{{ icons::close("h-5 w-5") }}</span>
|
||||
</button>
|
||||
<!-- Backdrop (click outside to close) -->
|
||||
<div class="fixed inset-0 z-40" data-show="$_navOpen" data-on:click="$_navOpen = false" style="display:none"></div>
|
||||
<!-- Dropdown menu -->
|
||||
<div class="absolute right-0 top-full z-50 mt-2 flex flex-col gap-1 rounded-lg border bg-surface p-3 whitespace-nowrap" data-show="$_navOpen" style="display:none">
|
||||
<a class="rounded-md px-4 py-2.5 transition flex items-center justify-end gap-4 {% if nav_active == "data" %}text-accent font-medium{% else %}text-text-muted hover:text-text hover:bg-surface-alt{% endif %}" href="/data">
|
||||
Data {% call icons::squares("h-4 w-4 shrink-0") %}
|
||||
Data {{ icons::squares("h-4 w-4 shrink-0") }}
|
||||
</a>
|
||||
<a class="rounded-md px-4 py-2.5 transition flex items-center justify-end gap-4 {% if nav_active == "timeline" %}text-accent font-medium{% else %}text-text-muted hover:text-text hover:bg-surface-alt{% endif %}" href="/timeline">
|
||||
Timeline {% call icons::timeline("h-4 w-4 shrink-0") %}
|
||||
Timeline {{ icons::timeline("h-4 w-4 shrink-0") }}
|
||||
</a>
|
||||
{% if is_authenticated %}
|
||||
<a class="rounded-md px-4 py-2.5 transition flex items-center justify-end gap-4 {% if nav_active == "checkin" %}text-accent font-medium{% else %}text-text-muted hover:text-text hover:bg-surface-alt{% endif %}" href="/check-in">
|
||||
Check In {% call icons::checkin("h-4 w-4 shrink-0") %}
|
||||
Check In {{ icons::checkin("h-4 w-4 shrink-0") }}
|
||||
</a>
|
||||
<a class="rounded-md px-4 py-2.5 transition flex items-center justify-end gap-4 {% if nav_active == "account" %}text-accent font-medium{% else %}text-text-muted hover:text-text hover:bg-surface-alt{% endif %}" href="/account">
|
||||
Admin {% call icons::cog("h-4 w-4 shrink-0") %}
|
||||
Admin {{ icons::cog("h-4 w-4 shrink-0") }}
|
||||
</a>
|
||||
<form method="post" action="/logout">
|
||||
<button type="submit" class="w-full rounded-md px-4 py-2.5 transition flex items-center justify-end gap-4 text-text-muted hover:text-text hover:bg-surface-alt">
|
||||
Sign Out {% call icons::logout("h-4 w-4 shrink-0") %}
|
||||
Sign Out {{ icons::logout("h-4 w-4 shrink-0") }}
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<a class="rounded-md px-4 py-2.5 transition flex items-center justify-end gap-4 text-text-muted hover:text-text hover:bg-surface-alt" href="/login">
|
||||
Login {% call icons::user("h-4 w-4 shrink-0") %}
|
||||
Login {{ icons::user("h-4 w-4 shrink-0") }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
class="shrink-0 inline-flex items-center justify-center rounded-md border p-2.5 text-accent transition hover:bg-surface-alt cursor-pointer"
|
||||
aria-label="Take Photo"
|
||||
>
|
||||
{% call icons::camera("h-5 w-5") %}
|
||||
{{ icons::camera("h-5 w-5") }}
|
||||
</brew-photo-capture>
|
||||
<input
|
||||
type="text"
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div data-show="{{ extracting_signal }}" style="display:none" class="flex items-center gap-3 text-sm text-accent">
|
||||
{% call icons::spinner("h-5 w-5") %}
|
||||
{{ icons::spinner("h-5 w-5") }}
|
||||
{{ spinner_text }}
|
||||
</div>
|
||||
<p data-show="{{ error_signal }}" data-text="{{ error_signal }}" style="display:none" class="mt-2 text-sm text-red-600"></p>
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
<span data-show="{{ tab_signal_js }} === '{{ tab.key }}'">{{ tab.label }}</span>
|
||||
{% endfor %}
|
||||
</span>
|
||||
<span data-show="!$_tabsOpen">{% call icons::chevron_down("h-5 w-5") %}</span>
|
||||
<span data-show="$_tabsOpen" style="display:none">{% call icons::chevron_up("h-5 w-5") %}</span>
|
||||
<span data-show="!$_tabsOpen">{{ icons::chevron_down("h-5 w-5") }}</span>
|
||||
<span data-show="$_tabsOpen" style="display:none">{{ icons::chevron_up("h-5 w-5") }}</span>
|
||||
</button>
|
||||
<div class="flex flex-col border-t" data-show="$_tabsOpen" style="display:none">
|
||||
{% for tab in tabs %}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<h2 id="{{ month.anchor }}" class="timeline-heading scroll-mt-24 mb-6 text-2xl font-semibold text-text" data-timeline-month>
|
||||
{{ month.heading }}
|
||||
<button type="button" class="timeline-top-btn" onclick="window.scrollTo({top: 0, behavior: 'smooth'})" aria-label="Back to top">
|
||||
{% call icons::arrow_up("h-5 w-5") %}
|
||||
{{ icons::arrow_up("h-5 w-5") }}
|
||||
</button>
|
||||
</h2>
|
||||
{% for event in month.events %}
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
rel="noreferrer noopener"
|
||||
aria-label="Open external link"
|
||||
>
|
||||
{% call icons::external_link("h-4 w-4") %}
|
||||
{{ icons::external_link("h-4 w-4") }}
|
||||
<span class="sr-only">Open external link</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
title="Brew again"
|
||||
>
|
||||
<span class="sr-only">Brew again</span>
|
||||
{% call icons::refresh("h-4 w-4") %}
|
||||
{{ icons::refresh("h-4 w-4") }}
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
<dd class="text-right flex items-center justify-end gap-1.5">
|
||||
{{ detail.value }}
|
||||
<a href="{{ detail.link.as_ref().unwrap() }}" target="_blank" rel="noreferrer noopener" class="text-accent hover:text-accent-hover" aria-label="View on map">
|
||||
{% call icons::map("h-4 w-4") %}
|
||||
{{ icons::map("h-4 w-4") }}
|
||||
</a>
|
||||
</dd>
|
||||
{% else if let Some(url) = detail.link %}
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ async fn timeline_page_signals_more_results_when_over_page_size() {
|
|||
|
||||
assert!(
|
||||
body.contains(
|
||||
"data-next-url=\"/timeline?page=2&page_size=5&sort=occurred-at&dir=desc\""
|
||||
"data-next-url=\"/timeline?page=2&page_size=5&sort=occurred-at&dir=desc\""
|
||||
),
|
||||
"Expected loader next-page URL missing from timeline HTML:\n{}",
|
||||
body
|
||||
|
|
|
|||
Loading…
Reference in a new issue