mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +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 { resolveBranchName } from '../core/blitzkit/branches';
|
||||||
import { homeTool, TOOLS } from '../constants/tools';
|
import { homeTool, TOOLS } from '../constants/tools';
|
||||||
import { NavbarAccount } from './NavbarAccount';
|
import { NavbarAccount } from './NavbarAccount';
|
||||||
import { times } from 'lodash-es';
|
|
||||||
|
|
||||||
const toolsFiltered = TOOLS.filter((tool) => !('href' in tool));
|
const toolsFiltered = TOOLS.filter((tool) => !('href' in tool));
|
||||||
const tools = [homeTool, ...toolsFiltered];
|
const tools = [homeTool, ...toolsFiltered];
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import { Share2Icon } from '@radix-ui/react-icons';
|
import { Share2Icon } from '@radix-ui/react-icons';
|
||||||
import { useRef } from 'react';
|
|
||||||
import { generateTierListParams } from '../../../../core/blitzkit/generateTierListParams';
|
import { generateTierListParams } from '../../../../core/blitzkit/generateTierListParams';
|
||||||
import { TierList } from '../../../../stores/tierList';
|
import { TierList } from '../../../../stores/tierList';
|
||||||
import { CopyButton } from '../../../CopyButton';
|
import { CopyButton } from '../../../CopyButton';
|
||||||
|
|
||||||
export function Share() {
|
export function Share() {
|
||||||
const tanks = TierList.use((state) => state.tanks);
|
const rows = TierList.use((state) => state.rows);
|
||||||
const input = useRef<HTMLInputElement>(null);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CopyButton
|
<CopyButton
|
||||||
variant="outline"
|
variant="outline"
|
||||||
copy={() =>
|
copy={() =>
|
||||||
`${location.origin}/tools/tier-list?${generateTierListParams(tanks)}`
|
`${location.origin}/tools/tier-list?${generateTierListParams(rows)}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Share2Icon /> Share
|
<Share2Icon /> Share
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { ReloadIcon } from '@radix-ui/react-icons';
|
import { ReloadIcon } from '@radix-ui/react-icons';
|
||||||
import { Button, Flex } from '@radix-ui/themes';
|
import { Button, Flex } from '@radix-ui/themes';
|
||||||
import { TierList } from '../../../stores/tierList';
|
import { TierList, tierListInitialState } from '../../../stores/tierList';
|
||||||
import { tierListRows } from '../Table/constants';
|
|
||||||
import { Share } from './components/Share';
|
import { Share } from './components/Share';
|
||||||
|
|
||||||
export function TierListControls() {
|
export function TierListControls() {
|
||||||
@@ -13,7 +12,7 @@ export function TierListControls() {
|
|||||||
color="red"
|
color="red"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
mutateTierList((draft) => {
|
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 { 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 { useEffect, useRef } from 'react';
|
||||||
import { Var } from '../../core/radix/var';
|
import { TierList } from '../../../stores/tierList';
|
||||||
import { TierList } from '../../stores/tierList';
|
import { tierListRowElements } from '../Table/constants';
|
||||||
import { tierListRowElements, tierListRows } from './Table/constants';
|
import { TierListTile } from '../Tile';
|
||||||
import { TierListTile } from './Tile';
|
import { Header } from './components/Header';
|
||||||
|
|
||||||
interface TierListRowProps {
|
interface TierListRowProps {
|
||||||
index: number;
|
index: number;
|
||||||
@@ -13,8 +13,7 @@ interface TierListRowProps {
|
|||||||
const tankDefinitions = await fetchTankDefinitions();
|
const tankDefinitions = await fetchTankDefinitions();
|
||||||
|
|
||||||
export function TierListRow({ index }: TierListRowProps) {
|
export function TierListRow({ index }: TierListRowProps) {
|
||||||
const rowStyle = tierListRows[index];
|
const tanks = TierList.use((state) => state.rows[index].tanks);
|
||||||
const tanks = TierList.use((state) => state.tanks[index]);
|
|
||||||
const row = useRef<HTMLTableRowElement>(null);
|
const row = useRef<HTMLTableRowElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -30,13 +29,8 @@ export function TierListRow({ index }: TierListRowProps) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table.Row key={rowStyle.name} ref={row} data-index={index}>
|
<Table.Row ref={row} data-index={index}>
|
||||||
<Table.RowHeaderCell
|
<Header index={index} />
|
||||||
width="0"
|
|
||||||
style={{ backgroundColor: Var(rowStyle.color) }}
|
|
||||||
>
|
|
||||||
<Heading>{rowStyle.name}</Heading>
|
|
||||||
</Table.RowHeaderCell>
|
|
||||||
|
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
<Flex wrap="wrap" height="100%">
|
<Flex wrap="wrap" height="100%">
|
||||||
@@ -106,10 +106,10 @@ export function TierListTile(props: TierListTileProps) {
|
|||||||
|
|
||||||
mutateTierList((draft) => {
|
mutateTierList((draft) => {
|
||||||
draft.dragging = false;
|
draft.dragging = false;
|
||||||
draft.tanks = draft.tanks.map((row) =>
|
draft.rows.forEach((row) => {
|
||||||
row.filter((tankId) => tankId !== props.tank.id),
|
row.tanks = row.tanks.filter((tankId) => tankId !== props.tank.id);
|
||||||
);
|
});
|
||||||
draft.tanks[rowIndex].splice(tileIndex, 0, props.tank.id);
|
draft.rows[rowIndex].tanks.splice(tileIndex, 0, props.tank.id);
|
||||||
draft.placedTanks.add(props.tank.id);
|
draft.placedTanks.add(props.tank.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -120,10 +120,10 @@ export function TierListTile(props: TierListTileProps) {
|
|||||||
|
|
||||||
mutateTierList((draft) => {
|
mutateTierList((draft) => {
|
||||||
draft.dragging = false;
|
draft.dragging = false;
|
||||||
draft.tanks = draft.tanks.map((row) =>
|
draft.rows.forEach((row) => {
|
||||||
row.filter((tankId) => tankId !== props.tank.id),
|
row.tanks = row.tanks.filter((tankId) => tankId !== props.tank.id);
|
||||||
);
|
});
|
||||||
draft.tanks[rowIndex].push(props.tank.id);
|
draft.rows[rowIndex].tanks.push(props.tank.id);
|
||||||
draft.placedTanks.add(props.tank.id);
|
draft.placedTanks.add(props.tank.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -135,9 +135,9 @@ export function TierListTile(props: TierListTileProps) {
|
|||||||
if (!wasPlaced) {
|
if (!wasPlaced) {
|
||||||
mutateTierList((draft) => {
|
mutateTierList((draft) => {
|
||||||
draft.dragging = false;
|
draft.dragging = false;
|
||||||
draft.tanks = draft.tanks.map((row) =>
|
draft.rows.forEach((row) => {
|
||||||
row.filter((tankId) => tankId !== props.tank.id),
|
row.tanks = row.tanks.filter((tankId) => tankId !== props.tank.id);
|
||||||
);
|
});
|
||||||
draft.placedTanks.delete(props.tank.id);
|
draft.placedTanks.delete(props.tank.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { TierList } from '../../stores/tierList';
|
|||||||
const tankDefinitions = await fetchTankDefinitions();
|
const tankDefinitions = await fetchTankDefinitions();
|
||||||
|
|
||||||
export function URLManager() {
|
export function URLManager() {
|
||||||
const tanks = TierList.use((state) => state.tanks);
|
const rows = TierList.use((state) => state.rows);
|
||||||
const mutateTierList = TierList.useMutation();
|
const mutateTierList = TierList.useMutation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -21,15 +21,15 @@ export function URLManager() {
|
|||||||
.filter((id) => id in tankDefinitions.tanks);
|
.filter((id) => id in tankDefinitions.tanks);
|
||||||
|
|
||||||
mutateTierList((draft) => {
|
mutateTierList((draft) => {
|
||||||
draft.tanks[index] = values;
|
draft.rows[index].tanks = values;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.history.replaceState(null, '', `?${generateTierListParams(tanks)}`);
|
window.history.replaceState(null, '', `?${generateTierListParams(rows)}`);
|
||||||
}, [tanks]);
|
}, [rows]);
|
||||||
|
|
||||||
return null;
|
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();
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
tanks.forEach((row, index) => {
|
rows.forEach((row, index) => {
|
||||||
params.set(`row-${index}`, row.join(','));
|
params.set(`row-${index}`, row.tanks.join(','));
|
||||||
});
|
});
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
|
|||||||
@@ -54,10 +54,6 @@ export function Page({ embed }: PageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Content({ embed }: PageProps) {
|
function Content({ embed }: PageProps) {
|
||||||
const wargaming = App.useDeferred(
|
|
||||||
(state) => state.logins.wargaming,
|
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
const embedStateStore = EmbedState.useStore();
|
const embedStateStore = EmbedState.useStore();
|
||||||
const config = embedConfigurations[embed] as EmbedConfig;
|
const config = embedConfigurations[embed] as EmbedConfig;
|
||||||
const [backgroundImage, setBackgroundImage] = useState(
|
const [backgroundImage, setBackgroundImage] = useState(
|
||||||
|
|||||||
@@ -6,18 +6,23 @@ import { createContextualStore } from '../core/zustand/createContextualStore';
|
|||||||
|
|
||||||
export interface TierList {
|
export interface TierList {
|
||||||
dragging: boolean;
|
dragging: boolean;
|
||||||
tanks: number[][];
|
rows: { name: string; tanks: number[] }[];
|
||||||
placedTanks: Set<number>;
|
placedTanks: Set<number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
enableMapSet();
|
enableMapSet();
|
||||||
|
|
||||||
|
export const tierListInitialState: TierList = {
|
||||||
|
dragging: false,
|
||||||
|
rows: tierListRows.map((row) => ({
|
||||||
|
name: row.name,
|
||||||
|
tanks: [],
|
||||||
|
})),
|
||||||
|
placedTanks: new Set(),
|
||||||
|
};
|
||||||
|
|
||||||
export const TierList = createContextualStore(() =>
|
export const TierList = createContextualStore(() =>
|
||||||
create<TierList>()(
|
create<TierList>()(
|
||||||
subscribeWithSelector<TierList>(() => ({
|
subscribeWithSelector<TierList>(() => tierListInitialState),
|
||||||
dragging: false,
|
|
||||||
tanks: tierListRows.map(() => []),
|
|
||||||
placedTanks: new Set(),
|
|
||||||
})),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
Reference in new issue
Block a user