feat: integrate AMESim media models and editor UI
This commit is contained in:
1 parent
3e4f466114
commit
e7177ab03e
181 files changed
+7042
-25270
No files matched your search
@@ -0,0 +1,235 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export type ComponentSymbolSurface = "palette" | "canvas";
|
||||
export type ComponentSymbolPresentation = "framed" | "bare";
|
||||
|
||||
type ComponentSymbolProps = {
|
||||
symbol: string;
|
||||
surface: ComponentSymbolSurface;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type SymbolDefinition = {
|
||||
presentation: ComponentSymbolPresentation;
|
||||
render: () => ReactNode;
|
||||
};
|
||||
|
||||
type SymbolSvgProps = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
function SymbolSvg({ children, className }: SymbolSvgProps) {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className={["component-symbol-svg", className].filter(Boolean).join(" ")}
|
||||
fill="none"
|
||||
focusable="false"
|
||||
viewBox="0 0 64 48"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
function CylinderSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M3 24h7M54 24h7" stroke="currentColor" strokeWidth="2" />
|
||||
<rect
|
||||
fill="#dbeafe"
|
||||
height="26"
|
||||
rx="11"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
width="44"
|
||||
x="10"
|
||||
y="11"
|
||||
/>
|
||||
<path d="M33 12v24M33 24h21" stroke="currentColor" strokeWidth="2" />
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function TankSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M32 2v5M32 41v5" stroke="currentColor" strokeWidth="2" />
|
||||
<path
|
||||
d="M16 13c0-4 7.2-7 16-7s16 3 16 7v22c0 4-7.2 7-16 7s-16-3-16-7V13Z"
|
||||
fill="#dcfce7"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path d="M16 13c0 4 7.2 7 16 7s16-3 16-7" stroke="currentColor" strokeWidth="2" />
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function PipeSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M2 19h60M2 29h60" stroke="currentColor" strokeWidth="2" />
|
||||
<path d="M9 17v14M55 17v14" stroke="currentColor" strokeWidth="2" />
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function OrificeSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M2 24h18M44 24h18" stroke="currentColor" strokeWidth="2" />
|
||||
<path
|
||||
d="m19 9 13 15-13 15V9ZM45 9 32 24l13 15V9Z"
|
||||
fill="#ffedd5"
|
||||
stroke="currentColor"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function TeeSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M2 27h60M32 27V3" stroke="currentColor" strokeWidth="8" />
|
||||
<path d="M2 27h60M32 27V3" stroke="#f8fafc" strokeWidth="4" />
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function GenericSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M2 24h9M53 24h9" stroke="currentColor" strokeWidth="2" />
|
||||
<rect
|
||||
fill="#f8fafc"
|
||||
height="30"
|
||||
rx="3"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
width="42"
|
||||
x="11"
|
||||
y="9"
|
||||
/>
|
||||
<path d="m23 30 18-12M23 18h18v12" stroke="currentColor" strokeWidth="1.5" />
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function SignalSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M2 24h8M54 24h8" stroke="currentColor" strokeWidth="2" />
|
||||
<circle cx="32" cy="24" fill="#f8fafc" r="22" stroke="currentColor" strokeWidth="2" />
|
||||
<path
|
||||
d="M16 25c4-13 8-13 12 0s8 13 12 0 6-10 8-4"
|
||||
stroke="#2563eb"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function JunctionSymbol() {
|
||||
return (
|
||||
<SymbolSvg>
|
||||
<path d="M2 24h60M32 2v44" stroke="currentColor" strokeWidth="2" />
|
||||
<circle cx="32" cy="24" fill="currentColor" r="5" />
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
function MediumSymbol({ label }: { label: "Air" | "He" }) {
|
||||
return (
|
||||
<SymbolSvg className="component-symbol-medium-svg">
|
||||
<circle cx="32" cy="24" fill="#ffffff" r="22" stroke="#c026d3" strokeWidth="2" />
|
||||
<text
|
||||
className="component-symbol-medium-label"
|
||||
data-symbol-label={label}
|
||||
dominantBaseline="central"
|
||||
fill="#a21caf"
|
||||
fontFamily="Arial, sans-serif"
|
||||
fontSize={label === "Air" ? 12 : 16}
|
||||
fontWeight="500"
|
||||
textAnchor="middle"
|
||||
x="32"
|
||||
y="24"
|
||||
>
|
||||
{label}
|
||||
</text>
|
||||
</SymbolSvg>
|
||||
);
|
||||
}
|
||||
|
||||
const symbolRegistry = {
|
||||
cylinder: { presentation: "framed", render: CylinderSymbol },
|
||||
tank: { presentation: "framed", render: TankSymbol },
|
||||
pipe: { presentation: "framed", render: PipeSymbol },
|
||||
orifice: { presentation: "framed", render: OrificeSymbol },
|
||||
tee: { presentation: "framed", render: TeeSymbol },
|
||||
generic: { presentation: "framed", render: GenericSymbol },
|
||||
signal: { presentation: "framed", render: SignalSymbol },
|
||||
junction: { presentation: "framed", render: JunctionSymbol },
|
||||
amesim_ideal_air_medium: {
|
||||
presentation: "bare",
|
||||
render: () => <MediumSymbol label="Air" />,
|
||||
},
|
||||
amesim_helium_medium: {
|
||||
presentation: "bare",
|
||||
render: () => <MediumSymbol label="He" />,
|
||||
},
|
||||
} satisfies Record<string, SymbolDefinition>;
|
||||
|
||||
type RegisteredComponentSymbol = keyof typeof symbolRegistry;
|
||||
|
||||
function isRegisteredComponentSymbol(symbol: string): symbol is RegisteredComponentSymbol {
|
||||
return Object.prototype.hasOwnProperty.call(symbolRegistry, symbol);
|
||||
}
|
||||
|
||||
export function hasComponentSymbol(symbol: string): boolean {
|
||||
return isRegisteredComponentSymbol(symbol);
|
||||
}
|
||||
|
||||
export function componentSymbolPresentation(
|
||||
symbol: string,
|
||||
): ComponentSymbolPresentation {
|
||||
return isRegisteredComponentSymbol(symbol)
|
||||
? symbolRegistry[symbol].presentation
|
||||
: "framed";
|
||||
}
|
||||
|
||||
export function ComponentSymbol({
|
||||
symbol,
|
||||
surface,
|
||||
className,
|
||||
}: ComponentSymbolProps) {
|
||||
const resolvedSymbol: RegisteredComponentSymbol = isRegisteredComponentSymbol(symbol)
|
||||
? symbol
|
||||
: "generic";
|
||||
const definition = symbolRegistry[resolvedSymbol];
|
||||
const rootClassName = [
|
||||
"component-symbol",
|
||||
`component-symbol-${surface}`,
|
||||
`component-symbol-${resolvedSymbol}`,
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
return (
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={rootClassName}
|
||||
data-component-symbol={resolvedSymbol}
|
||||
data-symbol-presentation={definition.presentation}
|
||||
>
|
||||
{definition.render()}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user