ttrpg-tools/src/components/md-deck/CardLayer.tsx

66 lines
2.3 KiB
TypeScript
Raw Normal View History

import {createMemo, For} from 'solid-js';
2026-03-13 11:14:01 +08:00
import {parseMarkdown} from '../../markdown';
2026-02-27 21:12:23 +08:00
import { getLayerStyle } from './hooks/dimensions';
2026-03-13 17:26:00 +08:00
import type { CardData, CardSide } from './types';
import {DeckStore} from "./hooks/deckStore";
import {processVariables} from "../utils/csv-loader";
2026-03-13 11:46:18 +08:00
import {resolvePath} from "../utils/path";
2026-02-27 21:12:23 +08:00
export interface CardLayerProps {
cardData: CardData;
store: DeckStore;
2026-03-13 17:26:00 +08:00
side?: CardSide;
2026-02-27 21:12:23 +08:00
}
export function CardLayer(props: CardLayerProps) {
2026-03-13 17:26:00 +08:00
const side = () => props.side || 'front';
const layers = createMemo(() =>
side() === 'front'
? props.store.state.frontLayerConfigs.filter((l) => l.visible)
: props.store.state.backLayerConfigs.filter((l) => l.visible)
);
const dimensions = () => props.store.state.dimensions!;
const showBounds = () => props.store.state.isEditing;
2026-03-13 17:26:00 +08:00
function renderLayerContent(content: string) {
2026-03-25 17:29:56 +08:00
const iconPath = resolvePath(props.store.state.cards.sourcePath, props.cardData.iconPath ?? "./assets");
2026-03-13 11:46:18 +08:00
return parseMarkdown(processVariables(content, props.cardData, props.store.state.cards), iconPath) as string;
}
2026-03-27 15:17:25 +08:00
const getAlignStyle = (align?: 'l' | 'c' | 'r') => {
if (align === 'l') return 'left';
if (align === 'r') return 'right';
return 'center';
};
2026-02-27 21:12:23 +08:00
return (
<For each={layers()}>
2026-02-27 22:56:06 +08:00
{(layer) => {
return (
<>
<article
2026-03-27 15:17:25 +08:00
class="absolute flex flex-col items-stretch justify-center prose prose-sm"
2026-02-27 22:37:11 +08:00
style={{
...getLayerStyle(layer, dimensions()),
2026-03-27 15:17:25 +08:00
'font-size': `${layer.fontSize || 3}mm`,
'text-align': getAlignStyle(layer.align)
2026-02-27 22:37:11 +08:00
}}
innerHTML={renderLayerContent(props.cardData[layer.prop])}
2026-02-27 22:37:11 +08:00
/>
{showBounds() && (
2026-02-27 22:56:06 +08:00
<div
class="absolute border-2 border-blue-500/50 pointer-events-none select-none"
style={{
left: `${(layer.x1 - 1) * dimensions().cellWidth}mm`,
top: `${(layer.y1 - 1) * dimensions().cellHeight}mm`,
width: `${(layer.x2 - layer.x1 + 1) * dimensions().cellWidth}mm`,
height: `${(layer.y2 - layer.y1 + 1) * dimensions().cellHeight}mm`
2026-02-27 22:56:06 +08:00
}}
/>
)}
</>
);
}}
2026-02-27 21:12:23 +08:00
</For>
);
}