Remove material pickers from side panels

This commit is contained in:
sudhir
2026-04-23 10:21:33 +05:30
parent fb3de8debc
commit 4483957a0d
10 changed files with 4 additions and 332 deletions
@@ -1,13 +1,12 @@
'use client'
import { type AnyNode, type CeilingNode, type MaterialSchema, useScene } from '@pascal-app/core'
import { type AnyNode, type CeilingNode, useScene } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { Edit, Move, Plus, Trash2 } from 'lucide-react'
import { useCallback, useEffect } from 'react'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { PanelSection } from '../controls/panel-section'
import { SliderControl } from '../controls/slider-control'
import { PanelWrapper } from './panel-wrapper'
@@ -32,20 +31,6 @@ export function CeilingPanel() {
[selectedId, updateNode],
)
const handleMaterialChange = useCallback(
(material: MaterialSchema) => {
handleUpdate({ material, materialPreset: undefined })
},
[handleUpdate],
)
const handleMaterialPresetChange = useCallback(
(materialPreset: string) => {
handleUpdate({ materialPreset, material: undefined })
},
[handleUpdate],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
setEditingHole(null)
@@ -257,15 +242,6 @@ export function CeilingPanel() {
</div>
</PanelSection>
<PanelSection title="Material">
<MaterialPicker
nodeType="ceiling"
onChange={handleMaterialChange}
onSelectMaterialPreset={handleMaterialPresetChange}
selectedMaterialPreset={node.materialPreset}
value={node.material}
/>
</PanelSection>
<ActionGroup>
<ActionButton icon={<Move className="h-3.5 w-3.5" />} label="Move" onClick={handleMove} />
</ActionGroup>
@@ -5,7 +5,6 @@ import {
type AnyNodeId,
DoorNode,
emitter,
type MaterialSchema,
useScene,
} from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
@@ -15,7 +14,6 @@ import { usePresetsAdapter } from '../../../contexts/presets-context'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { MetricControl } from '../controls/metric-control'
import { PanelSection } from '../controls/panel-section'
import { SegmentedControl } from '../controls/segmented-control'
@@ -46,13 +44,6 @@ export function DoorPanel() {
[selectedId, updateNode],
)
const handleMaterialChange = useCallback(
(material: MaterialSchema) => {
handleUpdate({ material })
},
[handleUpdate],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
}, [setSelection])
@@ -592,9 +583,6 @@ export function DoorPanel() {
/>
</ActionGroup>
</PanelSection>
<PanelSection title="Material">
<MaterialPicker onChange={handleMaterialChange} value={node.material} />
</PanelSection>
</PanelWrapper>
)
}
@@ -1,9 +1,8 @@
'use client'
import { type AnyNode, type AnyNodeId, type FenceNode, type MaterialSchema, useScene } from '@pascal-app/core'
import { type AnyNode, type AnyNodeId, type FenceNode, useScene } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { useCallback } from 'react'
import { MaterialPicker } from '../controls/material-picker'
import { PanelSection } from '../controls/panel-section'
import { SegmentedControl } from '../controls/segmented-control'
import { SliderControl } from '../controls/slider-control'
@@ -67,20 +66,6 @@ export function FencePanel() {
setSelection({ selectedIds: [] })
}, [setSelection])
const handleMaterialPresetChange = useCallback(
(materialPreset: string) => {
handleUpdate({ materialPreset, material: undefined })
},
[handleUpdate],
)
const handleCustomMaterialChange = useCallback(
(material: MaterialSchema) => {
handleUpdate({ material, materialPreset: undefined })
},
[handleUpdate],
)
if (!(node && node.type === 'fence' && selectedId && selectedCount === 1)) return null
const dx = node.end[0] - node.start[0]
@@ -204,15 +189,6 @@ export function FencePanel() {
/>
</PanelSection>
<PanelSection title="Material">
<MaterialPicker
nodeType="fence"
onChange={handleCustomMaterialChange}
onSelectMaterialPreset={handleMaterialPresetChange}
selectedMaterialPreset={node.materialPreset}
value={node.material}
/>
</PanelSection>
</PanelWrapper>
)
}
@@ -3,8 +3,6 @@
import {
type AnyNode,
type AnyNodeId,
getEffectiveRoofSurfaceMaterial,
type MaterialSchema,
type RoofNode,
RoofNode as RoofNodeSchema,
type RoofSegmentNode,
@@ -15,11 +13,9 @@ import { useViewer } from '@pascal-app/viewer'
import { Copy, Move, Plus, Trash2 } from 'lucide-react'
import { useCallback } from 'react'
import { useShallow } from 'zustand/react/shallow'
import { buildRoofSurfaceMaterialPatch } from '../../../lib/material-paint'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { PanelSection } from '../controls/panel-section'
import { SliderControl } from '../controls/slider-control'
import { PanelWrapper } from './panel-wrapper'
@@ -30,9 +26,6 @@ export function RoofPanel() {
const updateNode = useScene((s) => s.updateNode)
const createNode = useScene((s) => s.createNode)
const setMovingNode = useEditor((s) => s.setMovingNode)
const selectedMaterialTarget = useEditor((s) => s.selectedMaterialTarget)
const setActivePaintMaterial = useEditor((s) => s.setActivePaintMaterial)
const setActivePaintTarget = useEditor((s) => s.setActivePaintTarget)
const node = useScene((s) =>
selectedId ? (s.nodes[selectedId as AnyNode['id']] as RoofNode | undefined) : undefined,
@@ -55,37 +48,6 @@ export function RoofPanel() {
[selectedId, updateNode],
)
const materialTargetRole =
selectedMaterialTarget &&
selectedMaterialTarget.nodeId === node?.id &&
(selectedMaterialTarget.role === 'top' ||
selectedMaterialTarget.role === 'edge' ||
selectedMaterialTarget.role === 'wall')
? selectedMaterialTarget.role
: null
const materialPickerValue =
node && materialTargetRole ? getEffectiveRoofSurfaceMaterial(node, materialTargetRole) : {}
const handleTargetedMaterialChange = useCallback(
(material: MaterialSchema) => {
if (!node || !materialTargetRole) return
setActivePaintTarget('roof')
setActivePaintMaterial({ material, sourceTarget: 'roof' })
handleUpdate(buildRoofSurfaceMaterialPatch(node, materialTargetRole, material, undefined))
},
[handleUpdate, materialTargetRole, node, setActivePaintMaterial, setActivePaintTarget],
)
const handleTargetedMaterialPresetChange = useCallback(
(materialPreset: string) => {
if (!node || !materialTargetRole) return
setActivePaintTarget('roof')
setActivePaintMaterial({ materialPreset, sourceTarget: 'roof' })
handleUpdate(buildRoofSurfaceMaterialPatch(node, materialTargetRole, undefined, materialPreset))
},
[handleUpdate, materialTargetRole, node, setActivePaintMaterial, setActivePaintTarget],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
}, [setSelection])
@@ -290,22 +252,6 @@ export function RoofPanel() {
/>
</ActionGroup>
</PanelSection>
<PanelSection title="Material">
{!materialTargetRole ? (
<div className="mb-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 py-2 text-[11px] text-muted-foreground">
Click the roof surface you want to edit. Materials apply to one target at a time.
</div>
) : null}
<MaterialPicker
disabled={!materialTargetRole}
hideSideControl
nodeType="roof"
onChange={handleTargetedMaterialChange}
onSelectMaterialPreset={handleTargetedMaterialPresetChange}
selectedMaterialPreset={materialPickerValue.materialPreset}
value={materialPickerValue.material}
/>
</PanelSection>
</PanelWrapper>
)
}
@@ -3,7 +3,6 @@
import {
type AnyNode,
type AnyNodeId,
type MaterialSchema,
type RoofSegmentNode,
RoofSegmentNode as RoofSegmentNodeSchema,
type RoofType,
@@ -15,7 +14,6 @@ import { useCallback } from 'react'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { PanelSection } from '../controls/panel-section'
import { SegmentedControl } from '../controls/segmented-control'
import { SliderControl } from '../controls/slider-control'
@@ -52,20 +50,6 @@ export function RoofSegmentPanel() {
[selectedId, updateNode],
)
const handleMaterialChange = useCallback(
(material: MaterialSchema) => {
handleUpdate({ material, materialPreset: undefined })
},
[handleUpdate],
)
const handleMaterialPresetChange = useCallback(
(materialPreset: string) => {
handleUpdate({ materialPreset, material: undefined })
},
[handleUpdate],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
}, [setSelection])
@@ -322,15 +306,6 @@ export function RoofSegmentPanel() {
/>
</ActionGroup>
</PanelSection>
<PanelSection title="Material">
<MaterialPicker
nodeType="roof-segment"
onChange={handleMaterialChange}
onSelectMaterialPreset={handleMaterialPresetChange}
selectedMaterialPreset={node.materialPreset}
value={node.material}
/>
</PanelSection>
</PanelWrapper>
)
}
@@ -1,13 +1,12 @@
'use client'
import { type AnyNode, type MaterialSchema, type SlabNode, useScene } from '@pascal-app/core'
import { type AnyNode, type SlabNode, useScene } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { Edit, Move, Plus, Trash2 } from 'lucide-react'
import { useCallback, useEffect } from 'react'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { PanelSection } from '../controls/panel-section'
import { SliderControl } from '../controls/slider-control'
import { PanelWrapper } from './panel-wrapper'
@@ -32,20 +31,6 @@ export function SlabPanel() {
[selectedId, updateNode],
)
const handleMaterialPresetChange = useCallback(
(materialPreset: string) => {
handleUpdate({ materialPreset, material: undefined })
},
[handleUpdate],
)
const handleCustomMaterialChange = useCallback(
(material: MaterialSchema) => {
handleUpdate({ material, materialPreset: undefined })
},
[handleUpdate],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
setEditingHole(null)
@@ -257,15 +242,6 @@ export function SlabPanel() {
/>
</div>
</PanelSection>
<PanelSection title="Material">
<MaterialPicker
nodeType="slab"
onChange={handleCustomMaterialChange}
onSelectMaterialPreset={handleMaterialPresetChange}
selectedMaterialPreset={node.materialPreset}
value={node.material}
/>
</PanelSection>
<ActionGroup>
<ActionButton icon={<Move className="h-3.5 w-3.5" />} label="Move" onClick={handleMove} />
</ActionGroup>
@@ -3,9 +3,7 @@
import {
type AnyNode,
type AnyNodeId,
getEffectiveStairSurfaceMaterial,
type LevelNode,
type MaterialSchema,
type StairNode,
type StairRailingMode,
type StairSlabOpeningMode,
@@ -20,12 +18,10 @@ import { useViewer } from '@pascal-app/viewer'
import { Copy, Move, Plus, Trash2 } from 'lucide-react'
import { useCallback } from 'react'
import { useShallow } from 'zustand/react/shallow'
import { buildStairSurfaceMaterialPatch } from '../../../lib/material-paint'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { DEFAULT_SPIRAL_STAIR_SWEEP_ANGLE } from '../../tools/stair/stair-defaults'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { MetricControl } from '../controls/metric-control'
import { PanelSection } from '../controls/panel-section'
import { SegmentedControl } from '../controls/segmented-control'
@@ -64,9 +60,6 @@ export function StairPanel() {
const createNode = useScene((s) => s.createNode)
const createNodes = useScene((s) => s.createNodes)
const setMovingNode = useEditor((s) => s.setMovingNode)
const selectedMaterialTarget = useEditor((s) => s.selectedMaterialTarget)
const setActivePaintMaterial = useEditor((s) => s.setActivePaintMaterial)
const setActivePaintTarget = useEditor((s) => s.setActivePaintTarget)
const node = useScene((s) =>
selectedId ? (s.nodes[selectedId as AnyNode['id']] as StairNode | undefined) : undefined,
@@ -97,37 +90,6 @@ export function StairPanel() {
[selectedId, updateNode],
)
const materialTargetRole =
selectedMaterialTarget &&
selectedMaterialTarget.nodeId === node?.id &&
(selectedMaterialTarget.role === 'railing' ||
selectedMaterialTarget.role === 'tread' ||
selectedMaterialTarget.role === 'side')
? selectedMaterialTarget.role
: null
const materialPickerValue =
node && materialTargetRole ? getEffectiveStairSurfaceMaterial(node, materialTargetRole) : {}
const handleTargetedMaterialChange = useCallback(
(material: MaterialSchema) => {
if (!node || !materialTargetRole) return
setActivePaintTarget('stair')
setActivePaintMaterial({ material, sourceTarget: 'stair' })
handleUpdate(buildStairSurfaceMaterialPatch(node, materialTargetRole, material, undefined))
},
[handleUpdate, materialTargetRole, node, setActivePaintMaterial, setActivePaintTarget],
)
const handleTargetedMaterialPresetChange = useCallback(
(materialPreset: string) => {
if (!node || !materialTargetRole) return
setActivePaintTarget('stair')
setActivePaintMaterial({ materialPreset, sourceTarget: 'stair' })
handleUpdate(buildStairSurfaceMaterialPatch(node, materialTargetRole, undefined, materialPreset))
},
[handleUpdate, materialTargetRole, node, setActivePaintMaterial, setActivePaintTarget],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
}, [setSelection])
@@ -590,22 +552,6 @@ export function StairPanel() {
/>
</ActionGroup>
</PanelSection>
<PanelSection title="Material">
{!materialTargetRole ? (
<div className="mb-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 py-2 text-[11px] text-muted-foreground">
Click the stair surface you want to edit. Materials apply to one target at a time.
</div>
) : null}
<MaterialPicker
disabled={!materialTargetRole}
hideSideControl
nodeType="stair"
onChange={handleTargetedMaterialChange}
onSelectMaterialPreset={handleTargetedMaterialPresetChange}
selectedMaterialPreset={materialPickerValue.materialPreset}
value={materialPickerValue.material}
/>
</PanelSection>
</PanelWrapper>
)
}
@@ -4,7 +4,6 @@ import {
type AnyNode,
type AnyNodeId,
type AttachmentSide,
type MaterialSchema,
type StairSegmentNode,
StairSegmentNode as StairSegmentNodeSchema,
type StairSegmentType,
@@ -16,7 +15,6 @@ import { useCallback } from 'react'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { PanelSection } from '../controls/panel-section'
import { SegmentedControl } from '../controls/segmented-control'
import { SliderControl } from '../controls/slider-control'
@@ -61,20 +59,6 @@ export function StairSegmentPanel() {
[selectedId, updateNode],
)
const handleMaterialChange = useCallback(
(material: MaterialSchema) => {
handleUpdate({ material, materialPreset: undefined })
},
[handleUpdate],
)
const handleMaterialPresetChange = useCallback(
(materialPreset: string) => {
handleUpdate({ materialPreset, material: undefined })
},
[handleUpdate],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
}, [setSelection])
@@ -336,15 +320,6 @@ export function StairSegmentPanel() {
/>
</ActionGroup>
</PanelSection>
<PanelSection title="Material">
<MaterialPicker
nodeType="stair-segment"
onChange={handleMaterialChange}
onSelectMaterialPreset={handleMaterialPresetChange}
selectedMaterialPreset={node.materialPreset}
value={node.material}
/>
</PanelSection>
</PanelWrapper>
)
}
@@ -3,24 +3,19 @@
import {
type AnyNode,
type AnyNodeId,
getEffectiveWallSurfaceMaterial,
getClampedWallCurveOffset,
getMaxWallCurveOffset,
getWallCurveLength,
getWallSurfaceMaterialSignature,
normalizeWallCurveOffset,
type MaterialSchema,
useScene,
type WallNode,
} from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { Move, Spline } from 'lucide-react'
import { useCallback, useMemo } from 'react'
import { useCallback } from 'react'
import { sfxEmitter } from '../../../lib/sfx-bus'
import { buildWallSurfaceMaterialPatch } from '../../../lib/material-paint'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { PanelSection } from '../controls/panel-section'
import { SliderControl } from '../controls/slider-control'
import { PanelWrapper } from './panel-wrapper'
@@ -31,9 +26,6 @@ export function WallPanel() {
const updateNode = useScene((s) => s.updateNode)
const setMovingNode = useEditor((s) => s.setMovingNode)
const setCurvingWall = useEditor((s) => s.setCurvingWall)
const selectedMaterialTarget = useEditor((s) => s.selectedMaterialTarget)
const setActivePaintMaterial = useEditor((s) => s.setActivePaintMaterial)
const setActivePaintTarget = useEditor((s) => s.setActivePaintTarget)
const node = useScene((s) =>
selectedId ? (s.nodes[selectedId as AnyNode['id']] as WallNode | undefined) : undefined,
@@ -64,35 +56,6 @@ export function WallPanel() {
[selectedId, updateNode],
)
const effectiveInteriorMaterial = useMemo(
() => (node ? getEffectiveWallSurfaceMaterial(node, 'interior') : {}),
[node],
)
const effectiveExteriorMaterial = useMemo(
() => (node ? getEffectiveWallSurfaceMaterial(node, 'exterior') : {}),
[node],
)
const surfaceMaterialsMatch = useMemo(
() =>
getWallSurfaceMaterialSignature(effectiveInteriorMaterial) ===
getWallSurfaceMaterialSignature(effectiveExteriorMaterial),
[effectiveExteriorMaterial, effectiveInteriorMaterial],
)
const materialTargetSide =
selectedMaterialTarget &&
selectedMaterialTarget.nodeId === node?.id &&
(selectedMaterialTarget.role === 'interior' || selectedMaterialTarget.role === 'exterior')
? selectedMaterialTarget.role
: null
const materialPickerValue =
materialTargetSide === 'interior'
? effectiveInteriorMaterial
: materialTargetSide === 'exterior'
? effectiveExteriorMaterial
: surfaceMaterialsMatch
? effectiveInteriorMaterial
: {}
const handleUpdateLength = useCallback(
(newLength: number) => {
if (!node || newLength <= 0) return
@@ -116,26 +79,6 @@ export function WallPanel() {
[node, handleUpdate],
)
const handleMaterialPresetChange = useCallback(
(materialPreset: string) => {
if (!node || !materialTargetSide) return
setActivePaintTarget('wall')
setActivePaintMaterial({ materialPreset, sourceTarget: 'wall' })
handleUpdate(buildWallSurfaceMaterialPatch(node, materialTargetSide, undefined, materialPreset))
},
[handleUpdate, materialTargetSide, node, setActivePaintMaterial, setActivePaintTarget],
)
const handleCustomMaterialChange = useCallback(
(material: MaterialSchema) => {
if (!node || !materialTargetSide) return
setActivePaintTarget('wall')
setActivePaintMaterial({ material, sourceTarget: 'wall' })
handleUpdate(buildWallSurfaceMaterialPatch(node, materialTargetSide, material, undefined))
},
[handleUpdate, materialTargetSide, node, setActivePaintMaterial, setActivePaintTarget],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
}, [setSelection])
@@ -217,23 +160,6 @@ export function WallPanel() {
)}
</PanelSection>
<PanelSection title="Material">
{!materialTargetSide ? (
<div className="mb-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 py-2 text-[11px] text-muted-foreground">
Click the wall face you want to edit. Materials now apply to one side at a time.
</div>
) : null}
<MaterialPicker
disabled={!materialTargetSide}
hideSideControl
nodeType="wall"
onChange={handleCustomMaterialChange}
onSelectMaterialPreset={handleMaterialPresetChange}
selectedMaterialPreset={materialPickerValue.materialPreset}
value={materialPickerValue.material}
/>
</PanelSection>
<PanelSection title="Actions">
<ActionGroup>
<ActionButton icon={<Move className="h-3.5 w-3.5" />} label="Move" onClick={handleMove} />
@@ -4,7 +4,6 @@ import {
type AnyNode,
type AnyNodeId,
emitter,
type MaterialSchema,
useScene,
WindowNode,
} from '@pascal-app/core'
@@ -15,7 +14,6 @@ import { usePresetsAdapter } from '../../../contexts/presets-context'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import { ActionButton, ActionGroup } from '../controls/action-button'
import { MaterialPicker } from '../controls/material-picker'
import { MetricControl } from '../controls/metric-control'
import { PanelSection } from '../controls/panel-section'
import { SliderControl } from '../controls/slider-control'
@@ -45,13 +43,6 @@ export function WindowPanel() {
[selectedId, updateNode],
)
const handleMaterialChange = useCallback(
(material: MaterialSchema) => {
handleUpdate({ material })
},
[handleUpdate],
)
const handleClose = useCallback(() => {
setSelection({ selectedIds: [] })
}, [setSelection])
@@ -431,9 +422,6 @@ export function WindowPanel() {
/>
</ActionGroup>
</PanelSection>
<PanelSection title="Material">
<MaterialPicker onChange={handleMaterialChange} value={node.material} />
</PanelSection>
</PanelWrapper>
)
}