feat: port TechLog Studio editors
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import type { components } from "../../../contracts/studio/generated.ts";
|
||||
import { createLocalId } from "../../../domain/studio/local-id.ts";
|
||||
|
||||
type CatalogEntry = components["schemas"]["CatalogEntry"];
|
||||
type RelationInput = components["schemas"]["RelationInput"];
|
||||
|
||||
function ordered(relations: RelationInput[]): RelationInput[] {
|
||||
return relations.map((relation, order) => ({ ...relation, order }));
|
||||
}
|
||||
|
||||
export function RelationEditor({ relations, catalog, onChange }: { relations: RelationInput[]; catalog: CatalogEntry[]; onChange(relations: RelationInput[]): void }) {
|
||||
const update = (index: number, patch: Partial<RelationInput>) => onChange(ordered(relations.map((relation, candidateIndex) => candidateIndex === index ? { ...relation, ...patch } : relation)));
|
||||
const move = (index: number, delta: -1 | 1) => {
|
||||
const target = index + delta;
|
||||
if (target < 0 || target >= relations.length) return;
|
||||
const next = [...relations];
|
||||
[next[index], next[target]] = [next[target]!, next[index]!];
|
||||
onChange(ordered(next));
|
||||
};
|
||||
return (
|
||||
<fieldset className="studio-ordered-list">
|
||||
<legend>관계</legend>
|
||||
{relations.length === 0 ? <p>연결한 공개 기록이 없습니다.</p> : null}
|
||||
{relations.map((relation, index) => (
|
||||
<div className="studio-relation-item" key={relation.id ?? `relation-${index}`}>
|
||||
<label><span>관계 {index + 1} 대상</span><select value={relation.targetId ?? ""} onChange={(event) => update(index, { targetId: event.currentTarget.value || null })}><option value="">대상 선택</option>{catalog.map((entry) => <option key={entry.id} value={entry.id} disabled={relations.some((candidate, candidateIndex) => candidateIndex !== index && candidate.targetId === entry.id)}>{entry.label}</option>)}</select></label>
|
||||
<label><span>관계 {index + 1} 이유</span><input value={relation.reason} onChange={(event) => update(index, { reason: event.currentTarget.value })} /></label>
|
||||
<div className="studio-item-actions"><button type="button" onClick={() => move(index, -1)} disabled={index === 0}>위로</button><button type="button" onClick={() => move(index, 1)} disabled={index === relations.length - 1}>아래로</button><button type="button" onClick={() => onChange(ordered(relations.filter((_, candidateIndex) => candidateIndex !== index)))}>삭제</button></div>
|
||||
</div>
|
||||
))}
|
||||
<button className="studio-add-item" type="button" disabled={relations.length >= 20} onClick={() => { if (relations.length < 20) onChange(ordered([...relations, { id: createLocalId("relation"), targetId: null, reason: "", order: relations.length }])); }}>관계 추가</button>
|
||||
</fieldset>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user