mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: faster tankopedia
This commit is contained in:
1 parent
0a836826c2
commit
d86af7e7ab
6 files changed
+35
-75
No files matched your search
@@ -0,0 +1,9 @@
|
|||||||
|
import { Flex, Spinner } from '@radix-ui/themes';
|
||||||
|
|
||||||
|
export function PageLoader() {
|
||||||
|
return (
|
||||||
|
<Flex align="center" justify="center" flexGrow="1">
|
||||||
|
<Spinner />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
+2
-10
@@ -7,11 +7,11 @@ import { Roboto_Flex } from 'next/font/google';
|
|||||||
import { usePathname } from 'next/navigation';
|
import { usePathname } from 'next/navigation';
|
||||||
import { ReactNode, Suspense } from 'react';
|
import { ReactNode, Suspense } from 'react';
|
||||||
import { Footer } from '../components/Footer';
|
import { Footer } from '../components/Footer';
|
||||||
import { Loader } from '../components/Loader';
|
|
||||||
import Navbar, { NAVBAR_HEIGHT } from '../components/Navbar';
|
import Navbar, { NAVBAR_HEIGHT } from '../components/Navbar';
|
||||||
import { Party3 } from '../components/Party3';
|
import { Party3 } from '../components/Party3';
|
||||||
import * as App from '../stores/app';
|
import * as App from '../stores/app';
|
||||||
import { Checks } from './components/Checks';
|
import { Checks } from './components/Checks';
|
||||||
|
import { PageLoader } from './components/PageLoader';
|
||||||
import './layout.css';
|
import './layout.css';
|
||||||
|
|
||||||
config();
|
config();
|
||||||
@@ -75,15 +75,7 @@ export default function RootLayout({ children }: RootLayoutProps) {
|
|||||||
|
|
||||||
<Checks />
|
<Checks />
|
||||||
|
|
||||||
<Suspense
|
<Suspense fallback={<PageLoader />}>{children}</Suspense>
|
||||||
fallback={
|
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Suspense>
|
|
||||||
|
|
||||||
{!isEmbed && <Footer />}
|
{!isEmbed && <Footer />}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
import { provisionDefinitions } from '../../../../core/blitzkit/provisionDefinitions';
|
||||||
import { tankDefinitions } from '../../../../core/blitzkit/tankDefinitions';
|
import { tankDefinitions } from '../../../../core/blitzkit/tankDefinitions';
|
||||||
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
import { TIER_ROMAN_NUMERALS } from '../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
|
import { tankIcon } from '../../../../core/blitzkit/tankIcon';
|
||||||
|
import { useAwait } from '../../../../hooks/useAwait';
|
||||||
import strings from '../../../../lang/en-US.json';
|
import strings from '../../../../lang/en-US.json';
|
||||||
import * as Duel from '../../../../stores/duel';
|
import * as Duel from '../../../../stores/duel';
|
||||||
|
|
||||||
@@ -18,10 +20,16 @@ export default async function Layout({
|
|||||||
const title = `${tank.name} - Tier ${TIER_ROMAN_NUMERALS[tank.tier]} ${
|
const title = `${tank.name} - Tier ${TIER_ROMAN_NUMERALS[tank.tier]} ${
|
||||||
(strings.common.nations_adjectives as Record<string, string>)[tank.nation]
|
(strings.common.nations_adjectives as Record<string, string>)[tank.nation]
|
||||||
} ${strings.common.tank_class_short[tank.class]}`;
|
} ${strings.common.tank_class_short[tank.class]}`;
|
||||||
const description = `Statistics, armor profiles, and equipment for ${tank.name}`;
|
const description = `Statistics, armor, and equipment for ${tank.name}`;
|
||||||
|
const awaitedProvisionDefinitions = useAwait(provisionDefinitions);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Duel.Provider data={id}>
|
<Duel.Provider
|
||||||
|
data={{
|
||||||
|
tank: awaitedTankDefinitions[id],
|
||||||
|
provisionDefinitions: awaitedProvisionDefinitions,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
<meta name="description" content={description} />
|
<meta name="description" content={description} />
|
||||||
<meta property="og:title" content={title} />
|
<meta property="og:title" content={title} />
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { blackA } from '@radix-ui/colors';
|
|
||||||
import { Flex, Spinner, Text } from '@radix-ui/themes';
|
|
||||||
import { theme } from '../stitches.config';
|
|
||||||
|
|
||||||
const NAV_HEIGHT = 52.65;
|
|
||||||
|
|
||||||
interface LoaderProps {
|
|
||||||
naked?: boolean;
|
|
||||||
progress?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Loader({ naked, progress }: LoaderProps) {
|
|
||||||
const animation = (
|
|
||||||
<Flex align="center" gap="2">
|
|
||||||
<Spinner />
|
|
||||||
{progress !== undefined && (
|
|
||||||
<Text color="gray">{Math.round(progress * 100)}%</Text>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (naked) return animation;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
style={{
|
|
||||||
backgroundColor: blackA.blackA10,
|
|
||||||
position: 'fixed',
|
|
||||||
top: NAV_HEIGHT,
|
|
||||||
left: 0,
|
|
||||||
width: '100%',
|
|
||||||
height: `calc(100% - ${NAV_HEIGHT}px)`,
|
|
||||||
padding: theme.spaces.paddingMajor,
|
|
||||||
}}
|
|
||||||
align="center"
|
|
||||||
justify="center"
|
|
||||||
>
|
|
||||||
{animation}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,5 @@
|
|||||||
import { Draft, produce } from 'immer';
|
import { Draft, produce } from 'immer';
|
||||||
import {
|
import { createContext, ReactNode, useContext, useRef } from 'react';
|
||||||
createContext,
|
|
||||||
ReactNode,
|
|
||||||
useContext,
|
|
||||||
useMemo,
|
|
||||||
use as useReact,
|
|
||||||
useRef,
|
|
||||||
} from 'react';
|
|
||||||
import { StoreApi, useStore as useStoreZustand } from 'zustand';
|
import { StoreApi, useStore as useStoreZustand } from 'zustand';
|
||||||
|
|
||||||
type StoreProviderProps<InitData> = {
|
type StoreProviderProps<InitData> = {
|
||||||
@@ -21,7 +14,7 @@ type ExtractState<S> = S extends {
|
|||||||
: never;
|
: never;
|
||||||
|
|
||||||
export function createNextSafeStore<Store extends StoreApi<unknown>, InitData>(
|
export function createNextSafeStore<Store extends StoreApi<unknown>, InitData>(
|
||||||
initialize: (data: InitData) => Store | Promise<Store>,
|
initialize: (data: InitData) => Store,
|
||||||
) {
|
) {
|
||||||
type Type = Store extends StoreApi<infer T> ? T : never;
|
type Type = Store extends StoreApi<infer T> ? T : never;
|
||||||
|
|
||||||
@@ -29,12 +22,9 @@ export function createNextSafeStore<Store extends StoreApi<unknown>, InitData>(
|
|||||||
|
|
||||||
function Provider(props: StoreProviderProps<InitData>) {
|
function Provider(props: StoreProviderProps<InitData>) {
|
||||||
const storeRef = useRef<Store>();
|
const storeRef = useRef<Store>();
|
||||||
const storePromise = useMemo(
|
if (!storeRef.current) {
|
||||||
async () => await initialize((props as { data: InitData }).data),
|
storeRef.current = initialize((props as { data: InitData }).data);
|
||||||
[],
|
}
|
||||||
);
|
|
||||||
const awaitedStore = useReact(storePromise);
|
|
||||||
if (!storeRef.current) storeRef.current = awaitedStore;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Context.Provider value={storeRef.current}>
|
<Context.Provider value={storeRef.current}>
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { subscribeWithSelector } from 'zustand/middleware';
|
import { subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { provisionDefinitions } from '../../core/blitzkit/provisionDefinitions';
|
import { ProvisionDefinitions } from '../../core/blitzkit/provisionDefinitions';
|
||||||
import {
|
import {
|
||||||
EngineDefinition,
|
EngineDefinition,
|
||||||
GunDefinition,
|
GunDefinition,
|
||||||
ShellDefinition,
|
ShellDefinition,
|
||||||
TankDefinition,
|
TankDefinition,
|
||||||
tankDefinitions,
|
|
||||||
TrackDefinition,
|
TrackDefinition,
|
||||||
TurretDefinition,
|
TurretDefinition,
|
||||||
} from '../../core/blitzkit/tankDefinitions';
|
} from '../../core/blitzkit/tankDefinitions';
|
||||||
@@ -50,11 +49,14 @@ export interface Duel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
|
export const { Provider, use, useMutation, useStore } = createNextSafeStore(
|
||||||
async (id: number) => {
|
({
|
||||||
const awaitedTankDefinitions = await tankDefinitions;
|
tank,
|
||||||
const awaitedProvisionDefinitions = await provisionDefinitions;
|
provisionDefinitions,
|
||||||
const tank = awaitedTankDefinitions[id];
|
}: {
|
||||||
const protagonist = tankToDuelMember(tank, awaitedProvisionDefinitions);
|
tank: TankDefinition;
|
||||||
|
provisionDefinitions: ProvisionDefinitions;
|
||||||
|
}) => {
|
||||||
|
const protagonist = tankToDuelMember(tank, provisionDefinitions);
|
||||||
|
|
||||||
return create<Duel>()(
|
return create<Duel>()(
|
||||||
subscribeWithSelector<Duel>(() => ({
|
subscribeWithSelector<Duel>(() => ({
|
||||||
|
|||||||
Reference in new issue
Block a user