control bar

This commit is contained in:
wass08
2026-01-29 10:14:40 +09:00
parent 406a4f51b5
commit f4125db6a8
8 changed files with 174 additions and 31 deletions
-26
View File
@@ -178,29 +178,3 @@ const Grid = ({
</mesh>
)
}
const LevelModeSwitcher = () => {
const setLevelMode = useViewer((state) => state.setLevelMode)
const levelMode = useViewer((state) => state.levelMode)
return (
<div className="absolute top-4 left-4 z-10 flex gap-2">
<button
className={`px-4 py-2 rounded ${
levelMode === 'exploded' ? 'bg-blue-500 text-white' : 'bg-white'
}`}
onClick={() => setLevelMode('exploded')}
>
Exploded
</button>
<button
className={`px-4 py-2 rounded ${
levelMode === 'stacked' ? 'bg-blue-500 text-white' : 'bg-white'
}`}
onClick={() => setLevelMode('stacked')}
>
Stacked
</button>
</div>
)
}
@@ -418,8 +418,10 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
const newRotationY = (currentRotation[1] ?? 0) + rotationDelta
draft.rotation = [currentRotation[0], newRotationY, currentRotation[2]]
// Ref + cursor mesh only — no store update during drag
// Ref + cursor mesh + item mesh — no store update during drag
cursorRef.current.rotation.y = newRotationY
const mesh = sceneRegistry.nodes.get(draft.id)
if (mesh) mesh.rotation.y = newRotationY
revalidate()
}
}
@@ -10,7 +10,7 @@ import useEditor from "@/store/use-editor";
import { AnimatePresence, motion } from "motion/react";
import { ItemCatalog } from "../item-catalog/item-catalog";
import { FurnishTools } from "./furnish-tools";
// import { ViewToggles } from "./view-toggles";
import { ViewToggles } from "./view-toggles";
export function ActionMenu({ className }: { className?: string }) {
const phase = useEditor((state) => state.phase);
@@ -138,8 +138,8 @@ export function ActionMenu({ className }: { className?: string }) {
<PhaseSwitcher />
<div className="mx-1 h-5 w-px bg-zinc-700" />
<ControlModes />
{/* <div className="mx-1 h-5 w-px bg-zinc-700" /> */}
{/* <ViewToggles /> */}
<div className="mx-1 h-5 w-px bg-zinc-700" />
<ViewToggles />
</div>
</div>
</TooltipProvider>
@@ -0,0 +1,139 @@
'use client'
import { useViewer } from '@pascal-app/viewer'
import { Box, Camera, Diamond, Image, Layers, Layers2 } from 'lucide-react'
import { Button } from '@/components/ui/primitives/button'
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '@/components/ui/primitives/tooltip'
import { cn } from '@/lib/utils'
const levelModeLabels: Record<'stacked' | 'exploded' | 'solo', string> = {
stacked: 'Stacked',
exploded: 'Exploded',
solo: 'Solo',
}
const levelModeOrder: ('stacked' | 'exploded' | 'solo')[] = ['stacked', 'exploded', 'solo']
export function ViewToggles() {
const cameraMode = useViewer((state) => state.cameraMode)
const setCameraMode = useViewer((state) => state.setCameraMode)
const levelMode = useViewer((state) => state.levelMode)
const setLevelMode = useViewer((state) => state.setLevelMode)
const showScans = useViewer((state) => state.showScans)
const setShowScans = useViewer((state) => state.setShowScans)
const showGuides = useViewer((state) => state.showGuides)
const setShowGuides = useViewer((state) => state.setShowGuides)
const toggleCameraMode = () => {
setCameraMode(cameraMode === 'perspective' ? 'orthographic' : 'perspective')
}
const cycleLevelMode = () => {
if (levelMode === 'manual') {
setLevelMode('stacked')
return
}
const currentIndex = levelModeOrder.indexOf(levelMode as 'stacked' | 'exploded' | 'solo')
const nextIndex = (currentIndex + 1) % levelModeOrder.length
const nextMode = levelModeOrder[nextIndex]
if (nextMode) setLevelMode(nextMode)
}
return (
<div className="flex items-center gap-1">
{/* Camera Mode */}
<Tooltip>
<TooltipTrigger asChild>
<Button
className={cn(
'h-8 w-8 text-zinc-400 transition-all',
cameraMode === 'orthographic'
? 'bg-violet-500/20 text-violet-400'
: 'hover:bg-zinc-800',
)}
onClick={toggleCameraMode}
size="icon"
variant="ghost"
>
<Camera className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Camera: {cameraMode === 'perspective' ? 'Perspective' : 'Orthographic'}</p>
</TooltipContent>
</Tooltip>
{/* Level Mode */}
<Tooltip>
<TooltipTrigger asChild>
<Button
className={cn(
'h-8 w-8 text-zinc-400 transition-all',
levelMode !== 'stacked'
? 'bg-amber-500/20 text-amber-400'
: 'hover:bg-zinc-800',
)}
onClick={cycleLevelMode}
size="icon"
variant="ghost"
>
{levelMode === 'solo' && <Diamond className="h-4 w-4" />}
{levelMode === 'exploded' && <Layers2 className="h-4 w-4" />}
{(levelMode === 'stacked' || levelMode === 'manual') && <Layers className="h-4 w-4" />}
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Levels: {levelMode === 'manual' ? 'Manual' : levelModeLabels[levelMode as keyof typeof levelModeLabels]}</p>
</TooltipContent>
</Tooltip>
{/* Show Scans */}
<Tooltip>
<TooltipTrigger asChild>
<Button
className={cn(
'h-8 w-8 text-zinc-400 transition-all',
showScans
? 'bg-cyan-500/20 text-cyan-400'
: 'hover:bg-zinc-800',
)}
onClick={() => setShowScans(!showScans)}
size="icon"
variant="ghost"
>
<Box className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Scans: {showScans ? 'Visible' : 'Hidden'}</p>
</TooltipContent>
</Tooltip>
{/* Show Guides */}
<Tooltip>
<TooltipTrigger asChild>
<Button
className={cn(
'h-8 w-8 text-zinc-400 transition-all',
showGuides
? 'bg-purple-500/20 text-purple-400'
: 'hover:bg-zinc-800',
)}
onClick={() => setShowGuides(!showGuides)}
size="icon"
variant="ghost"
>
<Image className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Guides: {showGuides ? 'Visible' : 'Hidden'}</p>
</TooltipContent>
</Tooltip>
</div>
)
}