ttrpg-tools/src/components/editor-panel.tsx

140 lines
4.4 KiB
TypeScript
Raw Normal View History

2026-02-27 12:24:51 +08:00
import { Show, For } from 'solid-js';
import type { CardData, LayerConfig } from './types';
export interface DataEditorPanelProps {
cards: CardData[];
activeTab: number;
updateCardData: (key: string, value: string) => void;
}
export interface PropertiesEditorPanelProps {
localSize: string;
localGrid: string;
localBleed: string;
localPadding: string;
layerConfigs: LayerConfig[];
editingLayer: string | null;
onSizeChange: (value: string) => void;
onGridChange: (value: string) => void;
onBleedChange: (value: string) => void;
onPaddingChange: (value: string) => void;
onToggleLayerVisible: (prop: string) => void;
onStartEditingLayer: (prop: string) => void;
onCopyCode: () => void;
}
/**
* CSV
*/
export function DataEditorPanel(props: DataEditorPanelProps) {
return (
<div class="w-64 flex-shrink-0">
<h3 class="font-bold mb-2"></h3>
<div class="space-y-2 max-h-96 overflow-y-auto">
2026-02-27 14:02:11 +08:00
<For each={Object.keys(props.cards[props.activeTab] || {})}>
{(key) => (
<div>
<label class="block text-sm font-medium text-gray-700">{key}</label>
<textarea
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
rows={3}
value={props.cards[props.activeTab]?.[key] || ''}
onInput={(e) => props.updateCardData(key, e.target.value)}
/>
</div>
)}
</For>
2026-02-27 12:24:51 +08:00
</div>
</div>
);
}
/**
*
*/
export function PropertiesEditorPanel(props: PropertiesEditorPanelProps) {
return (
<div class="w-64 flex-shrink-0">
<h3 class="font-bold mb-2"></h3>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-700"> (mm)</label>
<input
type="text"
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
value={props.localSize}
onInput={(e) => props.onSizeChange(e.target.value)}
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700"></label>
<input
type="text"
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
value={props.localGrid}
onInput={(e) => props.onGridChange(e.target.value)}
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700"> (mm)</label>
<input
type="text"
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
value={props.localBleed}
onInput={(e) => props.onBleedChange(e.target.value)}
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700"> (mm)</label>
<input
type="text"
class="w-full border border-gray-300 rounded px-2 py-1 text-sm"
value={props.localPadding}
onInput={(e) => props.onPaddingChange(e.target.value)}
/>
</div>
<hr class="my-4" />
<h4 class="font-medium text-sm text-gray-700"></h4>
<For each={props.layerConfigs}>
{(layer) => (
<div class="flex items-center gap-2">
<input
type="checkbox"
checked={layer.visible}
onChange={() => props.onToggleLayerVisible(layer.prop)}
class="cursor-pointer"
/>
<span class="text-sm flex-1">{layer.prop}</span>
<button
onClick={() => props.onStartEditingLayer(layer.prop)}
class={`text-xs px-2 py-0.5 rounded cursor-pointer ${
props.editingLayer === layer.prop
? 'bg-blue-500 text-white'
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
}`}
>
{props.editingLayer === layer.prop ? '✓ 框选' : '编辑位置'}
</button>
</div>
)}
</For>
<hr class="my-4" />
<button
onClick={props.onCopyCode}
class="w-full bg-blue-600 hover:bg-blue-700 text-white px-3 py-2 rounded text-sm font-medium cursor-pointer"
>
📋
</button>
</div>
</div>
);
}