feature: change filterStore model

This commit is contained in:
Ilia Mashkov
2026-01-02 21:16:07 +03:00
parent 1bb699ea2d
commit d439e97729
7 changed files with 88 additions and 88 deletions

View File

@@ -4,7 +4,7 @@ import { buttonVariants } from '$shared/shadcn/ui/button';
import { Checkbox } from '$shared/shadcn/ui/checkbox';
import * as Collapsible from '$shared/shadcn/ui/collapsible';
import { Label } from '$shared/shadcn/ui/label';
import type { Category } from '$shared/store/createFilterStore';
import type { Property } from '$shared/store/createFilterStore';
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
import { onMount } from 'svelte';
import { cubicOut } from 'svelte/easing';
@@ -13,7 +13,7 @@ import { slide } from 'svelte/transition';
/**
* CheckboxFilter Component
*
* A collapsible category filter with checkboxes. Displays selected count as a badge
* A collapsible property filter with checkboxes. Displays selected count as a badge
* and supports reduced motion for accessibility. Used in sidebar filtering UIs.
*
* Design choices:
@@ -23,16 +23,16 @@ import { slide } from 'svelte/transition';
* - Local transition prevents animation when component first renders
*/
interface CategoryFilterProps {
/** Display name for this filter group (e.g., "Categories", "Tags") */
filterName: string;
/** Array of categories with their selection states */
categories: Category[];
/** Callback when a category checkbox is toggled */
onCategoryToggle: (id: string) => void;
interface PropertyFilterProps {
/** Label for this filter group (e.g., "Properties", "Tags") */
displayedLabel: string;
/** Array of properties with their selection states */
properties: Property[];
/** Callback when a property checkbox is toggled */
onPropertyToggle: (id: string) => void;
}
const { filterName, categories, onCategoryToggle }: CategoryFilterProps = $props();
const { displayedLabel, properties, onPropertyToggle }: PropertyFilterProps = $props();
// Toggle state - defaults to open for better discoverability
let isOpen = $state(true);
@@ -62,8 +62,8 @@ const slideConfig = $derived({
easing: cubicOut,
});
// Derived for reactive updates when categories change - avoids recomputing on every render
const selectedCount = $derived(categories.filter(c => c.selected).length);
// Derived for reactive updates when properties change - avoids recomputing on every render
const selectedCount = $derived(properties.filter(c => c.selected).length);
const hasSelection = $derived(selectedCount > 0);
</script>
@@ -82,7 +82,7 @@ const hasSelection = $derived(selectedCount > 0);
'flex-1 justify-between gap-2 hover:bg-transparent focus-visible:ring-1 focus-visible:ring-ring',
})}
>
<h4 class="text-sm font-semibold">{filterName}</h4>
<h4 class="text-sm font-semibold">{displayedLabel}</h4>
<!-- Chevron rotates based on open state for visual feedback -->
<div
@@ -112,10 +112,10 @@ const hasSelection = $derived(selectedCount > 0);
<div class="px-4 py-3">
<div class="flex flex-col gap-1.5">
<!-- Each item: checkbox + label with interactive hover/focus states -->
<!-- Keyed by category.id for efficient DOM updates -->
{#each categories as category (category.id)}
<!-- Keyed by property.id for efficient DOM updates -->
{#each properties as property (property.id)}
<Label
for={category.id}
for={property.id}
class="
group flex items-center gap-3 cursor-pointer rounded-md px-2 py-1.5 -mx-2
transition-colors duration-150 ease-out
@@ -127,9 +127,9 @@ const hasSelection = $derived(selectedCount > 0);
Checkbox handles toggle, styled for accessibility with focus rings
-->
<Checkbox
id={category.id}
checked={category.selected}
onclick={() => onCategoryToggle(category.id)}
id={property.id}
checked={property.selected}
onclick={() => onPropertyToggle(property.id)}
class="
shrink-0 cursor-pointer transition-all duration-150 ease-out
data-[state=checked]:scale-100
@@ -143,10 +143,10 @@ const hasSelection = $derived(selectedCount > 0);
text-sm select-none transition-all duration-150 ease-out
group-hover:text-foreground
text-muted-foreground
{category.selected ? 'font-medium text-foreground' : ''}
{property.selected ? 'font-medium text-foreground' : ''}
"
>
{category.name}
{property.name}
</span>
</Label>
{/each}