Adds first version of the app. Local storage only.

This commit is contained in:
2026-09-01 14:44:49 -05:00
commit 9710f1ee5a
44 changed files with 5865 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
import { useMemo } from 'react'
import { computeBom } from '../../domain/bom'
import { useProjectStore } from '../../state/projectStore'
export default function BomPanel() {
const project = useProjectStore((s) => s.project)
const bom = useMemo(() => computeBom(project), [project])
return (
<div className="space-y-4 p-3">
<section>
<h4 className="mb-1 text-xs font-semibold uppercase tracking-wide text-slate-500">Devices</h4>
{bom.devices.length === 0 ? (
<p className="text-xs italic text-slate-400">No devices on the canvas yet.</p>
) : (
<table className="w-full text-xs">
<tbody>
{bom.devices.map((line) => (
<tr key={line.key} className="border-b border-slate-100 last:border-0">
<td className="py-1 pr-2">
<div className="font-medium text-slate-700">{line.name}</div>
{(line.manufacturer || line.model) && (
<div className="text-[10px] text-slate-400">
{[line.manufacturer, line.model].filter(Boolean).join(' ')}
</div>
)}
</td>
<td className="py-1 text-right font-medium text-slate-600">×{line.count}</td>
</tr>
))}
</tbody>
</table>
)}
</section>
<section>
<h4 className="mb-1 text-xs font-semibold uppercase tracking-wide text-slate-500">Cables</h4>
{bom.cables.length === 0 ? (
<p className="text-xs italic text-slate-400">No cables wired up yet.</p>
) : (
<table className="w-full text-xs">
<thead>
<tr className="text-left text-[10px] uppercase tracking-wide text-slate-400">
<th className="pb-1 font-medium">Cable</th>
<th className="pb-1 text-right font-medium">Count</th>
<th className="pb-1 text-right font-medium">Total length</th>
</tr>
</thead>
<tbody>
{bom.cables.map((line) => (
<tr key={line.cableTypeId} className="border-b border-slate-100 last:border-0">
<td className="py-1 pr-2 font-medium text-slate-700">{line.cableTypeName}</td>
<td className="py-1 text-right text-slate-600">×{line.count}</td>
<td className="py-1 text-right text-slate-600">
{line.totalLength > 0 ? `${line.totalLength}${line.unit}` : '—'}
{line.connectionsMissingLength > 0 && (
<span className="ml-1 text-[10px] text-amber-500" title="Some cables are missing a distance">
({line.connectionsMissingLength} unset)
</span>
)}
</td>
</tr>
))}
</tbody>
</table>
)}
</section>
</div>
)
}