mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
new basic layout
This commit is contained in:
1 parent
6aa14d2faf
commit
73de6e3521
6 files changed
+254
-186
No files matched your search
@@ -1,24 +1,37 @@
|
||||
.characteristics {
|
||||
--cell-width: 2.5rem;
|
||||
--group-span: 7;
|
||||
--inner-padding: var(--space-4);
|
||||
|
||||
display: grid;
|
||||
grid-auto-rows: var(--cell-width);
|
||||
grid-template-columns: repeat(auto-fill, minmax(var(--cell-width), 1fr));
|
||||
grid-auto-flow: dense;
|
||||
|
||||
padding: var(--space-5);
|
||||
gap: var(--space-4);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-5);
|
||||
box-sizing: border-box;
|
||||
|
||||
.group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
gap: var(--space-4);
|
||||
grid-column: span var(--group-span);
|
||||
gap: inherit;
|
||||
|
||||
.title-wrapper {
|
||||
background-color: var(--amber-a3);
|
||||
grid-row: span 1;
|
||||
|
||||
padding: 0 var(--inner-padding);
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
gap: var(--space-3);
|
||||
|
||||
.title {
|
||||
.title-content {
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
@@ -31,67 +44,60 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.separator {
|
||||
height: var(--space-1);
|
||||
flex: 1;
|
||||
|
||||
background-color: var(--gray-5);
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
--cell-width: 2rem;
|
||||
--toy-span: 6;
|
||||
.item {
|
||||
padding: 0 var(--inner-padding);
|
||||
|
||||
display: grid;
|
||||
grid-auto-rows: var(--cell-width);
|
||||
grid-template-columns: repeat(auto-fill, minmax(var(--cell-width), 1fr));
|
||||
grid-auto-flow: row dense;
|
||||
gap: var(--space-4);
|
||||
grid-row: span 1;
|
||||
|
||||
.item {
|
||||
grid-row: span 1;
|
||||
grid-column: span var(--toy-span);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
|
||||
.value {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: var(--space-2);
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.value {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.ranking {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
|
||||
.ranking {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3);
|
||||
.bar-wrapper {
|
||||
flex: 1;
|
||||
height: var(--space-1);
|
||||
|
||||
.bar-wrapper {
|
||||
flex: 1;
|
||||
height: var(--space-1);
|
||||
background-color: var(--gray-3);
|
||||
border-radius: var(--radius-max);
|
||||
overflow: hidden;
|
||||
|
||||
background-color: var(--gray-3);
|
||||
border-radius: var(--radius-max);
|
||||
overflow: hidden;
|
||||
|
||||
.bar {
|
||||
background-color: var(--jade-9);
|
||||
width: 75%;
|
||||
height: 100%;
|
||||
}
|
||||
.bar {
|
||||
background-color: var(--jade-9);
|
||||
width: 75%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toy {
|
||||
grid-row: span var(--toy-span);
|
||||
grid-column: span var(--toy-span);
|
||||
.toy {
|
||||
grid-row: span var(--group-span);
|
||||
padding: var(--inner-padding);
|
||||
|
||||
background-color: var(--gray-3);
|
||||
border: var(--gray-5) solid var(--space-1);
|
||||
.content {
|
||||
background-color: green;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: var(--gray-2);
|
||||
outline: var(--gray-5) solid var(--space-1);
|
||||
|
||||
border-radius: var(--space-3);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { CaretDownIcon, CaretRightIcon } from "@radix-ui/react-icons";
|
||||
import { GearIcon } from "@radix-ui/react-icons";
|
||||
import { useCharacteristicRenderer } from "../../hooks/useCharacteristicRenderer";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import { Tankopedia } from "../../stores/tankopedia";
|
||||
import type { CharacteristicOutput } from "../../tankopedia/characteristics";
|
||||
import {
|
||||
characteristicsOrder,
|
||||
@@ -9,7 +8,6 @@ import {
|
||||
type CharacteristicsGroup,
|
||||
} from "../../tankopedia/characteristicsOrder";
|
||||
import type { ComputedCharacteristics } from "../../tankopedia/computeCharacteristics";
|
||||
import { Heading } from "../Heading";
|
||||
import { Text } from "../Text";
|
||||
import styles from "./index.module.css";
|
||||
|
||||
@@ -35,35 +33,35 @@ interface GroupProps {
|
||||
}
|
||||
|
||||
function Group({ group, characteristics }: GroupProps) {
|
||||
const isOpen = Tankopedia.use((state) => state.groups[group.group]);
|
||||
const strings = useStrings();
|
||||
const toys = group.order.filter((item) => "toy" in item).length;
|
||||
const items = group.order.filter((item) => "name" in item).length;
|
||||
const span = `calc(${toys} * var(--group-span) + ${items} + 1)`;
|
||||
|
||||
return (
|
||||
<div className={styles.group}>
|
||||
<div
|
||||
className={styles.group}
|
||||
style={{
|
||||
gridRow: `span ${span}`,
|
||||
gridTemplateRows: `repeat(${span}, 1fr)`,
|
||||
}}
|
||||
>
|
||||
<div className={styles["title-wrapper"]}>
|
||||
<Heading className={styles.title} size="3">
|
||||
<div className={styles["title-content"]}>
|
||||
{isOpen ? <CaretDownIcon /> : <CaretRightIcon />}
|
||||
{
|
||||
(strings.tanks.characteristics.titles as Record<string, string>)[
|
||||
group.group
|
||||
]
|
||||
}
|
||||
<Text className={styles.title}>
|
||||
<div className={styles.content}>
|
||||
{group.group}
|
||||
<GearIcon />
|
||||
</div>
|
||||
</Heading>
|
||||
|
||||
<div className={styles.separator} />
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className={styles.content}>
|
||||
{group.order.map((item) =>
|
||||
"toy" in item ? (
|
||||
<Toy {...item} />
|
||||
) : (
|
||||
<Item config={item} value={characteristics[item.name]} />
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
{group.order.map((item) =>
|
||||
"toy" in item ? (
|
||||
<Toy {...item} />
|
||||
) : (
|
||||
<Item config={item} value={characteristics[item.name]} />
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -80,13 +78,7 @@ function Item({ config, value }: ItemProps) {
|
||||
return (
|
||||
<span className={styles.item}>
|
||||
<div className={styles.value}>
|
||||
<Text lowContrast>
|
||||
{
|
||||
(strings.tanks.characteristics.items as Record<string, string>)[
|
||||
config.name
|
||||
]
|
||||
}
|
||||
</Text>
|
||||
<Text lowContrast>{config.name}</Text>
|
||||
<Text>{renderCharacteristic(value, config)}</Text>
|
||||
</div>
|
||||
|
||||
@@ -108,5 +100,11 @@ interface ToyProps {
|
||||
}
|
||||
|
||||
function Toy({ toy }: ToyProps) {
|
||||
return <span className={styles.toy}></span>;
|
||||
return (
|
||||
<div className={styles.toy}>
|
||||
<div className={styles.content}>
|
||||
<Text lowContrast>{toy} toy</Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Fragment, useMemo } from "react";
|
||||
import { useMemo } from "react";
|
||||
import { api } from "../../../../api/dynamic";
|
||||
import { TankopediaCharacteristics } from "../../../../components/TankopediaCharacteristics";
|
||||
import { TankopediaLoadout } from "../../../../components/TankopediaLoadout";
|
||||
@@ -6,10 +6,8 @@ import { TankopediaSandbox } from "../../../../components/TankopediaSandbox";
|
||||
import { withErrorWrapper } from "../../../../hocs/withErrorWrapper";
|
||||
import { withLocale } from "../../../../hocs/withLocale";
|
||||
import { useAwait } from "../../../../hooks/useAwait";
|
||||
import { useCharacteristicRenderer } from "../../../../hooks/useCharacteristicRenderer";
|
||||
import { useEquipment } from "../../../../hooks/useEquipment";
|
||||
import { Tankopedia } from "../../../../stores/tankopedia";
|
||||
import { characteristicsOrder } from "../../../../tankopedia/characteristicsOrder";
|
||||
import { computeCharacteristics } from "../../../../tankopedia/computeCharacteristics";
|
||||
import styles from "./_index.module.css";
|
||||
|
||||
@@ -50,62 +48,3 @@ export const Page = withErrorWrapper(
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
export const _Page = withErrorWrapper(
|
||||
withLocale<PageProps>(({ id }) => {
|
||||
const protagonistTank = useAwait(() => api.tank(id), `tank-${id}`);
|
||||
|
||||
Tankopedia.useInitialization(protagonistTank);
|
||||
|
||||
const renderCharacteristic = useCharacteristicRenderer();
|
||||
|
||||
const protagonist = Tankopedia.use((state) => state.protagonist);
|
||||
const protagonistEquipment = useEquipment(protagonistTank.tank!);
|
||||
|
||||
const { characteristics } = useMemo(
|
||||
() =>
|
||||
computeCharacteristics(
|
||||
protagonistTank,
|
||||
protagonistEquipment,
|
||||
protagonist,
|
||||
),
|
||||
[protagonist],
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>{protagonist.id}</h1>
|
||||
|
||||
<br />
|
||||
|
||||
<TankopediaLoadout characteristics={characteristics} />
|
||||
|
||||
<h2>characteristics</h2>
|
||||
|
||||
{characteristicsOrder.map((group) => {
|
||||
return (
|
||||
<Fragment key={group.group}>
|
||||
<h3>{group.group}</h3>
|
||||
|
||||
{group.order.map((item) => {
|
||||
if ("toy" in item) {
|
||||
return <span key={`toy-${item.toy}`}>toy: {item.toy}</span>;
|
||||
}
|
||||
|
||||
const value = characteristics[item.name];
|
||||
|
||||
if (value == null) return null;
|
||||
|
||||
return (
|
||||
<span key={`characteristic-${item.name}`}>
|
||||
{item.name}: {renderCharacteristic(value, item)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}),
|
||||
);
|
||||
@@ -23,6 +23,7 @@ const { id, locale } = Astro.props;
|
||||
<ColorScale color="red" />
|
||||
<ColorScale color="jade" />
|
||||
<ColorScale color="amber" />
|
||||
<ColorScale color="amber" alpha />
|
||||
|
||||
<Page {locale} {id} client:load />
|
||||
</BaseLayout>
|
||||
@@ -419,4 +419,60 @@ export const characteristics = {
|
||||
compensation({ tank }) {
|
||||
return tank.compensation!.compensation?.currency_reward?.amount ?? null;
|
||||
},
|
||||
|
||||
purchase_price() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
upgrade_price() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
research_level() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
crew_xp_multiplier() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
clipping_potential() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
burst_size() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
intra_burst() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
dispersion_angle() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
gun_yaw_range() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
brake_force() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
gun_traverse_speed() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
fire_health_burn() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
ramming_resistance() {
|
||||
return -Infinity;
|
||||
},
|
||||
|
||||
width() {
|
||||
return -Infinity;
|
||||
},
|
||||
} satisfies Record<string, Characteristic>;
|
||||
@@ -29,19 +29,25 @@ export interface CharacteristicRenderConfig {
|
||||
}) => ReactNode;
|
||||
}
|
||||
|
||||
export interface ToyRenderConfig {
|
||||
toy: string;
|
||||
}
|
||||
|
||||
export type CharacteristicsGroup = {
|
||||
group: string;
|
||||
order: (
|
||||
| CharacteristicRenderConfig
|
||||
| {
|
||||
toy: string;
|
||||
}
|
||||
)[];
|
||||
render: CharacteristicsGroupRender;
|
||||
order: (CharacteristicRenderConfig | ToyRenderConfig)[];
|
||||
};
|
||||
|
||||
export enum CharacteristicsGroupRender {
|
||||
Flashy,
|
||||
Statistical,
|
||||
}
|
||||
|
||||
export const characteristicsOrder: CharacteristicsGroup[] = [
|
||||
{
|
||||
group: "meta",
|
||||
render: CharacteristicsGroupRender.Flashy,
|
||||
order: [
|
||||
{
|
||||
name: "name",
|
||||
@@ -80,15 +86,29 @@ export const characteristicsOrder: CharacteristicsGroup[] = [
|
||||
return strings.tiers[name as keyof typeof strings.tiers];
|
||||
},
|
||||
},
|
||||
{ name: "compensation" },
|
||||
{ name: "id" },
|
||||
{ name: "slug" },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "firepower",
|
||||
group: "economics",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ name: "purchase_price" },
|
||||
{ name: "compensation" },
|
||||
{ name: "upgrade_price" },
|
||||
{ name: "research_level" },
|
||||
{ name: "crew_xp_multiplier" },
|
||||
|
||||
// TODO: investigate ATTRIBUTE_NAME_CREW_XP_MULTIPLIER
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "gun",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ toy: "reload" },
|
||||
{
|
||||
name: "gun_type",
|
||||
render({ output }) {
|
||||
@@ -96,75 +116,123 @@ export const characteristicsOrder: CharacteristicsGroup[] = [
|
||||
},
|
||||
},
|
||||
{ name: "dpm", decimals: 0, units: "hp_min" },
|
||||
{ name: "damage", units: "hp" },
|
||||
{ name: "module_damage", units: "hp" },
|
||||
{ name: "reload", decimals: 2, units: "s" },
|
||||
{ name: "reloads", decimals: 2, units: "s" },
|
||||
|
||||
{ name: "damage", units: "hp" },
|
||||
{ name: "module_damage", units: "hp" },
|
||||
{ toy: "reload" },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "clip",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ name: "clipping_potential" },
|
||||
{ name: "clip_size" },
|
||||
{ name: "optimal_shell" },
|
||||
{ name: "intra_clip", decimals: 2, units: "s" },
|
||||
// { name: "burst_size" }, // TODO: implement burst size
|
||||
// { name: 'intra_burst', decimals: 2, units: "s" }, // TODO: implement intra burst
|
||||
{ name: "burst_size" },
|
||||
{ name: "intra_burst", decimals: 2, units: "s" },
|
||||
|
||||
// TODO: investigate ATTRIBUTE_NAME_SHELLS_SLOTS
|
||||
// TODO: investigate ATTRIBUTE_NAME_RELOAD_SPEED_SCALE
|
||||
// TODO: investigate ATTRIBUTE_NAME_AVERAGE_THICKNESS
|
||||
// TODO: investigate ATTRIBUTE_NAME_TRACER_SHELLS_OBSERVATION_TIMEOUT
|
||||
],
|
||||
},
|
||||
|
||||
// { toy: "ricochet" },
|
||||
{
|
||||
group: "shell",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ name: "penetration", units: "mm" },
|
||||
{ name: "shell_velocity", units: "m_s" },
|
||||
{ name: "shell_range", units: "m" },
|
||||
{ name: "shell_capacity" },
|
||||
{ name: "caliber", units: "mm" },
|
||||
{ name: "normalization", units: "deg" },
|
||||
{ name: "ricochet", units: "deg" },
|
||||
|
||||
{ name: "shell_velocity", units: "m_s" },
|
||||
{ name: "shell_range", units: "m" },
|
||||
{ name: "shell_capacity" },
|
||||
|
||||
// { toy: "aim_time" },
|
||||
{ name: "aim_time", decimals: 1, units: "s" },
|
||||
{ name: "dispersion", decimals: 3, units: "m" },
|
||||
// { name: "dispersion_angle", decimals: 3, units: "m" }, // TODO: implement dispersion angle
|
||||
|
||||
// { toy: "flexibility" },
|
||||
{ name: "gun_depression", decimals: 0, units: "deg" },
|
||||
{ name: "gun_elevation", decimals: 0, units: "deg" },
|
||||
// { name: "gun_yaw_range", decimals: 0, units: "deg" }, // TODO: implement gun yaw range
|
||||
{ toy: "ricochet" },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "accuracy",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ name: "aim_time", decimals: 1, units: "s" },
|
||||
{ name: "dispersion", decimals: 3, units: "m" },
|
||||
{ name: "dispersion_angle", decimals: 3, units: "m" },
|
||||
{ toy: "aim_time" },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "flexibility",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ name: "gun_depression", decimals: 0, units: "deg" },
|
||||
{ name: "gun_elevation", decimals: 0, units: "deg" },
|
||||
{ name: "gun_yaw_range", decimals: 0, units: "deg" },
|
||||
|
||||
{ toy: "flexibility" },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "maneuverability",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
// { toy: "traverse" },
|
||||
{ name: "speed_forward", units: "km_h" },
|
||||
{ name: "speed_backward", units: "km_h" },
|
||||
|
||||
{ name: "engine_power", units: "bhp" },
|
||||
// { name: "brake_force", units: "N" }, // TODO: implement brake force
|
||||
{ name: "brake_force", units: "N" },
|
||||
{ name: "weight", decimals: 1, units: "t" },
|
||||
|
||||
{ name: "terrain_coefficient" },
|
||||
{ name: "power_to_weight", decimals: 1, units: "bhp_t" },
|
||||
|
||||
{ name: "hull_traverse_speed", units: "deg_s" },
|
||||
{ name: "turret_traverse_speed", units: "deg_s" },
|
||||
// { name: "gun_traverse_speed", units: "deg_s" }, // TODO: implement gun traverse speed
|
||||
{ name: "gun_traverse_speed", units: "deg_s" },
|
||||
|
||||
{ toy: "traverse" },
|
||||
|
||||
// TODO: investigate ATTRIBUTE_NAME_TERRAIN_SIDE_FRICTION
|
||||
// TODO: investigate ATTRIBUTE_NAME_TERRAIN_FORWARD_FRICTION
|
||||
// TODO: investigate ATTRIBUTE_NAME_RESERVE_TRACK_BACKWARD_SPEED
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "survivability",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ name: "health", units: "hp" },
|
||||
{ name: "fire_chance", units: "%" },
|
||||
// { name: "fire_health_burn", units: "hp_s" }, // TODO: implement fire health burn
|
||||
// { name: "ramming_resistance", units: "%" }, // TODO: implement ramming resistance
|
||||
{ name: "fire_health_burn", units: "hp_s" },
|
||||
{ name: "ramming_resistance", units: "%" },
|
||||
|
||||
// { toy: "view_range" },
|
||||
{ toy: "fire_health_burn" },
|
||||
|
||||
// TODO: investigate ATTRIBUTE_NAME_MAX_FIRE_DURATION
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
group: "concealment",
|
||||
render: CharacteristicsGroupRender.Statistical,
|
||||
order: [
|
||||
{ name: "view_range", units: "m" },
|
||||
{ name: "camouflage", decimals: 0, units: "%" },
|
||||
|
||||
// { name: "consumable_cooldown", decimals: 0, units: "%" }, // TODO: implement consumable cooldown
|
||||
// { name: "consumable_duration", decimals: 0, units: "s" }, // TODO: implement consumable duration
|
||||
// { name: "consumable_reload", decimals: 0, units: "s" }, // TODO: implement consumable reload
|
||||
{ toy: "view_range" },
|
||||
|
||||
// { name: "width", units: "m" }, // TODO: implement width
|
||||
{ name: "width", units: "m" },
|
||||
{ name: "height", units: "m" },
|
||||
{ name: "length", units: "m" },
|
||||
{ name: "volume", units: "m" },
|
||||
|
||||
Reference in new issue
Block a user