Remove material strips from roof, stair, and fence panels
This commit is contained in:
@@ -3,8 +3,6 @@
|
||||
import {
|
||||
type AnyNode,
|
||||
type AnyNodeId,
|
||||
getEffectiveRoofSurfaceMaterial,
|
||||
type MaterialSchema,
|
||||
type RoofNode,
|
||||
type RoofSegmentNode,
|
||||
RoofSegmentNode as RoofSegmentNodeSchema,
|
||||
@@ -33,7 +31,6 @@ export default 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 node = useScene((s) =>
|
||||
selectedId ? (s.nodes[selectedId as AnyNode['id']] as RoofNode | undefined) : undefined,
|
||||
@@ -56,35 +53,6 @@ export default 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
|
||||
handleUpdate(buildRoofSurfaceMaterialPatch(node, materialTargetRole, material, undefined))
|
||||
},
|
||||
[handleUpdate, materialTargetRole, node],
|
||||
)
|
||||
|
||||
const handleTargetedMaterialPresetChange = useCallback(
|
||||
(materialPreset: string) => {
|
||||
if (!(node && materialTargetRole)) return
|
||||
handleUpdate(
|
||||
buildRoofSurfaceMaterialPatch(node, materialTargetRole, undefined, materialPreset),
|
||||
)
|
||||
},
|
||||
[handleUpdate, materialTargetRole, node],
|
||||
)
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setSelection({ selectedIds: [] })
|
||||
}, [setSelection])
|
||||
@@ -260,22 +228,6 @@ export default function RoofPanel() {
|
||||
/>
|
||||
</ActionGroup>
|
||||
</PanelSection>
|
||||
<PanelSection title="Material">
|
||||
{materialTargetRole ? null : (
|
||||
<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>
|
||||
)}
|
||||
<MaterialPicker
|
||||
disabled={!materialTargetRole}
|
||||
hideSideControl
|
||||
nodeType="roof"
|
||||
onChange={handleTargetedMaterialChange}
|
||||
onSelectMaterialPreset={handleTargetedMaterialPresetChange}
|
||||
selectedMaterialPreset={materialPickerValue.materialPreset}
|
||||
value={materialPickerValue.material}
|
||||
/>
|
||||
</PanelSection>
|
||||
</PanelWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import { type RoofNode, useRegistry } from '@pascal-app/core'
|
||||
import { type RoofNode, useRegistry, useScene } from '@pascal-app/core'
|
||||
import { getRoofMaterialArray, NodeRenderer, useNodeEvents, useViewer } from '@pascal-app/viewer'
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react'
|
||||
import * as THREE from 'three'
|
||||
import { roofDebugMaterials, roofMaterials } from './roof-materials'
|
||||
|
||||
@@ -10,6 +10,9 @@ export const RoofRenderer = ({ node }: { node: RoofNode }) => {
|
||||
const ref = useRef<THREE.Group>(null!)
|
||||
|
||||
useRegistry(node.id, 'roof', ref)
|
||||
useLayoutEffect(() => {
|
||||
useScene.getState().markDirty(node.id)
|
||||
}, [node.id])
|
||||
|
||||
const handlers = useNodeEvents(node, 'roof')
|
||||
const debugColors = useViewer((s) => s.debugColors)
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
import {
|
||||
type AnyNode,
|
||||
type AnyNodeId,
|
||||
getEffectiveStairSurfaceMaterial,
|
||||
type LevelNode,
|
||||
type MaterialSchema,
|
||||
type StairNode,
|
||||
type StairRailingMode,
|
||||
type StairSegmentNode,
|
||||
@@ -66,7 +64,6 @@ export default function StairPanel() {
|
||||
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 node = useScene((s) =>
|
||||
selectedId ? (s.nodes[selectedId as AnyNode['id']] as StairNode | undefined) : undefined,
|
||||
@@ -97,35 +94,6 @@ export default 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
|
||||
handleUpdate(buildStairSurfaceMaterialPatch(node, materialTargetRole, material, undefined))
|
||||
},
|
||||
[handleUpdate, materialTargetRole, node],
|
||||
)
|
||||
|
||||
const handleTargetedMaterialPresetChange = useCallback(
|
||||
(materialPreset: string) => {
|
||||
if (!(node && materialTargetRole)) return
|
||||
handleUpdate(
|
||||
buildStairSurfaceMaterialPatch(node, materialTargetRole, undefined, materialPreset),
|
||||
)
|
||||
},
|
||||
[handleUpdate, materialTargetRole, node],
|
||||
)
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setSelection({ selectedIds: [] })
|
||||
}, [setSelection])
|
||||
@@ -557,22 +525,6 @@ export default function StairPanel() {
|
||||
/>
|
||||
</ActionGroup>
|
||||
</PanelSection>
|
||||
<PanelSection title="Material">
|
||||
{materialTargetRole ? null : (
|
||||
<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>
|
||||
)}
|
||||
<MaterialPicker
|
||||
disabled={!materialTargetRole}
|
||||
hideSideControl
|
||||
nodeType="stair"
|
||||
onChange={handleTargetedMaterialChange}
|
||||
onSelectMaterialPreset={handleTargetedMaterialPresetChange}
|
||||
selectedMaterialPreset={materialPickerValue.materialPreset}
|
||||
value={materialPickerValue.material}
|
||||
/>
|
||||
</PanelSection>
|
||||
</PanelWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -126,15 +126,19 @@ export const RoofSystem = () => {
|
||||
pendingRoofUpdates.delete(id)
|
||||
continue
|
||||
}
|
||||
|
||||
const group = sceneRegistry.nodes.get(id) as THREE.Group
|
||||
if (group) {
|
||||
const mergedMesh = group.getObjectByName('merged-roof') as THREE.Mesh | undefined
|
||||
if (mergedMesh?.visible !== false) {
|
||||
// Only rebuild when visible — RoofEditSystem re-triggers via markDirty on edit mode exit
|
||||
updateMergedRoofGeometry(node as RoofNode, group, nodes)
|
||||
roofsProcessed++
|
||||
}
|
||||
if (!group) continue
|
||||
|
||||
const mergedMesh = group.getObjectByName('merged-roof') as THREE.Mesh | undefined
|
||||
if (!mergedMesh) continue
|
||||
|
||||
if (mergedMesh.visible !== false) {
|
||||
// Only rebuild when visible — RoofEditSystem re-triggers via markDirty on edit mode exit
|
||||
updateMergedRoofGeometry(node as RoofNode, group, nodes)
|
||||
roofsProcessed++
|
||||
}
|
||||
|
||||
pendingRoofUpdates.delete(id)
|
||||
}
|
||||
}, 5) // Priority 5: run after all other systems have settled
|
||||
|
||||
Reference in New Issue
Block a user