mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: search page
This commit is contained in:
1 parent
408b561b75
commit
ffa1395b50
70 files changed
+492
-468
No files matched your search
@@ -30,11 +30,11 @@ export * from './normalizeBoundingBox';
|
|||||||
// export * from './patientFetch';
|
// export * from './patientFetch';
|
||||||
// export * from './patientFetchJSON';
|
// export * from './patientFetchJSON';
|
||||||
// export * from './progressiveStat';
|
// export * from './progressiveStat';
|
||||||
// export * from './provisionDefinitions';
|
export * from './provisionDefinitions';
|
||||||
export * from './resolveDpm';
|
export * from './resolveDpm';
|
||||||
// export * from './resolvePenetrationCoefficient';
|
export * from './resolvePenetrationCoefficient';
|
||||||
// export * from './reviews';
|
// export * from './reviews';
|
||||||
// export * from './skillDefinitions';
|
export * from './skillDefinitions';
|
||||||
// export * from './sum';
|
// export * from './sum';
|
||||||
export * from './superCompress';
|
export * from './superCompress';
|
||||||
export * from './superDecompress';
|
export * from './superDecompress';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { TankFilterDefinition } from '@blitzkit/core';
|
|
||||||
import { asset } from './asset';
|
import { asset } from './asset';
|
||||||
|
import { TankFilterDefinition } from './consumableDefinitions';
|
||||||
import { fetchCdonLz4 } from './fetchCdonLz4';
|
import { fetchCdonLz4 } from './fetchCdonLz4';
|
||||||
|
|
||||||
export type ProvisionEntry = {
|
export type ProvisionEntry = {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export * from './blitzkit';
|
|||||||
// export * from './blitzstars';
|
// export * from './blitzstars';
|
||||||
// export * from './databases';
|
// export * from './databases';
|
||||||
export * from './imgur';
|
export * from './imgur';
|
||||||
// export * from './math';
|
export * from './math';
|
||||||
export * from './patreon';
|
export * from './patreon';
|
||||||
// export * from './protobuf';
|
// export * from './protobuf';
|
||||||
export * from './statistics';
|
export * from './statistics';
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"next": "^14.2.7",
|
"next": "^14.2.7",
|
||||||
"three-stdlib": "^2.32.2",
|
"three-stdlib": "^2.32.2",
|
||||||
"@react-three/drei": "^9.111.5",
|
|
||||||
"@react-three/fiber": "^8.17.6",
|
|
||||||
"urlon": "^3.1.0",
|
"urlon": "^3.1.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"@vanilla-extract/css": "^1.15.5",
|
"@vanilla-extract/css": "^1.15.5",
|
||||||
@@ -29,7 +27,6 @@
|
|||||||
"react-fuzzysort": "^1.0.1",
|
"react-fuzzysort": "^1.0.1",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"@vanilla-extract/dynamic": "^2.1.2",
|
"@vanilla-extract/dynamic": "^2.1.2",
|
||||||
"zustand": "^4.5.5"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
|||||||
@@ -2,19 +2,19 @@ import { TIER_ROMAN_NUMERALS } from '@blitzkit/core';
|
|||||||
import strings from '@blitzkit/core/lang/en-US.json';
|
import strings from '@blitzkit/core/lang/en-US.json';
|
||||||
import { invalidate } from '@react-three/fiber';
|
import { invalidate } from '@react-three/fiber';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { CalloutsSection } from '../../../../../../../website/src/components/Tankopedia/CalloutsSection';
|
||||||
|
import { CharacteristicsSection } from '../../../../../../../website/src/components/Tankopedia/CharacteristicsSection';
|
||||||
|
import { GameModeSection } from '../../../../../../../website/src/components/Tankopedia/GameModeSection';
|
||||||
|
import { HeroSection } from '../../../../../../../website/src/components/Tankopedia/HeroSection';
|
||||||
|
import { HistorySection } from '../../../../../../../website/src/components/Tankopedia/HistorySection';
|
||||||
|
import { MetaSection } from '../../../../../../../website/src/components/Tankopedia/MetaSection';
|
||||||
|
import { ShotDisplaySection } from '../../../../../../../website/src/components/Tankopedia/ShotDisplaySection';
|
||||||
|
import { TechTreeSection } from '../../../../../../../website/src/components/Tankopedia/TechTreeSection';
|
||||||
import { AdMidSectionResponsive } from '../../../../../components/AdMidSectionResponsive';
|
import { AdMidSectionResponsive } from '../../../../../components/AdMidSectionResponsive';
|
||||||
import { PageWrapper } from '../../../../../components/PageWrapper';
|
import { PageWrapper } from '../../../../../components/PageWrapper';
|
||||||
import { useAdExempt } from '../../../../../hooks/useAdExempt';
|
import { useAdExempt } from '../../../../../hooks/useAdExempt';
|
||||||
import * as Duel from '../../../../../stores/duel';
|
import * as Duel from '../../../../../stores/duel';
|
||||||
import * as TankopediaEphemeral from '../../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../../stores/tankopediaEphemeral';
|
||||||
import { CalloutsSection } from './CalloutsSection';
|
|
||||||
import { HistorySection } from './HistorySection';
|
|
||||||
import { CharacteristicsSection } from './Model/CharacteristicsSection';
|
|
||||||
import { GameModeSection } from './Model/GameModeSection';
|
|
||||||
import { HeroSection } from './Model/HeroSection';
|
|
||||||
import { MetaSection } from './Model/MetaSection';
|
|
||||||
import { TechTreeSection } from './Model/TechTreeSection';
|
|
||||||
import { ShotDisplaySection } from './ShotDisplaySection';
|
|
||||||
import { VideoSection } from './VideoSection';
|
import { VideoSection } from './VideoSection';
|
||||||
|
|
||||||
export function Content() {
|
export function Content() {
|
||||||
|
|||||||
@@ -2,19 +2,19 @@ import { TIER_ROMAN_NUMERALS } from '@blitzkit/core';
|
|||||||
import strings from '@blitzkit/core/lang/en-US.json';
|
import strings from '@blitzkit/core/lang/en-US.json';
|
||||||
import { invalidate } from '@react-three/fiber';
|
import { invalidate } from '@react-three/fiber';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { CalloutsSection } from '../../../../../../website/src/components/Tankopedia/CalloutsSection';
|
||||||
|
import { CharacteristicsSection } from '../../../../../../website/src/components/Tankopedia/CharacteristicsSection';
|
||||||
|
import { GameModeSection } from '../../../../../../website/src/components/Tankopedia/GameModeSection';
|
||||||
|
import { HeroSection } from '../../../../../../website/src/components/Tankopedia/HeroSection';
|
||||||
|
import { HistorySection } from '../../../../../../website/src/components/Tankopedia/HistorySection';
|
||||||
|
import { MetaSection } from '../../../../../../website/src/components/Tankopedia/MetaSection';
|
||||||
|
import { ShotDisplaySection } from '../../../../../../website/src/components/Tankopedia/ShotDisplaySection';
|
||||||
|
import { TechTreeSection } from '../../../../../../website/src/components/Tankopedia/TechTreeSection';
|
||||||
import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive';
|
import { AdMidSectionResponsive } from '../../../../components/AdMidSectionResponsive';
|
||||||
import { PageWrapper } from '../../../../components/PageWrapper';
|
import { PageWrapper } from '../../../../components/PageWrapper';
|
||||||
import { useAdExempt } from '../../../../hooks/useAdExempt';
|
import { useAdExempt } from '../../../../hooks/useAdExempt';
|
||||||
import * as Duel from '../../../../stores/duel';
|
import * as Duel from '../../../../stores/duel';
|
||||||
import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../stores/tankopediaEphemeral';
|
||||||
import { CalloutsSection } from './components/CalloutsSection';
|
|
||||||
import { HistorySection } from './components/HistorySection';
|
|
||||||
import { CharacteristicsSection } from './components/Model/CharacteristicsSection';
|
|
||||||
import { GameModeSection } from './components/Model/GameModeSection';
|
|
||||||
import { HeroSection } from './components/Model/HeroSection';
|
|
||||||
import { MetaSection } from './components/Model/MetaSection';
|
|
||||||
import { TechTreeSection } from './components/Model/TechTreeSection';
|
|
||||||
import { ShotDisplaySection } from './components/ShotDisplaySection';
|
|
||||||
import { VideoSection } from './components/VideoSection';
|
import { VideoSection } from './components/VideoSection';
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
|||||||
@@ -10,6 +10,13 @@
|
|||||||
"include": [
|
"include": [
|
||||||
"src/**/*",
|
"src/**/*",
|
||||||
".next/types/**/*.ts",
|
".next/types/**/*.ts",
|
||||||
"../website/src/components/TankSearch/components/FilterControl.tsx"
|
"../website/src/components/TankSearch/components/FilterControl.tsx",
|
||||||
|
"../website/src/components/Tankopedia/HeroSection/index.tsx",
|
||||||
|
"../website/src/components/Tankopedia/GameModeSection.tsx",
|
||||||
|
"../website/src/components/Tankopedia/CharacteristicsSection.tsx",
|
||||||
|
"../website/src/components/Tankopedia/MetaSection",
|
||||||
|
"../website/src/components/Tankopedia/HistorySection.tsx",
|
||||||
|
"../website/src/components/Tankopedia/CalloutsSection.tsx",
|
||||||
|
"../website/src/components/Tankopedia/ShotDisplaySection.tsx"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -18,10 +18,13 @@
|
|||||||
"@radix-ui/themes": "^3.1.3",
|
"@radix-ui/themes": "^3.1.3",
|
||||||
"@vanilla-extract/css": "^1.15.5",
|
"@vanilla-extract/css": "^1.15.5",
|
||||||
"astro": "^4.15.6",
|
"astro": "^4.15.6",
|
||||||
|
"@react-three/drei": "^9.111.5",
|
||||||
|
"@react-three/fiber": "^8.17.6",
|
||||||
"astro-purgecss": "^4.6.0",
|
"astro-purgecss": "^4.6.0",
|
||||||
"nanostores": "^0.11.3",
|
"nanostores": "^0.11.3",
|
||||||
"purgecss": "^6.0.0",
|
"purgecss": "^6.0.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
|
"zustand": "^4.5.5",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-promise-suspense": "^0.3.4"
|
"react-promise-suspense": "^0.3.4"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ import {
|
|||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
import { Html } from '@react-three/drei';
|
import { Html } from '@react-three/drei';
|
||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { radToDeg } from 'three/src/math/MathUtils';
|
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
||||||
import { resolveArmorIndex } from '../../../../../website-legacy/src/core/blitzkit/resolveArmorIndex';
|
|
||||||
import * as App from '../../../../../website-legacy/src/stores/app';
|
|
||||||
import * as Duel from '../../../../../website-legacy/src/stores/duel';
|
|
||||||
import * as TankopediaEphemeral from '../../../../../website-legacy/src/stores/tankopediaEphemeral';
|
|
||||||
import { layerTypeNames } from './ShotDisplayCard';
|
import { layerTypeNames } from './ShotDisplayCard';
|
||||||
import { ArmorType } from './SpacedArmorScene';
|
import { ArmorType } from './SpacedArmorScene';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { GroupProps } from '@react-three/fiber';
|
import type { GroupProps } from '@react-three/fiber';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import { Group } from 'three';
|
import { Group } from 'three';
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { Group } from 'three';
|
import { Group } from 'three';
|
||||||
import { correctZYTuple } from '../../../../../website-legacy/src/core/blitz/correctZYTuple';
|
import { correctZYTuple } from '../../../core/blitz/correctZYTuple';
|
||||||
import { nameToArmorId } from '../../../../../website-legacy/src/core/blitzkit/nameToArmorId';
|
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
||||||
import { resolveArmor } from '../../../../../website-legacy/src/core/blitzkit/resolveThickness';
|
import { resolveArmor } from '../../../core/blitzkit/resolveThickness';
|
||||||
import { useArmor } from '../../../../../website-legacy/src/hooks/useArmor';
|
import { useArmor } from '../../../hooks/useArmor';
|
||||||
import { useTankModelDefinition } from '../../../../../website-legacy/src/hooks/useTankModelDefinition';
|
import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition';
|
||||||
import { useTankTransform } from '../../../../../website-legacy/src/hooks/useTankTransform';
|
import { useTankTransform } from '../../../hooks/useTankTransform';
|
||||||
import * as Duel from '../../../../../website-legacy/src/stores/duel';
|
|
||||||
import { ModelTankWrapper } from './ModelTankWrapper';
|
import { ModelTankWrapper } from './ModelTankWrapper';
|
||||||
import { PrimaryArmorSceneComponent } from './PrimaryArmorSceneComponent';
|
import { PrimaryArmorSceneComponent } from './PrimaryArmorSceneComponent';
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { Group, Plane, Scene, Vector3 } from 'three';
|
import { Group, Plane, Scene, Vector3 } from 'three';
|
||||||
import { correctZYTuple } from '../../../../../website-legacy/src/core/blitz/correctZYTuple';
|
import { correctZYTuple } from '../../../core/blitz/correctZYTuple';
|
||||||
import { nameToArmorId } from '../../../../../website-legacy/src/core/blitzkit/nameToArmorId';
|
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
||||||
import { resolveArmor } from '../../../../../website-legacy/src/core/blitzkit/resolveThickness';
|
import { resolveArmor } from '../../../core/blitzkit/resolveThickness';
|
||||||
import { useArmor } from '../../../../../website-legacy/src/hooks/useArmor';
|
import { useArmor } from '../../../hooks/useArmor';
|
||||||
import { useModel } from '../../../../../website-legacy/src/hooks/useModel';
|
import { useModel } from '../../../hooks/useModel';
|
||||||
import { useTankModelDefinition } from '../../../../../website-legacy/src/hooks/useTankModelDefinition';
|
import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition';
|
||||||
import { useTankTransform } from '../../../../../website-legacy/src/hooks/useTankTransform';
|
import { useTankTransform } from '../../../hooks/useTankTransform';
|
||||||
import * as Duel from '../../../../../website-legacy/src/stores/duel';
|
|
||||||
import { ModelTankWrapper } from './ModelTankWrapper';
|
import { ModelTankWrapper } from './ModelTankWrapper';
|
||||||
import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent';
|
import { SpacedArmorSceneComponent } from './SpacedArmorSceneComponent';
|
||||||
|
|
||||||
|
|||||||
+7
-9
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
ShellDefinition,
|
|
||||||
resolveNearPenetration,
|
resolveNearPenetration,
|
||||||
resolvePenetrationCoefficient,
|
resolvePenetrationCoefficient,
|
||||||
|
type ShellDefinition,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
@@ -11,10 +11,10 @@ import {
|
|||||||
Plane,
|
Plane,
|
||||||
ShaderMaterial,
|
ShaderMaterial,
|
||||||
} from 'three';
|
} from 'three';
|
||||||
import { ArmorUserData, ExternalModuleVariant } from '../..';
|
import type { ArmorUserData, ExternalModuleVariant } from '../..';
|
||||||
import { hasEquipment } from '../../../../../../../../website-legacy/src/core/blitzkit/hasEquipment';
|
import { hasEquipment } from '../../../../../../core/blitzkit/hasEquipment';
|
||||||
import { jsxTree } from '../../../../../../../../website-legacy/src/core/blitzkit/jsxTree';
|
import { jsxTree } from '../../../../../../core/blitzkit/jsxTree';
|
||||||
import * as Duel from '../../../../../../../../website-legacy/src/stores/duel';
|
import { Duel, type EquipmentMatrix } from '../../../../../../stores/duel';
|
||||||
import { ArmorType } from '../../../SpacedArmorScene';
|
import { ArmorType } from '../../../SpacedArmorScene';
|
||||||
import fragmentShader from './shaders/fragment.glsl';
|
import fragmentShader from './shaders/fragment.glsl';
|
||||||
import vertexShader from './shaders/vertex.glsl';
|
import vertexShader from './shaders/vertex.glsl';
|
||||||
@@ -56,7 +56,7 @@ export function SpacedArmorSubExternal({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function handleProtagonistEquipmentChange(
|
async function handleProtagonistEquipmentChange(
|
||||||
equipment: Duel.EquipmentMatrix,
|
equipment: EquipmentMatrix,
|
||||||
) {
|
) {
|
||||||
const duel = duelStore.getState();
|
const duel = duelStore.getState();
|
||||||
const hasEnhancedArmor = await hasEquipment(
|
const hasEnhancedArmor = await hasEquipment(
|
||||||
@@ -68,9 +68,7 @@ export function SpacedArmorSubExternal({
|
|||||||
? thickness * 1.03
|
? thickness * 1.03
|
||||||
: thickness;
|
: thickness;
|
||||||
}
|
}
|
||||||
async function handleAntagonistEquipmentChange(
|
async function handleAntagonistEquipmentChange(equipment: EquipmentMatrix) {
|
||||||
equipment: Duel.EquipmentMatrix,
|
|
||||||
) {
|
|
||||||
const duel = duelStore.getState();
|
const duel = duelStore.getState();
|
||||||
const shell = duel.antagonist.shell;
|
const shell = duel.antagonist.shell;
|
||||||
const penetration = resolveNearPenetration(shell.penetration);
|
const penetration = resolveNearPenetration(shell.penetration);
|
||||||
|
|||||||
@@ -1,20 +1,19 @@
|
|||||||
import { normalizeAngleRad } from '@blitzkit/core';
|
import { normalizeAngleRad } from '@blitzkit/core';
|
||||||
import { ThreeEvent, useThree } from '@react-three/fiber';
|
import { useThree, type ThreeEvent } from '@react-three/fiber';
|
||||||
import { memo, useRef } from 'react';
|
import { memo, useRef } from 'react';
|
||||||
import { Group, Plane, Vector2, Vector3 } from 'three';
|
import { Group, Plane, Vector2, Vector3 } from 'three';
|
||||||
import { applyPitchYawLimits } from '../../../../../website-legacy/src/core/blitz/applyPitchYawLimits';
|
import { applyPitchYawLimits } from '../../../core/blitz/applyPitchYawLimits';
|
||||||
import { correctZYTuple } from '../../../../../website-legacy/src/core/blitz/correctZYTuple';
|
import { correctZYTuple } from '../../../core/blitz/correctZYTuple';
|
||||||
import { hasEquipment } from '../../../../../website-legacy/src/core/blitzkit/hasEquipment';
|
import { hasEquipment } from '../../../core/blitzkit/hasEquipment';
|
||||||
import { modelTransformEvent } from '../../../../../website-legacy/src/core/blitzkit/modelTransform';
|
import { modelTransformEvent } from '../../../core/blitzkit/modelTransform';
|
||||||
import { nameToArmorId } from '../../../../../website-legacy/src/core/blitzkit/nameToArmorId';
|
import { nameToArmorId } from '../../../core/blitzkit/nameToArmorId';
|
||||||
import { resolveArmor } from '../../../../../website-legacy/src/core/blitzkit/resolveThickness';
|
import { resolveArmor } from '../../../core/blitzkit/resolveThickness';
|
||||||
import { useArmor } from '../../../../../website-legacy/src/hooks/useArmor';
|
import { useArmor } from '../../../hooks/useArmor';
|
||||||
import { useModel } from '../../../../../website-legacy/src/hooks/useModel';
|
import { useModel } from '../../../hooks/useModel';
|
||||||
import { useTankModelDefinition } from '../../../../../website-legacy/src/hooks/useTankModelDefinition';
|
import { useTankModelDefinition } from '../../../hooks/useTankModelDefinition';
|
||||||
import { useTankTransform } from '../../../../../website-legacy/src/hooks/useTankTransform';
|
import { useTankTransform } from '../../../hooks/useTankTransform';
|
||||||
import * as Duel from '../../../../../website-legacy/src/stores/duel';
|
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
||||||
import * as TankopediaEphemeral from '../../../../../website-legacy/src/stores/tankopediaEphemeral';
|
import { TankopediaPersistent } from '../../../stores/tankopediaPersistent';
|
||||||
import * as TankopediaPersistent from '../../../../../website-legacy/src/stores/tankopediaPersistent';
|
|
||||||
import { ModelTankWrapper } from './ModelTankWrapper';
|
import { ModelTankWrapper } from './ModelTankWrapper';
|
||||||
import { ArmorType } from './SpacedArmorScene';
|
import { ArmorType } from './SpacedArmorScene';
|
||||||
import { StaticArmorSceneComponent } from './StaticArmorSceneComponent';
|
import { StaticArmorSceneComponent } from './StaticArmorSceneComponent';
|
||||||
@@ -56,13 +55,13 @@ export const StaticArmor = memo<ArmorSceneProps>(({ thicknessRange }) => {
|
|||||||
? undefined
|
? undefined
|
||||||
: gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y;
|
: gunModelDefinition.mask + hullOrigin.y + turretOrigin.y + gunOrigin.y;
|
||||||
const showPrimaryArmor = TankopediaPersistent.use(
|
const showPrimaryArmor = TankopediaPersistent.use(
|
||||||
(state) => state.model.visual.showPrimaryArmor,
|
(state) => state.showPrimaryArmor,
|
||||||
);
|
);
|
||||||
const showSpacedArmor = TankopediaPersistent.use(
|
const showSpacedArmor = TankopediaPersistent.use(
|
||||||
(state) => state.model.visual.showSpacedArmor,
|
(state) => state.showSpacedArmor,
|
||||||
);
|
);
|
||||||
const showExternalModules = TankopediaPersistent.use(
|
const showExternalModules = TankopediaPersistent.use(
|
||||||
(state) => state.model.visual.showExternalModules,
|
(state) => state.showExternalModules,
|
||||||
);
|
);
|
||||||
const isDynamicArmorActive = Duel.use((state) =>
|
const isDynamicArmorActive = Duel.use((state) =>
|
||||||
state.protagonist.consumables.includes(73),
|
state.protagonist.consumables.includes(73),
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import {
|
|||||||
asset,
|
asset,
|
||||||
permanentSkills,
|
permanentSkills,
|
||||||
skillDefinitions,
|
skillDefinitions,
|
||||||
Tier,
|
|
||||||
TIER_ROMAN_NUMERALS,
|
TIER_ROMAN_NUMERALS,
|
||||||
|
type Tier,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Flex } from '@radix-ui/themes';
|
import { Flex } from '@radix-ui/themes';
|
||||||
import { use } from 'react';
|
|
||||||
import { GenericTankComponentButton } from './ModuleButtons/GenericTankComponentButton';
|
import { GenericTankComponentButton } from './ModuleButtons/GenericTankComponentButton';
|
||||||
|
|
||||||
interface CrewSkillManagerProps {
|
interface CrewSkillManagerProps {
|
||||||
@@ -14,12 +13,12 @@ interface CrewSkillManagerProps {
|
|||||||
onChange?: (skillLevels: Record<string, number>) => void;
|
onChange?: (skillLevels: Record<string, number>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const awaitedSkillDefinitions = await skillDefinitions;
|
||||||
|
|
||||||
export function CrewSkillManager({
|
export function CrewSkillManager({
|
||||||
skillLevels,
|
skillLevels,
|
||||||
onChange,
|
onChange,
|
||||||
}: CrewSkillManagerProps) {
|
}: CrewSkillManagerProps) {
|
||||||
const awaitedSkillDefinitions = use(skillDefinitions);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
{Object.entries(awaitedSkillDefinitions.classes).map(
|
{Object.entries(awaitedSkillDefinitions.classes).map(
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { asset, consumableDefinitions } from '@blitzkit/core';
|
import { asset, consumableDefinitions } from '@blitzkit/core';
|
||||||
import { ClockIcon, ReloadIcon } from '@radix-ui/react-icons';
|
import { ClockIcon, ReloadIcon } from '@radix-ui/react-icons';
|
||||||
import { Flex, Text } from '@radix-ui/themes';
|
import { Flex, Text } from '@radix-ui/themes';
|
||||||
import { use } from 'react';
|
|
||||||
import { useDelta } from '../../../../website-legacy/src/hooks/useDelta';
|
import { useDelta } from '../../../../website-legacy/src/hooks/useDelta';
|
||||||
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
||||||
import { TankComponentButtonProps } from './TankComponentButton';
|
import { TankComponentButtonProps } from './TankComponentButton';
|
||||||
@@ -12,13 +11,14 @@ interface ConsumableButtonProps extends TankComponentButtonProps {
|
|||||||
cooldown?: number;
|
cooldown?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const awaitedConsumableDefinitions = await consumableDefinitions;
|
||||||
|
|
||||||
export function ConsumableButton({
|
export function ConsumableButton({
|
||||||
consumable,
|
consumable,
|
||||||
cooldown,
|
cooldown,
|
||||||
duration,
|
duration,
|
||||||
...props
|
...props
|
||||||
}: ConsumableButtonProps) {
|
}: ConsumableButtonProps) {
|
||||||
const awaitedConsumableDefinitions = use(consumableDefinitions);
|
|
||||||
const cooldownDelta = useDelta(cooldown ?? 0);
|
const cooldownDelta = useDelta(cooldown ?? 0);
|
||||||
const durationDelta = useDelta(duration ?? 0);
|
const durationDelta = useDelta(duration ?? 0);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { asset, equipmentDefinitions } from '@blitzkit/core';
|
import { asset, equipmentDefinitions } from '@blitzkit/core';
|
||||||
import { use } from 'react';
|
|
||||||
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
||||||
import { TankComponentButtonProps } from './TankComponentButton';
|
import { TankComponentButtonProps } from './TankComponentButton';
|
||||||
|
|
||||||
@@ -7,9 +6,9 @@ interface EquipmentButtonProps extends TankComponentButtonProps {
|
|||||||
equipment: number;
|
equipment: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EquipmentButton({ equipment, ...props }: EquipmentButtonProps) {
|
const awaitedEquipmentDefinitions = await equipmentDefinitions;
|
||||||
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
|
||||||
|
|
||||||
|
export function EquipmentButton({ equipment, ...props }: EquipmentButtonProps) {
|
||||||
return (
|
return (
|
||||||
<GenericTankComponentButton
|
<GenericTankComponentButton
|
||||||
tooltip={awaitedEquipmentDefinitions.equipments[equipment].name}
|
tooltip={awaitedEquipmentDefinitions.equipments[equipment].name}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { HTMLAttributes } from 'react';
|
import type { HTMLAttributes } from 'react';
|
||||||
import {
|
import {
|
||||||
TankComponentButton,
|
TankComponentButton,
|
||||||
TankComponentButtonProps,
|
TankComponentButtonProps,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { asset, provisionDefinitions } from '@blitzkit/core';
|
import { asset, provisionDefinitions } from '@blitzkit/core';
|
||||||
import { use } from 'react';
|
|
||||||
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
import { GenericTankComponentButton } from './GenericTankComponentButton';
|
||||||
import { TankComponentButtonProps } from './TankComponentButton';
|
import { TankComponentButtonProps } from './TankComponentButton';
|
||||||
|
|
||||||
@@ -7,9 +6,9 @@ interface ProvisionButtonProps extends TankComponentButtonProps {
|
|||||||
provision: number;
|
provision: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProvisionButton({ provision, ...props }: ProvisionButtonProps) {
|
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
|
||||||
|
|
||||||
|
export function ProvisionButton({ provision, ...props }: ProvisionButtonProps) {
|
||||||
return (
|
return (
|
||||||
<GenericTankComponentButton
|
<GenericTankComponentButton
|
||||||
tooltip={awaitedProvisionDefinitions[provision].name}
|
tooltip={awaitedProvisionDefinitions[provision].name}
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
import { patreonLoginUrl } from '@blitzkit/core';
|
|
||||||
import { useStore } from '@nanostores/react';
|
|
||||||
import { PersonIcon } from '@radix-ui/react-icons';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Flex,
|
|
||||||
IconButton,
|
|
||||||
Inset,
|
|
||||||
Link,
|
|
||||||
Popover,
|
|
||||||
Separator,
|
|
||||||
Skeleton,
|
|
||||||
Text,
|
|
||||||
} from '@radix-ui/themes';
|
|
||||||
import { Suspense } from 'react';
|
|
||||||
import { $patreonLogin } from '../stores/patreonLogin';
|
|
||||||
import { $wargamingLogin } from '../stores/wargamingLogin';
|
|
||||||
import { BlitzKitTheme } from './BlitzKitTheme';
|
|
||||||
import { PatreonIcon } from './PatreonIcon';
|
|
||||||
import { WargamingAccountName } from './WargamingAccountName';
|
|
||||||
import { WargamingIcon } from './WargamingIcon';
|
|
||||||
import { WargamingLoginButton } from './WargamingLoginButton';
|
|
||||||
|
|
||||||
export function NavbarAccount() {
|
|
||||||
const patreonLogin = useStore($patreonLogin);
|
|
||||||
const wargamingLogin = useStore($wargamingLogin);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Popover.Root>
|
|
||||||
<Popover.Trigger>
|
|
||||||
<IconButton variant="ghost" color="gray">
|
|
||||||
<PersonIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Popover.Trigger>
|
|
||||||
|
|
||||||
<BlitzKitTheme>
|
|
||||||
<Popover.Content
|
|
||||||
align="end"
|
|
||||||
width="320px"
|
|
||||||
onOpenAutoFocus={(event) => event.preventDefault()}
|
|
||||||
>
|
|
||||||
{(patreonLogin.token || wargamingLogin.token) && (
|
|
||||||
<Flex direction="column" gap="2">
|
|
||||||
<Text align="center" color="gray">
|
|
||||||
Logged in accounts
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{patreonLogin.token && (
|
|
||||||
<Flex align="center" gap="2" justify="center">
|
|
||||||
<PatreonIcon width={15} height={15} />
|
|
||||||
<Text>Patreon</Text>
|
|
||||||
<Button
|
|
||||||
color="red"
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => {
|
|
||||||
$patreonLogin.set({ token: undefined });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Logout
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{wargamingLogin.token && (
|
|
||||||
<Flex align="center" gap="2" justify="center">
|
|
||||||
<WargamingIcon width={15} height={15} />
|
|
||||||
<Text>
|
|
||||||
<Suspense fallback={<Skeleton height="1em" width="5rem" />}>
|
|
||||||
<WargamingAccountName />
|
|
||||||
</Suspense>
|
|
||||||
</Text>
|
|
||||||
<Button
|
|
||||||
color="red"
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => {
|
|
||||||
$wargamingLogin.set({ token: undefined });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Logout
|
|
||||||
</Button>
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!patreonLogin.token !== !wargamingLogin.token && (
|
|
||||||
<Inset side="x">
|
|
||||||
<Separator my="4" size="4" />
|
|
||||||
</Inset>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(!patreonLogin.token || !wargamingLogin.token) && (
|
|
||||||
<Flex direction="column" gap="2">
|
|
||||||
<Text align="center" color="gray">
|
|
||||||
Log in with...
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
{!patreonLogin.token && (
|
|
||||||
<Link style={{ width: '100%' }} href={patreonLoginUrl()}>
|
|
||||||
<Button style={{ width: '100%' }} color="tomato">
|
|
||||||
<PatreonIcon width={15} height={15} /> Patreon
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!wargamingLogin.token && <WargamingLoginButton />}
|
|
||||||
</Flex>
|
|
||||||
)}
|
|
||||||
</Popover.Content>
|
|
||||||
</BlitzKitTheme>
|
|
||||||
</Popover.Root>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { patreonLoginUrl } from '@blitzkit/core';
|
||||||
|
import { useStore } from '@nanostores/react';
|
||||||
|
import { PersonIcon } from '@radix-ui/react-icons';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Flex,
|
||||||
|
IconButton,
|
||||||
|
Inset,
|
||||||
|
Link,
|
||||||
|
Popover,
|
||||||
|
Separator,
|
||||||
|
Skeleton,
|
||||||
|
Text,
|
||||||
|
} from '@radix-ui/themes';
|
||||||
|
import { Suspense } from 'react';
|
||||||
|
import { App } from '../../stores/app';
|
||||||
|
import { $patreonLogin } from '../../stores/patreonLogin';
|
||||||
|
import { $wargamingLogin } from '../../stores/wargamingLogin';
|
||||||
|
import { BlitzKitTheme } from '../BlitzKitTheme';
|
||||||
|
import { PatreonIcon } from '../PatreonIcon';
|
||||||
|
import { WargamingAccountName } from '../WargamingAccountName';
|
||||||
|
import { WargamingIcon } from '../WargamingIcon';
|
||||||
|
import { WargamingLoginButton } from '../WargamingLoginButton';
|
||||||
|
|
||||||
|
export function NavbarAccount() {
|
||||||
|
const patreon = useStore($patreonLogin);
|
||||||
|
const wargaming = useStore($wargamingLogin);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<App.Provider>
|
||||||
|
<Popover.Root>
|
||||||
|
<Popover.Trigger>
|
||||||
|
<IconButton variant="ghost" color="gray">
|
||||||
|
<PersonIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Popover.Trigger>
|
||||||
|
|
||||||
|
<BlitzKitTheme>
|
||||||
|
<Popover.Content
|
||||||
|
align="end"
|
||||||
|
width="320px"
|
||||||
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
|
>
|
||||||
|
{(patreon.token || wargaming.token) && (
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
<Text align="center" color="gray">
|
||||||
|
Logged in accounts
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{patreon.token && (
|
||||||
|
<Flex align="center" gap="2" justify="center">
|
||||||
|
<PatreonIcon width={15} height={15} />
|
||||||
|
<Text>Patreon</Text>
|
||||||
|
<Button
|
||||||
|
color="red"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => {
|
||||||
|
$patreonLogin.setKey('token', undefined);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Logout
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{wargaming.token && (
|
||||||
|
<Flex align="center" gap="2" justify="center">
|
||||||
|
<WargamingIcon width={15} height={15} />
|
||||||
|
<Text>
|
||||||
|
<Suspense
|
||||||
|
fallback={<Skeleton height="1em" width="5rem" />}
|
||||||
|
>
|
||||||
|
<WargamingAccountName />
|
||||||
|
</Suspense>
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
color="red"
|
||||||
|
variant="ghost"
|
||||||
|
onClick={() => {
|
||||||
|
$wargamingLogin.setKey('token', undefined);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Logout
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!patreon.token !== !wargaming.token && (
|
||||||
|
<Inset side="x">
|
||||||
|
<Separator my="4" size="4" />
|
||||||
|
</Inset>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(!patreon.token || !wargaming.token) && (
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
<Text align="center" color="gray">
|
||||||
|
Log in with...
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{!patreon.token && (
|
||||||
|
<Link style={{ width: '100%' }} href={patreonLoginUrl()}>
|
||||||
|
<Button style={{ width: '100%' }} color="tomato">
|
||||||
|
<PatreonIcon width={15} height={15} /> Patreon
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!wargaming.token && <WargamingLoginButton />}
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Popover.Content>
|
||||||
|
</BlitzKitTheme>
|
||||||
|
</Popover.Root>
|
||||||
|
</App.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -10,19 +10,13 @@ import {
|
|||||||
Separator,
|
Separator,
|
||||||
Text,
|
Text,
|
||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
import { useLayoutEffect, useState } from 'react';
|
|
||||||
import { useAdExempt } from '../hooks/useAdExempt';
|
import { useAdExempt } from '../hooks/useAdExempt';
|
||||||
import { $patreonLogin } from '../stores/patreonLogin';
|
import { $patreonLogin } from '../stores/patreonLogin';
|
||||||
import { PatreonIcon } from './PatreonIcon';
|
import { PatreonIcon } from './PatreonIcon';
|
||||||
|
|
||||||
export function Plugs() {
|
export function Plugs() {
|
||||||
const [hasPatreon, setHasPatreon] = useState(false);
|
|
||||||
const exempt = useAdExempt();
|
const exempt = useAdExempt();
|
||||||
const patreonLogin = useStore($patreonLogin);
|
const hasPatreon = useStore($patreonLogin).token !== undefined;
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
setHasPatreon(patreonLogin !== undefined);
|
|
||||||
}, [patreonLogin]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
|
|||||||
File renamed without changes.
+7
-7
@@ -1,11 +1,11 @@
|
|||||||
import { Flex, Heading } from '@radix-ui/themes';
|
import { Flex, Heading } from '@radix-ui/themes';
|
||||||
import { Characteristics } from '../Characteristics';
|
import { Characteristics } from '../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Characteristics';
|
||||||
import { Consumables } from '../Characteristics/components/Consumables';
|
import { Consumables } from '../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Characteristics/components/Consumables';
|
||||||
import { Equipment } from '../Characteristics/components/Equipment';
|
import { Equipment } from '../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Characteristics/components/Equipment';
|
||||||
import { Miscellaneous } from '../Characteristics/components/Miscellaneous';
|
import { Miscellaneous } from '../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Characteristics/components/Miscellaneous';
|
||||||
import { Modules } from '../Characteristics/components/Modules';
|
import { Modules } from '../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Characteristics/components/Modules';
|
||||||
import { Provisions } from '../Characteristics/components/Provisions';
|
import { Provisions } from '../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Characteristics/components/Provisions';
|
||||||
import { Skills } from '../Characteristics/components/Skills';
|
import { Skills } from '../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Characteristics/components/Skills';
|
||||||
|
|
||||||
export function CharacteristicsSection() {
|
export function CharacteristicsSection() {
|
||||||
return (
|
return (
|
||||||
+4
-4
@@ -5,14 +5,14 @@ import {
|
|||||||
provisionDefinitions,
|
provisionDefinitions,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
|
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
import { use } from 'react';
|
|
||||||
import * as Duel from '../../../../../../stores/duel';
|
import * as Duel from '../../../../../../stores/duel';
|
||||||
|
|
||||||
|
const awaitedGameDefinitions = await gameDefinitions;
|
||||||
|
const awaitedConsumableDefinitions = await consumableDefinitions;
|
||||||
|
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||||
|
|
||||||
export function GameModeSection() {
|
export function GameModeSection() {
|
||||||
const tank = Duel.use((state) => state.protagonist.tank);
|
const tank = Duel.use((state) => state.protagonist.tank);
|
||||||
const awaitedGameDefinitions = use(gameDefinitions);
|
|
||||||
const awaitedConsumableDefinitions = use(consumableDefinitions);
|
|
||||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
|
||||||
const roles = Object.entries(tank.roles);
|
const roles = Object.entries(tank.roles);
|
||||||
|
|
||||||
if (roles.length === 0) return null;
|
if (roles.length === 0) return null;
|
||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
import { asset } from '@blitzkit/core';
|
import { asset } from '@blitzkit/core';
|
||||||
import { IconButton } from '@radix-ui/themes';
|
import { IconButton } from '@radix-ui/themes';
|
||||||
import { invalidate } from '@react-three/fiber';
|
import { invalidate } from '@react-three/fiber';
|
||||||
import { useArmor } from '../../../../../../../../../hooks/useArmor';
|
import { useArmor } from '../../../../../../hooks/useArmor';
|
||||||
import * as Duel from '../../../../../../../../../stores/duel';
|
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
|
||||||
import * as TankopediaEphemeral from '../../../../../../../../../stores/tankopediaEphemeral';
|
|
||||||
|
|
||||||
export function DynamicArmorSwitcher() {
|
export function DynamicArmorSwitcher() {
|
||||||
const tank = Duel.use((state) => state.protagonist.tank);
|
const tank = Duel.use((state) => state.protagonist.tank);
|
||||||
File renamed without changes.
File renamed without changes.
+36
-41
@@ -1,4 +1,11 @@
|
|||||||
import { asset, imgur, resolveNearPenetration, resolvePenetrationCoefficient, TIER_ROMAN_NUMERALS, uniqueGuns } from '@blitzkit/core';
|
import {
|
||||||
|
asset,
|
||||||
|
imgur,
|
||||||
|
resolveNearPenetration,
|
||||||
|
resolvePenetrationCoefficient,
|
||||||
|
TIER_ROMAN_NUMERALS,
|
||||||
|
uniqueGuns,
|
||||||
|
} from '@blitzkit/core';
|
||||||
import {
|
import {
|
||||||
CameraIcon,
|
CameraIcon,
|
||||||
CopyIcon,
|
CopyIcon,
|
||||||
@@ -21,24 +28,22 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
import { invalidate } from '@react-three/fiber';
|
import { invalidate } from '@react-three/fiber';
|
||||||
import { RefObject, useEffect, useState } from 'react';
|
import { type RefObject, useState } from 'react';
|
||||||
import { useEquipment } from '../../../../../../../../hooks/useEquipment';
|
import { ENVIRONMENTS } from '../../../../../constants/lightingEnvironments';
|
||||||
import { useFullScreen } from '../../../../../../../../hooks/useFullScreen';
|
import { Pose, poseEvent } from '../../../../../core/blitzkit/pose';
|
||||||
import { useFullscreenAvailability } from '../../../../../../../../hooks/useFullscreenAvailability';
|
import { useEquipment } from '../../../../../hooks/useEquipment';
|
||||||
import * as App from '../../../../../../../../stores/app';
|
import { useFullScreen } from '../../../../../hooks/useFullScreen';
|
||||||
import * as Duel from '../../../../../../../../stores/duel';
|
import { useFullscreenAvailability } from '../../../../../hooks/useFullscreenAvailability';
|
||||||
import * as TankopediaEphemeral from '../../../../../../../../stores/tankopediaEphemeral';
|
import { useStoreBoolean } from '../../../../../hooks/useStoreBoolean';
|
||||||
import * as TankopediaPersistent from '../../../../../../../../stores/tankopediaPersistent';
|
import { useStoreKey } from '../../../../../hooks/useStoreKey';
|
||||||
import { TankopediaDisplay } from '../../../../../../../../stores/tankopediaPersistent/constants';
|
import { $app } from '../../../../../stores/app';
|
||||||
import { TankSearch } from '../../../../../components/TankSearch';
|
import { $tankopediaPersistent } from '../../../../../stores/tankopediaPersistent';
|
||||||
import { ENVIRONMENTS } from '../../../Lighting';
|
import { TankopediaDisplay } from '../../../../../stores/tankopediaPersistent/constants';
|
||||||
import { QuickInputs } from '../../../QuickInputs';
|
import type { ThicknessRange } from '../../../../Armor/components/StaticArmor';
|
||||||
import { Thicknesses } from '../../../Thicknesses';
|
import { ModuleButton } from '../../../../ModuleButtons/ModuleButton';
|
||||||
|
import { SmallTankIcon } from '../../../../SmallTankIcon';
|
||||||
|
import { TankSearch } from '../../../../TankSearch';
|
||||||
import { DynamicArmorSwitcher } from './components/DynamicArmorSwitcher';
|
import { DynamicArmorSwitcher } from './components/DynamicArmorSwitcher';
|
||||||
import { ThicknessRange } from '../../../../../../../../components/Armor/components/StaticArmor';
|
|
||||||
import { ModuleButton } from '../../../../../../../../components/ModuleButtons/ModuleButton';
|
|
||||||
import { SmallTankIcon } from '../../../../../../../../components/SmallTankIcon';
|
|
||||||
import { poseEvent, Pose } from '../../../../../../../../core/blitzkit/pose';
|
|
||||||
|
|
||||||
interface OptionsProps {
|
interface OptionsProps {
|
||||||
thicknessRange: ThicknessRange;
|
thicknessRange: ThicknessRange;
|
||||||
@@ -46,31 +51,23 @@ interface OptionsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Options({ thicknessRange, canvas }: OptionsProps) {
|
export function Options({ thicknessRange, canvas }: OptionsProps) {
|
||||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
// const { display } = useStore($tankopediaPersistent, { keys: ['display'] });
|
||||||
const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
|
const display = useStoreKey($tankopediaPersistent, 'display');
|
||||||
const displayRaw = TankopediaPersistent.use((state) => state.display);
|
|
||||||
const [display, setDisplay] = useState<TankopediaDisplay>(
|
|
||||||
TankopediaDisplay.Model,
|
|
||||||
);
|
|
||||||
const isFullScreen = useFullScreen();
|
const isFullScreen = useFullScreen();
|
||||||
const showGrid = TankopediaPersistent.use(
|
const showGrid = useStoreBoolean($tankopediaPersistent, 'showGrid');
|
||||||
(state) => state.model.visual.showGrid,
|
const showEnvironment = useStoreBoolean(
|
||||||
|
$tankopediaPersistent,
|
||||||
|
'showEnvironment',
|
||||||
);
|
);
|
||||||
const showEnvironment = TankopediaPersistent.use(
|
const greenPenetration = useStoreBoolean(
|
||||||
(state) => state.model.visual.showEnvironment,
|
$tankopediaPersistent,
|
||||||
|
'greenPenetration',
|
||||||
);
|
);
|
||||||
const greenPenetration = TankopediaPersistent.use(
|
const wireframe = useStoreBoolean($tankopediaPersistent, 'wireframe');
|
||||||
(state) => state.model.visual.greenPenetration,
|
const opaque = useStoreBoolean($tankopediaPersistent, 'opaque');
|
||||||
);
|
|
||||||
const wireframe = TankopediaPersistent.use(
|
|
||||||
(state) => state.model.visual.wireframe,
|
|
||||||
);
|
|
||||||
const opaque = TankopediaPersistent.use((state) => state.model.visual.opaque);
|
|
||||||
const fullScreenAvailable = useFullscreenAvailability();
|
const fullScreenAvailable = useFullscreenAvailability();
|
||||||
const environment = TankopediaPersistent.use(
|
const environment = useStoreKey($tankopediaPersistent, 'environment');
|
||||||
(state) => state.model.visual.environment,
|
const developerMode = useStoreBoolean($app, 'developerMode');
|
||||||
);
|
|
||||||
const developerMode = App.useDeferred(false, (state) => state.developerMode);
|
|
||||||
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
const protagonistTank = Duel.use((state) => state.protagonist.tank);
|
||||||
const antagonistGun = Duel.use((state) => state.antagonist.gun);
|
const antagonistGun = Duel.use((state) => state.antagonist.gun);
|
||||||
const antagonistShell = Duel.use((state) => state.antagonist.shell);
|
const antagonistShell = Duel.use((state) => state.antagonist.shell);
|
||||||
@@ -82,8 +79,6 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
const hasEnhancedArmor = useEquipment(110);
|
const hasEnhancedArmor = useEquipment(110);
|
||||||
const antagonistUniqueGuns = uniqueGuns(antagonistTank.turrets);
|
const antagonistUniqueGuns = uniqueGuns(antagonistTank.turrets);
|
||||||
|
|
||||||
useEffect(() => setDisplay(displayRaw), [displayRaw]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<QuickInputs />
|
<QuickInputs />
|
||||||
+6
-6
@@ -23,12 +23,12 @@ import * as Duel from '../../../../../../stores/duel';
|
|||||||
import * as TankopediaEphemeral from '../../../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../../../stores/tankopediaEphemeral';
|
||||||
import * as TankopediaPersistent from '../../../../../../stores/tankopediaPersistent';
|
import * as TankopediaPersistent from '../../../../../../stores/tankopediaPersistent';
|
||||||
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
|
import { TankopediaDisplay } from '../../../../../../stores/tankopediaPersistent/constants';
|
||||||
import { Controls } from '../Control';
|
import { Controls } from '../../../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Control';
|
||||||
import { Lighting } from '../Lighting';
|
import { Lighting } from '../../../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Lighting';
|
||||||
import { SceneProps } from '../SceneProps';
|
import { SceneProps } from '../../../../../../website-legacy/src/app/tools/tankopedia/[id]/components/SceneProps';
|
||||||
import { AutoClear } from './AutoClear';
|
import { AutoClear } from '../../../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Model/AutoClear';
|
||||||
import { ModelLoader } from './components/ModelLoader';
|
import { ModelLoader } from '../../../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Model/components/ModelLoader';
|
||||||
import { TankModel } from './components/TankModel';
|
import { TankModel } from '../../../../../../website-legacy/src/app/tools/tankopedia/[id]/components/Model/components/TankModel';
|
||||||
|
|
||||||
interface TankSandboxProps {
|
interface TankSandboxProps {
|
||||||
thicknessRange: ThicknessRange;
|
thicknessRange: ThicknessRange;
|
||||||
File renamed without changes.
+16
-12
@@ -1,20 +1,25 @@
|
|||||||
import { resolveNearPenetration, tankDefinitions } from '@blitzkit/core';
|
import { resolveNearPenetration, tankDefinitions } from '@blitzkit/core';
|
||||||
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
|
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
|
||||||
import { Suspense, use, useEffect, useMemo, useRef, useState } from 'react';
|
import { Suspense, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { ThicknessRange } from '../../../../../../components/Armor/components/StaticArmor';
|
import { NAVBAR_HEIGHT } from '../../../constants/navbar';
|
||||||
import { classIcons } from '../../../../../../components/ClassIcon';
|
import { Var } from '../../../core/radix/var';
|
||||||
import { NAVBAR_HEIGHT } from '../../../../../../components/Navbar/index.css';
|
import { useFullScreen } from '../../../hooks/useFullScreen';
|
||||||
import { Var } from '../../../../../../core/radix/var';
|
import type { ThicknessRange } from '../../Armor/components/StaticArmor';
|
||||||
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
import { classIcons } from '../../ClassIcon';
|
||||||
import * as Duel from '../../../../../../stores/duel';
|
|
||||||
import { TankSandbox } from './TankSandbox';
|
|
||||||
import { TankSandboxLoader } from './TankSandboxLoader';
|
|
||||||
import { Options } from './components/Options';
|
import { Options } from './components/Options';
|
||||||
|
import { TankSandbox } from './components/TankSandbox';
|
||||||
|
import { TankSandboxLoader } from './components/TankSandboxLoader';
|
||||||
|
|
||||||
export function HeroSection() {
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
|
|
||||||
|
interface HeroSectionProps {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function HeroSection({ id }: HeroSectionProps) {
|
||||||
const canvas = useRef<HTMLCanvasElement>(null);
|
const canvas = useRef<HTMLCanvasElement>(null);
|
||||||
const isFullScreen = useFullScreen();
|
const isFullScreen = useFullScreen();
|
||||||
const protagonist = Duel.use((state) => state.protagonist.tank);
|
const protagonist = awaitedTankDefinitions[id];
|
||||||
const Icon = classIcons[protagonist.class];
|
const Icon = classIcons[protagonist.class];
|
||||||
const [dummyLoader, setDummyLoader] = useState(true);
|
const [dummyLoader, setDummyLoader] = useState(true);
|
||||||
const treeColor =
|
const treeColor =
|
||||||
@@ -23,7 +28,6 @@ export function HeroSection() {
|
|||||||
: protagonist.treeType === 'premium'
|
: protagonist.treeType === 'premium'
|
||||||
? 'amber'
|
? 'amber'
|
||||||
: undefined;
|
: undefined;
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
|
||||||
const thicknessRange = useMemo(() => {
|
const thicknessRange = useMemo(() => {
|
||||||
const entries = Object.values(awaitedTankDefinitions);
|
const entries = Object.values(awaitedTankDefinitions);
|
||||||
const filtered = entries.filter(
|
const filtered = entries.filter(
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+4
-3
@@ -7,7 +7,7 @@ import {
|
|||||||
import strings from '@blitzkit/core/lang/en-US.json';
|
import strings from '@blitzkit/core/lang/en-US.json';
|
||||||
import { ChevronLeftIcon, MixIcon, UpdateIcon } from '@radix-ui/react-icons';
|
import { ChevronLeftIcon, MixIcon, UpdateIcon } from '@radix-ui/react-icons';
|
||||||
import { Button, Code, Dialog, Flex } from '@radix-ui/themes';
|
import { Button, Code, Dialog, Flex } from '@radix-ui/themes';
|
||||||
import { use, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { classIcons } from '../../../../../../../components/ClassIcon';
|
import { classIcons } from '../../../../../../../components/ClassIcon';
|
||||||
import { Link } from '../../../../../../../components/Link';
|
import { Link } from '../../../../../../../components/Link';
|
||||||
import { ScienceIcon } from '../../../../../../../components/ScienceIcon';
|
import { ScienceIcon } from '../../../../../../../components/ScienceIcon';
|
||||||
@@ -18,6 +18,9 @@ import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphe
|
|||||||
import { TankSearch } from '../../../../components/TankSearch';
|
import { TankSearch } from '../../../../components/TankSearch';
|
||||||
import { Listing } from './components/Listing';
|
import { Listing } from './components/Listing';
|
||||||
|
|
||||||
|
const awaitedProvisionDefinitions = await provisionDefinitions;
|
||||||
|
const awaitedModelDefinitions = await modelDefinitions;
|
||||||
|
|
||||||
export function MetaSection() {
|
export function MetaSection() {
|
||||||
const developerMode = App.useDeferred(false, (state) => state.developerMode);
|
const developerMode = App.useDeferred(false, (state) => state.developerMode);
|
||||||
const protagonist = Duel.use((state) => state.protagonist.tank);
|
const protagonist = Duel.use((state) => state.protagonist.tank);
|
||||||
@@ -29,9 +32,7 @@ export function MetaSection() {
|
|||||||
: [protagonist.id, antagonist.id];
|
: [protagonist.id, antagonist.id];
|
||||||
const mutateDuel = Duel.useMutation();
|
const mutateDuel = Duel.useMutation();
|
||||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
|
||||||
const [showSwapDialog, setShowSwapDialog] = useState(false);
|
const [showSwapDialog, setShowSwapDialog] = useState(false);
|
||||||
const awaitedModelDefinitions = use(modelDefinitions);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex justify="center" align="center">
|
<Flex justify="center" align="center">
|
||||||
File renamed without changes.
File renamed without changes.
+3
-3
@@ -7,7 +7,6 @@ import {
|
|||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import { Box, Flex, Text } from '@radix-ui/themes';
|
import { Box, Flex, Text } from '@radix-ui/themes';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { use } from 'react';
|
|
||||||
import * as TankopediaEphemeral from '../../../../../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../../../../../stores/tankopediaEphemeral';
|
||||||
|
|
||||||
interface NodeProps {
|
interface NodeProps {
|
||||||
@@ -16,12 +15,13 @@ interface NodeProps {
|
|||||||
highlight?: boolean;
|
highlight?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
|
const awaitedAverageDefinitions = await averageDefinitions;
|
||||||
|
|
||||||
export function Node({ id, highlight, nextIds }: NodeProps) {
|
export function Node({ id, highlight, nextIds }: NodeProps) {
|
||||||
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
|
||||||
const tank = awaitedTankDefinitions[id];
|
const tank = awaitedTankDefinitions[id];
|
||||||
const nextTanks = nextIds?.map((id) => awaitedTankDefinitions[id]);
|
const nextTanks = nextIds?.map((id) => awaitedTankDefinitions[id]);
|
||||||
const awaitedAverageDefinitions = use(averageDefinitions);
|
|
||||||
const thisTankXp =
|
const thisTankXp =
|
||||||
tank.xp === undefined || tank.tier === 1 ? 0 : tank.xp! / xpMultiplier;
|
tank.xp === undefined || tank.tier === 1 ? 0 : tank.xp! / xpMultiplier;
|
||||||
const nextTanksXp = nextTanks?.reduce(
|
const nextTanksXp = nextTanks?.reduce(
|
||||||
+3
-2
@@ -1,7 +1,7 @@
|
|||||||
import { asset, imgur, tankDefinitions } from '@blitzkit/core';
|
import { asset, imgur, tankDefinitions } from '@blitzkit/core';
|
||||||
import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons';
|
import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons';
|
||||||
import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes';
|
import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes';
|
||||||
import { Fragment, use, useEffect, useMemo, useRef, useState } from 'react';
|
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import * as Duel from '../../../../../../../stores/duel';
|
import * as Duel from '../../../../../../../stores/duel';
|
||||||
import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral';
|
import * as TankopediaEphemeral from '../../../../../../../stores/tankopediaEphemeral';
|
||||||
import { Arrow } from './components/Arrow';
|
import { Arrow } from './components/Arrow';
|
||||||
@@ -9,13 +9,14 @@ import { Node } from './components/Node';
|
|||||||
|
|
||||||
type Line = number[];
|
type Line = number[];
|
||||||
|
|
||||||
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
|
|
||||||
export const XP_MULTIPLIERS = [1, 2, 3, 4, 5, 10];
|
export const XP_MULTIPLIERS = [1, 2, 3, 4, 5, 10];
|
||||||
|
|
||||||
export function TechTreeSection() {
|
export function TechTreeSection() {
|
||||||
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
||||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||||
const master = Duel.use((state) => state.protagonist.tank);
|
const master = Duel.use((state) => state.protagonist.tank);
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
|
||||||
const container = useRef<HTMLDivElement>(null);
|
const container = useRef<HTMLDivElement>(null);
|
||||||
const lines = useMemo(() => {
|
const lines = useMemo(() => {
|
||||||
function extend(line: Line): Line[] {
|
function extend(line: Line): Line[] {
|
||||||
@@ -6,21 +6,21 @@ import usePromise from 'react-promise-suspense';
|
|||||||
import { $wargamingLogin } from '../stores/wargamingLogin';
|
import { $wargamingLogin } from '../stores/wargamingLogin';
|
||||||
|
|
||||||
export function WargamingAccountName() {
|
export function WargamingAccountName() {
|
||||||
const wargamingLogin = useStore($wargamingLogin);
|
const wargaming = useStore($wargamingLogin);
|
||||||
const promise = useMemo(async () => {
|
const promise = useMemo(async () => {
|
||||||
if (!wargamingLogin.token) return null;
|
if (!wargaming.token) return null;
|
||||||
|
|
||||||
const data = await getAccountInfo(
|
const data = await getAccountInfo(
|
||||||
idToRegion(Number(wargamingLogin.id)),
|
idToRegion(Number(wargaming.id)),
|
||||||
Number(wargamingLogin.id),
|
Number(wargaming.id),
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
access_token: wargamingLogin.token,
|
access_token: wargaming.token,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return data?.nickname as string | undefined;
|
return data?.nickname as string | undefined;
|
||||||
}, [wargamingLogin.token]);
|
}, [wargaming]);
|
||||||
const nickname = usePromise(() => promise, []);
|
const nickname = usePromise(() => promise, []);
|
||||||
|
|
||||||
return nickname ?? <Text color="gray">Unknown Account</Text>;
|
return nickname ?? <Text color="gray">Unknown Account</Text>;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Vector3, Vector3Tuple } from 'three';
|
import { Vector3, type Vector3Tuple } from 'three';
|
||||||
import { rotateDavaVector } from './rotateDavaVector';
|
import { rotateDavaVector } from './rotateDavaVector';
|
||||||
|
|
||||||
export function correctZYTuple(tuple: Vector3Tuple) {
|
export function correctZYTuple(tuple: Vector3Tuple) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { GroupProps, MeshProps } from '@react-three/fiber';
|
import type { GroupProps, MeshProps } from '@react-three/fiber';
|
||||||
import { Mesh, Object3D } from 'three';
|
import { Mesh, Object3D } from 'three';
|
||||||
|
|
||||||
export function jsxTree(
|
export function jsxTree(
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ type ExtractState<S> = S extends {
|
|||||||
? T
|
? T
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
export function createContextualSafeStore<
|
export function createContextualStore<
|
||||||
Store extends StoreApi<unknown>,
|
Store extends StoreApi<unknown>,
|
||||||
InitData,
|
InitData,
|
||||||
>(initialize: (data: InitData) => Store) {
|
>(initialize: (data: InitData) => Store) {
|
||||||
@@ -5,17 +5,17 @@ import { $patreonLogin } from '../stores/patreonLogin';
|
|||||||
let cache: Record<string, boolean | Promise<boolean>> = {};
|
let cache: Record<string, boolean | Promise<boolean>> = {};
|
||||||
|
|
||||||
export function useAdExempt() {
|
export function useAdExempt() {
|
||||||
const patreonLogin = useStore($patreonLogin);
|
const patreon = useStore($patreonLogin);
|
||||||
const [exempt, setExempt] = useState(false);
|
const [exempt, setExempt] = useState(false);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
if (!patreonLogin.token) return setExempt(false);
|
if (!patreon.token) return setExempt(false);
|
||||||
|
|
||||||
if (!(patreonLogin.token in cache)) {
|
if (!(patreon.token in cache)) {
|
||||||
cache[patreonLogin.token] = new Promise<boolean>(async (resolve) => {
|
cache[patreon.token] = new Promise<boolean>(async (resolve) => {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/patreon/membership/${patreonLogin.token}`,
|
`/api/patreon/membership/${patreon.token}`,
|
||||||
{ cache: 'force-cache' },
|
{ cache: 'force-cache' },
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -24,12 +24,12 @@ export function useAdExempt() {
|
|||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
const exempt = typeof json === 'boolean' && json;
|
const exempt = typeof json === 'boolean' && json;
|
||||||
|
|
||||||
cache[patreonLogin.token] = exempt;
|
cache[patreon.token] = exempt;
|
||||||
resolve(exempt);
|
resolve(exempt);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setExempt(await cache[patreonLogin.token]);
|
setExempt(await cache[patreon.token]);
|
||||||
})();
|
})();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { asset } from '@blitzkit/core';
|
import { asset } from '@blitzkit/core';
|
||||||
import { ObjectMap, useLoader } from '@react-three/fiber';
|
import { type ObjectMap, useLoader } from '@react-three/fiber';
|
||||||
import { GLTF, GLTFLoader } from 'three-stdlib';
|
import { type GLTF, GLTFLoader } from 'three-stdlib';
|
||||||
|
|
||||||
const cache: Record<
|
const cache: Record<
|
||||||
number,
|
number,
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { averageDefinitions, discoveredIdsDefinitions } from '@blitzkit/core';
|
import { averageDefinitions, discoveredIdsDefinitions } from '@blitzkit/core';
|
||||||
import { use } from 'react';
|
|
||||||
|
const awaitedDiscoveredIdsDefinitions = await discoveredIdsDefinitions;
|
||||||
|
const awaitedAverageDefinitions = await averageDefinitions;
|
||||||
|
|
||||||
export function useAveragesExclusionRatio() {
|
export function useAveragesExclusionRatio() {
|
||||||
const awaitedDiscoveredIdsDefinitions = use(discoveredIdsDefinitions);
|
|
||||||
const awaitedAverageDefinitions = use(averageDefinitions);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
awaitedDiscoveredIdsDefinitions.count /
|
awaitedDiscoveredIdsDefinitions.count /
|
||||||
awaitedAverageDefinitions.samples.total
|
awaitedAverageDefinitions.samples.total
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { TankDefinition, tankDefinitions } from '@blitzkit/core';
|
import { TankDefinition, tankDefinitions } from '@blitzkit/core';
|
||||||
import { sumBy } from 'lodash-es';
|
import { sumBy } from 'lodash-es';
|
||||||
import { use, useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import * as Duel from '../stores/duel';
|
import * as Duel from '../stores/duel';
|
||||||
|
|
||||||
export enum UseEccentricityMode {
|
export enum UseEccentricityMode {
|
||||||
@@ -8,8 +8,9 @@ export enum UseEccentricityMode {
|
|||||||
Class,
|
Class,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
|
|
||||||
export function useEccentricity(mode: UseEccentricityMode) {
|
export function useEccentricity(mode: UseEccentricityMode) {
|
||||||
const awaitedTankDefinitions = use(tankDefinitions);
|
|
||||||
const tank = Duel.use((state) => state.protagonist.tank);
|
const tank = Duel.use((state) => state.protagonist.tank);
|
||||||
const similarTanks = useMemo(
|
const similarTanks = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { equipmentDefinitions } from '@blitzkit/core';
|
import { equipmentDefinitions } from '@blitzkit/core';
|
||||||
import { use, useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import * as Duel from '../stores/duel';
|
import * as Duel from '../stores/duel';
|
||||||
|
|
||||||
|
const awaitedEquipmentDefinitions = await equipmentDefinitions;
|
||||||
|
|
||||||
export function useEquipment(id: number, antagonist = false) {
|
export function useEquipment(id: number, antagonist = false) {
|
||||||
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
|
||||||
const member = Duel.use(
|
const member = Duel.use(
|
||||||
(state) => state[antagonist ? 'antagonist' : 'protagonist']!,
|
(state) => state[antagonist ? 'antagonist' : 'protagonist']!,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { asset } from '@blitzkit/core';
|
import { asset } from '@blitzkit/core';
|
||||||
import { ObjectMap, useLoader } from '@react-three/fiber';
|
import { type ObjectMap, useLoader } from '@react-three/fiber';
|
||||||
import { Mesh, MeshStandardMaterial } from 'three';
|
import { Mesh, MeshStandardMaterial } from 'three';
|
||||||
import { GLTF, GLTFLoader } from 'three-stdlib';
|
import { type GLTF, GLTFLoader } from 'three-stdlib';
|
||||||
|
|
||||||
const cache: Record<
|
const cache: Record<
|
||||||
number,
|
number,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { RefObject, useEffect, useRef, useState } from 'react';
|
import { type RefObject, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thanks GuCier!
|
* Thanks GuCier!
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { type StoreKeys } from '@nanostores/react';
|
||||||
|
import type { Store } from 'nanostores';
|
||||||
|
import { useStoreKey } from './useStoreKey';
|
||||||
|
|
||||||
|
export function useStoreBoolean<Type>(
|
||||||
|
store: Store<Type>,
|
||||||
|
key: StoreKeys<Store<Type>>,
|
||||||
|
) {
|
||||||
|
return Boolean(useStoreKey(store, key));
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { useStore, type StoreKeys } from '@nanostores/react';
|
||||||
|
import type { Store } from 'nanostores';
|
||||||
|
|
||||||
|
export function useStoreKey<Type, Key extends StoreKeys<Store<Type>>>(
|
||||||
|
store: Store<Type>,
|
||||||
|
key: Key,
|
||||||
|
) {
|
||||||
|
const state = useStore(store, { keys: [key] });
|
||||||
|
return state[key];
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { I_HAT, J_HAT, K_HAT } from '@blitzkit/core';
|
import { I_HAT, J_HAT, K_HAT } from '@blitzkit/core';
|
||||||
import { RefObject, useEffect } from 'react';
|
import { type RefObject, useEffect } from 'react';
|
||||||
import { Euler, Group, Vector3 } from 'three';
|
import { Euler, Group, Vector3 } from 'three';
|
||||||
import { degToRad } from 'three/src/math/MathUtils';
|
import { degToRad } from 'three/src/math/MathUtils';
|
||||||
import { correctZYTuple } from '../core/blitz/correctZYTuple';
|
import { correctZYTuple } from '../core/blitz/correctZYTuple';
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
import { tankDefinitions } from '@blitzkit/core';
|
||||||
|
import type { GetStaticPaths } from 'astro';
|
||||||
|
import { Page } from './index';
|
||||||
|
|
||||||
|
export const getStaticPaths = (async () => {
|
||||||
|
const awaitedTankDefinitions = await tankDefinitions;
|
||||||
|
|
||||||
|
return Object.values(awaitedTankDefinitions).map((tank) => ({
|
||||||
|
params: { id: tank.id },
|
||||||
|
}));
|
||||||
|
}) satisfies GetStaticPaths;
|
||||||
|
|
||||||
|
const { id } = Astro.params;
|
||||||
|
---
|
||||||
|
|
||||||
|
<Page id={id} client:load />
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { PageWrapper } from '../../../../components/PageWrapper';
|
||||||
|
import { HeroSection } from '../../../../components/Tankopedia/HeroSection';
|
||||||
|
|
||||||
|
interface PageProps {
|
||||||
|
id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Page({ id }: PageProps) {
|
||||||
|
return (
|
||||||
|
<PageWrapper p="0" noMaxWidth color="purple" size={1600} gap="9">
|
||||||
|
<HeroSection id={id} />
|
||||||
|
{/* <ShotDisplaySection />
|
||||||
|
<MetaSection />
|
||||||
|
<TechTreeSection />
|
||||||
|
{!exempt && <AdMidSectionResponsive />}
|
||||||
|
<CalloutsSection />
|
||||||
|
<CharacteristicsSection />
|
||||||
|
{!exempt && <AdMidSectionResponsive />}
|
||||||
|
<GameModeSection />
|
||||||
|
<VideoSection />
|
||||||
|
<HistorySection />
|
||||||
|
{!exempt && <AdMidSectionResponsive mb="6" />} */}
|
||||||
|
</PageWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,23 +1,14 @@
|
|||||||
import lodash from 'lodash-es';
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist } from 'zustand/middleware';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
import { createContextualSafeStore } from '../../core/zustand/createContextualSafeStore';
|
|
||||||
|
|
||||||
export interface App {
|
interface AppStore {
|
||||||
developerMode: boolean;
|
developerMode: boolean;
|
||||||
policiesAgreementIndex: number;
|
policiesAgreementIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore, useDeferred } =
|
export const App = createContextualStore(() =>
|
||||||
createContextualSafeStore(() =>
|
create<AppStore>()(() => ({
|
||||||
create<App>()(
|
developerMode: false,
|
||||||
persist(
|
policiesAgreementIndex: 0,
|
||||||
(set) => ({
|
})),
|
||||||
developerMode: false,
|
);
|
||||||
policiesAgreementIndex: -1,
|
|
||||||
logins: {},
|
|
||||||
}),
|
|
||||||
{ name: 'app', merge: (a, b) => lodash.merge(b, a) },
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { DuelMember } from './duel';
|
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||||
|
import type { DuelMember } from './duel';
|
||||||
|
|
||||||
export interface CompareMember extends DuelMember {
|
export interface CompareMember extends DuelMember {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -14,10 +15,10 @@ export interface CompareEphemeral {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
||||||
createContextualSafeStore(() =>
|
() =>
|
||||||
create<CompareEphemeral>()(() => ({
|
create<CompareEphemeral>()(() => ({
|
||||||
crewSkills: {},
|
crewSkills: {},
|
||||||
members: [],
|
members: [],
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import lodash from 'lodash-es';
|
import lodash from 'lodash-es';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { createContextualSafeStore } from '../core/zustand/createContextualSafeStore';
|
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||||
|
|
||||||
export type DeltaMode = 'none' | 'percentage' | 'absolute';
|
export type DeltaMode = 'none' | 'percentage' | 'absolute';
|
||||||
export interface ComparePersistent {
|
export interface ComparePersistent {
|
||||||
deltaMode: DeltaMode;
|
deltaMode: DeltaMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
||||||
createContextualSafeStore(() =>
|
() =>
|
||||||
create<ComparePersistent>()(
|
create<ComparePersistent>()(
|
||||||
persist(
|
persist(
|
||||||
subscribeWithSelector<ComparePersistent>(() => ({
|
subscribeWithSelector<ComparePersistent>(() => ({
|
||||||
@@ -21,4 +21,4 @@ export const { Provider, use, useMutation, useStore } =
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { subscribeWithSelector } from 'zustand/middleware';
|
import { subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { tankToDuelMember } from '../../core/blitzkit/tankToDuelMember';
|
import { tankToDuelMember } from '../../core/blitzkit/tankToDuelMember';
|
||||||
import { createContextualSafeStore } from '../../core/zustand/createContextualSafeStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
|
|
||||||
type EquipmentMatrixItem = -1 | 0 | 1;
|
type EquipmentMatrixItem = -1 | 0 | 1;
|
||||||
type EquipmentMatrixRow = [
|
type EquipmentMatrixRow = [
|
||||||
@@ -41,27 +41,26 @@ export interface DuelMember {
|
|||||||
cooldownBooster: number;
|
cooldownBooster: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Duel {
|
export interface DuelStore {
|
||||||
protagonist: DuelMember;
|
protagonist: DuelMember;
|
||||||
antagonist: DuelMember;
|
antagonist: DuelMember;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const Duel = createContextualStore(
|
||||||
createContextualSafeStore(
|
({
|
||||||
({
|
tank,
|
||||||
tank,
|
provisionDefinitions,
|
||||||
provisionDefinitions,
|
}: {
|
||||||
}: {
|
tank: TankDefinition;
|
||||||
tank: TankDefinition;
|
provisionDefinitions: ProvisionDefinitions;
|
||||||
provisionDefinitions: ProvisionDefinitions;
|
}) => {
|
||||||
}) => {
|
const protagonist = tankToDuelMember(tank, provisionDefinitions);
|
||||||
const protagonist = tankToDuelMember(tank, provisionDefinitions);
|
|
||||||
|
|
||||||
return create<Duel>()(
|
return create<DuelStore>()(
|
||||||
subscribeWithSelector<Duel>(() => ({
|
subscribeWithSelector<DuelStore>(() => ({
|
||||||
protagonist,
|
protagonist,
|
||||||
antagonist: protagonist,
|
antagonist: protagonist,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as radixColors from '@radix-ui/colors';
|
import * as radixColors from '@radix-ui/colors';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { createContextualSafeStore } from '../../core/zustand/createContextualSafeStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
import {
|
import {
|
||||||
type EmbedConfigItemType,
|
type EmbedConfigItemType,
|
||||||
EmbedItemType,
|
EmbedItemType,
|
||||||
@@ -104,7 +104,6 @@ export type EmbedConfigItem = (
|
|||||||
|
|
||||||
export type EmbedState = Record<string, EmbedConfigItem['default']>;
|
export type EmbedState = Record<string, EmbedConfigItem['default']>;
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
||||||
createContextualSafeStore((init: EmbedState) =>
|
(init: EmbedState) => create<EmbedState>()(() => init),
|
||||||
create<EmbedState>()(() => init),
|
);
|
||||||
);
|
|
||||||
@@ -2,7 +2,7 @@ import { IndividualTankStats, Region, Stat } from '@blitzkit/core';
|
|||||||
import lodash from 'lodash-es';
|
import lodash from 'lodash-es';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
import { createContextualSafeStore } from '../core/zustand/createContextualSafeStore';
|
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||||
|
|
||||||
interface SessionBase {
|
interface SessionBase {
|
||||||
columns: Stat[];
|
columns: Stat[];
|
||||||
@@ -24,8 +24,8 @@ interface SessionNotTracking extends SessionBase {
|
|||||||
|
|
||||||
type Session = SessionTracking | SessionNotTracking;
|
type Session = SessionTracking | SessionNotTracking;
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
||||||
createContextualSafeStore(() =>
|
() =>
|
||||||
create<Session>()(
|
create<Session>()(
|
||||||
persist(
|
persist(
|
||||||
(set) => ({
|
(set) => ({
|
||||||
@@ -35,4 +35,4 @@ export const { Provider, use, useMutation, useStore } =
|
|||||||
{ name: 'session-2', merge: (a, b) => lodash.merge(b, a) },
|
{ name: 'session-2', merge: (a, b) => lodash.merge(b, a) },
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import lodash from 'lodash-es';
|
import lodash from 'lodash-es';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { createContextualSafeStore } from '../../core/zustand/createContextualSafeStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
import { PlayerCountPeriod } from './constants';
|
import { PlayerCountPeriod } from './constants';
|
||||||
|
|
||||||
export interface TankPerformancePersistent {
|
export interface TankPerformancePersistent {
|
||||||
playerCountPeriod: PlayerCountPeriod;
|
playerCountPeriod: PlayerCountPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
||||||
createContextualSafeStore(() =>
|
() =>
|
||||||
create<TankPerformancePersistent>()(
|
create<TankPerformancePersistent>()(
|
||||||
persist(
|
persist(
|
||||||
subscribeWithSelector<TankPerformancePersistent>(() => ({
|
subscribeWithSelector<TankPerformancePersistent>(() => ({
|
||||||
@@ -18,4 +18,4 @@ export const { Provider, use, useMutation, useStore } =
|
|||||||
{ name: 'tank-performance', merge: (a, b) => lodash.merge(b, a) },
|
{ name: 'tank-performance', merge: (a, b) => lodash.merge(b, a) },
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { createContextualSafeStore } from '../../core/zustand/createContextualSafeStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
import { TankPerformanceSortTypeNames } from './constants';
|
import { TankPerformanceSortTypeNames } from './constants';
|
||||||
|
|
||||||
export type TankPerformanceSortType = keyof typeof TankPerformanceSortTypeNames;
|
export type TankPerformanceSortType = keyof typeof TankPerformanceSortTypeNames;
|
||||||
@@ -9,10 +9,10 @@ export interface TankPerformanceSort {
|
|||||||
direction: -1 | 1;
|
direction: -1 | 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const { Provider, use, useMutation, useStore } = createContextualStore(
|
||||||
createContextualSafeStore(() =>
|
() =>
|
||||||
create<TankPerformanceSort>()(() => ({
|
create<TankPerformanceSort>()(() => ({
|
||||||
type: 'winrate',
|
type: 'winrate',
|
||||||
direction: -1,
|
direction: -1,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
@@ -1,34 +1,11 @@
|
|||||||
import { ModelDefinition } from '@blitzkit/core';
|
import type { ModelDefinition } from '@blitzkit/core';
|
||||||
import { Vector3 } from 'three';
|
import { Vector3 } from 'three';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { subscribeWithSelector } from 'zustand/middleware';
|
import { subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { XP_MULTIPLIERS } from '../app/tools/tankopedia/[id]/components/Model/TechTreeSection';
|
|
||||||
import { ArmorType } from '../components/Armor/components/SpacedArmorScene';
|
import { ArmorType } from '../components/Armor/components/SpacedArmorScene';
|
||||||
import { ExternalModuleVariant } from '../components/Armor/components/SpacedArmorSceneComponent';
|
import type { ExternalModuleVariant } from '../components/Armor/components/SpacedArmorSceneComponent';
|
||||||
import { createContextualSafeStore } from '../core/zustand/createContextualSafeStore';
|
import type { XP_MULTIPLIERS } from '../components/Tankopedia/TechTreeSection';
|
||||||
|
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||||
interface TankopediaEphemeral {
|
|
||||||
shot?: Shot;
|
|
||||||
skills: Record<string, number>;
|
|
||||||
controlsEnabled: boolean;
|
|
||||||
model: ModelDefinition;
|
|
||||||
editStatic: boolean;
|
|
||||||
highlightArmor?: {
|
|
||||||
editingPlate: boolean;
|
|
||||||
name: string;
|
|
||||||
point: Vector3;
|
|
||||||
thickness: number;
|
|
||||||
color: string;
|
|
||||||
} & (
|
|
||||||
| {
|
|
||||||
type: ArmorType.Primary | ArmorType.Spaced;
|
|
||||||
thicknessAngled: number;
|
|
||||||
angle: number;
|
|
||||||
}
|
|
||||||
| { type: ArmorType.External }
|
|
||||||
);
|
|
||||||
xpMultiplier: (typeof XP_MULTIPLIERS)[number];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ShotLayerBase {
|
export interface ShotLayerBase {
|
||||||
index: number;
|
index: number;
|
||||||
@@ -89,8 +66,8 @@ export type ArmorPiercingLayer =
|
|||||||
gap: number;
|
gap: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const TankopediaEphemeral = createContextualStore(
|
||||||
createContextualSafeStore((model: ModelDefinition) =>
|
(model: ModelDefinition) =>
|
||||||
create<TankopediaEphemeral>()(
|
create<TankopediaEphemeral>()(
|
||||||
subscribeWithSelector<TankopediaEphemeral>(() => ({
|
subscribeWithSelector<TankopediaEphemeral>(() => ({
|
||||||
editStatic: false,
|
editStatic: false,
|
||||||
@@ -100,4 +77,27 @@ export const { Provider, use, useMutation, useStore } =
|
|||||||
xpMultiplier: 1,
|
xpMultiplier: 1,
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
interface TankopediaEphemeral {
|
||||||
|
shot?: Shot;
|
||||||
|
skills: Record<string, number>;
|
||||||
|
controlsEnabled: boolean;
|
||||||
|
model: ModelDefinition;
|
||||||
|
editStatic: boolean;
|
||||||
|
highlightArmor?: {
|
||||||
|
editingPlate: boolean;
|
||||||
|
name: string;
|
||||||
|
point: Vector3;
|
||||||
|
thickness: number;
|
||||||
|
color: string;
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
type: ArmorType.Primary | ArmorType.Spaced;
|
||||||
|
thicknessAngled: number;
|
||||||
|
angle: number;
|
||||||
|
}
|
||||||
|
| { type: ArmorType.External }
|
||||||
);
|
);
|
||||||
|
xpMultiplier: (typeof XP_MULTIPLIERS)[number];
|
||||||
|
}
|
||||||
@@ -1,76 +1,53 @@
|
|||||||
import type { TankClass, Tier, TreeType } from '@blitzkit/core';
|
import * as lodash from 'lodash-es';
|
||||||
import lodash from 'lodash-es';
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
import { ENVIRONMENTS } from '../../constants/lightingEnvironments';
|
import { ENVIRONMENTS } from '../../constants/lightingEnvironments';
|
||||||
import { createContextualSafeStore } from '../../core/zustand/createContextualSafeStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
import { SORT_NAMES, TankopediaDisplay } from './constants';
|
import { SORT_NAMES, TankopediaDisplay } from './constants';
|
||||||
|
|
||||||
export type TankopediaSortBy = keyof typeof SORT_NAMES;
|
export type TankopediaSortBy = keyof typeof SORT_NAMES;
|
||||||
export type TankopediaSortDirection = 'ascending' | 'descending';
|
export type TankopediaSortDirection = 'ascending' | 'descending';
|
||||||
export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only';
|
export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only';
|
||||||
export interface TankopediaPersistent {
|
|
||||||
model: {
|
export interface TankopediaPersistentStore {
|
||||||
visual: {
|
wireframe: boolean;
|
||||||
wireframe: boolean;
|
opaque: boolean;
|
||||||
opaque: boolean;
|
environment: (typeof ENVIRONMENTS)[number];
|
||||||
environment: (typeof ENVIRONMENTS)[number];
|
showGrid: boolean;
|
||||||
showGrid: boolean;
|
greenPenetration: boolean;
|
||||||
greenPenetration: boolean;
|
showEnvironment: boolean;
|
||||||
showEnvironment: boolean;
|
showSpacedArmor: boolean;
|
||||||
showSpacedArmor: boolean;
|
showExternalModules: boolean;
|
||||||
showExternalModules: boolean;
|
showPrimaryArmor: boolean;
|
||||||
showPrimaryArmor: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
sort: {
|
sort: {
|
||||||
by: TankopediaSortBy;
|
by: TankopediaSortBy;
|
||||||
direction: TankopediaSortDirection;
|
direction: TankopediaSortDirection;
|
||||||
};
|
};
|
||||||
filters: {
|
|
||||||
tiers: Tier[];
|
|
||||||
types: TankClass[];
|
|
||||||
treeTypes: TreeType[];
|
|
||||||
nations: string[];
|
|
||||||
test: TankopediaTestTankDisplay;
|
|
||||||
page: number;
|
|
||||||
};
|
|
||||||
display: TankopediaDisplay;
|
display: TankopediaDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const { Provider, use, useMutation, useStore } =
|
export const TankopediaPersistent = createContextualStore(() =>
|
||||||
createContextualSafeStore(() =>
|
create<TankopediaPersistentStore>()(
|
||||||
create<TankopediaPersistent>()(
|
persist(
|
||||||
persist(
|
(set) => ({
|
||||||
subscribeWithSelector<TankopediaPersistent>(() => ({
|
wireframe: false,
|
||||||
model: {
|
opaque: false,
|
||||||
visual: {
|
environment: ENVIRONMENTS[0],
|
||||||
showSpacedArmor: true,
|
showGrid: true,
|
||||||
showExternalModules: true,
|
greenPenetration: true,
|
||||||
showPrimaryArmor: true,
|
showEnvironment: true,
|
||||||
wireframe: false,
|
showSpacedArmor: true,
|
||||||
opaque: false,
|
showExternalModules: true,
|
||||||
environment: ENVIRONMENTS[0],
|
showPrimaryArmor: true,
|
||||||
showGrid: true,
|
sort: {
|
||||||
greenPenetration: false,
|
by: 'meta.none',
|
||||||
showEnvironment: false,
|
direction: 'ascending',
|
||||||
},
|
},
|
||||||
},
|
display: TankopediaDisplay.Model,
|
||||||
sort: {
|
}),
|
||||||
by: 'meta.none',
|
{ name: 'tankopedia', merge: (a, b) => lodash.merge(b, a) },
|
||||||
direction: 'descending',
|
|
||||||
},
|
|
||||||
filters: {
|
|
||||||
tiers: [],
|
|
||||||
types: [],
|
|
||||||
treeTypes: [],
|
|
||||||
nations: [],
|
|
||||||
test: 'include',
|
|
||||||
page: 0,
|
|
||||||
},
|
|
||||||
display: TankopediaDisplay.Model,
|
|
||||||
})),
|
|
||||||
{ name: 'tankopedia', merge: (a, b) => lodash.merge(b, a) },
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
);
|
||||||
Reference in new issue
Block a user