Add spell management to book settings

- Moved spell-related components to the `book/settings/spells` directory for better organization.
- Added "Spells" as a new tool in book settings and composer sidebar with localization support.
- Integrated spell-related UI elements (`SpellComponent`, `SpellList`, `SpellTagManager`) into settings and sidebars.
- Updated logic to handle enabling/disabling of the spells tool per book.
This commit is contained in:
natreex
2026-01-19 23:00:33 -05:00
parent e7d35c0f0b
commit 9461eb6120
10 changed files with 64 additions and 6 deletions

View File

@@ -7,6 +7,7 @@ import {RefObject, useRef} from "react";
import PanelHeader from "@/components/PanelHeader"; import PanelHeader from "@/components/PanelHeader";
import LocationComponent from "@/components/book/settings/locations/LocationComponent"; import LocationComponent from "@/components/book/settings/locations/LocationComponent";
import CharacterComponent from "@/components/book/settings/characters/CharacterComponent"; import CharacterComponent from "@/components/book/settings/characters/CharacterComponent";
import SpellComponent from "@/components/book/settings/spells/SpellComponent";
import QuillSenseSetting from "@/components/book/settings/quillsense/QuillSenseSetting"; import QuillSenseSetting from "@/components/book/settings/quillsense/QuillSenseSetting";
import {useTranslations} from "next-intl"; // Ajouté pour la traduction import {useTranslations} from "next-intl"; // Ajouté pour la traduction
@@ -36,6 +37,9 @@ export default function BookSettingOption(
const characterRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ const characterRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{
handleSave: () => Promise<void> handleSave: () => Promise<void>
}>(null); }>(null);
const spellRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{
handleSave: () => Promise<void>
}>(null);
const quillSenseRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ const quillSenseRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{
handleSave: () => Promise<void> handleSave: () => Promise<void>
}>(null); }>(null);
@@ -54,6 +58,8 @@ export default function BookSettingOption(
return t("bookSettingOption.yourLocations"); return t("bookSettingOption.yourLocations");
case 'characters': case 'characters':
return t("bookSettingOption.characters"); return t("bookSettingOption.characters");
case 'spells':
return t("bookSettingOption.spells");
case 'objects': case 'objects':
return t("bookSettingOption.objectsList"); return t("bookSettingOption.objectsList");
case 'goals': case 'goals':
@@ -85,6 +91,9 @@ export default function BookSettingOption(
case 'characters': case 'characters':
characterRef.current?.handleSave(); characterRef.current?.handleSave();
break; break;
case 'spells':
spellRef.current?.handleSave();
break;
case 'quillsense': case 'quillsense':
quillSenseRef.current?.handleSave(); quillSenseRef.current?.handleSave();
break; break;
@@ -118,6 +127,8 @@ export default function BookSettingOption(
<LocationComponent ref={locationRef}/> <LocationComponent ref={locationRef}/>
) : setting === 'characters' ? ( ) : setting === 'characters' ? (
<CharacterComponent ref={characterRef}/> <CharacterComponent ref={characterRef}/>
) : setting === 'spells' ? (
<SpellComponent ref={spellRef}/>
) : setting === 'quillsense' ? ( ) : setting === 'quillsense' ? (
<QuillSenseSetting ref={quillSenseRef}/> <QuillSenseSetting ref={quillSenseRef}/>
) : <div ) : <div

View File

@@ -1,7 +1,16 @@
'use client' 'use client'
// Removed Next.js Link import for Electron // Removed Next.js Link import for Electron
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faBook, faFeather, faGlobe, faListAlt, faMapMarkedAlt, faPencilAlt, faUser} from "@fortawesome/free-solid-svg-icons"; import {
faBook,
faGlobe,
faHatWizard,
faListAlt,
faMapMarkedAlt,
faPencilAlt,
faUser,
faWandMagicSparkles
} from "@fortawesome/free-solid-svg-icons";
import {Dispatch, SetStateAction} from "react"; import {Dispatch, SetStateAction} from "react";
import {IconDefinition} from "@fortawesome/fontawesome-svg-core"; import {IconDefinition} from "@fortawesome/fontawesome-svg-core";
import {useTranslations} from "next-intl"; import {useTranslations} from "next-intl";
@@ -53,10 +62,15 @@ export default function BookSettingSidebar(
name: 'bookSetting.characters', name: 'bookSetting.characters',
icon: faUser icon: faUser
}, },
{
id: 'spells',
name: 'bookSetting.spells',
icon: faHatWizard
},
{ {
id: 'quillsense', id: 'quillsense',
name: 'bookSetting.quillsense', name: 'bookSetting.quillsense',
icon: faFeather icon: faWandMagicSparkles
}, },
// { // {
// id: 'objects', // id: 'objects',

View File

@@ -1,5 +1,5 @@
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {faFeather, faGlobe, faInfoCircle, faMapMarkerAlt, faUsers} from "@fortawesome/free-solid-svg-icons"; import {faFeather, faGlobe, faHatWizard, faInfoCircle, faMapMarkerAlt, faUsers} from "@fortawesome/free-solid-svg-icons";
import {RefObject, useContext, useEffect, useRef, useState} from "react"; import {RefObject, useContext, useEffect, useRef, useState} from "react";
import {BookContext} from "@/context/BookContext"; import {BookContext} from "@/context/BookContext";
import {PanelComponent} from "@/lib/models/Editor"; import {PanelComponent} from "@/lib/models/Editor";
@@ -9,6 +9,7 @@ import {faDiscord, faFacebook} from "@fortawesome/free-brands-svg-icons";
import WorldSetting from "@/components/book/settings/world/WorldSetting"; import WorldSetting from "@/components/book/settings/world/WorldSetting";
import LocationComponent from "@/components/book/settings/locations/LocationComponent"; import LocationComponent from "@/components/book/settings/locations/LocationComponent";
import CharacterComponent from "@/components/book/settings/characters/CharacterComponent"; import CharacterComponent from "@/components/book/settings/characters/CharacterComponent";
import SpellComponent from "@/components/book/settings/spells/SpellComponent";
import QuillSense from "@/components/quillsense/QuillSenseComponent"; import QuillSense from "@/components/quillsense/QuillSenseComponent";
import {useTranslations} from "next-intl"; import {useTranslations} from "next-intl";
import OfflineContext, {OfflineContextType} from "@/context/OfflineContext"; import OfflineContext, {OfflineContextType} from "@/context/OfflineContext";
@@ -28,6 +29,7 @@ export default function ComposerRightBar() {
const worldRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ handleSave: () => Promise<void> }>(null); const worldRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ handleSave: () => Promise<void> }>(null);
const locationRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ handleSave: () => Promise<void> }>(null); const locationRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ handleSave: () => Promise<void> }>(null);
const characterRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ handleSave: () => Promise<void> }>(null); const characterRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ handleSave: () => Promise<void> }>(null);
const spellRef: RefObject<{ handleSave: () => Promise<void> } | null> = useRef<{ handleSave: () => Promise<void> }>(null);
async function handleSaveClick(): Promise<void> { async function handleSaveClick(): Promise<void> {
switch (currentPanel?.id) { switch (currentPanel?.id) {
@@ -40,6 +42,9 @@ export default function ComposerRightBar() {
case 4: case 4:
characterRef.current?.handleSave(); characterRef.current?.handleSave();
break; break;
case 5:
spellRef.current?.handleSave();
break;
default: default:
break; break;
} }
@@ -93,8 +98,15 @@ export default function ComposerRightBar() {
badge: t("composerRightBar.editorComponents.characters.badge"), badge: t("composerRightBar.editorComponents.characters.badge"),
icon: faUsers icon: faUsers
}, },
/*{ {
id: 5, id: 5,
title: t("composerRightBar.editorComponents.spells.title"),
description: t("composerRightBar.editorComponents.spells.description"),
badge: t("composerRightBar.editorComponents.spells.badge"),
icon: faHatWizard
},
/*{
id: 6,
title: t("composerRightBar.editorComponents.items.title"), title: t("composerRightBar.editorComponents.items.title"),
description: t("composerRightBar.editorComponents.items.description"), description: t("composerRightBar.editorComponents.items.description"),
badge: t("composerRightBar.editorComponents.items.badge"), badge: t("composerRightBar.editorComponents.items.badge"),
@@ -148,7 +160,7 @@ export default function ComposerRightBar() {
description={currentPanel?.description ?? ''} description={currentPanel?.description ?? ''}
badge={currentPanel?.badge ?? ''} badge={currentPanel?.badge ?? ''}
icon={currentPanel?.icon} icon={currentPanel?.icon}
secondActionCallback={currentPanel?.id === 2 || currentPanel?.id === 3 || currentPanel?.id === 4 ? handleSaveClick : undefined} secondActionCallback={currentPanel?.id === 2 || currentPanel?.id === 3 || currentPanel?.id === 4 || currentPanel?.id === 5 ? handleSaveClick : undefined}
callBackAction={async () => setPanelHidden(!panelHidden)} callBackAction={async () => setPanelHidden(!panelHidden)}
/> />
<div className="flex-grow overflow-auto"> <div className="flex-grow overflow-auto">
@@ -164,6 +176,9 @@ export default function ComposerRightBar() {
{currentPanel?.id === 4 && ( {currentPanel?.id === 4 && (
<CharacterComponent ref={characterRef} showToggle={false}/> <CharacterComponent ref={characterRef} showToggle={false}/>
)} )}
{currentPanel?.id === 5 && (
<SpellComponent ref={spellRef} showToggle={false}/>
)}
</div> </div>
</div> </div>
</div> </div>
@@ -192,6 +207,10 @@ export default function ComposerRightBar() {
if (component.id === 4 && !book?.tools?.characters) { if (component.id === 4 && !book?.tools?.characters) {
return false; return false;
} }
// Filter Spells if tools.spells is disabled
if (component.id === 5 && !book?.tools?.spells) {
return false;
}
return true; return true;
}) })
.map((component: PanelComponent) => ( .map((component: PanelComponent) => (

View File

@@ -241,6 +241,11 @@
"description": "Create and manage your characters, their relationships, and story arcs.", "description": "Create and manage your characters, their relationships, and story arcs.",
"badge": "CHAR" "badge": "CHAR"
}, },
"spells": {
"title": "Spell Book",
"description": "Create and manage spells, magic systems, and supernatural abilities.",
"badge": "SPELL"
},
"items": { "items": {
"title": "Items", "title": "Items",
"description": "Manage important items in your story.", "description": "Manage important items in your story.",
@@ -548,6 +553,7 @@
"manageWorlds": "Manage worlds", "manageWorlds": "Manage worlds",
"yourLocations": "Your locations", "yourLocations": "Your locations",
"characters": "Characters", "characters": "Characters",
"spells": "Spell Book",
"objectsList": "Objects list", "objectsList": "Objects list",
"bookGoals": "Book goals", "bookGoals": "Book goals",
"quillsense": "QuillSense Settings", "quillsense": "QuillSense Settings",
@@ -869,6 +875,7 @@
"world": "Worlds", "world": "Worlds",
"locations": "Locations", "locations": "Locations",
"characters": "Characters", "characters": "Characters",
"spells": "Spells",
"objects": "Objects", "objects": "Objects",
"goals": "Goals", "goals": "Goals",
"quillsense": "QuillSense" "quillsense": "QuillSense"

View File

@@ -241,6 +241,11 @@
"description": "Créez et gérez vos personnages, leurs relations et leurs arcs narratifs.", "description": "Créez et gérez vos personnages, leurs relations et leurs arcs narratifs.",
"badge": "CHAR" "badge": "CHAR"
}, },
"spells": {
"title": "Livre des sortilèges",
"description": "Créez et gérez les sortilèges, systèmes de magie et capacités surnaturelles.",
"badge": "SPELL"
},
"items": { "items": {
"title": "Objets", "title": "Objets",
"description": "Gérez les objets importants de votre histoire.", "description": "Gérez les objets importants de votre histoire.",
@@ -548,6 +553,7 @@
"manageWorlds": "Gérer les mondes", "manageWorlds": "Gérer les mondes",
"yourLocations": "Vos lieux", "yourLocations": "Vos lieux",
"characters": "Les personnages", "characters": "Les personnages",
"spells": "Livre des sortilèges",
"objectsList": "Liste des objets", "objectsList": "Liste des objets",
"bookGoals": "Objectifs du livre", "bookGoals": "Objectifs du livre",
"quillsense": "Parametres QuillSense", "quillsense": "Parametres QuillSense",
@@ -870,6 +876,7 @@
"world": "Mondes", "world": "Mondes",
"locations": "Emplacements", "locations": "Emplacements",
"characters": "Personnages", "characters": "Personnages",
"spells": "Sortilèges",
"objects": "Objets", "objects": "Objets",
"goals": "Buts", "goals": "Buts",
"quillsense": "QuillSense" "quillsense": "QuillSense"