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 22ccb3cb..0a8404f8 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 @@ -36,7 +36,6 @@ import { filterRegionsBySizes, calculateSafeZoneViewBox, type SafeZoneMargins, - ASSISTANCE_LEVELS, } from '../maps' import { getCustomCrop } from '../customCrops' import type { RegionSize, ImportanceLevel, PopulationLevel, FilterCriteria } from '../maps' @@ -54,6 +53,7 @@ import { populationToRange, rangeToPopulation, } from '../utils/regionSizeUtils' +import { preventFlexExpansion } from '../utils/responsiveStyles' /** * Safe zone margins - must match MapRenderer for consistent positioning @@ -143,19 +143,6 @@ const PLANETS: PlanetData[] = [ { id: 'saturn', name: 'Saturn', color: '#ead6b8', size: 1.7, hasRings: true }, ] -/** Game mode options */ -type GameMode = 'cooperative' | 'race' | 'turn-based' - -/** Assistance level options */ -type AssistanceLevel = 'learning' | 'guided' | 'helpful' | 'standard' | 'none' - -/** Game mode display options */ -const GAME_MODE_OPTIONS: Array<{ value: GameMode; emoji: string; label: string }> = [ - { value: 'cooperative', emoji: '🤝', label: 'Co-op' }, - { value: 'race', emoji: '🏁', label: 'Race' }, - { value: 'turn-based', emoji: '↔️', label: 'Turns' }, -] - interface DrillDownMapSelectorProps { /** Callback when selection changes (map/continent for game start) */ onSelectionChange: (mapId: 'world' | 'usa', continentId: ContinentId | 'all') => void @@ -173,14 +160,6 @@ interface DrillDownMapSelectorProps { regionCountsBySize: Record /** When true, fills parent container and uses overlay positioning for UI elements */ fillContainer?: boolean - /** Current game mode (for unified controls in fillContainer mode) */ - gameMode?: GameMode - /** Callback when game mode changes */ - onGameModeChange?: (mode: GameMode) => void - /** Current assistance level (for unified controls in fillContainer mode) */ - assistanceLevel?: AssistanceLevel - /** Callback when assistance level changes */ - onAssistanceLevelChange?: (level: AssistanceLevel) => void } interface BreadcrumbItem { @@ -199,10 +178,6 @@ export function DrillDownMapSelector({ onRegionSizesChange, regionCountsBySize, fillContainer = false, - gameMode, - onGameModeChange, - assistanceLevel, - onAssistanceLevelChange, }: DrillDownMapSelectorProps) { const { resolvedTheme } = useTheme() const isDark = resolvedTheme === 'dark' @@ -1340,8 +1315,8 @@ export function DrillDownMapSelector({ rounded: 'xl', shadow: 'lg', width: '205px', - maxHeight: { base: 'none', md: fillContainer ? 'calc(100vh - 200px)' : 'none' }, - overflowY: 'auto', + maxHeight: { base: 'none', md: fillContainer ? '450px' : 'none' }, + overflow: 'hidden', })} > {/* Filter Criteria Tabs */} @@ -1522,157 +1497,6 @@ export function DrillDownMapSelector({ /> )} - - {/* Game Mode & Assistance Level - only in fillContainer mode */} - {fillContainer && gameMode && onGameModeChange && ( -
- {/* Game Mode Selector */} -
-
- Mode -
-
- {GAME_MODE_OPTIONS.map((option) => { - const isActive = gameMode === option.value - return ( - - ) - })} -
-
- - {/* Assistance Level Selector */} - {assistanceLevel && onAssistanceLevelChange && ( -
-
- Assistance -
-
- {ASSISTANCE_LEVELS.map((level) => { - const isActive = assistanceLevel === level.id - return ( - - ) - })} -
-
- )} -
- )} 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 86fb9e92..4d6c932e 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 @@ -1,11 +1,13 @@ 'use client' import { useCallback, useMemo } from 'react' +import * as Select from '@radix-ui/react-select' import { css } from '@styled/css' import { useTheme } from '@/contexts/ThemeContext' import { useKnowYourWorld } from '../Provider' import { DrillDownMapSelector } from './DrillDownMapSelector' -import { ALL_REGION_SIZES, getFilteredMapDataBySizesSync } from '../maps' +import { ALL_REGION_SIZES, ASSISTANCE_LEVELS, getFilteredMapDataBySizesSync } from '../maps' +import type { AssistanceLevelConfig } from '../maps' import { CONTINENTS, type ContinentId } from '../continents' // Travel-themed content for each region @@ -78,6 +80,49 @@ const REGION_THEMES: Record = { const DEFAULT_THEME: RegionTheme = REGION_THEMES.World +// Generate feature badges for an assistance level +function getFeatureBadges(level: AssistanceLevelConfig): Array<{ label: string; icon: string }> { + const badges: Array<{ label: string; icon: string }> = [] + + if (level.hotColdEnabled) { + badges.push({ label: 'Hot/cold', icon: '🔥' }) + } + + if (level.hintsMode === 'onRequest') { + if (level.autoHintDefault) { + badges.push({ label: 'Auto-hints', icon: '💡' }) + } else { + badges.push({ label: 'Hints', icon: '💡' }) + } + } else if (level.hintsMode === 'limited' && level.hintLimit) { + badges.push({ label: `${level.hintLimit} hints`, icon: '💡' }) + } + + return badges +} + +// Game mode options +const GAME_MODE_OPTIONS = [ + { + value: 'cooperative' as const, + emoji: '🤝', + label: 'Cooperative', + description: 'Work together to find all regions', + }, + { + value: 'race' as const, + emoji: '🏁', + label: 'Race', + description: 'First to click the correct region wins', + }, + { + value: 'turn-based' as const, + emoji: '↔️', + label: 'Turn-Based', + description: 'Take turns finding regions', + }, +] + export function SetupPhase() { const { resolvedTheme } = useTheme() const isDark = resolvedTheme === 'dark' @@ -111,6 +156,11 @@ export function SetupPhase() { [setMap, setContinent] ) + // Get selected options for display + const selectedMode = GAME_MODE_OPTIONS.find((opt) => opt.value === state.gameMode) + const selectedAssistance = ASSISTANCE_LEVELS.find((level) => level.id === state.assistanceLevel) + const selectedAssistanceBadges = selectedAssistance ? getFeatureBadges(selectedAssistance) : [] + // Calculate total region count for start button const totalRegionCount = useMemo(() => { return state.includeSizes.reduce((sum, size) => sum + (regionCountsBySize[size] || 0), 0) @@ -130,6 +180,57 @@ export function SetupPhase() { return REGION_THEMES[contextLabel] ?? DEFAULT_THEME }, [contextLabel]) + // Card trigger styles - responsive dimensions + // On mobile, full width in vertical stack; on desktop, fixed width in horizontal row + const cardTriggerStyles = css({ + display: 'flex', + alignItems: 'center', + gap: { base: '1.5', sm: '3' }, + padding: { base: '1.5', sm: '3' }, + bg: isDark ? 'gray.700/80' : 'white/80', + rounded: 'xl', + cursor: 'pointer', + transition: 'all 0.15s', + width: { base: '160px', sm: '220px' }, + height: { base: '48px', sm: '72px' }, + textAlign: 'left', + _hover: { + bg: isDark ? 'gray.600/90' : 'white', + }, + _focus: { + outline: 'none', + ring: '2px solid', + ringColor: 'blue.500', + }, + }) + + const contentStyles = css({ + bg: isDark ? 'gray.800' : 'white', + border: '1px solid', + borderColor: isDark ? 'gray.600' : 'gray.200', + rounded: 'xl', + shadow: 'xl', + overflow: 'hidden', + zIndex: 1000, + minWidth: '280px', + }) + + const itemStyles = css({ + display: 'flex', + alignItems: 'center', + gap: '3', + padding: '3', + cursor: 'pointer', + outline: 'none', + transition: 'all 0.1s', + _hover: { + bg: isDark ? 'gray.700' : 'blue.50', + }, + '&[data-state="checked"]': { + bg: isDark ? 'blue.900/50' : 'blue.100', + }, + }) + return (
- {/* Start Button - centered at bottom */} + {/* TOP-RIGHT: Settings Panel - positioned like gameplay controls */}
+
+ {/* Game Mode Selector */} + setMode(value as 'cooperative' | 'race' | 'turn-based')} + > + + + {selectedMode?.emoji} + +
+
+ + {selectedMode?.label} + + + ▼ + +
+
+ {selectedMode?.description} +
+
+
+ + + + {GAME_MODE_OPTIONS.map((option) => ( + + {option.emoji} +
+ + + {option.label} + + +
+ {option.description} +
+
+
+ ))} +
+
+
+
+ + {/* Assistance Level Selector */} + + setAssistanceLevel(value as 'learning' | 'guided' | 'helpful' | 'standard' | 'none') + } + > + + + {selectedAssistance?.emoji || '💡'} + +
+
+ + {selectedAssistance?.label} + + + ▼ + +
+
+ {selectedAssistance?.description} +
+ {selectedAssistanceBadges.length > 0 && ( +
+ {selectedAssistanceBadges.map((badge) => ( + + {badge.icon} {badge.label} + + ))} +
+ )} +
+
+ + + + {ASSISTANCE_LEVELS.map((level) => { + const badges = getFeatureBadges(level) + return ( + + {level.emoji} +
+ + + {level.label} + + +
+ {level.description} +
+ {badges.length > 0 && ( +
+ {badges.map((badge) => ( + + {badge.icon} {badge.label} + + ))} +
+ )} +
+
+ ) + })} +
+
+
+
+
+
+ + {/* BOTTOM-CENTER: Start Button - positioned prominently */} +