mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: edit headers
This commit is contained in:
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>
|
||||
);
|
||||
}
|
||||
+8
-14
@@ -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(
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
);
|
||||
Reference in new issue
Block a user