refactor(GetFonts): centralize filterManager/sortStore → fontStore bridge

Move the duplicated $effect blocks that mapped filterManager and sortStore
into fontStore params out of Search, FontSearch and FilterControls into a
single $effect.root in features/GetFonts/model/state/bindings.svelte.ts.

Consumers now bind to the manager/store directly; the bridge is installed
once via a side-effect import from the feature barrel.
This commit is contained in:
Ilia Mashkov
2026-05-24 15:05:28 +03:00
parent 1573950605
commit e60309af78
5 changed files with 46 additions and 30 deletions
+6
View File
@@ -29,6 +29,12 @@ export {
filterManager,
} from './state/manager.svelte';
/**
* Side-effect import: installs the global filterManager+sortStore → fontStore
* bridge on first import of this feature barrel. No exports.
*/
import './state/bindings.svelte';
/**
* Sorting logic
*/
@@ -0,0 +1,36 @@
/**
* Bridges feature-level UI state (filterManager + sortStore) to the
* entity-level fontStore query params.
*
* Centralizing this here means consumers (Search, FontSearch,
* FilterControls, etc.) bind to the manager/store directly without
* each repeating the same mapping effect. The bridge is a singleton
* concern — it tracks singleton state and writes to a singleton query
* observer, so it lives at module scope, not in any individual widget.
*/
import { fontStore } from '$entities/Font';
import { untrack } from 'svelte';
import { mapManagerToParams } from '../../lib/mapper/mapManagerToParams';
import { sortStore } from '../store/sortStore.svelte';
import { filterManager } from './manager.svelte';
$effect.root(() => {
/**
* Mirror filter selections + debounced search query into fontStore params.
* untrack the write so fontStore's internal $state reads don't feed back
* into this effect's dependency graph.
*/
$effect(() => {
const params = mapManagerToParams(filterManager);
untrack(() => fontStore.setParams(params));
});
/**
* Mirror sort selection into fontStore.
*/
$effect(() => {
const apiSort = sortStore.apiValue;
untrack(() => fontStore.setSort(apiSort));
});
});
@@ -4,16 +4,12 @@
Sits below the filter list, separated by a top border.
-->
<script lang="ts">
import { fontStore } from '$entities/Font';
import type { ResponsiveManager } from '$shared/lib';
import { cn } from '$shared/lib';
import { Button } from '$shared/ui';
import { Label } from '$shared/ui';
import RefreshCwIcon from '@lucide/svelte/icons/refresh-cw';
import {
getContext,
untrack,
} from 'svelte';
import { getContext } from 'svelte';
import {
SORT_OPTIONS,
filterManager,
@@ -31,11 +27,6 @@ const {
class: className,
}: Props = $props();
$effect(() => {
const apiSort = sortStore.apiValue;
untrack(() => fontStore.setSort(apiSort));
});
const responsive = getContext<ResponsiveManager>('responsive');
const isMobileOrTabletPortrait = $derived(responsive.isMobile || responsive.isTabletPortrait);
@@ -1,21 +1,12 @@
<!--
Component: Search
Typeface search input for the comparison view.
Updates the global filterManager query to filter the font list.
Writes through filterManager; the global bridge in $features/GetFonts
propagates the value into fontStore.
-->
<script lang="ts">
import { fontStore } from '$entities/Font';
import {
filterManager,
mapManagerToParams,
} from '$features/GetFonts';
import { filterManager } from '$features/GetFonts';
import { SearchBar } from '$shared/ui';
import { untrack } from 'svelte';
$effect(() => {
const params = mapManagerToParams(filterManager);
untrack(() => fontStore.setParams(params));
});
</script>
<div class="p-6 border-b border-black/5">
@@ -3,12 +3,10 @@
Provides a search input and filtration for fonts
-->
<script lang="ts">
import { fontStore } from '$entities/Font';
import {
FilterControls,
Filters,
filterManager,
mapManagerToParams,
} from '$features/GetFonts';
import { springySlideFade } from '$shared/lib';
import {
@@ -16,7 +14,6 @@ import {
SearchBar,
} from '$shared/ui';
import SlidersHorizontalIcon from '@lucide/svelte/icons/sliders-horizontal';
import { untrack } from 'svelte';
import { cubicOut } from 'svelte/easing';
import {
Tween,
@@ -34,11 +31,6 @@ interface Props {
let { showFilters = $bindable(true) }: Props = $props();
$effect(() => {
const params = mapManagerToParams(filterManager);
untrack(() => fontStore.setParams(params));
});
const transform = new Tween(
{ scale: 1, rotate: 0 },
{ duration: 250, easing: cubicOut },