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