chore: Fix useButtonType linter errors
This commit is contained in:
@@ -329,7 +329,12 @@ export default function CharacterSheet() {
|
|||||||
b: c.benefits,
|
b: c.benefits,
|
||||||
s: c.skills,
|
s: c.skills,
|
||||||
})),
|
})),
|
||||||
oc: otherClasses.map((c) => ({ n: c.name, lv: c.level, b: c.benefits, s: c.skills })),
|
oc: otherClasses.map((c) => ({
|
||||||
|
n: c.name,
|
||||||
|
lv: c.level,
|
||||||
|
b: c.benefits,
|
||||||
|
s: c.skills,
|
||||||
|
})),
|
||||||
sp: spells.map((s) => ({
|
sp: spells.map((s) => ({
|
||||||
n: s.name,
|
n: s.name,
|
||||||
cl: s.spellClass,
|
cl: s.spellClass,
|
||||||
@@ -612,7 +617,7 @@ export default function CharacterSheet() {
|
|||||||
<div className="logo">Fabula Ultima</div>
|
<div className="logo">Fabula Ultima</div>
|
||||||
<div className="tabs">
|
<div className="tabs">
|
||||||
{["main", "classes", "spells", "manage"].map((tab, i) => (
|
{["main", "classes", "spells", "manage"].map((tab, i) => (
|
||||||
<button
|
<button type="button"
|
||||||
key={tab}
|
key={tab}
|
||||||
className={`tab${activeTab === tab ? " active" : ""}`}
|
className={`tab${activeTab === tab ? " active" : ""}`}
|
||||||
onClick={() => setActiveTab(tab)}
|
onClick={() => setActiveTab(tab)}
|
||||||
@@ -625,10 +630,10 @@ export default function CharacterSheet() {
|
|||||||
<span className={`save-status${saveStatus ? " show" : ""}`}>
|
<span className={`save-status${saveStatus ? " show" : ""}`}>
|
||||||
Saved!
|
Saved!
|
||||||
</span>
|
</span>
|
||||||
<button className="btn-print" onClick={() => window.print()}>
|
<button type="button" className="btn-print" onClick={() => window.print()}>
|
||||||
⎙ Print
|
⎙ Print
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button type="button"
|
||||||
className="btn-theme"
|
className="btn-theme"
|
||||||
onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}
|
onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}
|
||||||
>
|
>
|
||||||
@@ -725,7 +730,7 @@ export default function CharacterSheet() {
|
|||||||
<div className="level-display">
|
<div className="level-display">
|
||||||
<span className="level-num">{level}</span>
|
<span className="level-num">{level}</span>
|
||||||
<span className="level-text">Character Level</span>
|
<span className="level-text">Character Level</span>
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
style={{
|
style={{
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
@@ -736,7 +741,7 @@ export default function CharacterSheet() {
|
|||||||
>
|
>
|
||||||
+ Level Up
|
+ Level Up
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
style={{
|
style={{
|
||||||
marginTop: 4,
|
marginTop: 4,
|
||||||
@@ -821,12 +826,14 @@ export default function CharacterSheet() {
|
|||||||
<span className="icon">◈</span> Attributes
|
<span className="icon">◈</span> Attributes
|
||||||
</div>
|
</div>
|
||||||
<div className="attr-grid">
|
<div className="attr-grid">
|
||||||
{([
|
{(
|
||||||
{ label: "Dexterity", base: "dexBase", cur: "dexCur" },
|
[
|
||||||
{ label: "Insight", base: "insBase", cur: "insCur" },
|
{ label: "Dexterity", base: "dexBase", cur: "dexCur" },
|
||||||
{ label: "Might", base: "migBase", cur: "migCur" },
|
{ label: "Insight", base: "insBase", cur: "insCur" },
|
||||||
{ label: "Willpower", base: "wlpBase", cur: "wlpCur" },
|
{ label: "Might", base: "migBase", cur: "migCur" },
|
||||||
] as const).map(({ label, base, cur }) => (
|
{ label: "Willpower", base: "wlpBase", cur: "wlpCur" },
|
||||||
|
] as const
|
||||||
|
).map(({ label, base, cur }) => (
|
||||||
<div key={label} className="attr-block">
|
<div key={label} className="attr-block">
|
||||||
<div className="attr-name">{label}</div>
|
<div className="attr-name">{label}</div>
|
||||||
<div className="attr-inputs">
|
<div className="attr-inputs">
|
||||||
@@ -901,7 +908,7 @@ export default function CharacterSheet() {
|
|||||||
{inCrisis && <div className="crisis-badge">CRISIS</div>}
|
{inCrisis && <div className="crisis-badge">CRISIS</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
style={{ padding: "4px 8px" }}
|
style={{ padding: "4px 8px" }}
|
||||||
onClick={calcHP}
|
onClick={calcHP}
|
||||||
@@ -931,7 +938,7 @@ export default function CharacterSheet() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
style={{ padding: "4px 8px" }}
|
style={{ padding: "4px 8px" }}
|
||||||
onClick={calcMP}
|
onClick={calcMP}
|
||||||
@@ -1099,36 +1106,38 @@ export default function CharacterSheet() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: 14 }}>
|
<div style={{ marginTop: 14 }}>
|
||||||
{([
|
{(
|
||||||
{
|
[
|
||||||
slot: "Accessory",
|
{
|
||||||
name: "accName",
|
slot: "Accessory",
|
||||||
desc: "accDesc",
|
name: "accName",
|
||||||
namePh: "Item name",
|
desc: "accDesc",
|
||||||
descPh: "Description / effect",
|
namePh: "Item name",
|
||||||
},
|
descPh: "Description / effect",
|
||||||
{
|
},
|
||||||
slot: "Armor",
|
{
|
||||||
name: "armName",
|
slot: "Armor",
|
||||||
desc: "armDesc",
|
name: "armName",
|
||||||
namePh: "Item name",
|
desc: "armDesc",
|
||||||
descPh: "Defense bonus / effect",
|
namePh: "Item name",
|
||||||
},
|
descPh: "Defense bonus / effect",
|
||||||
{
|
},
|
||||||
slot: "Main Hand",
|
{
|
||||||
name: "mhName",
|
slot: "Main Hand",
|
||||||
desc: "mhDesc",
|
name: "mhName",
|
||||||
namePh: "Weapon name",
|
desc: "mhDesc",
|
||||||
descPh: "Damage / effect",
|
namePh: "Weapon name",
|
||||||
},
|
descPh: "Damage / effect",
|
||||||
{
|
},
|
||||||
slot: "Off-Hand",
|
{
|
||||||
name: "ohName",
|
slot: "Off-Hand",
|
||||||
desc: "ohDesc",
|
name: "ohName",
|
||||||
namePh: "Weapon / shield",
|
desc: "ohDesc",
|
||||||
descPh: "Damage / effect",
|
namePh: "Weapon / shield",
|
||||||
},
|
descPh: "Damage / effect",
|
||||||
] as const).map(({ slot, name, desc, namePh, descPh }) => (
|
},
|
||||||
|
] as const
|
||||||
|
).map(({ slot, name, desc, namePh, descPh }) => (
|
||||||
<div key={slot} className="equip-row">
|
<div key={slot} className="equip-row">
|
||||||
<div className="equip-slot">{slot}</div>
|
<div className="equip-slot">{slot}</div>
|
||||||
<div className="equip-fields">
|
<div className="equip-fields">
|
||||||
@@ -1160,75 +1169,128 @@ export default function CharacterSheet() {
|
|||||||
placeholder="Items, notes, lore…"
|
placeholder="Items, notes, lore…"
|
||||||
style={{ minHeight: 200 }}
|
style={{ minHeight: 200 }}
|
||||||
/>
|
/>
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
style={{ marginTop: 8 }}
|
style={{ marginTop: 8 }}
|
||||||
onClick={() => { setWeaponCategory("all"); setWeaponPickerOpen(true); }}
|
onClick={() => {
|
||||||
|
setWeaponCategory("all");
|
||||||
|
setWeaponPickerOpen(true);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
+ Add Equipment
|
+ Add Equipment
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{weaponPickerOpen && (() => {
|
{weaponPickerOpen &&
|
||||||
const allWeapons = (weaponsFile as WeaponsFile).weapons;
|
(() => {
|
||||||
const allArmorShields = (armorShieldsFile as ArmorShieldsFile).armor_shields;
|
const allWeapons = (weaponsFile as WeaponsFile).weapons;
|
||||||
type PickerItem =
|
const allArmorShields = (armorShieldsFile as ArmorShieldsFile)
|
||||||
| { kind: "weapon"; data: WeaponTemplate }
|
.armor_shields;
|
||||||
| { kind: "armor"; data: ArmorShieldTemplate };
|
type PickerItem =
|
||||||
const allItems: PickerItem[] = [
|
| { kind: "weapon"; data: WeaponTemplate }
|
||||||
...allWeapons.map(w => ({ kind: "weapon" as const, data: w })),
|
| { kind: "armor"; data: ArmorShieldTemplate };
|
||||||
...allArmorShields.map(a => ({ kind: "armor" as const, data: a })),
|
const allItems: PickerItem[] = [
|
||||||
];
|
...allWeapons.map((w) => ({
|
||||||
const categories = ["all", ...Array.from(new Set(allItems.map(i => i.data.category))).sort()];
|
kind: "weapon" as const,
|
||||||
const visible = weaponCategory === "all" ? allItems : allItems.filter(i => i.data.category === weaponCategory);
|
data: w,
|
||||||
const formatLine = (item: PickerItem) => {
|
})),
|
||||||
if (item.kind === "weapon") {
|
...allArmorShields.map((a) => ({
|
||||||
const w = item.data;
|
kind: "armor" as const,
|
||||||
return `• ${w.name}: Acc ${w.accuracy}, Dmg ${w.damage}${w.description ? ` | ${w.description}` : ""}${w.cost > 0 ? ` (${w.cost}z)` : ""}`;
|
data: a,
|
||||||
} else {
|
})),
|
||||||
const a = item.data;
|
];
|
||||||
const init = a.initiative ?? a.initative ?? 0;
|
const categories = [
|
||||||
return `• ${a.name}: DEF ${a.defense}, MDEF ${a.magic_defense}, Init ${init}${a.description ? ` | ${a.description}` : ""}${a.cost > 0 ? ` (${a.cost}z)` : ""}`;
|
"all",
|
||||||
}
|
...Array.from(
|
||||||
};
|
new Set(allItems.map((i) => i.data.category)),
|
||||||
return (
|
).sort(),
|
||||||
<div className="spell-picker-overlay" onClick={() => setWeaponPickerOpen(false)}>
|
];
|
||||||
<div className="spell-picker-modal" onClick={e => e.stopPropagation()}>
|
const visible =
|
||||||
<div className="spell-picker-header">
|
weaponCategory === "all"
|
||||||
<span>Choose equipment</span>
|
? allItems
|
||||||
<button className="spell-picker-close" onClick={() => setWeaponPickerOpen(false)}>✕</button>
|
: allItems.filter(
|
||||||
</div>
|
(i) => i.data.category === weaponCategory,
|
||||||
<div style={{ display: "flex", gap: 6, flexWrap: "wrap", padding: "8px 14px", borderBottom: "1px solid var(--border)" }}>
|
);
|
||||||
{categories.map(cat => (
|
const formatLine = (item: PickerItem) => {
|
||||||
<button
|
if (item.kind === "weapon") {
|
||||||
key={cat}
|
const w = item.data;
|
||||||
className={`add-btn${weaponCategory === cat ? " active-filter" : ""}`}
|
return `• ${w.name}: Acc ${w.accuracy}, Dmg ${w.damage}${w.description ? ` | ${w.description}` : ""}${w.cost > 0 ? ` (${w.cost}z)` : ""}`;
|
||||||
style={{ padding: "2px 8px", fontSize: "0.65rem", textTransform: "capitalize" }}
|
} else {
|
||||||
onClick={() => setWeaponCategory(cat)}
|
const a = item.data;
|
||||||
|
const init = a.initiative ?? a.initative ?? 0;
|
||||||
|
return `• ${a.name}: DEF ${a.defense}, MDEF ${a.magic_defense}, Init ${init}${a.description ? ` | ${a.description}` : ""}${a.cost > 0 ? ` (${a.cost}z)` : ""}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="spell-picker-overlay"
|
||||||
|
onClick={() => setWeaponPickerOpen(false)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="spell-picker-modal"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<div className="spell-picker-header">
|
||||||
|
<span>Choose equipment</span>
|
||||||
|
<button type="button"
|
||||||
|
className="spell-picker-close"
|
||||||
|
onClick={() => setWeaponPickerOpen(false)}
|
||||||
>
|
>
|
||||||
{cat}
|
✕
|
||||||
</button>
|
</button>
|
||||||
))}
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
gap: 6,
|
||||||
|
flexWrap: "wrap",
|
||||||
|
padding: "8px 14px",
|
||||||
|
borderBottom: "1px solid var(--border)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{categories.map((cat) => (
|
||||||
|
<button type="button"
|
||||||
|
key={cat}
|
||||||
|
className={`add-btn${weaponCategory === cat ? " active-filter" : ""}`}
|
||||||
|
style={{
|
||||||
|
padding: "2px 8px",
|
||||||
|
fontSize: "0.65rem",
|
||||||
|
textTransform: "capitalize",
|
||||||
|
}}
|
||||||
|
onClick={() => setWeaponCategory(cat)}
|
||||||
|
>
|
||||||
|
{cat}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<ul className="spell-picker-list">
|
||||||
|
{visible.map((item, i) => (
|
||||||
|
<li
|
||||||
|
key={i}
|
||||||
|
className="spell-picker-item"
|
||||||
|
onClick={() => {
|
||||||
|
const line = formatLine(item);
|
||||||
|
f(
|
||||||
|
"backpack",
|
||||||
|
fields.backpack
|
||||||
|
? fields.backpack + "\n" + line
|
||||||
|
: line,
|
||||||
|
);
|
||||||
|
setWeaponPickerOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="spell-picker-name">
|
||||||
|
{item.data.name}
|
||||||
|
</span>
|
||||||
|
<span className="spell-picker-class">
|
||||||
|
{item.data.category}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<ul className="spell-picker-list">
|
|
||||||
{visible.map((item, i) => (
|
|
||||||
<li
|
|
||||||
key={i}
|
|
||||||
className="spell-picker-item"
|
|
||||||
onClick={() => {
|
|
||||||
const line = formatLine(item);
|
|
||||||
f("backpack", fields.backpack ? fields.backpack + "\n" + line : line);
|
|
||||||
setWeaponPickerOpen(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span className="spell-picker-name">{item.data.name}</span>
|
|
||||||
<span className="spell-picker-class">{item.data.category}</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
})()}
|
||||||
})()}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1275,7 +1337,9 @@ export default function CharacterSheet() {
|
|||||||
<textarea
|
<textarea
|
||||||
placeholder="Skill information…"
|
placeholder="Skill information…"
|
||||||
value={cls.skills || ""}
|
value={cls.skills || ""}
|
||||||
ref={(el) => { if (el) autoResize(el); }}
|
ref={(el) => {
|
||||||
|
if (el) autoResize(el);
|
||||||
|
}}
|
||||||
onInput={(e) => autoResize(e.currentTarget)}
|
onInput={(e) => autoResize(e.currentTarget)}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setPrimaryClasses((prev) =>
|
setPrimaryClasses((prev) =>
|
||||||
@@ -1295,7 +1359,14 @@ export default function CharacterSheet() {
|
|||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<label style={{ display: "flex", alignItems: "center", gap: "6px", fontSize: "0.85em" }}>
|
<label
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "6px",
|
||||||
|
fontSize: "0.85em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
Level
|
Level
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@@ -1305,14 +1376,16 @@ export default function CharacterSheet() {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setPrimaryClasses((prev) =>
|
setPrimaryClasses((prev) =>
|
||||||
prev.map((c, i) =>
|
prev.map((c, i) =>
|
||||||
i === idx ? { ...c, level: Number(e.target.value) } : c,
|
i === idx
|
||||||
|
? { ...c, level: Number(e.target.value) }
|
||||||
|
: c,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
style={{ width: "50px" }}
|
style={{ width: "50px" }}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<button
|
<button type="button"
|
||||||
className="spell-del-btn"
|
className="spell-del-btn"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setPrimaryClasses((prev) =>
|
setPrimaryClasses((prev) =>
|
||||||
@@ -1325,7 +1398,7 @@ export default function CharacterSheet() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
disabled={primaryClasses.length >= 3}
|
disabled={primaryClasses.length >= 3}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -1393,7 +1466,14 @@ export default function CharacterSheet() {
|
|||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<label style={{ display: "flex", alignItems: "center", gap: "6px", fontSize: "0.85em" }}>
|
<label
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "6px",
|
||||||
|
fontSize: "0.85em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
Level
|
Level
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
@@ -1403,14 +1483,16 @@ export default function CharacterSheet() {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setOtherClasses((prev) =>
|
setOtherClasses((prev) =>
|
||||||
prev.map((c, i) =>
|
prev.map((c, i) =>
|
||||||
i === idx ? { ...c, level: Number(e.target.value) } : c,
|
i === idx
|
||||||
|
? { ...c, level: Number(e.target.value) }
|
||||||
|
: c,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
style={{ width: "50px" }}
|
style={{ width: "50px" }}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<button
|
<button type="button"
|
||||||
className="spell-del-btn"
|
className="spell-del-btn"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setOtherClasses((prev) =>
|
setOtherClasses((prev) =>
|
||||||
@@ -1423,7 +1505,7 @@ export default function CharacterSheet() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setOtherClasses((prev) => [
|
setOtherClasses((prev) => [
|
||||||
@@ -1496,7 +1578,9 @@ export default function CharacterSheet() {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setSpells((prev) =>
|
setSpells((prev) =>
|
||||||
prev.map((sp, j) =>
|
prev.map((sp, j) =>
|
||||||
j === i ? { ...sp, spellClass: e.target.value } : sp,
|
j === i
|
||||||
|
? { ...sp, spellClass: e.target.value }
|
||||||
|
: sp,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1538,14 +1622,16 @@ export default function CharacterSheet() {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setSpells((prev) =>
|
setSpells((prev) =>
|
||||||
prev.map((sp, j) =>
|
prev.map((sp, j) =>
|
||||||
j === i ? { ...sp, duration: e.target.value } : sp,
|
j === i
|
||||||
|
? { ...sp, duration: e.target.value }
|
||||||
|
: sp,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td className="spell-del-col">
|
<td className="spell-del-col">
|
||||||
<button
|
<button type="button"
|
||||||
className="spell-del-btn"
|
className="spell-del-btn"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setSpells((prev) => prev.filter((_, j) => j !== i))
|
setSpells((prev) => prev.filter((_, j) => j !== i))
|
||||||
@@ -1560,7 +1646,9 @@ export default function CharacterSheet() {
|
|||||||
<textarea
|
<textarea
|
||||||
placeholder="Notes / effect description…"
|
placeholder="Notes / effect description…"
|
||||||
value={s.notes || ""}
|
value={s.notes || ""}
|
||||||
ref={(el) => { if (el) autoResize(el); }}
|
ref={(el) => {
|
||||||
|
if (el) autoResize(el);
|
||||||
|
}}
|
||||||
onInput={(e) => autoResize(e.currentTarget)}
|
onInput={(e) => autoResize(e.currentTarget)}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setSpells((prev) =>
|
setSpells((prev) =>
|
||||||
@@ -1577,18 +1665,25 @@ export default function CharacterSheet() {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div style={{ display: "flex", gap: 8, marginTop: 10 }}>
|
<div style={{ display: "flex", gap: 8, marginTop: 10 }}>
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
setSpells((prev) => [
|
setSpells((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{ name: "", spellClass: "", notes: "", mp: "", targets: "", duration: "" },
|
{
|
||||||
|
name: "",
|
||||||
|
spellClass: "",
|
||||||
|
notes: "",
|
||||||
|
mp: "",
|
||||||
|
targets: "",
|
||||||
|
duration: "",
|
||||||
|
},
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
+ Add Spell / Arcana
|
+ Add Spell / Arcana
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button type="button"
|
||||||
className="add-btn"
|
className="add-btn"
|
||||||
onClick={() => setSpellPickerOpen(true)}
|
onClick={() => setSpellPickerOpen(true)}
|
||||||
>
|
>
|
||||||
@@ -1597,11 +1692,22 @@ export default function CharacterSheet() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{spellPickerOpen && (
|
{spellPickerOpen && (
|
||||||
<div className="spell-picker-overlay" onClick={() => setSpellPickerOpen(false)}>
|
<div
|
||||||
<div className="spell-picker-modal" onClick={(e) => e.stopPropagation()}>
|
className="spell-picker-overlay"
|
||||||
|
onClick={() => setSpellPickerOpen(false)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="spell-picker-modal"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
<div className="spell-picker-header">
|
<div className="spell-picker-header">
|
||||||
<span>Choose a spell</span>
|
<span>Choose a spell</span>
|
||||||
<button className="spell-picker-close" onClick={() => setSpellPickerOpen(false)}>✕</button>
|
<button type="button"
|
||||||
|
className="spell-picker-close"
|
||||||
|
onClick={() => setSpellPickerOpen(false)}
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ul className="spell-picker-list">
|
<ul className="spell-picker-list">
|
||||||
{(spellsFile as SpellsFile).spells.map((t, i) => (
|
{(spellsFile as SpellsFile).spells.map((t, i) => (
|
||||||
@@ -1673,10 +1779,10 @@ export default function CharacterSheet() {
|
|||||||
a previously saved sheet.
|
a previously saved sheet.
|
||||||
</p>
|
</p>
|
||||||
<div className="manage-btn-row">
|
<div className="manage-btn-row">
|
||||||
<button className="btn-save btn-lg" onClick={saveSheet}>
|
<button type="button" className="btn-save btn-lg" onClick={saveSheet}>
|
||||||
✦ Save to Browser
|
✦ Save to Browser
|
||||||
</button>
|
</button>
|
||||||
<button className="btn-load btn-lg" onClick={loadSheet}>
|
<button type="button" className="btn-load btn-lg" onClick={loadSheet}>
|
||||||
↑ Load from Browser
|
↑ Load from Browser
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1691,13 +1797,13 @@ export default function CharacterSheet() {
|
|||||||
import from a previously exported file.
|
import from a previously exported file.
|
||||||
</p>
|
</p>
|
||||||
<div className="manage-btn-row">
|
<div className="manage-btn-row">
|
||||||
<button
|
<button type="button"
|
||||||
className="btn-save btn-export btn-lg"
|
className="btn-save btn-export btn-lg"
|
||||||
onClick={exportSheet}
|
onClick={exportSheet}
|
||||||
>
|
>
|
||||||
↓ Export JSON
|
↓ Export JSON
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button type="button"
|
||||||
className="btn-load btn-import btn-lg"
|
className="btn-load btn-import btn-lg"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!importFileRef.current) return;
|
if (!importFileRef.current) return;
|
||||||
@@ -1727,7 +1833,7 @@ export default function CharacterSheet() {
|
|||||||
disabled for viewers.
|
disabled for viewers.
|
||||||
</p>
|
</p>
|
||||||
<div className="manage-btn-row">
|
<div className="manage-btn-row">
|
||||||
<button
|
<button type="button"
|
||||||
className="btn-save btn-export btn-lg"
|
className="btn-save btn-export btn-lg"
|
||||||
onClick={copyShareURL}
|
onClick={copyShareURL}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user