- Removed unused FontFeatures, FontMetadata, FontProvider from normalize.ts imports - Removed unused UnifiedFont from normalize.test.ts imports - Removed unused FontSubset from store.ts imports - Changed unused queryClient variables to void calls to suppress warnings
214 lines
5.4 KiB
TypeScript
214 lines
5.4 KiB
TypeScript
/**
|
|
* Service for fetching Google Fonts
|
|
*
|
|
* Integrates with TanStack Query for caching, deduplication,
|
|
* and automatic refetching.
|
|
*
|
|
* Uses reactive query args pattern for Svelte 5 compatibility.
|
|
*/
|
|
|
|
import { fetchGoogleFonts } from '$entities/Font/api/google/googleFonts';
|
|
import { normalizeGoogleFonts } from '$entities/Font/api/normalize/normalize';
|
|
import type {
|
|
FontCategory,
|
|
FontSubset,
|
|
} from '$entities/Font/model/types';
|
|
import type { UnifiedFont } from '$entities/Font/model/types/normalize';
|
|
import type { QueryFunction } from '@tanstack/svelte-query';
|
|
import {
|
|
createQuery,
|
|
useQueryClient,
|
|
} from '@tanstack/svelte-query';
|
|
|
|
/**
|
|
* Google Fonts query parameters
|
|
*/
|
|
export interface GoogleFontsQueryParams {
|
|
/** Font category filter */
|
|
category?: FontCategory;
|
|
/** Character subset filter */
|
|
subset?: FontSubset;
|
|
/** Sort order */
|
|
sort?: 'popularity' | 'alpha' | 'date';
|
|
/** Search query (for specific font) */
|
|
search?: string;
|
|
/** Force refetch even if cached */
|
|
forceRefetch?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Query key factory for Google Fonts
|
|
* Generates consistent query keys for cache management
|
|
*/
|
|
export function getGoogleFontsQueryKey(
|
|
params: GoogleFontsQueryParams,
|
|
): readonly unknown[] {
|
|
return ['googleFonts', params];
|
|
}
|
|
|
|
/**
|
|
* Query function for fetching Google Fonts
|
|
* Handles caching, loading states, and errors
|
|
*/
|
|
export const fetchGoogleFontsQuery: QueryFunction<
|
|
UnifiedFont[],
|
|
readonly unknown[]
|
|
> = async ({ queryKey }) => {
|
|
const params = queryKey[1] as GoogleFontsQueryParams;
|
|
|
|
try {
|
|
const response = await fetchGoogleFonts({
|
|
category: params.category,
|
|
subset: params.subset,
|
|
sort: params.sort,
|
|
});
|
|
|
|
const normalizedFonts = normalizeGoogleFonts(response.items);
|
|
return normalizedFonts;
|
|
} catch (error) {
|
|
// User-friendly error messages
|
|
if (error instanceof Error) {
|
|
if (error.message.includes('Failed to fetch')) {
|
|
throw new Error(
|
|
'Unable to connect to Google Fonts. Please check your internet connection and try again.',
|
|
);
|
|
}
|
|
if (error.message.includes('404')) {
|
|
throw new Error('Font not found in Google Fonts catalog.');
|
|
}
|
|
throw new Error(
|
|
'Failed to load fonts from Google Fonts. Please try again later.',
|
|
);
|
|
}
|
|
throw new Error('An unexpected error occurred while fetching fonts.');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create a Google Fonts query hook
|
|
* Use this in Svelte components to fetch Google Fonts with caching
|
|
*
|
|
* @param params - Query parameters
|
|
* @returns Query result with data, loading state, and error
|
|
*
|
|
* @example
|
|
* ```svelte
|
|
* <script lang="ts">
|
|
* let { category }: { category?: FontCategory } = $props();
|
|
*
|
|
* const query = useGoogleFontsQuery({ category });
|
|
*
|
|
* if ($query.isLoading) {
|
|
* return <LoadingSpinner />;
|
|
* }
|
|
*
|
|
* if ($query.error) {
|
|
* return <ErrorMessage message={$query.error.message} />;
|
|
* }
|
|
*
|
|
* const fonts = $query.data ?? [];
|
|
* </script>
|
|
*
|
|
* {#each fonts as font}
|
|
* <FontCard {font} />
|
|
* {/each}
|
|
* ```
|
|
*/
|
|
export function useGoogleFontsQuery(params: GoogleFontsQueryParams = {}) {
|
|
useQueryClient();
|
|
|
|
const query = createQuery(() => ({
|
|
queryKey: getGoogleFontsQueryKey(params),
|
|
queryFn: fetchGoogleFontsQuery,
|
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
gcTime: 10 * 60 * 1000, // 10 minutes
|
|
}));
|
|
|
|
return query;
|
|
}
|
|
|
|
/**
|
|
* Prefetch Google Fonts
|
|
* Fetch fonts in background without showing loading state
|
|
*
|
|
* @param params - Query parameters for prefetch
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* // Prefetch fonts when user hovers over button
|
|
* function onMouseEnter() {
|
|
* prefetchGoogleFonts({ category: 'sans-serif' });
|
|
* }
|
|
* ```
|
|
*/
|
|
export async function prefetchGoogleFonts(
|
|
params: GoogleFontsQueryParams = {},
|
|
): Promise<void> {
|
|
const queryClient = useQueryClient();
|
|
|
|
await queryClient.prefetchQuery({
|
|
queryKey: getGoogleFontsQueryKey(params),
|
|
queryFn: fetchGoogleFontsQuery,
|
|
staleTime: 5 * 60 * 1000,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Invalidate Google Fonts cache
|
|
* Forces refetch on next query
|
|
*
|
|
* @param params - Query parameters to invalidate (all if not provided)
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* // Invalidate all Google Fonts cache
|
|
* invalidateGoogleFonts();
|
|
*
|
|
* // Invalidate specific category cache
|
|
* invalidateGoogleFonts({ category: 'sans-serif' });
|
|
* ```
|
|
*/
|
|
export function invalidateGoogleFonts(
|
|
params?: GoogleFontsQueryParams,
|
|
): void {
|
|
const queryClient = useQueryClient();
|
|
|
|
if (params) {
|
|
queryClient.invalidateQueries({
|
|
queryKey: getGoogleFontsQueryKey(params),
|
|
});
|
|
} else {
|
|
queryClient.invalidateQueries({
|
|
queryKey: ['googleFonts'],
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cancel Google Fonts queries
|
|
* Abort in-flight requests
|
|
*
|
|
* @param params - Query parameters to cancel (all if not provided)
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* // Cancel all Google Fonts queries
|
|
* cancelGoogleFontsQueries();
|
|
* ```
|
|
*/
|
|
export function cancelGoogleFontsQueries(
|
|
params?: GoogleFontsQueryParams,
|
|
): void {
|
|
const queryClient = useQueryClient();
|
|
|
|
if (params) {
|
|
queryClient.cancelQueries({
|
|
queryKey: getGoogleFontsQueryKey(params),
|
|
});
|
|
} else {
|
|
queryClient.cancelQueries({
|
|
queryKey: ['googleFonts'],
|
|
});
|
|
}
|
|
}
|