mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: host functionality
This commit is contained in:
1 parent
3c7a10a949
commit
8512557e76
6 files changed
+93
-34
No files matched your search
@@ -9,9 +9,9 @@ interface PreviewWrapperProps {
|
||||
}
|
||||
|
||||
export function PreviewWrapper({ name }: PreviewWrapperProps) {
|
||||
const { useState } = useEmbedStateCurry();
|
||||
const width = useState('width');
|
||||
const height = useState('height');
|
||||
const { useEmbedState } = useEmbedStateCurry();
|
||||
const width = useEmbedState('width');
|
||||
const height = useEmbedState('height');
|
||||
const Preview = embedPreviews[name];
|
||||
const wrapper = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import { compositeStatsKeys, fetchTankDefinitions } from '@blitzkit/core';
|
||||
import {
|
||||
compositeStatsKeys,
|
||||
deltaTankStats,
|
||||
fetchTankDefinitions,
|
||||
getTankStats,
|
||||
idToRegion,
|
||||
type IndividualTankStats,
|
||||
} from '@blitzkit/core';
|
||||
import strings from '@blitzkit/core/lang/en-US.json';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { breakdownConfig } from '../../constants/embeds';
|
||||
import { EmbedBreakdownPersistent } from '../../stores/embedBreakdownPersistent';
|
||||
import { useEmbedStateCurry } from '../../stores/embedState/utilities';
|
||||
import { BreakdownEmbedCard, BreakdownEmbedWrapper } from '../TanksEmbed';
|
||||
|
||||
@@ -9,18 +18,17 @@ export const compositeStatsKeysOptions = compositeStatsKeys.map((value) => ({
|
||||
value,
|
||||
}));
|
||||
|
||||
const tanks = await fetchTankDefinitions().then((tanks) =>
|
||||
Object.values(tanks.tanks),
|
||||
);
|
||||
const tankDefinitions = await fetchTankDefinitions();
|
||||
const tanks = Object.values(tankDefinitions);
|
||||
|
||||
export function BreakdownPreview() {
|
||||
const { useState } = useEmbedStateCurry<typeof breakdownConfig>();
|
||||
const { useEmbedState } = useEmbedStateCurry<typeof breakdownConfig>();
|
||||
|
||||
return (
|
||||
<BreakdownEmbedWrapper>
|
||||
{useState('showTotal') && <BreakdownEmbedCard tank={null} />}
|
||||
{useEmbedState('showTotal') && <BreakdownEmbedCard tank={null} />}
|
||||
|
||||
{tanks.slice(0, useState('listMaxTanks')).map((tank) => (
|
||||
{tanks.slice(0, useEmbedState('listMaxTanks')).map((tank) => (
|
||||
<BreakdownEmbedCard key={tank.id} tank={tank} />
|
||||
))}
|
||||
</BreakdownEmbedWrapper>
|
||||
@@ -28,15 +36,48 @@ export function BreakdownPreview() {
|
||||
}
|
||||
|
||||
export function BreakdownRenderer() {
|
||||
const { useState } = useEmbedStateCurry<typeof breakdownConfig>();
|
||||
return (
|
||||
<EmbedBreakdownPersistent.Provider>
|
||||
<BreakdownRendererContent />
|
||||
</EmbedBreakdownPersistent.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function BreakdownRendererContent() {
|
||||
const { useEmbedState } = useEmbedStateCurry<typeof breakdownConfig>();
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const id = Number(params.get('id'));
|
||||
const tankStatsA = EmbedBreakdownPersistent.use((state) => state[id] ?? []);
|
||||
const [tankStatsB, setTankStatsB] = useState<IndividualTankStats[]>([]);
|
||||
const diff = useMemo(
|
||||
() =>
|
||||
deltaTankStats(tankStatsA, tankStatsB).sort(
|
||||
(a, b) => b.last_battle_time - a.last_battle_time,
|
||||
),
|
||||
[tankStatsB],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(async () => {
|
||||
const newB = await getTankStats(idToRegion(id), id);
|
||||
|
||||
if (newB === null) return;
|
||||
|
||||
setTankStatsB(newB);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<BreakdownEmbedWrapper>
|
||||
{useState('showTotal') && <BreakdownEmbedCard tank={null} />}
|
||||
{useEmbedState('showTotal') && <BreakdownEmbedCard tank={null} />}
|
||||
|
||||
{tanks.slice(0, useState('listMaxTanks')).map((tank) => (
|
||||
<BreakdownEmbedCard key={tank.id} tank={tank} />
|
||||
))}
|
||||
{diff.slice(0, useEmbedState('listMaxTanks')).map((diff) => {
|
||||
const tank = tankDefinitions.tanks[diff.tank_id];
|
||||
|
||||
return <BreakdownEmbedCard key={tank.id} tank={tank} />;
|
||||
})}
|
||||
</BreakdownEmbedWrapper>
|
||||
);
|
||||
}
|
||||
@@ -25,10 +25,10 @@ interface BreakdownEmbedWrapperProps {
|
||||
export function BreakdownEmbedWrapper({
|
||||
children,
|
||||
}: BreakdownEmbedWrapperProps) {
|
||||
const { useState } = useEmbedStateCurry<typeof breakdownConfig>();
|
||||
const { useEmbedState } = useEmbedStateCurry<typeof breakdownConfig>();
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap={useState('listGap')} height="100%">
|
||||
<Flex direction="column" gap={useEmbedState('listGap')} height="100%">
|
||||
{children}
|
||||
</Flex>
|
||||
);
|
||||
@@ -39,7 +39,7 @@ interface BreakdownEmbedCardProps {
|
||||
}
|
||||
|
||||
export function BreakdownEmbedCard({ tank }: BreakdownEmbedCardProps) {
|
||||
const { useState, useRichText } =
|
||||
const { useEmbedState, useRichText } =
|
||||
useEmbedStateCurry<typeof breakdownConfig>();
|
||||
|
||||
return (
|
||||
@@ -47,17 +47,17 @@ export function BreakdownEmbedCard({ tank }: BreakdownEmbedCardProps) {
|
||||
flexShrink="0"
|
||||
direction="column"
|
||||
style={{
|
||||
borderRadius: toRadiusVar(useState('cardRadius')),
|
||||
borderRadius: toRadiusVar(useEmbedState('cardRadius')),
|
||||
overflow: 'hidden',
|
||||
backgroundColor: useState('cardBodyBackgroundColor'),
|
||||
backgroundColor: useEmbedState('cardBodyBackgroundColor'),
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
justify="center"
|
||||
style={{
|
||||
backgroundColor: useState('cardHeaderBackgroundColor'),
|
||||
backgroundColor: useEmbedState('cardHeaderBackgroundColor'),
|
||||
}}
|
||||
p={useState('cardHeaderPadding')}
|
||||
p={useEmbedState('cardHeaderPadding')}
|
||||
>
|
||||
<Text
|
||||
{...{
|
||||
@@ -66,7 +66,7 @@ export function BreakdownEmbedCard({ tank }: BreakdownEmbedCardProps) {
|
||||
tank === null
|
||||
? undefined
|
||||
: tank.type === TankType.RESEARCHABLE ||
|
||||
!useState('cardTitleTypeColor')
|
||||
!useEmbedState('cardTitleTypeColor')
|
||||
? undefined
|
||||
: {
|
||||
color:
|
||||
@@ -77,7 +77,7 @@ export function BreakdownEmbedCard({ tank }: BreakdownEmbedCardProps) {
|
||||
}}
|
||||
>
|
||||
<Flex align="center" gap="1">
|
||||
{useState('cardTitleClassIcon') && tank !== null && (
|
||||
{useEmbedState('cardTitleClassIcon') && tank !== null && (
|
||||
<>
|
||||
{tank.class === TankClass.LIGHT && (
|
||||
<ClassLight width="1em" height="1em" />
|
||||
@@ -98,18 +98,20 @@ export function BreakdownEmbedCard({ tank }: BreakdownEmbedCardProps) {
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex p={useState('cardBodyPadding')}>
|
||||
<Flex p={useEmbedState('cardBodyPadding')}>
|
||||
{times(4, (index) => {
|
||||
const column = (index + 1) as 1 | 2 | 3 | 4;
|
||||
const columnState = useState(`column${column}`) as CompositeStatsKey;
|
||||
const customLabel = useState(`column${column}CustomLabel`);
|
||||
const columnState = useEmbedState(
|
||||
`column${column}`,
|
||||
) as CompositeStatsKey;
|
||||
const customLabel = useEmbedState(`column${column}CustomLabel`);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
key={column}
|
||||
direction="column"
|
||||
align="center"
|
||||
gap={useState('columnGap')}
|
||||
gap={useEmbedState('columnGap')}
|
||||
flexGrow="1"
|
||||
>
|
||||
<Text {...useRichText('columnValue')}>
|
||||
|
||||
@@ -40,9 +40,9 @@ export function Page({ embed }: PageProps) {
|
||||
|
||||
function Content({ embed }: PageProps) {
|
||||
const Renderer = embedRenderers[embed];
|
||||
const { useState } = useEmbedStateCurry();
|
||||
const width = useState('width');
|
||||
const height = useState('height');
|
||||
const { useEmbedState } = useEmbedStateCurry();
|
||||
const width = useEmbedState('width');
|
||||
const height = useEmbedState('height');
|
||||
|
||||
return (
|
||||
<BlitzKitTheme style={{ background: 'transparent' }}>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { type IndividualTankStats } from '@blitzkit/core';
|
||||
import * as lodash from 'lodash-es';
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { createContextualStore } from '../core/zustand/createContextualStore';
|
||||
|
||||
type EmbedBreakdownPersistentStore = Record<number, IndividualTankStats[]>;
|
||||
|
||||
export const EmbedBreakdownPersistent = createContextualStore(() =>
|
||||
create<EmbedBreakdownPersistentStore>()(
|
||||
persist(() => ({}), {
|
||||
name: 'embed-breakdown',
|
||||
merge: (a, b) => lodash.merge(b, a),
|
||||
}),
|
||||
),
|
||||
);
|
||||
@@ -3,7 +3,7 @@ import { EmbedState, type EmbedConfig, type ExtractEmbedConfigTypes } from '.';
|
||||
import type { EmbedConfigItemType, EmbedItemType } from './constants';
|
||||
|
||||
export function useEmbedStateCurry<Config extends EmbedConfig>() {
|
||||
function useState<Key extends keyof Config>(key: Key) {
|
||||
function useEmbedState<Key extends keyof Config>(key: Key) {
|
||||
return EmbedState.use((state) => {
|
||||
return (state as ExtractEmbedConfigTypes<Config>)[key];
|
||||
});
|
||||
@@ -16,7 +16,7 @@ export function useEmbedStateCurry<Config extends EmbedConfig>() {
|
||||
: never;
|
||||
}[keyof Config],
|
||||
>(key: Key) {
|
||||
const { color, ...state } = useState(
|
||||
const { color, ...state } = useEmbedState(
|
||||
key,
|
||||
) as EmbedConfigItemType<EmbedItemType.RichText>['default'];
|
||||
|
||||
@@ -26,5 +26,5 @@ export function useEmbedStateCurry<Config extends EmbedConfig>() {
|
||||
} satisfies TextProps;
|
||||
}
|
||||
|
||||
return { useState, useRichText };
|
||||
return { useEmbedState, useRichText };
|
||||
}
|
||||
Reference in new issue
Block a user