feature/fetch-fonts #14
@@ -1,263 +0,0 @@
|
|||||||
/**
|
|
||||||
* Font collection store
|
|
||||||
*
|
|
||||||
* Main font collection cache using Svelte stores.
|
|
||||||
* Integrates with TanStack Query for advanced caching and deduplication.
|
|
||||||
*
|
|
||||||
* Provides derived stores for filtered/sorted fonts.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type {
|
|
||||||
FontCategory,
|
|
||||||
FontCollectionFilters,
|
|
||||||
FontCollectionSort,
|
|
||||||
FontCollectionState,
|
|
||||||
FontCollectionStore,
|
|
||||||
FontProvider,
|
|
||||||
FontSubset,
|
|
||||||
UnifiedFont,
|
|
||||||
} from '$entities/Font/model/types';
|
|
||||||
import { createCollectionCache } from '$shared/lib/fetch/collectionCache';
|
|
||||||
import type { Writable } from 'svelte/store';
|
|
||||||
import {
|
|
||||||
derived,
|
|
||||||
get,
|
|
||||||
writable,
|
|
||||||
} from 'svelte/store';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create font collection store
|
|
||||||
*
|
|
||||||
* @param initialState - Initial state for collection
|
|
||||||
* @returns Font collection store instance
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* const fontCollection = createFontCollectionStore({
|
|
||||||
* fonts: {},
|
|
||||||
* filters: {},
|
|
||||||
* sort: { field: 'name', direction: 'asc' }
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* // Add fonts to collection
|
|
||||||
* fontCollection.addFonts([font1, font2]);
|
|
||||||
*
|
|
||||||
* // Use in component
|
|
||||||
* $fontCollection.filteredFonts
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export function createFontCollectionStore(
|
|
||||||
initialState?: Partial<FontCollectionState>,
|
|
||||||
): FontCollectionStore {
|
|
||||||
const cache = createCollectionCache<UnifiedFont>({
|
|
||||||
defaultTTL: 5 * 60 * 1000, // 5 minutes
|
|
||||||
maxSize: 1000,
|
|
||||||
});
|
|
||||||
|
|
||||||
const defaultState: FontCollectionState = {
|
|
||||||
fonts: {},
|
|
||||||
filters: {},
|
|
||||||
sort: { field: 'name', direction: 'asc' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const state: Writable<FontCollectionState> = writable({
|
|
||||||
...defaultState,
|
|
||||||
...initialState,
|
|
||||||
});
|
|
||||||
|
|
||||||
const isLoading = writable(false);
|
|
||||||
const error = writable<string | undefined>();
|
|
||||||
|
|
||||||
// Derived store for fonts as array
|
|
||||||
const fonts = derived(state, $state => {
|
|
||||||
return Object.values($state.fonts);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Derived store for filtered fonts
|
|
||||||
const filteredFonts = derived([state, fonts], ([$state, $fonts]) => {
|
|
||||||
let filtered = [...$fonts];
|
|
||||||
|
|
||||||
// Apply search filter
|
|
||||||
if ($state.filters.searchQuery) {
|
|
||||||
const query = $state.filters.searchQuery.toLowerCase();
|
|
||||||
filtered = filtered.filter(font => font.name.toLowerCase().includes(query));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply provider filter
|
|
||||||
if ($state.filters.provider) {
|
|
||||||
filtered = filtered.filter(
|
|
||||||
font => font.provider === $state.filters.provider,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply category filter
|
|
||||||
if ($state.filters.category) {
|
|
||||||
filtered = filtered.filter(
|
|
||||||
font => font.category === $state.filters.category,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply subset filter
|
|
||||||
if ($state.filters.subsets?.length) {
|
|
||||||
filtered = filtered.filter(font =>
|
|
||||||
$state.filters.subsets!.some(subset => font.subsets.includes(subset as FontSubset))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply sort
|
|
||||||
const { field, direction } = $state.sort;
|
|
||||||
const multiplier = direction === 'asc' ? 1 : -1;
|
|
||||||
|
|
||||||
filtered.sort((a, b) => {
|
|
||||||
let comparison = 0;
|
|
||||||
|
|
||||||
if (field === 'name') {
|
|
||||||
comparison = a.name.localeCompare(b.name);
|
|
||||||
} else if (field === 'popularity') {
|
|
||||||
const aPop = a.metadata.popularity ?? 0;
|
|
||||||
const bPop = b.metadata.popularity ?? 0;
|
|
||||||
comparison = aPop - bPop;
|
|
||||||
} else if (field === 'category') {
|
|
||||||
comparison = a.category.localeCompare(b.category);
|
|
||||||
}
|
|
||||||
|
|
||||||
return comparison * multiplier;
|
|
||||||
});
|
|
||||||
|
|
||||||
return filtered;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Derived store for count
|
|
||||||
const count = derived(fonts, $fonts => $fonts.length);
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Expose main state
|
|
||||||
state,
|
|
||||||
|
|
||||||
// Expose derived stores
|
|
||||||
fonts,
|
|
||||||
filteredFonts,
|
|
||||||
count,
|
|
||||||
isLoading,
|
|
||||||
error,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add multiple fonts to collection
|
|
||||||
*/
|
|
||||||
addFonts: (newFonts: UnifiedFont[]) => {
|
|
||||||
state.update($state => {
|
|
||||||
const fontsMap = { ...$state.fonts };
|
|
||||||
|
|
||||||
for (const font of newFonts) {
|
|
||||||
fontsMap[font.id] = font;
|
|
||||||
cache.set(font.id, font);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...$state,
|
|
||||||
fonts: fontsMap,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add single font to collection
|
|
||||||
*/
|
|
||||||
addFont: (font: UnifiedFont) => {
|
|
||||||
state.update($state => ({
|
|
||||||
...$state,
|
|
||||||
fonts: {
|
|
||||||
...$state.fonts,
|
|
||||||
[font.id]: font,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
cache.set(font.id, font);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove font from collection
|
|
||||||
*/
|
|
||||||
removeFont: (fontId: string) => {
|
|
||||||
state.update($state => {
|
|
||||||
const { [fontId]: _, ...rest } = $state.fonts;
|
|
||||||
return {
|
|
||||||
...$state,
|
|
||||||
fonts: rest,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
cache.remove(fontId);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear all fonts
|
|
||||||
*/
|
|
||||||
clear: () => {
|
|
||||||
state.set({
|
|
||||||
...get(state),
|
|
||||||
fonts: {},
|
|
||||||
});
|
|
||||||
cache.clear();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update filters
|
|
||||||
*/
|
|
||||||
setFilters: (filters: Partial<FontCollectionFilters>) => {
|
|
||||||
state.update($state => ({
|
|
||||||
...$state,
|
|
||||||
filters: {
|
|
||||||
...$state.filters,
|
|
||||||
...filters,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear filters
|
|
||||||
*/
|
|
||||||
clearFilters: () => {
|
|
||||||
state.update($state => ({
|
|
||||||
...$state,
|
|
||||||
filters: {},
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update sort configuration
|
|
||||||
*/
|
|
||||||
setSort: (sort: FontCollectionSort) => {
|
|
||||||
state.update($state => ({
|
|
||||||
...$state,
|
|
||||||
sort,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get font by ID
|
|
||||||
*/
|
|
||||||
getFont: (fontId: string) => {
|
|
||||||
const currentState = get(state);
|
|
||||||
return currentState.fonts[fontId];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get fonts by provider
|
|
||||||
*/
|
|
||||||
getFontsByProvider: (provider: FontProvider) => {
|
|
||||||
const currentState = get(state);
|
|
||||||
return Object.values(currentState.fonts).filter(
|
|
||||||
font => font.provider === provider,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get fonts by category
|
|
||||||
*/
|
|
||||||
getFontsByCategory: (category: FontCategory) => {
|
|
||||||
const currentState = get(state);
|
|
||||||
return Object.values(currentState.fonts).filter(
|
|
||||||
font => font.category === category,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
/**
|
|
||||||
* Font collection store exports
|
|
||||||
*
|
|
||||||
* Exports font collection store types and factory function
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type {
|
|
||||||
FontCollectionFilters,
|
|
||||||
FontCollectionSort,
|
|
||||||
FontCollectionState,
|
|
||||||
FontCollectionStore,
|
|
||||||
} from '../types';
|
|
||||||
export { createFontCollectionStore } from './fontCollectionStore';
|
|
||||||
Reference in New Issue
Block a user