refactor(idaa): compact filter bar — sr-only labels, +/- stepper for max results

- Group labels (Location, Type, Sort, Max) moved to sr-only — visually hidden,
  accessible to screen readers. Chips are self-descriptive without them.
- Max results chips replaced with a [−] 150 [+] stepper that steps through
  predefined values [25, 50, 100, 150] (+ 200/500 for trusted_access). Minus/plus
  buttons disable at the ends of the list. limit_steps and limit_idx computed as
  $derived in script so onclick closures have access without @const gymnastics.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-05-18 17:18:59 -04:00
parent bb84117991
commit 6857f1226c

View File

@@ -37,6 +37,14 @@ import Help_tech from '$lib/app_components/e_app_help_tech.svelte';
let ae_promises: key_val = $state({}); let ae_promises: key_val = $state({});
// Predefined limit steps for the +/- stepper. Trusted staff get larger options
// since they often query with disabled/hidden meetings included.
let limit_steps = $derived($ae_loc.trusted_access ? [25, 50, 100, 150, 200, 500] : [25, 50, 100, 150]);
let limit_idx = $derived.by(() => {
const idx = limit_steps.indexOf($idaa_loc.recovery_meetings.qry__limit);
return idx >= 0 ? idx : limit_steps.length - 1;
});
// *** Functions and Logic // *** Functions and Logic
/** /**
* Reactive Search Trigger * Reactive Search Trigger
@@ -184,7 +192,7 @@ function set_sort_mode(mode: string) {
<!-- Location: independent toggles (a meeting can be both virtual and in-person) --> <!-- Location: independent toggles (a meeting can be both virtual and in-person) -->
<div class="flex flex-row flex-wrap items-center gap-1"> <div class="flex flex-row flex-wrap items-center gap-1">
<span class="text-xs opacity-50">Location:</span> <span class="sr-only">Location:</span>
<button <button
type="button" type="button"
onclick={() => { $idaa_loc.recovery_meetings.qry__virtual = !$idaa_loc.recovery_meetings.qry__virtual; }} onclick={() => { $idaa_loc.recovery_meetings.qry__virtual = !$idaa_loc.recovery_meetings.qry__virtual; }}
@@ -211,7 +219,7 @@ function set_sort_mode(mode: string) {
<!-- Type: mutually exclusive; clicking the active chip deselects (goes back to All) --> <!-- Type: mutually exclusive; clicking the active chip deselects (goes back to All) -->
<div class="flex flex-row flex-wrap items-center gap-1"> <div class="flex flex-row flex-wrap items-center gap-1">
<span class="text-xs opacity-50">Type:</span> <span class="sr-only">Type:</span>
{#each [ {#each [
['', 'All', 'Show all meeting types'], ['', 'All', 'Show all meeting types'],
['IDAA', 'IDAA', 'Open to IDAA members only'], ['IDAA', 'IDAA', 'Open to IDAA members only'],
@@ -253,12 +261,12 @@ function set_sort_mode(mode: string) {
<div <div
class="ae_group ae_row flex w-full max-w-full flex-row flex-wrap items-center justify-center gap-2 p-1"> class="ae_group ae_row flex w-full max-w-full flex-row flex-wrap items-center justify-center gap-2 p-1">
<!-- Sort + Limit chips --> <!-- Sort chips + Max results stepper -->
<span class="flex flex-row flex-wrap items-center justify-center gap-x-4 gap-y-1"> <span class="flex flex-row flex-wrap items-center justify-center gap-x-4 gap-y-1">
<!-- Sort: mutually exclusive chips --> <!-- Sort: mutually exclusive chips -->
<div class="flex flex-row flex-wrap items-center gap-1"> <div class="flex flex-row flex-wrap items-center gap-1">
<span class="text-xs opacity-50">Sort:</span> <span class="sr-only">Sort:</span>
{#each [ {#each [
['updated_on', 'Last Updated', 'fa-clock'], ['updated_on', 'Last Updated', 'fa-clock'],
['name_asc', 'Name AZ', 'fa-sort-alpha-down'], ['name_asc', 'Name AZ', 'fa-sort-alpha-down'],
@@ -279,39 +287,32 @@ function set_sort_mode(mode: string) {
{/each} {/each}
</div> </div>
<!-- Limit: mutually exclusive chips; 200/500 for trusted staff only --> <!-- Max results: +/- stepper through predefined steps -->
<div class="flex flex-row flex-wrap items-center gap-1"> <div class="flex flex-row items-center gap-1">
<span class="text-xs opacity-50">Max:</span> <span class="sr-only">Max results:</span>
{#each [25, 50, 100, 150] as n} <button
{@const active = $idaa_loc.recovery_meetings.qry__limit === n} type="button"
<button onclick={() => { if (limit_idx > 0) $idaa_loc.recovery_meetings.qry__limit = limit_steps[limit_idx - 1]; }}
type="button" disabled={limit_idx <= 0}
onclick={() => { $idaa_loc.recovery_meetings.qry__limit = n; }} title="Show fewer results"
aria-pressed={active} class="novi_btn btn btn-sm preset-outlined-surface-300-700 transition-all
title="Show up to {n} results" {limit_idx <= 0 ? 'opacity-30 cursor-not-allowed' : 'opacity-60 hover:opacity-100'}">
class="novi_btn btn btn-sm transition-all <span class="fas fa-minus"></span>
{active </button>
? 'preset-filled-tertiary-400-600' <span
: 'preset-outlined-surface-300-700 opacity-60 hover:opacity-100'}"> class="min-w-10 text-center text-sm font-semibold tabular-nums"
{n} title="Max results shown">
</button> {$idaa_loc.recovery_meetings.qry__limit}
{/each} </span>
{#if $ae_loc.trusted_access} <button
{#each [200, 500] as n} type="button"
{@const active = $idaa_loc.recovery_meetings.qry__limit === n} onclick={() => { if (limit_idx < limit_steps.length - 1) $idaa_loc.recovery_meetings.qry__limit = limit_steps[limit_idx + 1]; }}
<button disabled={limit_idx >= limit_steps.length - 1}
type="button" title="Show more results"
onclick={() => { $idaa_loc.recovery_meetings.qry__limit = n; }} class="novi_btn btn btn-sm preset-outlined-surface-300-700 transition-all
aria-pressed={active} {limit_idx >= limit_steps.length - 1 ? 'opacity-30 cursor-not-allowed' : 'opacity-60 hover:opacity-100'}">
title="Show up to {n} results" <span class="fas fa-plus"></span>
class="novi_btn btn btn-sm transition-all </button>
{active
? 'preset-filled-tertiary-400-600'
: 'preset-outlined-surface-300-700 opacity-60 hover:opacity-100'}">
{n}
</button>
{/each}
{/if}
</div> </div>
</span> </span>