mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 19:49:50 +01:00
migrate tank filters
This commit is contained in:
1 parent
d477a3a7a4
commit
1e1040816b
13 files changed
+153
-60
No files matched your search
@@ -10,6 +10,7 @@ export interface ButtonProps extends ComponentProps<"button"> {
|
|||||||
size?: "regular" | "minor";
|
size?: "regular" | "minor";
|
||||||
array?: boolean;
|
array?: boolean;
|
||||||
parentArray?: boolean;
|
parentArray?: boolean;
|
||||||
|
highContrast?: boolean; // TODO: add high contrast
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LIGHT_TEXT_COLORS = new Set<Color>([
|
export const LIGHT_TEXT_COLORS = new Set<Color>([
|
||||||
@@ -51,4 +52,4 @@ export function Button({
|
|||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import type { ComponentProps } from "react";
|
||||||
|
import type { Space } from "../../types/space";
|
||||||
|
import { classNames } from "../../ui/classNames";
|
||||||
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
|
interface Props extends ComponentProps<"div"> {
|
||||||
|
gap?: Space;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Flex({ children, className, gap, ...props }: Props) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
className={classNames(styles.flex, className)}
|
||||||
|
data-gap={gap}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.icon-button {
|
||||||
|
padding: var(--space-3);
|
||||||
|
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { classNames } from "../../ui/classNames";
|
||||||
|
import { Button, type ButtonProps } from "../Button";
|
||||||
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
|
export function IconButton({ className, ...props }: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
className={classNames(className, styles["icon-button"])}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ import { App } from "../stores/app";
|
|||||||
import { TankFilters } from "../stores/tankFilters";
|
import { TankFilters } from "../stores/tankFilters";
|
||||||
import type { MaybeSkeletonComponentProps } from "../types/maybeSkeletonComponentProps";
|
import type { MaybeSkeletonComponentProps } from "../types/maybeSkeletonComponentProps";
|
||||||
import { LinkI18n } from "./LinkI18n";
|
import { LinkI18n } from "./LinkI18n";
|
||||||
import { FilterControl } from "./TankSearch/components/FilterControl";
|
import { TankSearchFilters } from "./TankSearchFilters";
|
||||||
|
|
||||||
const tankDefinitions = await api.tankDefinitions();
|
const tankDefinitions = await api.tankDefinitions();
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ export function PlaylistGenerator({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
direction={{ initial: "column-reverse", md: "row" }}
|
direction={{ initial: "column-reverse", md: "row" }}
|
||||||
>
|
>
|
||||||
<Flex direction="column" gap="4" align="center">
|
<Flex direction="column" gap="4" align="center">
|
||||||
<FilterControl />
|
<TankSearchFilters />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonCompo
|
|||||||
import { Callout } from "../Callout";
|
import { Callout } from "../Callout";
|
||||||
import { ExperimentIcon } from "../ExperimentIcon";
|
import { ExperimentIcon } from "../ExperimentIcon";
|
||||||
import { Link } from "../Link";
|
import { Link } from "../Link";
|
||||||
|
import { TankSearchBar } from "../TankSearchBar";
|
||||||
|
import { TankSearchFilters } from "../TankSearchFilters";
|
||||||
import { Text } from "../Text";
|
import { Text } from "../Text";
|
||||||
import { TankSearchCard } from "./components/Card";
|
import { TankSearchCard } from "./components/Card";
|
||||||
import { FilterControl } from "./components/FilterControl";
|
|
||||||
import { NoResults } from "./components/NoResults";
|
import { NoResults } from "./components/NoResults";
|
||||||
import { RecentlyViewed } from "./components/RecentlyViewed";
|
import { RecentlyViewed } from "./components/RecentlyViewed";
|
||||||
import { TankSearchBar } from "../TankSearchBar";
|
|
||||||
import { SkeletonTankCard } from "./components/SkeletonTankCard";
|
import { SkeletonTankCard } from "./components/SkeletonTankCard";
|
||||||
import { TankCardWrapper } from "./components/TankCardWrapper";
|
import { TankCardWrapper } from "./components/TankCardWrapper";
|
||||||
import { MAX_RECENTLY_VIEWED } from "./constants";
|
import { MAX_RECENTLY_VIEWED } from "./constants";
|
||||||
@@ -437,7 +437,7 @@ export const TankSearch = memo<TankSearchProps>(
|
|||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!tankFilters.search && !tankFilters.searching && <FilterControl />}
|
{!tankFilters.search && !tankFilters.searching && <TankSearchFilters />}
|
||||||
|
|
||||||
{!skeleton && !compact && <RecentlyViewed />}
|
{!skeleton && !compact && <RecentlyViewed />}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
.nation-option {
|
||||||
|
/* width="calc(100% + calc(4 * var(--space-2)))"
|
||||||
|
height="100%"
|
||||||
|
position="absolute"
|
||||||
|
right="0"
|
||||||
|
mr="-2"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(${alias("api", `/flags/scratched/${nation}.webp`)})`,
|
||||||
|
backgroundSize: "100%",
|
||||||
|
backgroundRepeat: "no-repeat",
|
||||||
|
backgroundPosition: "5rem center",
|
||||||
|
}} */
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
/* width="100%"
|
||||||
|
height="100%"
|
||||||
|
style={{
|
||||||
|
background: `linear-gradient(90deg, var(--gray-2) 50%, transparent)`,
|
||||||
|
}} */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.overflow-plus {
|
||||||
|
/* ml="1" */
|
||||||
|
}
|
||||||
+33
-50
@@ -17,18 +17,25 @@ import {
|
|||||||
} from "@radix-ui/react-icons";
|
} from "@radix-ui/react-icons";
|
||||||
import { times } from "lodash-es";
|
import { times } from "lodash-es";
|
||||||
import { Fragment, type ComponentProps, type ReactNode } from "react";
|
import { Fragment, type ComponentProps, type ReactNode } from "react";
|
||||||
import { api } from "../../../core/blitzkit/api";
|
import { api } from "../../core/blitzkit/api";
|
||||||
import { useLocale } from "../../../hooks/useLocale";
|
import { useLocale } from "../../hooks/useLocale";
|
||||||
import { App } from "../../../stores/app";
|
import { App } from "../../stores/app";
|
||||||
import { TankFilters, type CaseType } from "../../../stores/tankFilters";
|
import { TankFilters, type CaseType } from "../../stores/tankFilters";
|
||||||
import { classIcons } from "../../ClassIcon";
|
import { Button } from "../Button";
|
||||||
import { GunAutoloaderIcon } from "../../GunAutoloaderIcon";
|
import { classIcons } from "../ClassIcon";
|
||||||
import { GunAutoreloaderIcon } from "../../GunAutoreloaderIcon";
|
import { DropdownMenu } from "../DropdownMenu";
|
||||||
import { GunRegularIcon } from "../../GunRegularIcon";
|
import { Flex } from "../Flex";
|
||||||
import { MissingShellIcon } from "../../MissingShellIcon";
|
import { GunAutoloaderIcon } from "../GunAutoloaderIcon";
|
||||||
import { ResearchedIcon } from "../../ResearchedIcon";
|
import { GunAutoreloaderIcon } from "../GunAutoreloaderIcon";
|
||||||
import { ScienceIcon } from "../../ScienceIcon";
|
import { GunRegularIcon } from "../GunRegularIcon";
|
||||||
import { ScienceOffIcon } from "../../ScienceOffIcon";
|
import { IconButton } from "../IconButton";
|
||||||
|
import { MissingShellIcon } from "../MissingShellIcon";
|
||||||
|
import { ResearchedIcon } from "../ResearchedIcon";
|
||||||
|
import { ScienceIcon } from "../ScienceIcon";
|
||||||
|
import { ScienceOffIcon } from "../ScienceOffIcon";
|
||||||
|
import { Text } from "../Text";
|
||||||
|
import { Tooltip } from "../Tooltip";
|
||||||
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
const gameDefinitions = await api.gameDefinitions();
|
const gameDefinitions = await api.gameDefinitions();
|
||||||
const consumableDefinitions = await api.consumableDefinitions();
|
const consumableDefinitions = await api.consumableDefinitions();
|
||||||
@@ -165,14 +172,9 @@ const MAX_ICONS = 4;
|
|||||||
|
|
||||||
const TIERS = times(10, (i) => 10 - i);
|
const TIERS = times(10, (i) => 10 - i);
|
||||||
|
|
||||||
export function FilterControl() {
|
export function TankSearchFilters() {
|
||||||
return (
|
return (
|
||||||
<Flex
|
<div className={styles.container}>
|
||||||
align="center"
|
|
||||||
justify={{ initial: "start", md: "center" }}
|
|
||||||
gap="2"
|
|
||||||
wrap="wrap"
|
|
||||||
>
|
|
||||||
<TiersFilter />
|
<TiersFilter />
|
||||||
<ClassFilter />
|
<ClassFilter />
|
||||||
<TypeFilter />
|
<TypeFilter />
|
||||||
@@ -188,7 +190,7 @@ export function FilterControl() {
|
|||||||
<GameModeAbilitiesFilter />
|
<GameModeAbilitiesFilter />
|
||||||
|
|
||||||
<ResetButton />
|
<ResetButton />
|
||||||
</Flex>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,13 +219,13 @@ function TiersFilter() {
|
|||||||
<Button color="gray" variant="surface">
|
<Button color="gray" variant="surface">
|
||||||
<Flex gap="1">
|
<Flex gap="1">
|
||||||
{tiers.slice(0, MAX_ICONS).map((tier) => (
|
{tiers.slice(0, MAX_ICONS).map((tier) => (
|
||||||
<Text size="1" key={tier}>
|
<Text size="minor" key={tier}>
|
||||||
{TIER_ROMAN_NUMERALS[tier]}
|
{TIER_ROMAN_NUMERALS[tier]}
|
||||||
</Text>
|
</Text>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{tiers.length > MAX_ICONS && (
|
{tiers.length > MAX_ICONS && (
|
||||||
<Text size="1">
|
<Text size="minor">
|
||||||
{literals(strings.common.units.plus, {
|
{literals(strings.common.units.plus, {
|
||||||
value: tiers.length - MAX_ICONS,
|
value: tiers.length - MAX_ICONS,
|
||||||
})}
|
})}
|
||||||
@@ -330,27 +332,9 @@ function NationsFilter() {
|
|||||||
position: "relative",
|
position: "relative",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<div className={styles["nation-option"]}>
|
||||||
width="calc(100% + calc(4 * var(--space-2)))"
|
<div className={styles.overlay} />
|
||||||
height="100%"
|
</div>
|
||||||
position="absolute"
|
|
||||||
right="0"
|
|
||||||
mr="-2"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url(${alias("api", `/flags/scratched/${nation}.webp`)})`,
|
|
||||||
backgroundSize: "100%",
|
|
||||||
backgroundRepeat: "no-repeat",
|
|
||||||
backgroundPosition: "5rem center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
style={{
|
|
||||||
background: `linear-gradient(90deg, var(--gray-2) 50%, transparent)`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<Text style={{ zIndex: 1 }}>
|
<Text style={{ zIndex: 1 }}>
|
||||||
{
|
{
|
||||||
@@ -651,7 +635,6 @@ function IndividualShellFilter({
|
|||||||
<DropdownMenu.Root modal={false}>
|
<DropdownMenu.Root modal={false}>
|
||||||
<DropdownMenu.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<IconButton
|
<IconButton
|
||||||
ml="-0.5px"
|
|
||||||
variant="surface"
|
variant="surface"
|
||||||
style={{
|
style={{
|
||||||
borderTopLeftRadius: index === 0 ? undefined : 0,
|
borderTopLeftRadius: index === 0 ? undefined : 0,
|
||||||
@@ -756,19 +739,19 @@ function OwnershipFilter() {
|
|||||||
return wargaming ? (
|
return wargaming ? (
|
||||||
<OwnershipFilterInternal />
|
<OwnershipFilterInternal />
|
||||||
) : (
|
) : (
|
||||||
<Tooltip content={strings.website.common.tank_search.login}>
|
<Tooltip tooltip={strings.website.common.tank_search.login}>
|
||||||
<OwnershipFilterInternal />
|
<OwnershipFilterInternal />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function OwnershipFilterInternal(props: FlexProps) {
|
function OwnershipFilterInternal() {
|
||||||
const wargaming = App.use((state) => state.logins.wargaming);
|
const wargaming = App.use((state) => state.logins.wargaming);
|
||||||
const showOwned = TankFilters.use((state) => state.showOwned);
|
const showOwned = TankFilters.use((state) => state.showOwned);
|
||||||
const showUnowned = TankFilters.use((state) => state.showUnowned);
|
const showUnowned = TankFilters.use((state) => state.showUnowned);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex {...props}>
|
<Flex>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={{
|
style={{
|
||||||
borderTopRightRadius: 0,
|
borderTopRightRadius: 0,
|
||||||
@@ -883,7 +866,7 @@ function ConsumablesFilter() {
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
{consumables.length > MAX_ICONS && (
|
{consumables.length > MAX_ICONS && (
|
||||||
<Text size="1" ml="1">
|
<Text size="minor" className={styles["overflow-plus"]}>
|
||||||
{literals(strings.common.units.plus, {
|
{literals(strings.common.units.plus, {
|
||||||
value: consumables.length - MAX_ICONS,
|
value: consumables.length - MAX_ICONS,
|
||||||
})}
|
})}
|
||||||
@@ -977,7 +960,7 @@ function ProvisionsFilter() {
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
{provisions.length > MAX_ICONS && (
|
{provisions.length > MAX_ICONS && (
|
||||||
<Text size="1" ml="1">
|
<Text size="minor" className={styles["overflow-plus"]}>
|
||||||
{literals(strings.common.units.plus, {
|
{literals(strings.common.units.plus, {
|
||||||
value: provisions.length - MAX_ICONS,
|
value: provisions.length - MAX_ICONS,
|
||||||
})}
|
})}
|
||||||
@@ -1086,7 +1069,7 @@ function GameModeAbilitiesFilter() {
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
{icons.length > MAX_ICONS && (
|
{icons.length > MAX_ICONS && (
|
||||||
<Text size="1" ml="1">
|
<Text size="minor" className={styles["overflow-plus"]}>
|
||||||
{literals(strings.common.units.plus, {
|
{literals(strings.common.units.plus, {
|
||||||
value: icons.length - MAX_ICONS,
|
value: icons.length - MAX_ICONS,
|
||||||
})}
|
})}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
.tooltip {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.text {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
z-index: 1;
|
||||||
|
background-color: var(--gray-12);
|
||||||
|
color: var(--gray-1);
|
||||||
|
border-radius: var(--space-3);
|
||||||
|
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
margin-bottom: var(--space-3);
|
||||||
|
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.text {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import type { ReactNode } from "react";
|
||||||
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: ReactNode;
|
||||||
|
tooltip: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Tooltip({ children, tooltip }: Props) {
|
||||||
|
return (
|
||||||
|
<div className={styles.tooltip}>
|
||||||
|
<div className={styles.text}>{tooltip}</div>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||||
import { PlayerCountControl } from "../../../../components/Performance/PlayerCountControl";
|
import { PlayerCountControl } from "../../../../components/Performance/PlayerCountControl";
|
||||||
import { TankTable } from "../../../../components/Performance/Table";
|
import { TankTable } from "../../../../components/Performance/Table";
|
||||||
import { FilterControl } from "../../../../components/TankSearch/components/FilterControl";
|
import { TankSearchFilters } from "../../../../components/TankSearchFilters";
|
||||||
import {
|
import {
|
||||||
LocaleProvider,
|
LocaleProvider,
|
||||||
type LocaleAcceptorProps,
|
type LocaleAcceptorProps,
|
||||||
@@ -21,7 +21,7 @@ export function Page({ skeleton, locale }: PageProps) {
|
|||||||
function Content({ skeleton }: MaybeSkeletonComponentProps) {
|
function Content({ skeleton }: MaybeSkeletonComponentProps) {
|
||||||
return (
|
return (
|
||||||
<PageWrapper pb="0" px="0" color="jade" maxWidth="100%">
|
<PageWrapper pb="0" px="0" color="jade" maxWidth="100%">
|
||||||
<FilterControl />
|
<TankSearchFilters />
|
||||||
<PlayerCountControl />
|
<PlayerCountControl />
|
||||||
|
|
||||||
<TankTable skeleton={skeleton} />
|
<TankTable skeleton={skeleton} />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||||
import { FilterControl } from "../../../../components/TankSearch/components/FilterControl";
|
import { TankSearchFilters } from "../../../../components/TankSearchFilters";
|
||||||
import { TierListControls } from "../../../../components/TierList/Controls";
|
import { TierListControls } from "../../../../components/TierList/Controls";
|
||||||
import { TierListTable } from "../../../../components/TierList/Table";
|
import { TierListTable } from "../../../../components/TierList/Table";
|
||||||
import { TierListTiles } from "../../../../components/TierList/Tiles";
|
import { TierListTiles } from "../../../../components/TierList/Tiles";
|
||||||
@@ -23,7 +23,7 @@ function Content() {
|
|||||||
<URLManager />
|
<URLManager />
|
||||||
<TierListControls />
|
<TierListControls />
|
||||||
<TierListTable />
|
<TierListTable />
|
||||||
<FilterControl />
|
<TankSearchFilters />
|
||||||
<TierListTiles />
|
<TierListTiles />
|
||||||
</PageWrapper>
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user