From c311a6ab8befce65f02439e4fb8ce07072cf2b4a Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Sat, 14 Nov 2026 01:17:38 -0600 Subject: [PATCH] migrate compare and tankopedia loadout to new data-driven components, splitting the old monolithic loadout and compare UI into smaller pieces and adding shared Table, Dialog and Scroller primitives --- packages/core/src/blitz/permanentSkills.tsx | 12 +- packages/core/src/blitzkit/index.ts | 2 +- packages/i18n/strings/en.json | 39 + .../website/src/components/BaseStyles.astro | 3 - .../src/components/Button/index.module.css | 70 +- .../website/src/components/Button/index.tsx | 2 +- .../website/src/components/CanvasControl.tsx | 94 +- .../CharacteristicValue/index.module.css | 5 + .../components/CharacteristicValue/index.tsx | 32 + .../src/components/Checkbox/index.module.css | 38 +- .../website/src/components/Checkbox/index.tsx | 17 +- .../website/src/components/Compare/Body.tsx | 326 ----- .../src/components/Compare/CompareRow.tsx | 172 --- .../Compare/CompareSectionTitle.tsx | 22 - .../src/components/Compare/CompareTable.tsx | 654 ---------- .../src/components/Compare/Controls.tsx | 142 --- .../Compare/IntersectionMarker/constants.ts | 2 - .../Compare/IntersectionMarker/index.tsx | 40 - .../src/components/Compare/TankControl.tsx | 83 -- .../CompareControls/index.module.css | 13 + .../src/components/CompareControls/index.tsx | 124 ++ .../CompareEnvironment/index.module.css | 34 + .../components/CompareEnvironment/index.tsx | 85 ++ .../CompareInsertionMarker/constants.ts | 4 + .../CompareInsertionMarker/index.module.css | 14 + .../CompareInsertionMarker/index.tsx | 24 + .../CompareLoadout/index.module.css | 72 ++ .../src/components/CompareLoadout/index.tsx | 358 ++++++ .../components/CompareTable/index.module.css | 41 + .../src/components/CompareTable/index.tsx | 380 ++++++ .../CompareTankCard/index.module.css | 48 +- .../src/components/CompareTankCard/index.tsx | 66 +- .../CompareTankControl/index.module.css | 5 + .../components/CompareTankControl/index.tsx | 81 ++ .../src/components/ConsumablesManager.tsx | 72 -- .../src/components/CrewSkillManager.tsx | 57 - .../components/CustomShellButton/index.tsx | 13 +- .../website/src/components/DamageWarning.tsx | 28 - .../src/components/Dialog/index.module.css | 61 + .../website/src/components/Dialog/index.tsx | 30 + .../components/DropdownMenu/index.module.css | 1 + .../components/EmptyState/index.module.css | 9 + .../src/components/EmptyState/index.tsx | 17 + .../src/components/EquipmentManager/index.css | 9 - .../src/components/EquipmentManager/index.tsx | 63 - .../components/IconButton/index.module.css | 9 - .../src/components/IconButton/index.tsx | 1 + .../src/components/InitialCameraAligner.tsx | 17 +- .../LoadoutConsumables/index.module.css | 32 + .../components/LoadoutConsumables/index.tsx | 124 ++ .../LoadoutEquipment/index.module.css | 21 + .../src/components/LoadoutEquipment/index.tsx | 125 ++ .../LoadoutModules/index.module.css | 111 ++ .../src/components/LoadoutModules/index.tsx | 317 +++++ .../LoadoutProvisions/index.module.css | 13 + .../components/LoadoutProvisions/index.tsx | 112 ++ .../LoadoutSection/index.module.css | 18 + .../src/components/LoadoutSection/index.tsx | 27 + .../components/LoadoutShells/index.module.css | 3 + .../src/components/LoadoutShells/index.tsx | 48 + .../components/LoadoutSkills/index.module.css | 14 + .../src/components/LoadoutSkills/index.tsx | 109 ++ .../components/LoadoutStatus/index.module.css | 15 + .../src/components/LoadoutStatus/index.tsx | 59 + .../website/src/components/ModuleManager.tsx | 203 ---- .../src/components/PrimaryArmorScene.tsx | 41 +- .../PrimaryArmorSceneComponent/index.tsx | 11 +- .../src/components/ProvisionsManager.tsx | 52 - .../src/components/Scroller/index.module.css | 131 +- .../website/src/components/Scroller/index.tsx | 306 ++++- .../src/components/SpacedArmorScene.tsx | 53 +- .../components/SpacedArmorSceneComponent.tsx | 8 +- .../SpacedArmorSubExternal/index.tsx | 12 +- .../components/SpacedArmorSubSpaced/index.tsx | 12 +- .../components/StaticArmorSceneComponent.tsx | 9 +- .../src/components/Table/index.module.css | 85 ++ .../website/src/components/Table/index.tsx | 138 +++ packages/website/src/components/TankModel.tsx | 29 +- .../src/components/TankStaticArmor.tsx | 71 +- .../TankopediaAntagonistControl/index.tsx | 17 +- .../index.module.css | 6 - .../TankopediaCharacteristics/index.tsx | 23 +- .../TankopediaFlexibilityCanvas.tsx | 33 +- .../TankopediaGameModeAbilities/index.tsx | 6 +- .../TankopediaLoadout/index.module.css | 325 ----- .../components/TankopediaLoadout/index.tsx | 1064 +++-------------- .../components/TankopediaSandbox/index.tsx | 32 +- .../TankopediaSkinSwitcher/index.tsx | 10 +- .../src/components/TankopediaToys/index.tsx | 47 +- .../src/components/TankopediaVideos/index.tsx | 6 +- .../website/src/components/Tooltip/index.tsx | 15 +- .../src/core/blitzkit/tankToCompareMember.ts | 11 +- .../src/hooks/useCharacteristicRenderer.tsx | 14 +- .../src/hooks/useComparisonCharacteristics.ts | 19 +- packages/website/src/hooks/useDuel.ts | 126 -- packages/website/src/hooks/useDuelModels.ts | 14 + packages/website/src/hooks/useDuelModules.ts | 14 + .../pages/[...chunk_api]/icons/camo.webp.ts | 10 +- .../icons/consumables/[id].webp.ts | 2 - .../[...locale]/compare/_index.module.css | 28 + .../[...locale]/compare/_index.tsx | 152 +-- .../[...locale]/compare/index.astro | 12 +- .../[...locale]/guesser/_index.tsx | 7 +- .../tanks/[slug]/_index.module.css | 1 - .../[...locale]/tanks/[slug]/_index.tsx | 18 +- .../website/src/stores/compareEphemeral.ts | 31 +- .../website/src/stores/comparePersistent.ts | 2 +- .../src/tankopedia/calculateRankings.ts | 2 +- .../src/tankopedia/resolveTankModels.ts | 14 + .../src/tankopedia/resolveTankModules.ts | 17 + .../website/src/tankopedia/selectModule.ts | 48 + 111 files changed, 4009 insertions(+), 3917 deletions(-) create mode 100644 packages/website/src/components/CharacteristicValue/index.module.css create mode 100644 packages/website/src/components/CharacteristicValue/index.tsx delete mode 100644 packages/website/src/components/Compare/Body.tsx delete mode 100644 packages/website/src/components/Compare/CompareRow.tsx delete mode 100644 packages/website/src/components/Compare/CompareSectionTitle.tsx delete mode 100644 packages/website/src/components/Compare/CompareTable.tsx delete mode 100644 packages/website/src/components/Compare/Controls.tsx delete mode 100644 packages/website/src/components/Compare/IntersectionMarker/constants.ts delete mode 100644 packages/website/src/components/Compare/IntersectionMarker/index.tsx delete mode 100644 packages/website/src/components/Compare/TankControl.tsx create mode 100644 packages/website/src/components/CompareControls/index.module.css create mode 100644 packages/website/src/components/CompareControls/index.tsx create mode 100644 packages/website/src/components/CompareEnvironment/index.module.css create mode 100644 packages/website/src/components/CompareEnvironment/index.tsx create mode 100644 packages/website/src/components/CompareInsertionMarker/constants.ts create mode 100644 packages/website/src/components/CompareInsertionMarker/index.module.css create mode 100644 packages/website/src/components/CompareInsertionMarker/index.tsx create mode 100644 packages/website/src/components/CompareLoadout/index.module.css create mode 100644 packages/website/src/components/CompareLoadout/index.tsx create mode 100644 packages/website/src/components/CompareTable/index.module.css create mode 100644 packages/website/src/components/CompareTable/index.tsx create mode 100644 packages/website/src/components/CompareTankControl/index.module.css create mode 100644 packages/website/src/components/CompareTankControl/index.tsx delete mode 100644 packages/website/src/components/ConsumablesManager.tsx delete mode 100644 packages/website/src/components/CrewSkillManager.tsx delete mode 100644 packages/website/src/components/DamageWarning.tsx create mode 100644 packages/website/src/components/Dialog/index.module.css create mode 100644 packages/website/src/components/Dialog/index.tsx create mode 100644 packages/website/src/components/EmptyState/index.module.css create mode 100644 packages/website/src/components/EmptyState/index.tsx delete mode 100644 packages/website/src/components/EquipmentManager/index.css delete mode 100644 packages/website/src/components/EquipmentManager/index.tsx create mode 100644 packages/website/src/components/LoadoutConsumables/index.module.css create mode 100644 packages/website/src/components/LoadoutConsumables/index.tsx create mode 100644 packages/website/src/components/LoadoutEquipment/index.module.css create mode 100644 packages/website/src/components/LoadoutEquipment/index.tsx create mode 100644 packages/website/src/components/LoadoutModules/index.module.css create mode 100644 packages/website/src/components/LoadoutModules/index.tsx create mode 100644 packages/website/src/components/LoadoutProvisions/index.module.css create mode 100644 packages/website/src/components/LoadoutProvisions/index.tsx create mode 100644 packages/website/src/components/LoadoutSection/index.module.css create mode 100644 packages/website/src/components/LoadoutSection/index.tsx create mode 100644 packages/website/src/components/LoadoutShells/index.module.css create mode 100644 packages/website/src/components/LoadoutShells/index.tsx create mode 100644 packages/website/src/components/LoadoutSkills/index.module.css create mode 100644 packages/website/src/components/LoadoutSkills/index.tsx create mode 100644 packages/website/src/components/LoadoutStatus/index.module.css create mode 100644 packages/website/src/components/LoadoutStatus/index.tsx delete mode 100644 packages/website/src/components/ModuleManager.tsx delete mode 100644 packages/website/src/components/ProvisionsManager.tsx create mode 100644 packages/website/src/components/Table/index.module.css create mode 100644 packages/website/src/components/Table/index.tsx delete mode 100644 packages/website/src/components/TankopediaLoadout/index.module.css delete mode 100644 packages/website/src/hooks/useDuel.ts create mode 100644 packages/website/src/hooks/useDuelModels.ts create mode 100644 packages/website/src/hooks/useDuelModules.ts create mode 100644 packages/website/src/pages/[...chunk_default]/[...locale]/compare/_index.module.css create mode 100644 packages/website/src/tankopedia/resolveTankModels.ts create mode 100644 packages/website/src/tankopedia/resolveTankModules.ts create mode 100644 packages/website/src/tankopedia/selectModule.ts diff --git a/packages/core/src/blitz/permanentSkills.tsx b/packages/core/src/blitz/permanentSkills.tsx index ebf2c6f05..674edd7f8 100644 --- a/packages/core/src/blitz/permanentSkills.tsx +++ b/packages/core/src/blitz/permanentSkills.tsx @@ -1,8 +1,8 @@ export const permanentSkills = [ - 'smooth_turn', - 'soft_recoil', - 'smooth_driving', - 'smooth_turret', - 'virtuoso', - 'camouflage', + "smooth_turn", + "soft_recoil", + "smooth_driving", + "smooth_turret", + "virtuoso", + "camouflage", ]; diff --git a/packages/core/src/blitzkit/index.ts b/packages/core/src/blitzkit/index.ts index 0ef532686..1aba18434 100644 --- a/packages/core/src/blitzkit/index.ts +++ b/packages/core/src/blitzkit/index.ts @@ -24,9 +24,9 @@ export * from "./romanize"; export * from "./sluggify"; export * from "./staticAsset"; export * from "./sum"; +export * from "./tankBoundingBox"; export * from "./tankDefinitions"; export * from "./tankEnvironment"; -export * from "./tankBoundingBox"; export * from "./tankIcon"; export * from "./tankNames"; export * from "./unionBoundingBox"; diff --git a/packages/i18n/strings/en.json b/packages/i18n/strings/en.json index 8d26e139c..d6d530a7e 100644 --- a/packages/i18n/strings/en.json +++ b/packages/i18n/strings/en.json @@ -20,6 +20,37 @@ "clear": "Clear" }, + "compare": { + "no_tanks": { + "title": "No tanks to compare", + "body": "Add a tank to get started" + }, + "add": { + "button": "Add", + "title": "Add tank", + "description": "Select a tank to add to the comparison" + }, + "swap_dialog": { + "title": "Swap tank", + "description": "Select a tank to replace this one" + }, + "clear": "Clear", + "deltas": { + "label": "Deltas", + "none": "No deltas", + "percentage": "Percentage", + "absolute": "Absolute" + }, + "sync_shells": "Sync shells", + "equalize": "Equalize", + "loadout": "Loadout", + "stock": "Stock", + "apply_to_all": "Apply to all", + "remove": "Remove", + "swap": "Swap", + "open": "Open in Tankopedia" + }, + "units": { "m": "{value}m", "mm": "{value}mm", @@ -257,10 +288,18 @@ "consumables": "Consumables", "provisions": "Provisions", "modules": "Modules", + "camouflage": "Camouflage", + "module_types": { + "turret": "Turret", + "gun": "Gun", + "engine": "Engine", + "chassis": "Chassis" + }, "equipment": "Equipment", "shells": "Shells", "clear": "Clear", "maximize": "Maximize", + "stock": "Stock", "skills": "Crew skills", "alternative": "Alt" }, diff --git a/packages/website/src/components/BaseStyles.astro b/packages/website/src/components/BaseStyles.astro index 00b37a559..6fd35b30f 100644 --- a/packages/website/src/components/BaseStyles.astro +++ b/packages/website/src/components/BaseStyles.astro @@ -18,9 +18,6 @@ import "@fontsource-variable/roboto-flex"; --page-width: 64rem; - /* idk how to actually get or apply this without uglifying the scrollbar */ - --scrollbar-width: 15px; - --max-size: max(100vw, 100vh); --radius-max: var(--max-size); diff --git a/packages/website/src/components/Button/index.module.css b/packages/website/src/components/Button/index.module.css index e9969a087..b192233d3 100644 --- a/packages/website/src/components/Button/index.module.css +++ b/packages/website/src/components/Button/index.module.css @@ -1,36 +1,44 @@ .button { - display: flex; - align-items: center; - justify-content: center; - gap: var(--space-3); - - border-radius: var(--max-size); - padding: var(--space-3) var(--space-4); - border: none; - font-family: var(--font-family-regular); - font-size: var(--font-size-regular); - color: var(--gray-1); - font-weight: var(--weight-medium); + display: flex; + align-items: center; + gap: var(--space-3); cursor: pointer; - &[data-even-padding] { - padding: var(--space-3); + &[data-size="minor"] { + --padding: var(--space-2); + --content-size: calc(0.85 * var(--font-size-regular)); } - &[data-size="minor"] { - font-size: var(--font-size-minor); - padding: var(--space-2) var(--space-3); - - &[data-even-padding] { - padding: var(--space-2); - } + &[data-size="regular"] { + --padding: var(--space-3); + --content-size: calc(1 * var(--font-size-regular)); } &[data-size="major"] { - font-size: var(--font-size-major); + --padding: var(--space-3); + --content-size: calc(1.5 * var(--font-size-regular)); + } + + padding: var(--padding) calc(2 * var(--padding)); + font-size: var(--content-size); + + &[data-even-padding="true"] { + padding: var(--padding); + } + + &[data-variant="ghost"] { + padding: 0; + } + + img, + svg { + width: 1em; + height: 1em; + + object-fit: contain; } &[data-list-child="horizontal"]:not(:first-child), @@ -65,12 +73,10 @@ border-bottom-width: var(--space-0); } - svg, - img { - width: 1.25em; - height: 1.25em; - - object-fit: contain; + &[data-variant="surface"], + &[data-variant="soft"] { + background-color: var(--accent-a3); + color: var(--gray-12); } &[data-light-text="true"] { @@ -100,11 +106,11 @@ &[data-variant="ghost"], &[data-variant="outline"] { background: none; - color: var(--accent-12); - } + color: var(--accent-11); - &[data-variant="ghost"] { - padding: 0; + &[data-high-contrast="true"] { + color: var(--accent-12); + } } &[data-variant="surface"], diff --git a/packages/website/src/components/Button/index.tsx b/packages/website/src/components/Button/index.tsx index f16398efd..dc85414ea 100644 --- a/packages/website/src/components/Button/index.tsx +++ b/packages/website/src/components/Button/index.tsx @@ -37,7 +37,7 @@ export function Button({ style, radius = "max", size = "regular", - evenPadding, + evenPadding = false, listChild, parentListChild, diff --git a/packages/website/src/components/CanvasControl.tsx b/packages/website/src/components/CanvasControl.tsx index e1ad3a771..796ebe167 100644 --- a/packages/website/src/components/CanvasControl.tsx +++ b/packages/website/src/components/CanvasControl.tsx @@ -2,14 +2,14 @@ import { I_HAT, J_HAT } from "@blitzkit/core"; import { OrbitControls } from "@react-three/drei"; import { invalidate, useFrame, useThree } from "@react-three/fiber"; import type { QuicklimeEvent } from "quicklime"; -import { useEffect, useRef } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { PerspectiveCamera, Vector3 } from "three"; import { OrbitControls as OrbitControlsClass } from "three-stdlib"; -import { api } from "../api/dynamic"; import { applyPitchYawLimits } from "../core/blitz/applyPitchYawLimits"; import { Pose, poseEvent } from "../core/blitzkit/pose"; import { controlsEnabledEvent } from "../core/controlsEnabled"; -import { DuelModule, getDuel, useDuel } from "../hooks/useDuel"; +import { useDuelModels } from "../hooks/useDuelModels"; +import { getDuelModules, useDuelModules } from "../hooks/useDuelModules"; import { hasEquipment } from "../hooks/useEquipment"; import { Tankopedia } from "../stores/tankopedia"; @@ -21,8 +21,6 @@ const poseDistances: Record = { const inspectModeInitialPosition = new Vector3(-8, 2, -13); -const modelDefinitions = await api.models(); - interface ControlsProps { autoRotate?: boolean; zoomable?: boolean; @@ -37,42 +35,46 @@ export function CanvasControl({ const camera = useThree((state) => state.camera as PerspectiveCamera); const canvas = useThree((state) => state.gl.domElement); const orbitControls = useRef(null); - const protagonistTurret = useDuel("protagonist", DuelModule.Turret); - const antagonistTurret = useDuel("antagonist", DuelModule.Turret); - const protagonistTrack = useDuel("protagonist", DuelModule.Track); - const protagonistTank = useDuel("protagonist", DuelModule.Tank); - const antagonistTank = useDuel("antagonist", DuelModule.Tank); - const protagonistGun = useDuel("protagonist", DuelModule.Gun); - const protagonistModelDefinition = - modelDefinitions.models[protagonistTank.id]; - const protagonistTrackModelDefinition = - modelDefinitions.models[protagonistTank.id].tracks[protagonistTrack.id]; - const antagonistModelDefinition = modelDefinitions.models[antagonistTank.id]; - const protagonistTurretModelDefinition = - protagonistModelDefinition.turrets[protagonistTurret.id]; - const antagonistTurretModelDefinition = - antagonistModelDefinition.turrets[antagonistTurret.id]; - const protagonistGunModelDefinition = - protagonistTurretModelDefinition.guns[protagonistGun.id]; - const protagonistHullOrigin = new Vector3( - protagonistTrackModelDefinition.origin!.x, - protagonistTrackModelDefinition.origin!.y, - -protagonistTrackModelDefinition.origin!.z, + const protagonist = useDuelModules("protagonist"); + const antagonist = useDuelModules("antagonist"); + const protagonistModels = useDuelModels("protagonist"); + const antagonistModels = useDuelModels("antagonist"); + + const protagonistHullOrigin = useMemo( + () => + new Vector3( + protagonistModels.track.origin!.x, + protagonistModels.track.origin!.y, + -protagonistModels.track.origin!.z, + ), + [protagonistModels.track], ); - const protagonistTurretOrigin = new Vector3( - protagonistModelDefinition.turret_origin!.x, - protagonistModelDefinition.turret_origin!.y, - -protagonistModelDefinition.turret_origin!.z, + const protagonistTurretOrigin = useMemo( + () => + new Vector3( + protagonistModels.tank.turret_origin!.x, + protagonistModels.tank.turret_origin!.y, + -protagonistModels.tank.turret_origin!.z, + ), + [protagonistModels.tank], ); - const protagonistGunOrigin = new Vector3( - protagonistTurretModelDefinition.gun_origin!.x, - protagonistTurretModelDefinition.gun_origin!.y, - -protagonistTurretModelDefinition.gun_origin!.z, + const protagonistGunOrigin = useMemo( + () => + new Vector3( + protagonistModels.turret.gun_origin!.x, + protagonistModels.turret.gun_origin!.y, + -protagonistModels.turret.gun_origin!.z, + ), + [protagonistModels.turret], ); - const antagonistGunHeight = - protagonistTrackModelDefinition.origin!.y + - antagonistModelDefinition.turret_origin!.y + - antagonistTurretModelDefinition.gun_origin!.y; + const antagonistGunHeight = useMemo( + () => + protagonistModels.track.origin!.y + + antagonistModels.tank.turret_origin!.y + + antagonistModels.turret.gun_origin!.y, + [protagonistModels.track, antagonistModels.tank, antagonistModels.turret], + ); + const disturbed = Tankopedia.use((state) => state.disturbed); const doAutoRotate = autoRotate && !disturbed; const gunHeight = @@ -89,16 +91,16 @@ export function CanvasControl({ controlsEnabledEvent.on(handleControlsEnabled); function handlePoseEvent(event: Pose) { - const protagonist = getDuel("protagonist", DuelModule.Tank); + const { tank } = getDuelModules("protagonist"); const hasImprovedVerticalStabilizer = hasEquipment( 122, - protagonist.equipment_preset, + tank.equipment_preset, Tankopedia.state.protagonist.equipment, ); const hasDownImprovedVerticalStabilizer = hasEquipment( 124, - protagonist.equipment_preset, + tank.equipment_preset, Tankopedia.state.protagonist.equipment, ); @@ -107,8 +109,8 @@ export function CanvasControl({ const [pitch] = applyPitchYawLimits( -Infinity, 0, - protagonistGunModelDefinition.pitch!, - protagonistTurretModelDefinition.yaw, + protagonistModels.gun.pitch!, + protagonistModels.turret.yaw, hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); @@ -140,8 +142,8 @@ export function CanvasControl({ const [pitch] = applyPitchYawLimits( 0, 0, - protagonistGunModelDefinition.pitch!, - protagonistTurretModelDefinition.yaw, + protagonistModels.gun.pitch!, + protagonistModels.turret.yaw, hasImprovedVerticalStabilizer, hasDownImprovedVerticalStabilizer, ); @@ -190,7 +192,7 @@ export function CanvasControl({ controlsEnabledEvent.off(handleControlsEnabled); poseEvent.off(handlePoseEvent); }; - }, [camera, protagonistTank.id, antagonistTank.id]); + }, [camera, protagonist.tank, antagonist.tank]); useEffect(() => { function handleWheel(event: WheelEvent) { diff --git a/packages/website/src/components/CharacteristicValue/index.module.css b/packages/website/src/components/CharacteristicValue/index.module.css new file mode 100644 index 000000000..89a32cd10 --- /dev/null +++ b/packages/website/src/components/CharacteristicValue/index.module.css @@ -0,0 +1,5 @@ +.value { + display: flex; + align-items: end; + gap: var(--space-1); +} diff --git a/packages/website/src/components/CharacteristicValue/index.tsx b/packages/website/src/components/CharacteristicValue/index.tsx new file mode 100644 index 000000000..76c50500c --- /dev/null +++ b/packages/website/src/components/CharacteristicValue/index.tsx @@ -0,0 +1,32 @@ +import { useCharacteristicRenderer } from "../../hooks/useCharacteristicRenderer"; +import type { + CharacteristicRenderConfig, + CharacteristicReturnType, +} from "../../types/characteristics"; +import { Text } from "../Text"; +import styles from "./index.module.css"; + +interface CharacteristicValueProps { + config: CharacteristicRenderConfig; + value: CharacteristicReturnType; + units?: boolean; +} + +export function CharacteristicValue({ + config, + value, + units = true, +}: CharacteristicValueProps) { + const renderCharacteristic = useCharacteristicRenderer(units); + const hasUnits = units && config.units !== undefined; + + return ( + + {renderCharacteristic(value, config)} + + ); +} diff --git a/packages/website/src/components/Checkbox/index.module.css b/packages/website/src/components/Checkbox/index.module.css index 3b33fe81f..6ee05df5f 100644 --- a/packages/website/src/components/Checkbox/index.module.css +++ b/packages/website/src/components/Checkbox/index.module.css @@ -3,13 +3,43 @@ align-items: center; gap: var(--space-3); - .control { - width: 1.25em; - height: 1.25em; + .Root { + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + box-sizing: border-box; + width: 1em; + height: 1em; margin: 0; + padding: 0; - accent-color: var(--accent-9); + border: none; + border-radius: var(--space-2); + background-color: var(--gray-a3); + outline: var(--space-1) solid var(--gray-a5); + color: var(--white-a12); + + &[data-state="checked"] { + background-color: var(--accent-8); + outline-color: var(--accent-8); + } + + &:focus-visible { + outline: var(--outline-focus); + } + + .Indicator { + display: flex; + width: 100%; + height: 100%; + + svg { + width: 100%; + height: 100%; + } + } } &, diff --git a/packages/website/src/components/Checkbox/index.tsx b/packages/website/src/components/Checkbox/index.tsx index d7f1c597c..add78bf3e 100644 --- a/packages/website/src/components/Checkbox/index.tsx +++ b/packages/website/src/components/Checkbox/index.tsx @@ -1,7 +1,12 @@ +import { CheckIcon } from "@radix-ui/react-icons"; +import { Checkbox as _Checkbox } from "radix-ui"; import { useId, type ReactNode } from "react"; import { Text } from "../Text"; +import { composeRadixComponents } from "../../ui/compose"; import styles from "./index.module.css"; +const _ = composeRadixComponents(_Checkbox, styles); + export interface CheckboxProps { checked: boolean; onCheckedChange(checked: boolean): void; @@ -17,13 +22,15 @@ export function Checkbox({ return (
- onCheckedChange(event.target.checked)} - /> + onCheckedChange={(value) => onCheckedChange(value === true)} + > + <_.Indicator> + + + {children && (