From 81301ab1484247e905f05faba81862d63256b5bd Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Wed, 26 Nov 2025 21:03:02 -0600 Subject: [PATCH] feat(know-your-world): move region size filters inside map preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the region type checkboxes from a standalone section into an overlay inside the map preview. The filters now appear in the bottom-right corner with a semi-transparent backdrop. - Add region size filter overlay to DrillDownMapSelector - Remove standalone region sizes section from SetupPhase - Clean up unused imports (Checkbox, REGION_SIZE_CONFIG) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../components/DrillDownMapSelector.tsx | 141 ++++++++++++++ .../know-your-world/components/SetupPhase.tsx | 179 +----------------- 2 files changed, 145 insertions(+), 175 deletions(-) diff --git a/apps/web/src/arcade-games/know-your-world/components/DrillDownMapSelector.tsx b/apps/web/src/arcade-games/know-your-world/components/DrillDownMapSelector.tsx index 03b4cd2d..13d827ad 100644 --- a/apps/web/src/arcade-games/know-your-world/components/DrillDownMapSelector.tsx +++ b/apps/web/src/arcade-games/know-your-world/components/DrillDownMapSelector.tsx @@ -1,6 +1,7 @@ 'use client' import { useState, useCallback, useMemo, useRef, useEffect } from 'react' +import * as Checkbox from '@radix-ui/react-checkbox' import { css } from '@styled/css' import { useTheme } from '@/contexts/ThemeContext' import { MapSelectorMap } from './MapSelectorMap' @@ -15,6 +16,8 @@ import { parseViewBox, calculateFitCropViewBox, getFilteredMapDataBySizesSync, + REGION_SIZE_CONFIG, + ALL_REGION_SIZES, } from '../maps' import type { RegionSize } from '../maps' import { @@ -67,6 +70,10 @@ interface DrillDownMapSelectorProps { selectedContinent: ContinentId | 'all' /** Region sizes to include (for showing excluded regions dimmed) */ includeSizes: RegionSize[] + /** Callback when region sizes change */ + onRegionSizesChange: (sizes: RegionSize[]) => void + /** Region counts per size category */ + regionCountsBySize: Record } interface BreadcrumbItem { @@ -82,6 +89,8 @@ export function DrillDownMapSelector({ selectedMap, selectedContinent, includeSizes, + onRegionSizesChange, + regionCountsBySize, }: DrillDownMapSelectorProps) { const { resolvedTheme } = useTheme() const isDark = resolvedTheme === 'dark' @@ -715,6 +724,138 @@ export function DrillDownMapSelector({ ) })()} + + {/* Region Size Filters - positioned inside map, bottom right */} +
+
+ {ALL_REGION_SIZES.map((size) => { + const config = REGION_SIZE_CONFIG[size] + const isChecked = includeSizes.includes(size) + const isOnlyOne = includeSizes.length === 1 && isChecked + const count = regionCountsBySize[size] || 0 + + const handleToggle = () => { + if (isOnlyOne) return + if (isChecked) { + onRegionSizesChange(includeSizes.filter((s) => s !== size)) + } else { + onRegionSizesChange([...includeSizes, size]) + } + } + + return ( + + {config.emoji} + + {config.label} + + + {count} + + + ) + })} +
+
{/* Peer Navigation - Mini-map thumbnails below main map (or planets at world level) */} diff --git a/apps/web/src/arcade-games/know-your-world/components/SetupPhase.tsx b/apps/web/src/arcade-games/know-your-world/components/SetupPhase.tsx index 793cf58b..343a7c64 100644 --- a/apps/web/src/arcade-games/know-your-world/components/SetupPhase.tsx +++ b/apps/web/src/arcade-games/know-your-world/components/SetupPhase.tsx @@ -2,25 +2,14 @@ import { useCallback, useMemo } from 'react' import * as Select from '@radix-ui/react-select' -import * as Checkbox from '@radix-ui/react-checkbox' import { css } from '@styled/css' import { useTheme } from '@/contexts/ThemeContext' import { useKnowYourWorld } from '../Provider' import { DrillDownMapSelector } from './DrillDownMapSelector' -import { - ALL_REGION_SIZES, - ASSISTANCE_LEVELS, - getFilteredMapDataBySizesSync, - REGION_SIZE_CONFIG, -} from '../maps' -import type { RegionSize, AssistanceLevelConfig } from '../maps' +import { ALL_REGION_SIZES, ASSISTANCE_LEVELS, getFilteredMapDataBySizesSync } from '../maps' +import type { AssistanceLevelConfig } from '../maps' import type { ContinentId } from '../continents' -// Get term for regions based on map type -function getRegionTerm(selectedMap: 'world' | 'usa'): string { - return selectedMap === 'world' ? 'countries' : 'states' -} - // Generate feature badges for an assistance level function getFeatureBadges(level: AssistanceLevelConfig): Array<{ label: string; icon: string }> { const badges: Array<{ label: string; icon: string }> = [] @@ -124,14 +113,6 @@ export function SetupPhase() { return counts }, [state.selectedMap, state.selectedContinent]) - // Calculate the total region count for current selection - const totalRegionCount = useMemo(() => { - return state.includeSizes.reduce((sum, size) => sum + (regionCountsBySize[size] || 0), 0) - }, [state.includeSizes, regionCountsBySize]) - - // Get the term for regions (countries/states) - const regionTerm = getRegionTerm(state.selectedMap) - // Handle selection change from drill-down selector const handleSelectionChange = useCallback( (mapId: 'world' | 'usa', continentId: ContinentId | 'all') => { @@ -146,20 +127,6 @@ export function SetupPhase() { const selectedStudyTime = STUDY_TIME_OPTIONS.find((opt) => opt.value === state.studyDuration) const selectedAssistance = ASSISTANCE_LEVELS.find((level) => level.id === state.assistanceLevel) - // Handle toggling a region size - const toggleRegionSize = useCallback( - (size: RegionSize) => { - if (state.includeSizes.includes(size)) { - // Don't allow removing the last size - if (state.includeSizes.length === 1) return - setRegionSizes(state.includeSizes.filter((s) => s !== size)) - } else { - setRegionSizes([...state.includeSizes, size]) - } - }, - [state.includeSizes, setRegionSizes] - ) - // Styles for Radix Select components const triggerStyles = css({ display: 'flex', @@ -270,6 +237,8 @@ export function SetupPhase() { onSelectionChange={handleSelectionChange} onStartGame={startGame} includeSizes={state.includeSizes} + onRegionSizesChange={setRegionSizes} + regionCountsBySize={regionCountsBySize} /> @@ -563,146 +532,6 @@ export function SetupPhase() { - {/* Region Types Selection */} -
-
- - - {totalRegionCount} {regionTerm} selected - -
-
- {ALL_REGION_SIZES.map((size) => { - const config = REGION_SIZE_CONFIG[size] - const isChecked = state.includeSizes.includes(size) - const isOnlyOne = state.includeSizes.length === 1 && isChecked - const count = regionCountsBySize[size] || 0 - - return ( - toggleRegionSize(size)} - disabled={isOnlyOne} - className={css({ - display: 'inline-flex', - alignItems: 'center', - gap: '2', - paddingX: '3', - paddingY: '2', - bg: isChecked - ? isDark - ? 'blue.800' - : 'blue.500' - : isDark - ? 'gray.700' - : 'white', - border: '1px solid', - borderColor: isChecked - ? isDark - ? 'blue.600' - : 'blue.600' - : isDark - ? 'gray.600' - : 'gray.300', - rounded: 'full', - cursor: isOnlyOne ? 'not-allowed' : 'pointer', - opacity: isOnlyOne ? 0.5 : 1, - transition: 'all 0.15s', - _hover: isOnlyOne - ? {} - : { - bg: isChecked - ? isDark - ? 'blue.700' - : 'blue.600' - : isDark - ? 'gray.600' - : 'gray.100', - }, - _focus: { - outline: 'none', - boxShadow: '0 0 0 2px rgba(59, 130, 246, 0.3)', - }, - })} - > - {config.emoji} - - {config.label} - - - {count} - - - ) - })} -
-
- {/* Tips Section */}