Improve toolbox architecture and initial bundle loading
All checks were successful
Deploy Sokko G / deploy (push) Successful in 15s

This commit is contained in:
Shinuwa 2026-08-14 09:13:53 +02:00
parent f76cddcc95
commit b221257616
34 changed files with 8358 additions and 6744 deletions

View file

@ -1,5 +1,5 @@
// Rôle : fournit l'outil Combos avec palettes d'inputs, rendu visuel et échange texte.
import { useEffect, useMemo, useState } from "react";
import { useMemo, useState } from "react";
import { Icon } from "../../../components/Icon.jsx";
import { useInlineEdit } from "../../../hooks/useInlineEdit.js";
import {

View file

@ -43,10 +43,6 @@ const EQUIPMENT_ICONS = [
const TRAIT_ICONS = ["sword", "shield"];
const DETAIL_TABS = ["stats", "sockets", "craft"];
function getEquipmentIconLabel(icon) {
return EQUIPMENT_ICONS.find((item) => item.icon === icon)?.label || "Équipement";
}
function getCharacteristicCategories(equipment) {
const categories = equipment.characteristics.map((trait) => trait.category).filter(Boolean);
return [

View file

@ -396,12 +396,6 @@ export function TableModule({ toolboxId, moduleId, context, editing }) {
});
}
function stopEditing(address) {
setEditingCell("");
const parsed = parseCellAddress(address);
if (parsed) focusCell(parsed.rowIndex, parsed.columnIndex);
}
function insertFormulaText(text, options = {}) {
const input = getActiveFormulaInput();
if (!input || !text) return false;

View file

@ -1,5 +1,5 @@
// Rôle : fournit l'outil timer avec chronomètre, comptes à rebours et échange texte.
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { Icon } from "../../../components/Icon.jsx";
import { Tabs } from "../../../components/Tabs.jsx";
import { useDraftForm } from "../../../hooks/useDraftForm.js";

View file

@ -6,6 +6,7 @@ import { Icon } from "../../../components/Icon.jsx";
import { useGroupedReorder } from "../../../hooks/useGroupedReorder.js";
import { useInlineEdit } from "../../../hooks/useInlineEdit.js";
import { lockBodyScroll } from "../../../utils/bodyScrollLock.js";
import { TOOLBOX_MODULE_DEFINITIONS, TOOLBOX_MODULES } from "../toolboxModuleRegistry.js";
import { CalculatorModule } from "./CalculatorModule.jsx";
import { ChecklistModule } from "./ChecklistModule.jsx";
import { CombosModule } from "./CombosModule.jsx";
@ -20,26 +21,23 @@ import { TaskPlannerModule } from "./TaskPlannerModule.jsx";
import { TimerModule } from "./TimerModule.jsx";
const MODULE_COMPONENTS = {
notepad: { label: "Bloc notes", icon: "notepad", Component: NotepadModule, editable: true },
checklist: { label: "Checklist", icon: "checklist", Component: ChecklistModule, editable: true, scrollable: true },
images: { label: "Images", icon: "picture", Component: ImagesModule, editable: true, scrollable: true },
links: { label: "Liens", icon: "link", Component: LinksModule, editable: true, scrollable: true },
counters: { label: "Compteurs", icon: "abacus", Component: CountersModule, editable: true, scrollable: true },
combos: { label: "Combos", icon: "controller", Component: CombosModule, editable: true, scrollable: true },
calculator: { label: "Calculateur", icon: "calculator", Component: CalculatorModule, editable: true },
table: { label: "Tableau", icon: "table", Component: TableModule, editable: true, scrollable: true },
timer: { label: "Timer", icon: "clock", Component: TimerModule, editable: true },
taskPlanner: { label: "Planificateur de tâches", icon: "tasklist", Component: TaskPlannerModule, editable: true, scrollable: true },
equipmentPlanner: { label: "Planificateur d'équipements", icon: "chest-armor", Component: EquipmentPlannerModule, editable: true, scrollable: true },
imageAnnotation: { label: "Annotation d'images", icon: "map", Component: ImageAnnotationModule, editable: true }
notepad: { ...TOOLBOX_MODULE_DEFINITIONS.notepad, Component: NotepadModule },
checklist: { ...TOOLBOX_MODULE_DEFINITIONS.checklist, Component: ChecklistModule },
images: { ...TOOLBOX_MODULE_DEFINITIONS.images, Component: ImagesModule },
links: { ...TOOLBOX_MODULE_DEFINITIONS.links, Component: LinksModule },
counters: { ...TOOLBOX_MODULE_DEFINITIONS.counters, Component: CountersModule },
combos: { ...TOOLBOX_MODULE_DEFINITIONS.combos, Component: CombosModule },
calculator: { ...TOOLBOX_MODULE_DEFINITIONS.calculator, Component: CalculatorModule },
table: { ...TOOLBOX_MODULE_DEFINITIONS.table, Component: TableModule },
timer: { ...TOOLBOX_MODULE_DEFINITIONS.timer, Component: TimerModule },
taskPlanner: { ...TOOLBOX_MODULE_DEFINITIONS.taskPlanner, Component: TaskPlannerModule },
equipmentPlanner: { ...TOOLBOX_MODULE_DEFINITIONS.equipmentPlanner, Component: EquipmentPlannerModule },
imageAnnotation: { ...TOOLBOX_MODULE_DEFINITIONS.imageAnnotation, Component: ImageAnnotationModule }
};
const MODULE_COLUMN_IDS = ["left", "right"];
export const TOOLBOX_MODULES = Object.fromEntries(Object.entries(MODULE_COMPONENTS).map(([type, module]) => [
type,
{ label: module.label, icon: module.icon }
]));
export { TOOLBOX_MODULES };
function getModuleMap(modules) {
return new Map(modules.map((module) => [module.id, module]));
@ -191,13 +189,12 @@ export function AddToolControls({ onAdd }) {
}
export function ToolboxModules({ toolbox, moduleColumns, context, onRename, onUpdateModule, onDelete, onModuleOrderChange }) {
const moduleIdSignature = useMemo(() => toolbox.modules.map((module) => module.id).join("|"), [toolbox.modules]);
const twoColumnOrder = toolbox.moduleOrder?.two || [[], []];
const orderedModules = useMemo(() => getModulesByIds(toolbox.modules, toolbox.moduleOrder?.one || []), [toolbox.modules, toolbox.moduleOrder?.one, moduleIdSignature]);
const twoColumnOrder = useMemo(() => toolbox.moduleOrder?.two || [[], []], [toolbox.moduleOrder?.two]);
const orderedModules = useMemo(() => getModulesByIds(toolbox.modules, toolbox.moduleOrder?.one || []), [toolbox.modules, toolbox.moduleOrder?.one]);
const columns = useMemo(() => [
getModulesByIds(toolbox.modules, twoColumnOrder[0]),
getModulesByIds(toolbox.modules, twoColumnOrder[1])
], [toolbox.modules, twoColumnOrder, moduleIdSignature]);
], [toolbox.modules, twoColumnOrder]);
const {
itemReorder,
getItemProps,

View file

@ -60,7 +60,7 @@ function tokenize(expression) {
continue;
}
const numberMatch = expression.slice(index).match(/^(?:\d+(?:[\.,]\d*)?|[\.,]\d+)/);
const numberMatch = expression.slice(index).match(/^(?:\d+(?:[.,]\d*)?|[.,]\d+)/);
if (numberMatch) {
const value = Number(numberMatch[0].replace(",", "."));
if (!Number.isFinite(value)) throw new Error("invalid");

View file

@ -425,7 +425,7 @@ function exportComboInput(input) {
}
function parseComboInput(text) {
const match = String(text || "").trim().match(/^([a-zA-Z]+):([^\[]+?)(?:\[(hold|\d+s)\])?$/);
const match = String(text || "").trim().match(/^([a-zA-Z]+):([^[]+?)(?:\[(hold|\d+s)\])?$/);
if (!match || !COMBO_INPUT_KINDS.has(match[1])) throw new Error(`Input combo invalide: ${text}`);
const input = { kind: match[1], value: match[2].trim() };
if (!input.value) throw new Error(`Input combo invalide: ${text}`);
@ -481,7 +481,7 @@ function importCombosText(text, context) {
const sequence = cleanLine.split("|").map((part) => part.trim()).filter((part, index) => index > 0 && !part.includes("=")).join(" | ");
const comboDevice = lineMeta.device || device;
if (!COMBO_DEVICES.has(comboDevice)) throw lineError(index, `périphérique combo invalide: ${comboDevice}`);
let inputs = [];
let inputs;
try {
inputs = sequence ? String(sequence).split(">").map((step) => step.split("+").map(parseComboInput)) : [];
} catch (error) {