mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: upgrade Guess
This commit is contained in:
1 parent
7d164e415a
commit
f56c31fb48
5 files changed
+80
-82
No files matched your search
@@ -1,13 +1,13 @@
|
||||
import { Box } from '@radix-ui/themes';
|
||||
import { useEffect } from 'react';
|
||||
import { awaitableModelDefinitions } from '../../core/awaitables/modelDefinitions';
|
||||
import { awaitableProvisionDefinitions } from '../../core/awaitables/provisionDefinitions';
|
||||
import { tankToDuelMember } from '../../core/blitzkit/tankToDuelMember';
|
||||
import { Var } from '../../core/radix/var';
|
||||
import { Duel } from '../../stores/duel';
|
||||
import { GuessEphemeral } from '../../stores/guessEphemeral';
|
||||
import { TankopediaEphemeral } from '../../stores/tankopediaEphemeral';
|
||||
import './index.css';
|
||||
import { Box } from "@radix-ui/themes";
|
||||
import { useEffect } from "react";
|
||||
import { awaitableModelDefinitions } from "../../core/awaitables/modelDefinitions";
|
||||
import { awaitableProvisionDefinitions } from "../../core/awaitables/provisionDefinitions";
|
||||
import { tankToDuelMember } from "../../core/blitzkit/tankToDuelMember";
|
||||
import { Var } from "../../core/radix/var";
|
||||
import { Duel } from "../../stores/duel";
|
||||
import { Guess } from "../../stores/guessEphemeral";
|
||||
import { TankopediaEphemeral } from "../../stores/tankopediaEphemeral";
|
||||
import "./index.css";
|
||||
|
||||
const [modelDefinitions, provisionDefinitions] = await Promise.all([
|
||||
awaitableModelDefinitions,
|
||||
@@ -15,8 +15,8 @@ const [modelDefinitions, provisionDefinitions] = await Promise.all([
|
||||
]);
|
||||
|
||||
export function GuessBackground() {
|
||||
const guessState = GuessEphemeral.use((state) => state.guessState);
|
||||
const tank = GuessEphemeral.use((state) => state.tank);
|
||||
const guessState = Guess.use((state) => state.guessState);
|
||||
const tank = Guess.use((state) => state.tank);
|
||||
const mutateDuel = Duel.useMutation();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -37,13 +37,13 @@ export function GuessBackground() {
|
||||
top="0"
|
||||
left="0"
|
||||
style={{
|
||||
transitionDuration: '2s',
|
||||
transitionDuration: "2s",
|
||||
backgroundColor: Var(
|
||||
guessState === null
|
||||
? 'accent-2'
|
||||
? "accent-2"
|
||||
: guessState
|
||||
? 'jade-3'
|
||||
: 'tomato-3',
|
||||
? "jade-3"
|
||||
: "tomato-3"
|
||||
),
|
||||
}}
|
||||
>
|
||||
@@ -51,7 +51,7 @@ export function GuessBackground() {
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{
|
||||
background: `radial-gradient(circle, ${Var('color-panel-translucent')}, ${Var('color-panel-solid')})`,
|
||||
background: `radial-gradient(circle, ${Var("color-panel-translucent")}, ${Var("color-panel-solid")})`,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
@@ -65,13 +65,13 @@ export function GuessBackground() {
|
||||
left="0"
|
||||
style={{
|
||||
backgroundImage: `
|
||||
radial-gradient(circle, ${Var('white-a1')} 20%, transparent 20%),
|
||||
radial-gradient(circle at 0 0, ${Var('white-a1')} 10%, transparent 10%),
|
||||
radial-gradient(circle at 100% 0, ${Var('white-a1')} 10%, transparent 10%),
|
||||
radial-gradient(circle at 0 100%, ${Var('white-a1')} 10%, transparent 10%),
|
||||
radial-gradient(circle at 100% 100%, ${Var('white-a1')} 10%, transparent 10%)
|
||||
radial-gradient(circle, ${Var("white-a1")} 20%, transparent 20%),
|
||||
radial-gradient(circle at 0 0, ${Var("white-a1")} 10%, transparent 10%),
|
||||
radial-gradient(circle at 100% 0, ${Var("white-a1")} 10%, transparent 10%),
|
||||
radial-gradient(circle at 0 100%, ${Var("white-a1")} 10%, transparent 10%),
|
||||
radial-gradient(circle at 100% 100%, ${Var("white-a1")} 10%, transparent 10%)
|
||||
`,
|
||||
backgroundSize: '4rem 4rem',
|
||||
backgroundSize: "4rem 4rem",
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { GuessEphemeral } from '../stores/guessEphemeral';
|
||||
import { SmartCanvas } from './SmartCanvas';
|
||||
import { Controls } from './Tankopedia/HeroSection/components/TankSandbox/components/Control';
|
||||
import { Lighting } from './Tankopedia/HeroSection/components/TankSandbox/components/Lighting';
|
||||
import { TankModel } from './Tankopedia/HeroSection/components/TankSandbox/components/TankModel';
|
||||
import { Guess } from "../stores/guessEphemeral";
|
||||
import { SmartCanvas } from "./SmartCanvas";
|
||||
import { Controls } from "./Tankopedia/HeroSection/components/TankSandbox/components/Control";
|
||||
import { Lighting } from "./Tankopedia/HeroSection/components/TankSandbox/components/Lighting";
|
||||
import { TankModel } from "./Tankopedia/HeroSection/components/TankSandbox/components/TankModel";
|
||||
|
||||
const BRIGHTNESS = 2 ** -5.5;
|
||||
const CONTRAST = 2 ** 2;
|
||||
|
||||
export function GuessRenderer() {
|
||||
const guessState = GuessEphemeral.use((state) => state.guessState);
|
||||
const guessState = Guess.use((state) => state.guessState);
|
||||
const isRevealed = guessState !== null;
|
||||
|
||||
return (
|
||||
<SmartCanvas
|
||||
style={{
|
||||
filter: `grayscale(${isRevealed ? 0 : 1}) contrast(${isRevealed ? 1 : CONTRAST}) brightness(${isRevealed ? 1 : BRIGHTNESS})`,
|
||||
transitionDuration: isRevealed ? '2s' : undefined,
|
||||
transitionProperty: 'filter',
|
||||
transitionDuration: isRevealed ? "2s" : undefined,
|
||||
transitionProperty: "filter",
|
||||
}}
|
||||
camera={{ position: [-5, 5, -5] }}
|
||||
>
|
||||
|
||||
@@ -2,13 +2,13 @@ import {
|
||||
SEARCH_KEYS,
|
||||
TankDefinition,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
} from "@blitzkit/core";
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import {
|
||||
ArrowRightIcon,
|
||||
MagnifyingGlassIcon,
|
||||
PaperPlaneIcon,
|
||||
} from '@radix-ui/react-icons';
|
||||
} from "@radix-ui/react-icons";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -17,16 +17,16 @@ import {
|
||||
Spinner,
|
||||
Text,
|
||||
TextField,
|
||||
} from '@radix-ui/themes';
|
||||
import fuzzysort from 'fuzzysort';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions';
|
||||
import { awaitableTankNames } from '../core/awaitables/tankNames';
|
||||
import { useLocale } from '../hooks/useLocale';
|
||||
import { GuessEphemeral } from '../stores/guessEphemeral';
|
||||
import { classIcons } from './ClassIcon';
|
||||
import { SearchResults } from './SearchResults';
|
||||
} from "@radix-ui/themes";
|
||||
import fuzzysort from "fuzzysort";
|
||||
import { debounce } from "lodash-es";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { awaitableTankDefinitions } from "../core/awaitables/tankDefinitions";
|
||||
import { awaitableTankNames } from "../core/awaitables/tankNames";
|
||||
import { useLocale } from "../hooks/useLocale";
|
||||
import { Guess } from "../stores/guessEphemeral";
|
||||
import { classIcons } from "./ClassIcon";
|
||||
import { SearchResults } from "./SearchResults";
|
||||
|
||||
const { go } = fuzzysort;
|
||||
|
||||
@@ -38,16 +38,15 @@ const [tankNames, tankDefinitions] = await Promise.all([
|
||||
const ids = Object.keys(tankDefinitions.tanks);
|
||||
|
||||
export function Guesser() {
|
||||
const tank = GuessEphemeral.use((state) => state.tank);
|
||||
const guessState = GuessEphemeral.use((state) => state.guessState);
|
||||
const correctGuesses = GuessEphemeral.use((state) => state.correctGuesses);
|
||||
const totalGuesses = GuessEphemeral.use((state) => state.totalGuesses);
|
||||
const tank = Guess.use((state) => state.tank);
|
||||
const guessState = Guess.use((state) => state.guessState);
|
||||
const correctGuesses = Guess.use((state) => state.correctGuesses);
|
||||
const totalGuesses = Guess.use((state) => state.totalGuesses);
|
||||
const { strings, unwrap } = useLocale();
|
||||
const input = useRef<HTMLInputElement>(null);
|
||||
const [searching, setSearching] = useState(false);
|
||||
const [results, setResults] = useState<TankDefinition[] | null>(null);
|
||||
const [selected, setSelected] = useState<TankDefinition | null>(null);
|
||||
const mutateGuessEphemeral = GuessEphemeral.useMutation();
|
||||
|
||||
const requestSearch = useCallback(() => {
|
||||
setSelected(null);
|
||||
@@ -72,10 +71,10 @@ export function Guesser() {
|
||||
});
|
||||
|
||||
setResults(
|
||||
searchResults.map((result) => tankDefinitions.tanks[result.obj.id]),
|
||||
searchResults.map((result) => tankDefinitions.tanks[result.obj.id])
|
||||
);
|
||||
}, 500),
|
||||
[],
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -88,7 +87,7 @@ export function Guesser() {
|
||||
position="absolute"
|
||||
bottom="0"
|
||||
left="50%"
|
||||
style={{ transform: 'translateX(-50%)' }}
|
||||
style={{ transform: "translateX(-50%)" }}
|
||||
width="100%"
|
||||
p="4"
|
||||
maxWidth="25rem"
|
||||
@@ -138,7 +137,7 @@ export function Guesser() {
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<Flex justify="center" style={{ userSelect: 'none' }}>
|
||||
<Flex justify="center" style={{ userSelect: "none" }}>
|
||||
<Text>
|
||||
{literals(strings.website.tools.guess.stats, [
|
||||
`${correctGuesses}`,
|
||||
@@ -164,12 +163,12 @@ export function Guesser() {
|
||||
|
||||
<Button
|
||||
size="3"
|
||||
color={guessState === null && selected === null ? 'red' : undefined}
|
||||
color={guessState === null && selected === null ? "red" : undefined}
|
||||
onClick={() => {
|
||||
if (guessState === null) {
|
||||
const correct = selected !== null && selected.id === tank.id;
|
||||
|
||||
mutateGuessEphemeral((draft) => {
|
||||
Guess.mutate((draft) => {
|
||||
draft.guessState = correct;
|
||||
draft.totalGuesses++;
|
||||
draft.correctGuesses += correct ? 1 : 0;
|
||||
@@ -178,12 +177,12 @@ export function Guesser() {
|
||||
const id = Number(ids[Math.floor(Math.random() * ids.length)]);
|
||||
const tank = tankDefinitions.tanks[id];
|
||||
|
||||
mutateGuessEphemeral((draft) => {
|
||||
Guess.mutate((draft) => {
|
||||
if (!input.current) return;
|
||||
|
||||
draft.tank = tank;
|
||||
draft.guessState = null;
|
||||
input.current.value = '';
|
||||
input.current.value = "";
|
||||
});
|
||||
}
|
||||
}}
|
||||
@@ -192,7 +191,7 @@ export function Guesser() {
|
||||
<>
|
||||
{
|
||||
strings.website.tools.guess.search[
|
||||
selected === null ? 'skip' : 'guess'
|
||||
selected === null ? "skip" : "guess"
|
||||
]
|
||||
}
|
||||
{selected === null ? <ArrowRightIcon /> : <PaperPlaneIcon />}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
useLocale,
|
||||
} from "../../../hooks/useLocale";
|
||||
import { Duel } from "../../../stores/duel";
|
||||
import { GuessEphemeral } from "../../../stores/guessEphemeral";
|
||||
import { Guess } from "../../../stores/guessEphemeral";
|
||||
import { TankopediaEphemeral } from "../../../stores/tankopediaEphemeral";
|
||||
|
||||
const [tankDefinitions, modelDefinitions, provisionDefinitions] =
|
||||
@@ -26,20 +26,20 @@ const [tankDefinitions, modelDefinitions, provisionDefinitions] =
|
||||
const ids = Object.keys(tankDefinitions.tanks);
|
||||
|
||||
export function Page({ locale }: LocaleAcceptorProps) {
|
||||
const initialId = Number(ids[Math.floor(Math.random() * ids.length)]);
|
||||
const initialTank = tankDefinitions.tanks[initialId];
|
||||
const id = Number(ids[Math.floor(Math.random() * ids.length)]);
|
||||
const tank = tankDefinitions.tanks[id];
|
||||
|
||||
Guess.useInitialization(tank);
|
||||
|
||||
return (
|
||||
<GuessEphemeral.Provider data={initialTank}>
|
||||
<LocaleProvider locale={locale}>
|
||||
<Container />
|
||||
</LocaleProvider>
|
||||
</GuessEphemeral.Provider>
|
||||
<LocaleProvider locale={locale}>
|
||||
<Container />
|
||||
</LocaleProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function Container() {
|
||||
const tank = GuessEphemeral.use((state) => state.tank);
|
||||
const tank = Guess.use((state) => state.tank);
|
||||
const model = modelDefinitions.models[tank.id];
|
||||
|
||||
TankopediaEphemeral.useInitialization(model);
|
||||
@@ -53,8 +53,8 @@ function Container() {
|
||||
|
||||
function Content() {
|
||||
const { unwrap } = useLocale();
|
||||
const tank = GuessEphemeral.use((state) => state.tank);
|
||||
const guessState = GuessEphemeral.use((state) => state.guessState);
|
||||
const tank = Guess.use((state) => state.tank);
|
||||
const guessState = Guess.use((state) => state.guessState);
|
||||
const isRevealed = guessState !== null;
|
||||
const name = unwrap(tank.name);
|
||||
const fontSize = `min(48vh, ${55 / name.length}vw)`;
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import type { TankDefinition } from '@blitzkit/core';
|
||||
import { create } from 'zustand';
|
||||
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||
import type { TankDefinition } from "@blitzkit/core";
|
||||
import { Varuna } from "varuna";
|
||||
|
||||
export interface GuessEphemeral {
|
||||
export interface Guess {
|
||||
tank: TankDefinition;
|
||||
// true = correct, false = incorrect, null = not guessed
|
||||
/**
|
||||
* true = correct, false = incorrect, null = not guessed
|
||||
*/
|
||||
guessState: boolean | null;
|
||||
totalGuesses: number;
|
||||
correctGuesses: number;
|
||||
}
|
||||
|
||||
export const GuessEphemeral = createContextualStore((tank: TankDefinition) =>
|
||||
create<GuessEphemeral>()(() => ({
|
||||
tank,
|
||||
guessState: null,
|
||||
totalGuesses: 0,
|
||||
correctGuesses: 0,
|
||||
})),
|
||||
);
|
||||
export const Guess = new Varuna<Guess, TankDefinition>((tank) => ({
|
||||
tank,
|
||||
guessState: null,
|
||||
totalGuesses: 0,
|
||||
correctGuesses: 0,
|
||||
}));
|
||||
Reference in new issue
Block a user