mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02: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";
|
||||
array?: boolean;
|
||||
parentArray?: boolean;
|
||||
highContrast?: boolean; // TODO: add high contrast
|
||||
}
|
||||
|
||||
export const LIGHT_TEXT_COLORS = new Set<Color>([
|
||||
@@ -51,4 +52,4 @@ export function Button({
|
||||
{...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 type { MaybeSkeletonComponentProps } from "../types/maybeSkeletonComponentProps";
|
||||
import { LinkI18n } from "./LinkI18n";
|
||||
import { FilterControl } from "./TankSearch/components/FilterControl";
|
||||
import { TankSearchFilters } from "./TankSearchFilters";
|
||||
|
||||
const tankDefinitions = await api.tankDefinitions();
|
||||
|
||||
@@ -87,7 +87,7 @@ export function PlaylistGenerator({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
direction={{ initial: "column-reverse", md: "row" }}
|
||||
>
|
||||
<Flex direction="column" gap="4" align="center">
|
||||
<FilterControl />
|
||||
<TankSearchFilters />
|
||||
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
||||
@@ -25,12 +25,12 @@ import type { MaybeSkeletonComponentProps } from "../../types/maybeSkeletonCompo
|
||||
import { Callout } from "../Callout";
|
||||
import { ExperimentIcon } from "../ExperimentIcon";
|
||||
import { Link } from "../Link";
|
||||
import { TankSearchBar } from "../TankSearchBar";
|
||||
import { TankSearchFilters } from "../TankSearchFilters";
|
||||
import { Text } from "../Text";
|
||||
import { TankSearchCard } from "./components/Card";
|
||||
import { FilterControl } from "./components/FilterControl";
|
||||
import { NoResults } from "./components/NoResults";
|
||||
import { RecentlyViewed } from "./components/RecentlyViewed";
|
||||
import { TankSearchBar } from "../TankSearchBar";
|
||||
import { SkeletonTankCard } from "./components/SkeletonTankCard";
|
||||
import { TankCardWrapper } from "./components/TankCardWrapper";
|
||||
import { MAX_RECENTLY_VIEWED } from "./constants";
|
||||
@@ -437,7 +437,7 @@ export const TankSearch = memo<TankSearchProps>(
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
|
||||
{!tankFilters.search && !tankFilters.searching && <FilterControl />}
|
||||
{!tankFilters.search && !tankFilters.searching && <TankSearchFilters />}
|
||||
|
||||
{!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";
|
||||
import { times } from "lodash-es";
|
||||
import { Fragment, type ComponentProps, type ReactNode } from "react";
|
||||
import { api } from "../../../core/blitzkit/api";
|
||||
import { useLocale } from "../../../hooks/useLocale";
|
||||
import { App } from "../../../stores/app";
|
||||
import { TankFilters, type CaseType } from "../../../stores/tankFilters";
|
||||
import { classIcons } from "../../ClassIcon";
|
||||
import { GunAutoloaderIcon } from "../../GunAutoloaderIcon";
|
||||
import { GunAutoreloaderIcon } from "../../GunAutoreloaderIcon";
|
||||
import { GunRegularIcon } from "../../GunRegularIcon";
|
||||
import { MissingShellIcon } from "../../MissingShellIcon";
|
||||
import { ResearchedIcon } from "../../ResearchedIcon";
|
||||
import { ScienceIcon } from "../../ScienceIcon";
|
||||
import { ScienceOffIcon } from "../../ScienceOffIcon";
|
||||
import { api } from "../../core/blitzkit/api";
|
||||
import { useLocale } from "../../hooks/useLocale";
|
||||
import { App } from "../../stores/app";
|
||||
import { TankFilters, type CaseType } from "../../stores/tankFilters";
|
||||
import { Button } from "../Button";
|
||||
import { classIcons } from "../ClassIcon";
|
||||
import { DropdownMenu } from "../DropdownMenu";
|
||||
import { Flex } from "../Flex";
|
||||
import { GunAutoloaderIcon } from "../GunAutoloaderIcon";
|
||||
import { GunAutoreloaderIcon } from "../GunAutoreloaderIcon";
|
||||
import { GunRegularIcon } from "../GunRegularIcon";
|
||||
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 consumableDefinitions = await api.consumableDefinitions();
|
||||
@@ -165,14 +172,9 @@ const MAX_ICONS = 4;
|
||||
|
||||
const TIERS = times(10, (i) => 10 - i);
|
||||
|
||||
export function FilterControl() {
|
||||
export function TankSearchFilters() {
|
||||
return (
|
||||
<Flex
|
||||
align="center"
|
||||
justify={{ initial: "start", md: "center" }}
|
||||
gap="2"
|
||||
wrap="wrap"
|
||||
>
|
||||
<div className={styles.container}>
|
||||
<TiersFilter />
|
||||
<ClassFilter />
|
||||
<TypeFilter />
|
||||
@@ -188,7 +190,7 @@ export function FilterControl() {
|
||||
<GameModeAbilitiesFilter />
|
||||
|
||||
<ResetButton />
|
||||
</Flex>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -217,13 +219,13 @@ function TiersFilter() {
|
||||
<Button color="gray" variant="surface">
|
||||
<Flex gap="1">
|
||||
{tiers.slice(0, MAX_ICONS).map((tier) => (
|
||||
<Text size="1" key={tier}>
|
||||
<Text size="minor" key={tier}>
|
||||
{TIER_ROMAN_NUMERALS[tier]}
|
||||
</Text>
|
||||
))}
|
||||
|
||||
{tiers.length > MAX_ICONS && (
|
||||
<Text size="1">
|
||||
<Text size="minor">
|
||||
{literals(strings.common.units.plus, {
|
||||
value: tiers.length - MAX_ICONS,
|
||||
})}
|
||||
@@ -330,27 +332,9 @@ function NationsFilter() {
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
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",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{
|
||||
background: `linear-gradient(90deg, var(--gray-2) 50%, transparent)`,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<div className={styles["nation-option"]}>
|
||||
<div className={styles.overlay} />
|
||||
</div>
|
||||
|
||||
<Text style={{ zIndex: 1 }}>
|
||||
{
|
||||
@@ -651,7 +635,6 @@ function IndividualShellFilter({
|
||||
<DropdownMenu.Root modal={false}>
|
||||
<DropdownMenu.Trigger>
|
||||
<IconButton
|
||||
ml="-0.5px"
|
||||
variant="surface"
|
||||
style={{
|
||||
borderTopLeftRadius: index === 0 ? undefined : 0,
|
||||
@@ -756,19 +739,19 @@ function OwnershipFilter() {
|
||||
return wargaming ? (
|
||||
<OwnershipFilterInternal />
|
||||
) : (
|
||||
<Tooltip content={strings.website.common.tank_search.login}>
|
||||
<Tooltip tooltip={strings.website.common.tank_search.login}>
|
||||
<OwnershipFilterInternal />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
function OwnershipFilterInternal(props: FlexProps) {
|
||||
function OwnershipFilterInternal() {
|
||||
const wargaming = App.use((state) => state.logins.wargaming);
|
||||
const showOwned = TankFilters.use((state) => state.showOwned);
|
||||
const showUnowned = TankFilters.use((state) => state.showUnowned);
|
||||
|
||||
return (
|
||||
<Flex {...props}>
|
||||
<Flex>
|
||||
<IconButton
|
||||
style={{
|
||||
borderTopRightRadius: 0,
|
||||
@@ -883,7 +866,7 @@ function ConsumablesFilter() {
|
||||
))}
|
||||
|
||||
{consumables.length > MAX_ICONS && (
|
||||
<Text size="1" ml="1">
|
||||
<Text size="minor" className={styles["overflow-plus"]}>
|
||||
{literals(strings.common.units.plus, {
|
||||
value: consumables.length - MAX_ICONS,
|
||||
})}
|
||||
@@ -977,7 +960,7 @@ function ProvisionsFilter() {
|
||||
))}
|
||||
|
||||
{provisions.length > MAX_ICONS && (
|
||||
<Text size="1" ml="1">
|
||||
<Text size="minor" className={styles["overflow-plus"]}>
|
||||
{literals(strings.common.units.plus, {
|
||||
value: provisions.length - MAX_ICONS,
|
||||
})}
|
||||
@@ -1086,7 +1069,7 @@ function GameModeAbilitiesFilter() {
|
||||
))}
|
||||
|
||||
{icons.length > MAX_ICONS && (
|
||||
<Text size="1" ml="1">
|
||||
<Text size="minor" className={styles["overflow-plus"]}>
|
||||
{literals(strings.common.units.plus, {
|
||||
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 { PlayerCountControl } from "../../../../components/Performance/PlayerCountControl";
|
||||
import { TankTable } from "../../../../components/Performance/Table";
|
||||
import { FilterControl } from "../../../../components/TankSearch/components/FilterControl";
|
||||
import { TankSearchFilters } from "../../../../components/TankSearchFilters";
|
||||
import {
|
||||
LocaleProvider,
|
||||
type LocaleAcceptorProps,
|
||||
@@ -21,7 +21,7 @@ export function Page({ skeleton, locale }: PageProps) {
|
||||
function Content({ skeleton }: MaybeSkeletonComponentProps) {
|
||||
return (
|
||||
<PageWrapper pb="0" px="0" color="jade" maxWidth="100%">
|
||||
<FilterControl />
|
||||
<TankSearchFilters />
|
||||
<PlayerCountControl />
|
||||
|
||||
<TankTable skeleton={skeleton} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PageWrapper } from "../../../../components/PageWrapper";
|
||||
import { FilterControl } from "../../../../components/TankSearch/components/FilterControl";
|
||||
import { TankSearchFilters } from "../../../../components/TankSearchFilters";
|
||||
import { TierListControls } from "../../../../components/TierList/Controls";
|
||||
import { TierListTable } from "../../../../components/TierList/Table";
|
||||
import { TierListTiles } from "../../../../components/TierList/Tiles";
|
||||
@@ -23,7 +23,7 @@ function Content() {
|
||||
<URLManager />
|
||||
<TierListControls />
|
||||
<TierListTable />
|
||||
<FilterControl />
|
||||
<TankSearchFilters />
|
||||
<TierListTiles />
|
||||
</PageWrapper>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user