'use client' import { Icon as IconifyIcon } from '@iconify/react' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, useEditor, useSidebarStore, type ViewMode, } from '@pascal-app/editor' import { CLAY_PALETTE, type EdgeMode, getSceneTheme, SCENE_THEMES, useViewer, } from '@pascal-app/viewer' import { Box, Check, ChevronsLeft, ChevronsRight, Columns2, Contrast, Eye, EyeOff, Footprints, Grid2X2, PenLine, Sparkles, SwatchBook, } from 'lucide-react' import Image from 'next/image' import { type ReactNode, useCallback } from 'react' import { cn } from '@/lib/utils' import { Tooltip, TooltipContent, TooltipTrigger } from './toolbar-tooltip' const TOOLBAR_CONTAINER = 'inline-flex h-8 items-stretch overflow-hidden rounded-xl border border-border bg-background/90 shadow-2xl backdrop-blur-md' const TOOLBAR_BTN = 'flex w-8 items-center justify-center text-muted-foreground/80 transition-colors hover:bg-white/8 hover:text-foreground/90' function ToolbarTooltip({ children, label }: { children: ReactNode; label: string }) { return ( {children} {label} ) } 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: , }, ] const levelModeOrder = ['stacked', 'exploded', 'solo'] as const const levelModeLabels: Record = { manual: 'Stack', stacked: 'Stack', exploded: 'Exploded', solo: 'Solo', } 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' }, } const SHADING_OPTIONS = [ { id: 'solid', name: 'Solid', detail: 'Flat and fast — no ambient occlusion', icon: Box }, { id: 'rendered', name: 'Rendered', detail: 'Full ambient occlusion', icon: Sparkles }, ] as const function ViewModeControl() { const viewMode = useEditor((state) => state.viewMode) const setViewMode = useEditor((state) => state.setViewMode) return (
{VIEW_MODES.map((mode) => { const isActive = viewMode === mode.id return ( ) })}
) } function CollapseSidebarButton() { const isCollapsed = useSidebarStore((state) => state.isCollapsed) const setIsCollapsed = useSidebarStore((state) => state.setIsCollapsed) const toggle = useCallback(() => { setIsCollapsed(!isCollapsed) }, [isCollapsed, setIsCollapsed]) return (
) } function LevelModeToggle() { const levelMode = useViewer((state) => state.levelMode) const setLevelMode = useViewer((state) => state.setLevelMode) const isDefault = levelMode === 'stacked' || levelMode === 'manual' const cycle = () => { if (levelMode === 'manual') { setLevelMode('stacked') return } const index = levelModeOrder.indexOf(levelMode as (typeof levelModeOrder)[number]) const next = levelModeOrder[(index + 1) % levelModeOrder.length] if (next) setLevelMode(next) } const label = `Levels: ${levelMode === 'manual' ? 'Manual' : (levelModeLabels[levelMode] ?? 'Stack')}` return ( ) } function WallModeToggle() { const wallMode = useViewer((state) => state.wallMode) const setWallMode = useViewer((state) => state.setWallMode) const config = wallModeConfig[wallMode] ?? wallModeConfig.cutaway! const cycle = () => { const index = wallModeOrder.indexOf(wallMode as (typeof wallModeOrder)[number]) const next = wallModeOrder[(index + 1) % wallModeOrder.length] if (next) setWallMode(next) } return ( ) } function RenderModeMenu() { const shading = useViewer((state) => state.shading) const setShading = useViewer((state) => state.setShading) const active = SHADING_OPTIONS.find((option) => option.id === shading) ?? SHADING_OPTIONS[0] const ActiveIcon = active.icon return ( {SHADING_OPTIONS.map((option) => { const OptionIcon = option.icon return ( setShading(option.id)}>
{option.name} {option.detail}
{shading === option.id ? : null}
) })}
) } function SceneThemeMenu() { const sceneTheme = useViewer((state) => state.sceneTheme) const setSceneTheme = useViewer((state) => state.setSceneTheme) const active = getSceneTheme(sceneTheme) return ( {SCENE_THEMES.map((theme) => { const swatches = (['wall', 'roof', 'floor', 'glazing'] as const).map( (role) => theme.clayTints?.[role] ?? CLAY_PALETTE[role], ) return ( setSceneTheme(theme.id)}> {swatches.map((color, index) => ( ))} {theme.name} {sceneTheme === theme.id ? ( ) : null} ) })} ) } const EDGE_OPTIONS = [ { id: 'off', name: 'Off', detail: 'No edge lines' }, { id: 'soft', name: 'Soft', detail: 'Faint outline of major creases' }, { id: 'strong', name: 'Strong', detail: 'Crisp, opaque edge lines' }, ] as const satisfies readonly { id: EdgeMode; name: string; detail: string }[] function EdgesMenu() { const edges = useViewer((state) => state.edges) const setEdges = useViewer((state) => state.setEdges) const active = EDGE_OPTIONS.find((option) => option.id === edges) ?? EDGE_OPTIONS[0] return ( {EDGE_OPTIONS.map((option) => ( setEdges(option.id)}>
{option.name} {option.detail}
{edges === option.id ? : null}
))}
) } function GridVisibilityToggle() { const showGrid = useViewer((state) => state.showGrid) const setShowGrid = useViewer((state) => state.setShowGrid) return ( ) } function ShadowsToggle() { const shadows = useViewer((state) => state.shadows) const setShadows = useViewer((state) => state.setShadows) return ( ) } function UnitToggle() { const unit = useViewer((state) => state.unit) const setUnit = useViewer((state) => state.setUnit) return ( ) } function CameraModeToggle() { const cameraMode = useViewer((state) => state.cameraMode) const setCameraMode = useViewer((state) => state.setCameraMode) return ( ) } function WalkthroughButton() { const isFirstPersonMode = useEditor((state) => state.isFirstPersonMode) const setFirstPersonMode = useEditor((state) => state.setFirstPersonMode) return ( ) } function PreviewButton() { return ( ) } export function CommunityViewerToolbarLeft() { return ( <> ) } export function CommunityViewerToolbarRight() { return (
) }