Simplify paint material compatibility logic

This commit is contained in:
sudhir
2026-04-25 00:15:29 +05:30
parent cb268509ea
commit 275a42cc7f
7 changed files with 25 additions and 112 deletions
-1
View File
@@ -40,7 +40,6 @@ export {
export { baseMaterial, glassMaterial } from './materials'
export {
getCatalogMaterialById,
getMaterialCategoryTargets,
getLibraryMaterialIdFromRef,
getMaterialPresetByRef,
getMaterialsForCategory,
-40
View File
@@ -1,7 +1,5 @@
import {
type MaterialPresetPayload,
type MaterialTarget,
MaterialTarget as MaterialTargetSchema,
} from './schema/material'
export type MaterialCatalogItem = {
@@ -24,40 +22,6 @@ export const MATERIAL_CATEGORIES = [
] as const
export type MaterialCategory = (typeof MATERIAL_CATEGORIES)[number]
export const MATERIAL_CATEGORY_TARGETS: Record<MaterialCategory, MaterialTarget[]> = {
wood: [
MaterialTargetSchema.enum.wall,
MaterialTargetSchema.enum.slab,
MaterialTargetSchema.enum.stair,
MaterialTargetSchema.enum['stair-segment'],
MaterialTargetSchema.enum.fence,
MaterialTargetSchema.enum.roof,
MaterialTargetSchema.enum['roof-segment'],
],
wallpaper: [MaterialTargetSchema.enum.wall],
parquet: [
MaterialTargetSchema.enum.slab,
MaterialTargetSchema.enum.stair,
MaterialTargetSchema.enum['stair-segment'],
],
granite: [MaterialTargetSchema.enum.slab],
marble: [
MaterialTargetSchema.enum.slab,
MaterialTargetSchema.enum.stair,
MaterialTargetSchema.enum['stair-segment'],
],
other: [
MaterialTargetSchema.enum.wall,
MaterialTargetSchema.enum.roof,
MaterialTargetSchema.enum['roof-segment'],
MaterialTargetSchema.enum.stair,
MaterialTargetSchema.enum['stair-segment'],
MaterialTargetSchema.enum.fence,
MaterialTargetSchema.enum.slab,
MaterialTargetSchema.enum.ceiling,
],
}
export const MATERIAL_CATALOG: MaterialCatalogItem[] = [
{
id: 'wall-wood1',
@@ -609,10 +573,6 @@ export function getMaterialsForCategory(category: MaterialCategory): MaterialCat
return MATERIAL_CATALOG.filter((item) => item.category === category)
}
export function getMaterialCategoryTargets(category: MaterialCategory): MaterialTarget[] {
return MATERIAL_CATEGORY_TARGETS[category]
}
export function getCatalogMaterialById(id?: string): MaterialCatalogItem | undefined {
if (!id) return undefined
return MATERIAL_CATALOG.find((item) => item.id === id)
@@ -44,7 +44,6 @@ import {
buildStairSurfaceMaterialPatch,
buildWallSurfaceMaterialPatch,
hasActivePaintMaterial,
isActivePaintMaterialCompatible,
resolveActivePaintMaterialFromSelection,
} from '../../lib/material-paint'
import { sfxEmitter } from '../../lib/sfx-bus'
@@ -741,8 +740,7 @@ export const SelectionManager = () => {
if (node.type === 'wall') {
const role = resolveWallMaterialTarget(event as WallEvent)
const compatible =
role !== null && isActivePaintMaterialCompatible(activePaintMaterial, 'wall')
const compatible = role !== null && hasActivePaintMaterial(activePaintMaterial)
return {
key: `wall:${node.id}:${role ?? 'unsupported'}`,
hoveredId: node.id as AnyNodeId,
@@ -783,8 +781,7 @@ export const SelectionManager = () => {
if (!roofNode || roofNode.type !== 'roof') return null
const role = resolveRoofMaterialTarget(event as RoofEvent | RoofSegmentEvent)
const compatible =
role !== null && isActivePaintMaterialCompatible(activePaintMaterial, 'roof')
const compatible = role !== null && hasActivePaintMaterial(activePaintMaterial)
return {
key: `roof:${roofNode.id}:${role ?? 'unsupported'}`,
hoveredId: roofNode.id as AnyNodeId,
@@ -825,8 +822,7 @@ export const SelectionManager = () => {
if (!stairNode || stairNode.type !== 'stair') return null
const role = resolveStairMaterialTarget(event as StairEvent | StairSegmentEvent)
const compatible =
role !== null && isActivePaintMaterialCompatible(activePaintMaterial, 'stair')
const compatible = role !== null && hasActivePaintMaterial(activePaintMaterial)
return {
key: `stair:${stairNode.id}:${role ?? 'unsupported'}`,
hoveredId: stairNode.id as AnyNodeId,
@@ -858,13 +854,10 @@ export const SelectionManager = () => {
}
if (node.type === 'fence' || node.type === 'slab' || node.type === 'ceiling') {
const target = node.type
const compatible =
isActivePaintMaterialCompatible(activePaintMaterial, target) &&
hasActivePaintMaterial(activePaintMaterial)
const compatible = hasActivePaintMaterial(activePaintMaterial)
return {
key: `${target}:${node.id}:surface`,
key: `${node.type}:${node.id}:surface`,
hoveredId: node.id as AnyNodeId,
hoverMode: compatible ? 'paint-ready' : 'paint-disabled',
apply: compatible
@@ -40,11 +40,11 @@ function PaintMaterialTray() {
return (
<div className="w-[42rem] max-w-[calc(100vw-2rem)]">
<MaterialPicker
onChange={(material, category) => {
setActivePaintMaterial({ material, category, sourceTarget: activePaintTarget })
onChange={(material) => {
setActivePaintMaterial({ material, sourceTarget: activePaintTarget })
}}
onSelectMaterialPreset={(materialPreset, category) => {
setActivePaintMaterial({ materialPreset, category, sourceTarget: activePaintTarget })
onSelectMaterialPreset={(materialPreset) => {
setActivePaintMaterial({ materialPreset, sourceTarget: activePaintTarget })
}}
selectedMaterialPreset={activePaintMaterial?.materialPreset}
value={activePaintMaterial?.material}
@@ -6,7 +6,6 @@ import {
getMaterialsForCategory,
MATERIAL_CATEGORIES,
toLibraryMaterialRef,
type MaterialCategory,
type MaterialSchema,
} from '@pascal-app/core'
import { useEffect, useRef, useState } from 'react'
@@ -15,8 +14,8 @@ import useEditor from '../../../store/use-editor'
type MaterialPickerProps = {
value?: MaterialSchema
selectedMaterialPreset?: string
onChange?: (material: MaterialSchema, category: MaterialCategory) => void
onSelectMaterialPreset?: (materialPreset: string, category: MaterialCategory) => void
onChange?: (material: MaterialSchema) => void
onSelectMaterialPreset?: (materialPreset: string) => void
disabled?: boolean
}
@@ -29,7 +28,9 @@ export function MaterialPicker({
}: MaterialPickerProps) {
const setPaintPanelOpen = useEditor((state) => state.setPaintPanelOpen)
const [showCustom, setShowCustom] = useState<boolean>(!!value?.properties)
const [selectedCategory, setSelectedCategory] = useState<MaterialCategory>(MATERIAL_CATEGORIES[0])
const [selectedCategory, setSelectedCategory] = useState<(typeof MATERIAL_CATEGORIES)[number]>(
MATERIAL_CATEGORIES[0],
)
const catalogScrollRef = useRef<HTMLDivElement>(null)
const categoryScrollRef = useRef<HTMLDivElement>(null)
const catalogItems =
@@ -62,9 +63,7 @@ export function MaterialPicker({
if (disabled) return
setShowCustom(false)
setPaintPanelOpen(false)
const category = getCatalogMaterialById(materialId)?.category
if (!category) return
onSelectMaterialPreset?.(toLibraryMaterialRef(materialId), category)
onSelectMaterialPreset?.(toLibraryMaterialRef(materialId))
}
useEffect(() => {
@@ -113,8 +112,7 @@ export function MaterialPicker({
if (disabled) return
setShowCustom(true)
setPaintPanelOpen(true)
onChange?.(
{
onChange?.({
preset: 'custom',
properties: {
color: value?.properties?.color || '#ffffff',
@@ -124,9 +122,7 @@ export function MaterialPicker({
transparent: value?.properties?.transparent ?? false,
side: value?.properties?.side ?? 'front',
},
},
'other',
)
})
}
return (
@@ -47,7 +47,6 @@ export function PaintPanel() {
transparent: nextTransparent,
},
},
category: 'other',
sourceTarget: activePaintMaterial?.sourceTarget ?? activePaintTarget,
})
}
-34
View File
@@ -8,8 +8,6 @@ import {
getEffectiveStairSurfaceMaterial,
getEffectiveWallSurfaceMaterial,
getLibraryMaterialIdFromRef,
getMaterialCategoryTargets,
type MaterialCategory,
type MaterialSchema,
type MaterialTarget,
type RoofNode,
@@ -31,7 +29,6 @@ export type SingleSurfaceMaterialRole = 'surface'
export type ActivePaintMaterial = {
material?: MaterialSchema
materialPreset?: string
category?: MaterialCategory
sourceTarget: PaintableMaterialTarget
}
@@ -50,34 +47,10 @@ function getCatalogEntryForActivePaintMaterial(material: ActivePaintMaterial | n
return getCatalogMaterialById(catalogId)
}
function resolvePaintMaterialCategory(
material: MaterialSchema | undefined,
materialPreset: string | undefined,
): MaterialCategory | undefined {
const catalogId = getLibraryMaterialIdFromRef(materialPreset) ?? material?.id ?? undefined
const catalogEntry = getCatalogMaterialById(catalogId)
if (catalogEntry?.category) return catalogEntry.category
if (material || materialPreset === undefined) return 'other'
return undefined
}
export function getActivePaintMaterialLabel(material: ActivePaintMaterial | null | undefined) {
return getCatalogEntryForActivePaintMaterial(material)?.label ?? 'Custom'
}
export function isActivePaintMaterialCompatible(
material: ActivePaintMaterial | null | undefined,
target: PaintableMaterialTarget,
) {
if (!hasActivePaintMaterial(material)) return false
const catalogEntry = getCatalogEntryForActivePaintMaterial(material)
const category = material?.category ?? catalogEntry?.category
if (!category) return false
return getMaterialCategoryTargets(category).includes(target)
}
export function buildWallSurfaceMaterialPatch(
node: WallNode,
targetSide: WallSurfaceSide,
@@ -200,7 +173,6 @@ export function resolveActivePaintMaterialFromSelection(params: {
? {
material: surface.material,
materialPreset: surface.materialPreset,
category: resolvePaintMaterialCategory(surface.material, surface.materialPreset),
sourceTarget: 'wall',
}
: null
@@ -221,7 +193,6 @@ export function resolveActivePaintMaterialFromSelection(params: {
? {
material: surface.material,
materialPreset: surface.materialPreset,
category: resolvePaintMaterialCategory(surface.material, surface.materialPreset),
sourceTarget: 'roof',
}
: null
@@ -242,7 +213,6 @@ export function resolveActivePaintMaterialFromSelection(params: {
? {
material: surface.material,
materialPreset: surface.materialPreset,
category: resolvePaintMaterialCategory(surface.material, surface.materialPreset),
sourceTarget: 'stair',
}
: null
@@ -263,10 +233,6 @@ export function resolveActivePaintMaterialFromSelection(params: {
? {
material: selectedNode.material,
materialPreset: selectedNode.materialPreset,
category: resolvePaintMaterialCategory(
selectedNode.material,
selectedNode.materialPreset,
),
sourceTarget: target,
}
: null