mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
module wrapping
This commit is contained in:
1 parent
402d054b30
commit
d66d25a261
7 files changed
+87
-43
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
.link {
|
.link {
|
||||||
text-decoration-color: currentColor;
|
text-decoration-color: currentColor;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
display: inline;
|
display: inline;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
.price {
|
.price {
|
||||||
|
font-size: var(--font-size-minor);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
|
height: 1em;
|
||||||
|
|
||||||
.entry {
|
.entry {
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
font-size: inherit;
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ export function Price({ price, className, ...props }: PriceProps) {
|
|||||||
{price.price_list.map((entry, index) => (
|
{price.price_list.map((entry, index) => (
|
||||||
<PriceEntry key={index} entry={entry} />
|
<PriceEntry key={index} entry={entry} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{price.price_list.length === 0 && (
|
||||||
|
<Text className={styles.entry} lowContrast>
|
||||||
|
Free
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -27,8 +33,6 @@ interface PriceEntryProps {
|
|||||||
|
|
||||||
function PriceEntry({ entry }: PriceEntryProps) {
|
function PriceEntry({ entry }: PriceEntryProps) {
|
||||||
if (entry.premium_time_price !== undefined) {
|
if (entry.premium_time_price !== undefined) {
|
||||||
console.log(entry);
|
|
||||||
|
|
||||||
throw new Error("Unsupported price type");
|
throw new Error("Unsupported price type");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +64,7 @@ function PriceInternal({ icon, value }: PriceInternalProps) {
|
|||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text weight="light" size="minor" lowContrast className={styles.entry}>
|
<Text weight="light" lowContrast className={styles.entry}>
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<img className={styles.icon} src={icon} />
|
<img className={styles.icon} src={icon} />
|
||||||
{formatCompact(locale, value)}
|
{formatCompact(locale, value)}
|
||||||
|
|||||||
@@ -60,40 +60,57 @@
|
|||||||
|
|
||||||
.line {
|
.line {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
|
|
||||||
.wrapper {
|
.line-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--space-2);
|
|
||||||
|
|
||||||
.stage {
|
gap: var(--space-3);
|
||||||
position: relative;
|
|
||||||
|
|
||||||
padding: var(--space-3);
|
.wrap-marker {
|
||||||
|
padding-bottom: var(--font-size-minor);
|
||||||
|
|
||||||
font-size: 2em;
|
svg {
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 1em;
|
width: 1em;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
|
|
||||||
transform: translate(var(--space-1), var(--space-1));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tier {
|
.wrapper {
|
||||||
position: absolute;
|
display: flex;
|
||||||
left: var(--space-2);
|
flex-direction: column;
|
||||||
top: var(--space-2);
|
align-items: center;
|
||||||
}
|
gap: var(--space-2);
|
||||||
|
|
||||||
.price {
|
.stage {
|
||||||
position: absolute;
|
position: relative;
|
||||||
left: 50%;
|
|
||||||
bottom: var(--space-2);
|
padding: var(--space-3);
|
||||||
transform: translateX(-50%);
|
|
||||||
|
font-size: 2em;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
|
||||||
|
transform: translate(var(--space-1), var(--space-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tier {
|
||||||
|
position: absolute;
|
||||||
|
left: var(--space-2);
|
||||||
|
top: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
bottom: var(--space-2);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import { romanize } from "@blitzkit/core";
|
import { romanize } from "@blitzkit/core";
|
||||||
import type { BlitzStaticEquipmentPresetComponent_EquipmentSlot } from "@protos/blitz_static_equipment_preset_component";
|
import type { BlitzStaticEquipmentPresetComponent_EquipmentSlot } from "@protos/blitz_static_equipment_preset_component";
|
||||||
import { Grade } from "@protos/blitz_static_standard_grades_enum";
|
import { Grade } from "@protos/blitz_static_standard_grades_enum";
|
||||||
import type { StandardPrice } from "@protos/blitz_static_standard_price";
|
import { StandardPrice } from "@protos/blitz_static_standard_price";
|
||||||
import type { UpgradeLine } from "@protos/blitz_static_tank_upgrade_line";
|
import type { UpgradeLine } from "@protos/blitz_static_tank_upgrade_line";
|
||||||
import type { StageParameters } from "@protos/blitz_static_tank_upgrade_single_stage";
|
import type { StageParameters } from "@protos/blitz_static_tank_upgrade_single_stage";
|
||||||
import { DoubleArrowDownIcon, DoubleArrowUpIcon } from "@radix-ui/react-icons";
|
import {
|
||||||
|
CornerBottomLeftIcon,
|
||||||
|
DoubleArrowLeftIcon,
|
||||||
|
DoubleArrowRightIcon,
|
||||||
|
} from "@radix-ui/react-icons";
|
||||||
import { chunk } from "lodash-es";
|
import { chunk } from "lodash-es";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { equipmentColumns } from "../../config/equipment";
|
import { equipmentColumns } from "../../config/equipment";
|
||||||
@@ -12,6 +16,7 @@ import { catImages } from "../../config/images";
|
|||||||
import {
|
import {
|
||||||
alternativeLines,
|
alternativeLines,
|
||||||
isAlternativeLine,
|
isAlternativeLine,
|
||||||
|
maxModulesPerRow,
|
||||||
originalLineName,
|
originalLineName,
|
||||||
} from "../../config/modules";
|
} from "../../config/modules";
|
||||||
import { useEquipment } from "../../hooks/useEquipment";
|
import { useEquipment } from "../../hooks/useEquipment";
|
||||||
@@ -21,7 +26,7 @@ import { useUpgradePreset } from "../../hooks/useUpgradePreset";
|
|||||||
import { Tankopedia } from "../../stores/tankopedia";
|
import { Tankopedia } from "../../stores/tankopedia";
|
||||||
import { Button } from "../Button";
|
import { Button } from "../Button";
|
||||||
import { Heading } from "../Heading";
|
import { Heading } from "../Heading";
|
||||||
import { IconButton } from "../IconButton";
|
import { Link } from "../Link";
|
||||||
import { Price } from "../Price";
|
import { Price } from "../Price";
|
||||||
import { Section } from "../Section";
|
import { Section } from "../Section";
|
||||||
import { Text } from "../Text";
|
import { Text } from "../Text";
|
||||||
@@ -167,7 +172,7 @@ function Modules() {
|
|||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<Heading size="4">{strings.tanks.loadout.modules}</Heading>
|
<Heading size="4">{strings.tanks.loadout.modules}</Heading>
|
||||||
|
|
||||||
<IconButton
|
<Link
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Tankopedia.mutate((draft) => {
|
Tankopedia.mutate((draft) => {
|
||||||
for (const line of tank.tank!.upgrade_lines) {
|
for (const line of tank.tank!.upgrade_lines) {
|
||||||
@@ -178,13 +183,12 @@ function Modules() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
color="tomato"
|
color="gray"
|
||||||
variant="ghost"
|
|
||||||
>
|
>
|
||||||
<DoubleArrowDownIcon />
|
<DoubleArrowLeftIcon />
|
||||||
</IconButton>
|
</Link>
|
||||||
|
|
||||||
<IconButton
|
<Link
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Tankopedia.mutate((draft) => {
|
Tankopedia.mutate((draft) => {
|
||||||
for (const line of tank.tank!.upgrade_lines) {
|
for (const line of tank.tank!.upgrade_lines) {
|
||||||
@@ -197,11 +201,10 @@ function Modules() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
color="jade"
|
color="gray"
|
||||||
variant="ghost"
|
|
||||||
>
|
>
|
||||||
<DoubleArrowUpIcon />
|
<DoubleArrowRightIcon />
|
||||||
</IconButton>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.lines}>
|
<div className={styles.lines}>
|
||||||
@@ -254,8 +257,23 @@ function Line({ name, lines }: LineProps) {
|
|||||||
function LineInner({ name, lines }: LineProps) {
|
function LineInner({ name, lines }: LineProps) {
|
||||||
const line = lines.find((line) => line.name === name)!;
|
const line = lines.find((line) => line.name === name)!;
|
||||||
|
|
||||||
return line.stages.map((stage, index) => (
|
return chunk(line.stages, maxModulesPerRow).map((chunk, wrapIndex) => (
|
||||||
<LineElement key={index} index={index} lineName={name} stage={stage} />
|
<div className={styles["line-wrap"]}>
|
||||||
|
{wrapIndex > 0 && (
|
||||||
|
<Text size="minor" className={styles["wrap-marker"]} lowContrast>
|
||||||
|
<CornerBottomLeftIcon />
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{chunk.map((stage, elementIndex) => (
|
||||||
|
<LineElement
|
||||||
|
key={elementIndex}
|
||||||
|
index={wrapIndex * maxModulesPerRow + elementIndex}
|
||||||
|
lineName={name}
|
||||||
|
stage={stage}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +315,8 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
|
|||||||
price = override.price;
|
price = override.price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
price ??= StandardPrice.create();
|
||||||
|
|
||||||
let isSelected: boolean;
|
let isSelected: boolean;
|
||||||
|
|
||||||
if (isAlternativeLine(lineName)) {
|
if (isAlternativeLine(lineName)) {
|
||||||
@@ -395,7 +415,7 @@ function LineElement({ index, lineName, stage }: LineElementProps) {
|
|||||||
</Text>
|
</Text>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{price && <Price className={styles.price} price={price} />}
|
{<Price className={styles.price} price={price} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
export const maxModulesPerRow = 5;
|
||||||
|
|
||||||
export const alternativeLines: Record<string, string> = {
|
export const alternativeLines: Record<string, string> = {
|
||||||
guns: "alternative_guns",
|
guns: "alternative_guns",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import "@radix-ui/colors/violet-dark.css";
|
import "@radix-ui/colors/violet-dark.css";
|
||||||
import { api } from "../../../../api/dynamic";
|
import { api } from "../../../../api/dynamic";
|
||||||
import { mixStaticPaths } from "../../../../astro/mixStaticPaths";
|
import { mixStaticPaths } from "../../../../astro/mixStaticPaths";
|
||||||
import ColorScale from "../../../../components/ColorScale.astro";
|
|
||||||
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
import BaseLayout from "../../../../layouts/BaseLayout.astro";
|
||||||
import { getStaticPaths as _getStaticPaths } from "../index.astro";
|
import { getStaticPaths as _getStaticPaths } from "../index.astro";
|
||||||
import { Page } from "./_index";
|
import { Page } from "./_index";
|
||||||
@@ -20,8 +19,6 @@ const { id, locale } = Astro.props;
|
|||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout {locale} accent="violet">
|
<BaseLayout {locale} accent="violet">
|
||||||
<ColorScale color="tomato" />
|
|
||||||
<ColorScale color="jade" />
|
|
||||||
|
|
||||||
<Page {locale} {id} client:load />
|
<Page {locale} {id} client:load />
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
Reference in new issue
Block a user