fix: Expand spell notes textarea full-width; add inter-spell padding

Split each spell into two table rows: the inputs row (name, MP, targets,
duration, delete) and a full-width notes row (colspan=5). Adds 10px
padding above/below each spell for visual separation between entries.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 16:46:46 -04:00
parent e26f135b79
commit b6d8e34090
2 changed files with 105 additions and 82 deletions

View File

@@ -1335,88 +1335,94 @@ export default function CharacterSheet() {
</thead> </thead>
<tbody> <tbody>
{spells.map((s, i) => ( {spells.map((s, i) => (
<tr key={i}> <React.Fragment key={i}>
<td className="spell-name-col"> <tr className="spell-inputs-row">
<input <td className="spell-name-col">
type="text" <input
placeholder="Spell / Arcana name…" type="text"
value={s.name || ""} placeholder="Spell / Arcana name…"
onChange={(e) => value={s.name || ""}
setSpells((prev) => onChange={(e) =>
prev.map((sp, j) => setSpells((prev) =>
j === i ? { ...sp, name: e.target.value } : sp, prev.map((sp, j) =>
), j === i ? { ...sp, name: e.target.value } : sp,
) ),
} )
/> }
<textarea />
placeholder="Notes / effect description…" </td>
value={s.notes || ""} <td className="spell-mp-col">
ref={(el) => { if (el) autoResize(el); }} <input
onInput={(e) => autoResize(e.currentTarget)} type="number"
onChange={(e) => placeholder="0"
setSpells((prev) => value={s.mp || ""}
prev.map((sp, j) => onChange={(e) =>
j === i ? { ...sp, notes: e.target.value } : sp, setSpells((prev) =>
), prev.map((sp, j) =>
) j === i ? { ...sp, mp: e.target.value } : sp,
} ),
/> )
</td> }
<td className="spell-mp-col"> style={{ minHeight: 32 }}
<input />
type="number" </td>
placeholder="0" <td className="spell-targets-col">
value={s.mp || ""} <input
onChange={(e) => type="text"
setSpells((prev) => placeholder="Target(s)…"
prev.map((sp, j) => value={s.targets || ""}
j === i ? { ...sp, mp: e.target.value } : sp, onChange={(e) =>
), setSpells((prev) =>
) prev.map((sp, j) =>
} j === i ? { ...sp, targets: e.target.value } : sp,
style={{ minHeight: 32 }} ),
/> )
</td> }
<td className="spell-targets-col"> />
<input </td>
type="text" <td className="spell-dur-col">
placeholder="Target(s)…" <input
value={s.targets || ""} type="text"
onChange={(e) => placeholder="Duration…"
setSpells((prev) => value={s.duration || ""}
prev.map((sp, j) => onChange={(e) =>
j === i ? { ...sp, targets: e.target.value } : sp, setSpells((prev) =>
), prev.map((sp, j) =>
) j === i ? { ...sp, duration: e.target.value } : sp,
} ),
/> )
</td> }
<td className="spell-dur-col"> />
<input </td>
type="text" <td className="spell-del-col">
placeholder="Duration…" <button
value={s.duration || ""} className="spell-del-btn"
onChange={(e) => onClick={() =>
setSpells((prev) => setSpells((prev) => prev.filter((_, j) => j !== i))
prev.map((sp, j) => }
j === i ? { ...sp, duration: e.target.value } : sp, >
),
) </button>
} </td>
/> </tr>
</td> <tr className="spell-notes-row">
<td className="spell-del-col"> <td colSpan={5}>
<button <textarea
className="spell-del-btn" placeholder="Notes / effect description…"
onClick={() => value={s.notes || ""}
setSpells((prev) => prev.filter((_, j) => j !== i)) ref={(el) => { if (el) autoResize(el); }}
} onInput={(e) => autoResize(e.currentTarget)}
> onChange={(e) =>
setSpells((prev) =>
</button> prev.map((sp, j) =>
</td> j === i ? { ...sp, notes: e.target.value } : sp,
</tr> ),
)
}
/>
</td>
</tr>
</React.Fragment>
))} ))}
</tbody> </tbody>
</table> </table>

View File

@@ -765,6 +765,23 @@ input[type="number"] {
min-height: 55px; min-height: 55px;
} }
.spell-inputs-row td {
border-bottom: none;
padding-top: 10px;
}
.spell-notes-row td {
padding-top: 0;
padding-bottom: 10px;
}
.spell-notes-row textarea {
display: block;
width: 100%;
min-height: 0;
box-sizing: border-box;
}
.spell-name-col { .spell-name-col {
width: 35%; width: 35%;
} }