'use client'
import { Icon as IconifyIcon } from '@iconify/react'
import { useViewer } from '@pascal-app/viewer'
import { Check, ChevronsLeft, ChevronsRight, Columns2, Eye, Footprints, Moon, Sun } from 'lucide-react'
import { useCallback } from 'react'
import { cn } from '../../lib/utils'
import useEditor from '../../store/use-editor'
import type { GridSnapStep, ViewMode } from '../../store/use-editor'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from './primitives/dropdown-menu'
import { useSidebarStore } from './primitives/sidebar'
import { Tooltip, TooltipContent, TooltipTrigger } from './primitives/tooltip'
// ── Shared styles ───────────────────────────────────────────────────────────
/** Container for a group of buttons — no padding, overflow-hidden clips children flush. */
const TOOLBAR_CONTAINER =
'inline-flex h-8 items-stretch overflow-hidden rounded-xl border border-border bg-background/90 shadow-2xl backdrop-blur-md'
/** Ghost button inside a container — flush edges, no individual border/radius. */
const TOOLBAR_BTN =
'flex items-center justify-center w-8 text-muted-foreground/80 transition-colors hover:bg-white/8 hover:text-foreground/90'
// ── View mode segmented control ─────────────────────────────────────────────
const VIEW_MODES: { id: ViewMode; label: string; icon: React.ReactNode }[] = [
{
id: '3d',
label: '3D',
icon:
,
},
{
id: '2d',
label: '2D',
icon:
,
},
{
id: 'split',
label: 'Split',
icon: ,
},
]
function ViewModeControl() {
const viewMode = useEditor((s) => s.viewMode)
const setViewMode = useEditor((s) => s.setViewMode)
return (
{VIEW_MODES.map((mode) => {
const isActive = viewMode === mode.id
return (
)
})}
)
}
// ── Collapse sidebar button ─────────────────────────────────────────────────
function CollapseSidebarButton() {
const isCollapsed = useSidebarStore((s) => s.isCollapsed)
const setIsCollapsed = useSidebarStore((s) => s.setIsCollapsed)
const toggle = useCallback(() => {
setIsCollapsed(!isCollapsed)
}, [isCollapsed, setIsCollapsed])
return (
)
}
// ── Right toolbar buttons ───────────────────────────────────────────────────
function WalkthroughButton() {
const isFirstPersonMode = useEditor((s) => s.isFirstPersonMode)
const setFirstPersonMode = useEditor((s) => s.setFirstPersonMode)
const toggle = () => {
setFirstPersonMode(!isFirstPersonMode)
}
return (
Walkthrough
)
}
function UnitToggle() {
const unit = useViewer((s) => s.unit)
const setUnit = useViewer((s) => s.setUnit)
return (
{unit === 'metric' ? 'Metric (m)' : 'Imperial (ft)'}
)
}
function ThemeToggle() {
const theme = useViewer((s) => s.theme)
const setTheme = useViewer((s) => s.setTheme)
return (
{theme === 'dark' ? 'Dark' : 'Light'}
)
}
// ── Level mode toggle ───────────────────────────────────────────────────────
const levelModeOrder = ['stacked', 'exploded', 'solo'] as const
const levelModeLabels: Record = {
manual: 'Stack',
stacked: 'Stack',
exploded: 'Exploded',
solo: 'Solo',
}
const gridSnapOrder: GridSnapStep[] = [0.5, 0.25, 0.1, 0.05]
const gridSnapLabels: Record = {
0.5: '0.50',
0.25: '0.25',
0.1: '0.10',
0.05: '0.05',
}
function formatGridSnapStep(step: GridSnapStep): string {
return gridSnapLabels[step]
}
function LevelModeToggle() {
const levelMode = useViewer((s) => s.levelMode)
const setLevelMode = useViewer((s) => s.setLevelMode)
const cycle = () => {
if (levelMode === 'manual') {
setLevelMode('stacked')
return
}
const idx = levelModeOrder.indexOf(levelMode as (typeof levelModeOrder)[number])
const next = levelModeOrder[(idx + 1) % levelModeOrder.length]
if (next) setLevelMode(next)
}
const isDefault = levelMode === 'stacked' || levelMode === 'manual'
return (
Levels: {levelMode === 'manual' ? 'Manual' : levelModeLabels[levelMode]}
)
}
function GridSnapToggle() {
const gridSnapStep = useEditor((s) => s.gridSnapStep)
const setGridSnapStep = useEditor((s) => s.setGridSnapStep)
return (
Grid snap: {formatGridSnapStep(gridSnapStep)}
{gridSnapOrder.map((step) => {
const isActive = step === gridSnapStep
return (
setGridSnapStep(step)}>
{formatGridSnapStep(step)}
{isActive ? : }
)
})}
)
}
// ── Wall mode toggle ────────────────────────────────────────────────────────
const wallModeOrder = ['cutaway', 'up', 'down'] as const
const wallModeConfig: Record = {
up: { icon: '/icons/room.png', label: 'Full height' },
cutaway: { icon: '/icons/wallcut.png', label: 'Cutaway' },
down: { icon: '/icons/walllow.png', label: 'Low' },
}
function WallModeToggle() {
const wallMode = useViewer((s) => s.wallMode)
const setWallMode = useViewer((s) => s.setWallMode)
const cycle = () => {
const idx = wallModeOrder.indexOf(wallMode as (typeof wallModeOrder)[number])
const next = wallModeOrder[(idx + 1) % wallModeOrder.length]
if (next) setWallMode(next)
}
const config = wallModeConfig[wallMode] ?? wallModeConfig.cutaway!
return (
Walls: {config.label}
)
}
// ── Camera mode toggle ──────────────────────────────────────────────────────
function CameraModeToggle() {
const cameraMode = useViewer((s) => s.cameraMode)
const setCameraMode = useViewer((s) => s.setCameraMode)
return (
{cameraMode === 'perspective' ? 'Perspective' : 'Orthographic'}
)
}
function PreviewButton() {
return (
Preview mode
)
}
// ── Composed toolbar sections ───────────────────────────────────────────────
export function ViewerToolbarLeft() {
return (
<>
>
)
}
export function ViewerToolbarRight() {
return (
)
}