improve web ui
This commit is contained in:
+11
-11
@@ -1,29 +1,29 @@
|
||||
// Thin reactive layer over Paraglide. Paraglide's `m.*` message functions and
|
||||
// `setLocale`/`getLocale` are framework-agnostic; this hook re-renders React when the
|
||||
// locale changes (Paraglide's localStorage strategy persists the choice across reloads).
|
||||
import { useSyncExternalStore } from 'react'
|
||||
import { getLocale, setLocale, locales } from '@/paraglide/runtime'
|
||||
import { useSyncExternalStore } from "react";
|
||||
import { getLocale, locales, setLocale } from "@/paraglide/runtime";
|
||||
|
||||
/** The available locales as a union (`'en' | 'de'`), derived from Paraglide's `locales`. */
|
||||
export type Locale = (typeof locales)[number]
|
||||
export type Locale = (typeof locales)[number];
|
||||
|
||||
const listeners = new Set<() => void>()
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
/** Switch locale and notify subscribers (Paraglide also persists it per its strategy). */
|
||||
export function changeLocale(locale: Locale) {
|
||||
// `reload: false` keeps the SPA mounted; we re-render via the store below.
|
||||
setLocale(locale, { reload: false })
|
||||
for (const l of listeners) l()
|
||||
// `reload: false` keeps the SPA mounted; we re-render via the store below.
|
||||
setLocale(locale, { reload: false });
|
||||
for (const l of listeners) l();
|
||||
}
|
||||
|
||||
function subscribe(cb: () => void) {
|
||||
listeners.add(cb)
|
||||
return () => listeners.delete(cb)
|
||||
listeners.add(cb);
|
||||
return () => listeners.delete(cb);
|
||||
}
|
||||
|
||||
/** Current locale, reactive — components using `m.*` should read this so they re-render. */
|
||||
export function useLocale(): Locale {
|
||||
return useSyncExternalStore(subscribe, getLocale, () => 'en' as Locale)
|
||||
return useSyncExternalStore(subscribe, getLocale, () => "en" as Locale);
|
||||
}
|
||||
|
||||
export { locales }
|
||||
export { locales };
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* The slice of a React Query result a presentational view needs: just enough to
|
||||
* drive <QueryState> + render the data. A `UseQueryResult` satisfies it directly
|
||||
* (so containers pass the query through), and stories can hand-build one without
|
||||
* mocking the network.
|
||||
*/
|
||||
export interface Loadable<T> {
|
||||
data?: T;
|
||||
isLoading: boolean;
|
||||
error: unknown;
|
||||
refetch?: () => void;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
/** shadcn/ui's class combiner: merge conditional classes, dedupe Tailwind conflicts. */
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user