feat: edit headers

This commit is contained in:
tresabhi committed 2024-11-26 20:44:44 -06:00
1 parent 53d811eeef
commit 5f256ed84d
10 files changed
+155 -50

No files matched your search

@@ -20,7 +20,6 @@ import {
import { resolveBranchName } from '../core/blitzkit/branches';
import { homeTool, TOOLS } from '../constants/tools';
import { NavbarAccount } from './NavbarAccount';
import { times } from 'lodash-es';
const toolsFiltered = TOOLS.filter((tool) => !('href' in tool));
const tools = [homeTool, ...toolsFiltered];
@@ -1,18 +1,16 @@
import { Share2Icon } from '@radix-ui/react-icons';
import { useRef } from 'react';
import { generateTierListParams } from '../../../../core/blitzkit/generateTierListParams';
import { TierList } from '../../../../stores/tierList';
import { CopyButton } from '../../../CopyButton';
export function Share() {
const tanks = TierList.use((state) => state.tanks);
const input = useRef<HTMLInputElement>(null);
const rows = TierList.use((state) => state.rows);
return (
<CopyButton
variant="outline"
copy={() =>
`${location.origin}/tools/tier-list?${generateTierListParams(tanks)}`
`${location.origin}/tools/tier-list?${generateTierListParams(rows)}`
}
>
<Share2Icon /> Share
@@ -1,7 +1,6 @@
import { ReloadIcon } from '@radix-ui/react-icons';
import { Button, Flex } from '@radix-ui/themes';
import { TierList } from '../../../stores/tierList';
import { tierListRows } from '../Table/constants';
import { TierList, tierListInitialState } from '../../../stores/tierList';
import { Share } from './components/Share';
export function TierListControls() {
@@ -13,7 +12,7 @@ export function TierListControls() {
color="red"
onClick={() => {
mutateTierList((draft) => {
draft.tanks = tierListRows.map(() => []);
Object.assign(draft, tierListInitialState);
});
}}
>
@@ -0,0 +1,112 @@
import {
CheckIcon,
Cross1Icon,
Pencil1Icon,
Pencil2Icon,
} from '@radix-ui/react-icons';
import {
Button,
Flex,
Heading,
IconButton,
Popover,
Table,
TextField,
} from '@radix-ui/themes';
import { useRef, useState } from 'react';
import { Var } from '../../../../core/radix/var';
import { TierList } from '../../../../stores/tierList';
import { tierListRows } from '../../Table/constants';
interface HeaderProps {
index: number;
}
export function Header({ index }: HeaderProps) {
const rowStyle = tierListRows[index];
const name = TierList.use((state) => state.rows[index].name);
const input = useRef<HTMLInputElement>(null);
const mutateTierList = TierList.useMutation();
const [open, setOpen] = useState(false);
return (
<Table.RowHeaderCell
width="0"
style={{ backgroundColor: Var(rowStyle.color) }}
>
<Popover.Root open={open} onOpenChange={setOpen}>
<Popover.Trigger>
<Heading>
<Flex direction="column" align="center" gap="2">
{name}
<IconButton variant="solid" color="gray" highContrast>
<Pencil2Icon />
</IconButton>
</Flex>
</Heading>
</Popover.Trigger>
<Popover.Content>
<Flex direction="column" gap="2">
<TextField.Root
placeholder="Tier name"
ref={input}
defaultValue={name}
onKeyDown={(event) => {
if (!input.current) return;
if (event.key === 'Enter') {
input.current.blur();
} else if (event.key === 'Escape') {
input.current.value = name;
input.current.blur();
}
}}
onBlur={() => {
if (!input.current) return;
mutateTierList((draft) => {
if (!input.current) return;
draft.rows[index].name = input.current.value;
});
setOpen(false);
}}
>
<TextField.Slot>
<Pencil1Icon />
</TextField.Slot>
</TextField.Root>
<Flex gap="1" width="100%">
<Popover.Close
onClick={() => {
if (!input.current) return;
input.current.value = name;
}}
>
<Button variant="outline" color="red" style={{ flex: 1 }}>
<Cross1Icon /> Cancel
</Button>
</Popover.Close>
<Button
style={{ flex: 1 }}
onClick={() => {
if (!input.current) return;
input.current.blur();
}}
>
<CheckIcon /> Apply
</Button>
</Flex>
</Flex>
</Popover.Content>
</Popover.Root>
</Table.RowHeaderCell>
);
}
@@ -1,10 +1,10 @@
import { fetchTankDefinitions } from '@blitzkit/core';
import { Flex, Heading, Table } from '@radix-ui/themes';
import { Flex, Table } from '@radix-ui/themes';
import { useEffect, useRef } from 'react';
import { Var } from '../../core/radix/var';
import { TierList } from '../../stores/tierList';
import { tierListRowElements, tierListRows } from './Table/constants';
import { TierListTile } from './Tile';
import { TierList } from '../../../stores/tierList';
import { tierListRowElements } from '../Table/constants';
import { TierListTile } from '../Tile';
import { Header } from './components/Header';
interface TierListRowProps {
index: number;
@@ -13,8 +13,7 @@ interface TierListRowProps {
const tankDefinitions = await fetchTankDefinitions();
export function TierListRow({ index }: TierListRowProps) {
const rowStyle = tierListRows[index];
const tanks = TierList.use((state) => state.tanks[index]);
const tanks = TierList.use((state) => state.rows[index].tanks);
const row = useRef<HTMLTableRowElement>(null);
useEffect(() => {
@@ -30,13 +29,8 @@ export function TierListRow({ index }: TierListRowProps) {
});
return (
<Table.Row key={rowStyle.name} ref={row} data-index={index}>
<Table.RowHeaderCell
width="0"
style={{ backgroundColor: Var(rowStyle.color) }}
>
<Heading>{rowStyle.name}</Heading>
</Table.RowHeaderCell>
<Table.Row ref={row} data-index={index}>
<Header index={index} />
<Table.Cell>
<Flex wrap="wrap" height="100%">
@@ -106,10 +106,10 @@ export function TierListTile(props: TierListTileProps) {
mutateTierList((draft) => {
draft.dragging = false;
draft.tanks = draft.tanks.map((row) =>
row.filter((tankId) => tankId !== props.tank.id),
);
draft.tanks[rowIndex].splice(tileIndex, 0, props.tank.id);
draft.rows.forEach((row) => {
row.tanks = row.tanks.filter((tankId) => tankId !== props.tank.id);
});
draft.rows[rowIndex].tanks.splice(tileIndex, 0, props.tank.id);
draft.placedTanks.add(props.tank.id);
});
@@ -120,10 +120,10 @@ export function TierListTile(props: TierListTileProps) {
mutateTierList((draft) => {
draft.dragging = false;
draft.tanks = draft.tanks.map((row) =>
row.filter((tankId) => tankId !== props.tank.id),
);
draft.tanks[rowIndex].push(props.tank.id);
draft.rows.forEach((row) => {
row.tanks = row.tanks.filter((tankId) => tankId !== props.tank.id);
});
draft.rows[rowIndex].tanks.push(props.tank.id);
draft.placedTanks.add(props.tank.id);
});
@@ -135,9 +135,9 @@ export function TierListTile(props: TierListTileProps) {
if (!wasPlaced) {
mutateTierList((draft) => {
draft.dragging = false;
draft.tanks = draft.tanks.map((row) =>
row.filter((tankId) => tankId !== props.tank.id),
);
draft.rows.forEach((row) => {
row.tanks = row.tanks.filter((tankId) => tankId !== props.tank.id);
});
draft.placedTanks.delete(props.tank.id);
});
}
@@ -6,7 +6,7 @@ import { TierList } from '../../stores/tierList';
const tankDefinitions = await fetchTankDefinitions();
export function URLManager() {
const tanks = TierList.use((state) => state.tanks);
const rows = TierList.use((state) => state.rows);
const mutateTierList = TierList.useMutation();
useEffect(() => {
@@ -21,15 +21,15 @@ export function URLManager() {
.filter((id) => id in tankDefinitions.tanks);
mutateTierList((draft) => {
draft.tanks[index] = values;
draft.rows[index].tanks = values;
});
}
});
}, []);
useEffect(() => {
window.history.replaceState(null, '', `?${generateTierListParams(tanks)}`);
}, [tanks]);
window.history.replaceState(null, '', `?${generateTierListParams(rows)}`);
}, [rows]);
return null;
}
@@ -1,8 +1,10 @@
export function generateTierListParams(tanks: number[][]) {
import type { TierList } from '../../stores/tierList';
export function generateTierListParams(rows: TierList['rows']) {
const params = new URLSearchParams();
tanks.forEach((row, index) => {
params.set(`row-${index}`, row.join(','));
rows.forEach((row, index) => {
params.set(`row-${index}`, row.tanks.join(','));
});
return params;
@@ -54,10 +54,6 @@ export function Page({ embed }: PageProps) {
}
function Content({ embed }: PageProps) {
const wargaming = App.useDeferred(
(state) => state.logins.wargaming,
undefined,
);
const embedStateStore = EmbedState.useStore();
const config = embedConfigurations[embed] as EmbedConfig;
const [backgroundImage, setBackgroundImage] = useState(
+11 -6
View File
@@ -6,18 +6,23 @@ import { createContextualStore } from '../core/zustand/createContextualStore';
export interface TierList {
dragging: boolean;
tanks: number[][];
rows: { name: string; tanks: number[] }[];
placedTanks: Set<number>;
}
enableMapSet();
export const tierListInitialState: TierList = {
dragging: false,
rows: tierListRows.map((row) => ({
name: row.name,
tanks: [],
})),
placedTanks: new Set(),
};
export const TierList = createContextualStore(() =>
create<TierList>()(
subscribeWithSelector<TierList>(() => ({
dragging: false,
tanks: tierListRows.map(() => []),
placedTanks: new Set(),
})),
subscribeWithSelector<TierList>(() => tierListInitialState),
),
);