diff --git a/packages/varuna/src/index.ts b/packages/varuna/src/index.ts index 2d077cafc..dbe3d3e44 100644 --- a/packages/varuna/src/index.ts +++ b/packages/varuna/src/index.ts @@ -43,11 +43,17 @@ export class Varuna { } mutate(mutator: (state: Type) => void) { - this.state = produce(this.state, mutator); + this.set(produce(this.state, mutator)); + } + + set(state: Type) { + this.state = state; this.dispatch(); } - use(slicer: (state: Type) => Slice) { + use( + slicer: (state: Type) => Slice = (state) => state as unknown as Slice, + ) { const [slice, setSlice] = useState(slicer(this.state)); useEffect(() => this.on(slicer, setSlice), []); return slice; diff --git a/packages/website/src/components/TankSearch/components/Card.tsx b/packages/website/src/components/TankSearch/components/Card.tsx index ea7ac9142..d15d15a5e 100644 --- a/packages/website/src/components/TankSearch/components/Card.tsx +++ b/packages/website/src/components/TankSearch/components/Card.tsx @@ -4,11 +4,10 @@ import { unionBoundingBox, type TankDefinition, } from '@blitzkit/core'; -import { useStore } from '@nanostores/react'; import { useMemo } from 'react'; import { awaitableModelDefinitions } from '../../../core/awaitables/modelDefinitions'; import { resolveReload } from '../../../core/blitzkit/resolveReload'; -import { $tankopediaSort } from '../../../stores/tankopediaSort'; +import { TankSort } from '../../../stores/tankopediaSort'; import { TankCard } from '../../TankCard'; interface TankSearchCardProps { @@ -19,9 +18,9 @@ interface TankSearchCardProps { const modelDefinitions = await awaitableModelDefinitions; export function TankSearchCard({ tank, onSelect }: TankSearchCardProps) { - const tankopediaSort = useStore($tankopediaSort); + const by = TankSort.use((state) => state.by); const discriminator = useMemo(() => { - if (tankopediaSort.by.startsWith('meta')) return undefined; + if (by.startsWith('meta')) return undefined; const turret = tank.turrets.at(-1)!; const gun = turret.guns.at(-1)!; @@ -34,7 +33,7 @@ export function TankSearchCard({ tank, onSelect }: TankSearchCardProps) { const turretModelDefinition = tankModelDefinition.turrets[turret.id]; const gunModelDefinition = turretModelDefinition.guns[gun.id]; - switch (tankopediaSort.by) { + switch (by) { case 'fire.aimTime': return gun.aim_time.toFixed(2); case 'fire.caliber': @@ -133,7 +132,7 @@ export function TankSearchCard({ tank, onSelect }: TankSearchCardProps) { return Math.max(bounds.x, bounds.y, bounds.z).toFixed(0); } } - }, [tankopediaSort.by]); + }, [by]); return ( { event.preventDefault(); $tankFilters.set(initialTankFilters); - $tankopediaSort.set(initialTankopediaSort); + TankSort.set(TankSort.initial); }} > {strings.website.common.tank_search.clear_filters} diff --git a/packages/website/src/components/TankSearch/components/RecentlyViewed.tsx b/packages/website/src/components/TankSearch/components/RecentlyViewed.tsx index bd2777937..94484fec1 100644 --- a/packages/website/src/components/TankSearch/components/RecentlyViewed.tsx +++ b/packages/website/src/components/TankSearch/components/RecentlyViewed.tsx @@ -6,7 +6,7 @@ import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitio import { useLocale } from '../../../hooks/useLocale'; import { $tankFilters, initialTankFilters } from '../../../stores/tankFilters'; import { TankopediaPersistent } from '../../../stores/tankopediaPersistent'; -import { $tankopediaSort } from '../../../stores/tankopediaSort'; +import { TankSort } from '../../../stores/tankopediaSort'; import { TankCard } from '../../TankCard'; import { TankCardWrapper } from './TankCardWrapper'; @@ -19,7 +19,6 @@ export function RecentlyViewed() { const recentlyViewed = tankopediaPersistentStore .getState() .recentlyViewed.filter((id) => id in tankDefinitions.tanks); - const sort = useStore($tankopediaSort); const hasFilters = useMemo( () => Object.entries(filters).some(([key, value]) => { @@ -31,8 +30,9 @@ export function RecentlyViewed() { [filters], ); const { strings } = useLocale(); + const by = TankSort.use((state) => state.by); - if (recentlyViewed.length === 0 || sort.by !== 'meta.none' || hasFilters) { + if (recentlyViewed.length === 0 || by !== 'meta.none' || hasFilters) { return null; } diff --git a/packages/website/src/components/TankSearch/components/Sort.tsx b/packages/website/src/components/TankSearch/components/Sort.tsx index 8a201c849..71898443d 100644 --- a/packages/website/src/components/TankSearch/components/Sort.tsx +++ b/packages/website/src/components/TankSearch/components/Sort.tsx @@ -1,4 +1,3 @@ -import { useStore } from '@nanostores/react'; import { CaretDownIcon } from '@radix-ui/react-icons'; import { Button, DropdownMenu } from '@radix-ui/themes'; import { useLocale } from '../../../hooks/useLocale'; @@ -6,7 +5,7 @@ import type { TankopediaSortBy, TankopediaSortDirection, } from '../../../stores/tankopediaPersistent'; -import { $tankopediaSort } from '../../../stores/tankopediaSort'; +import { TankSort } from '../../../stores/tankopediaSort'; interface ItemProps { by: TankopediaSortBy; @@ -18,13 +17,15 @@ interface ItemProps { function Item({ by }: ItemProps) { const { strings } = useLocale(); - const tankopediaSort = useStore($tankopediaSort); + const _by = TankSort.use((state) => state.by); return ( { - $tankopediaSort.setKey('by', by); + TankSort.mutate((draft) => { + draft.by = by; + }); }} > {strings.website.common.tank_search.sort[by]} @@ -33,7 +34,7 @@ function Item({ by }: ItemProps) { } export function Sort() { - const tankopediaSort = useStore($tankopediaSort); + const direction = TankSort.use((state) => state.direction); const { strings } = useLocale(); return ( @@ -119,12 +120,11 @@ export function Sort() { } { - $tankopediaSort.setKey( - 'direction', - value as TankopediaSortDirection, - ); + TankSort.mutate((draft) => { + draft.direction = value as TankopediaSortDirection; + }); }} > diff --git a/packages/website/src/components/TankSearch/components/TierFilter.tsx b/packages/website/src/components/TankSearch/components/TierFilter.tsx index 01aefd9d9..c4e7ccdbc 100644 --- a/packages/website/src/components/TankSearch/components/TierFilter.tsx +++ b/packages/website/src/components/TankSearch/components/TierFilter.tsx @@ -4,13 +4,13 @@ import { Flex, IconButton, Text } from '@radix-ui/themes'; import { times } from 'lodash-es'; import { memo } from 'react'; import { $tankFilters } from '../../../stores/tankFilters'; -import { $tankopediaSort } from '../../../stores/tankopediaSort'; +import { TankSort } from '../../../stores/tankopediaSort'; export const TierFilter = memo(() => { const tankFilters = useStore($tankFilters); - const tankopediaSort = useStore($tankopediaSort); + const by = TankSort.use((state) => state.by); - if (tankopediaSort.by !== 'meta.none' || tankFilters.search) return null; + if (by !== 'meta.none' || tankFilters.search) return null; return ( diff --git a/packages/website/src/components/TankSearch/index.tsx b/packages/website/src/components/TankSearch/index.tsx index 735539d5e..c5fa3fc7f 100644 --- a/packages/website/src/components/TankSearch/index.tsx +++ b/packages/website/src/components/TankSearch/index.tsx @@ -22,7 +22,7 @@ import { useLocale } from '../../hooks/useLocale'; import { $tankFilters } from '../../stores/tankFilters'; import { TankopediaPersistent } from '../../stores/tankopediaPersistent'; import { SORT_UNITS } from '../../stores/tankopediaPersistent/constants'; -import { $tankopediaSort } from '../../stores/tankopediaSort'; +import { TankSort } from '../../stores/tankopediaSort'; import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps'; import { ExperimentIcon } from '../ExperimentIcon'; import { TankSearchCard } from './components/Card'; @@ -58,7 +58,7 @@ export const TankSearch = memo( const mutateTankopediaPersistent = TankopediaPersistent.useMutation(); const awaitedTanksDefinitionsArray = Object.values(tankDefinitions.tanks); const tankFilters = useStore($tankFilters); - const tankopediaSort = useStore($tankopediaSort); + const tankopediaSort = TankSort.use(); const tanksFiltered = useMemo(() => { if (tankFilters.search === null) { const filtered = awaitedTanksDefinitionsArray.filter((tank) => diff --git a/packages/website/src/pages/[...locale]/performance/_index.tsx b/packages/website/src/pages/[...locale]/performance/_index.tsx index 98bf345d8..3f5b6fdd2 100644 --- a/packages/website/src/pages/[...locale]/performance/_index.tsx +++ b/packages/website/src/pages/[...locale]/performance/_index.tsx @@ -7,7 +7,6 @@ import { LocaleProvider, type LocaleAcceptorProps, } from '../../../hooks/useLocale'; -import { TankPerformanceEphemeral } from '../../../stores/tankPerformanceEphemeral'; import { TankPerformanceSort } from '../../../stores/tankPerformanceSort'; import type { MaybeSkeletonComponentProps } from '../../../types/maybeSkeletonComponentProps'; @@ -17,9 +16,7 @@ export function Page({ skeleton, locale }: PageProps) { return ( - - - + ); diff --git a/packages/website/src/stores/tankopediaSort.ts b/packages/website/src/stores/tankopediaSort.ts index edf28d1ca..45e3b169a 100644 --- a/packages/website/src/stores/tankopediaSort.ts +++ b/packages/website/src/stores/tankopediaSort.ts @@ -1,17 +1,15 @@ -import { map } from 'nanostores'; +import { Varuna } from 'varuna'; import { type TankopediaSortBy, type TankopediaSortDirection, } from './tankopediaPersistent'; -export interface TankopediaSort { +export interface TankSort { by: TankopediaSortBy; direction: TankopediaSortDirection; } -export const initialTankopediaSort: TankopediaSort = { +export const TankSort = new Varuna({ by: 'meta.none', direction: 'descending', -}; - -export const $tankopediaSort = map(initialTankopediaSort); +});