/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * Material display component for IFC element materials. * Handles all IFC material types: direct, layer sets, profile sets, * constituent sets, and material lists. */ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { Layers } from 'lucide-react'; import type { MaterialInfo } from '@ifc-lite/parser'; const TYPE_LABELS: Record = { Material: 'Material', MaterialLayerSet: 'Layer Set', MaterialProfileSet: 'Profile Set', MaterialConstituentSet: 'Constituent Set', MaterialList: 'Material List', }; export function MaterialCard({ material }: { material: MaterialInfo }) { const typeLabel = TYPE_LABELS[material.type] || material.type; const displayName = material.name || typeLabel; return ( {displayName} {typeLabel}
{/* Direct material */} {material.type === 'Material' && ( <> {material.name && ( )} {material.description && ( )} )} {/* Layer Set */} {material.type === 'MaterialLayerSet' && material.layers && ( <> {material.name && } {material.layers.map((layer, i) => (
Layer {i + 1} {layer.thickness !== undefined && ( {formatThickness(layer.thickness)} )}
{layer.materialName && ( <> Material {layer.materialName} )} {layer.name && ( <> Name {layer.name} )} {layer.category && ( <> Category {layer.category} )} {layer.isVentilated && ( <> Ventilated Yes )}
))} )} {/* Profile Set */} {material.type === 'MaterialProfileSet' && material.profiles && ( <> {material.name && } {material.profiles.map((profile, i) => (
Profile {i + 1}
{profile.materialName && ( <> Material {profile.materialName} )} {profile.name && ( <> Name {profile.name} )} {profile.category && ( <> Category {profile.category} )}
))} )} {/* Constituent Set */} {material.type === 'MaterialConstituentSet' && material.constituents && ( <> {material.name && } {material.constituents.map((constituent, i) => (
{constituent.name || `Constituent ${i + 1}`} {constituent.fraction !== undefined && ( {(constituent.fraction * 100).toFixed(1)}% )}
{constituent.materialName && ( <> Material {constituent.materialName} )} {constituent.category && ( <> Category {constituent.category} )}
))} )} {/* Material List */} {material.type === 'MaterialList' && material.materials && ( <> {material.materials.map((m, i) => ( ))} )}
); } function MaterialRow({ label, value }: { label: string; value: string }) { return (
{label} {value}
); } function formatThickness(thickness: number): string { if (thickness <= 0) return `${thickness.toFixed(1)} m`; if (thickness >= 1) { return `${thickness.toFixed(1)} m`; } // Show in mm for sub-meter thicknesses const mm = thickness * 1000; return `${mm.toFixed(1)} mm`; }