improve notepad features and add drawing canvas
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s

This commit is contained in:
Shinuwa 2026-07-29 13:51:42 +02:00
parent e73d754082
commit de1b8a5638
20 changed files with 1732 additions and 141 deletions

View file

@ -1,6 +1,7 @@
// Rôle : registre des outils toolbox, rendu commun et contrôles d'ajout/réorganisation.
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { CompactDropdown } from "../../../components/CompactDropdown.jsx";
import { Icon } from "../../../components/Icon.jsx";
import { usePointerReorder } from "../../../hooks/usePointerReorder.js";
import { lockBodyScroll } from "../../../utils/bodyScrollLock.js";
@ -75,8 +76,6 @@ function chooseMeasuredSplitIndex(modules, moduleHeights, fallbackSplitIndex) {
export function AddToolControls({ onAdd }) {
const [open, setOpen] = useState(false);
const [quickOpen, setQuickOpen] = useState(false);
const controlsRef = useRef(null);
const modules = Object.entries(TOOLBOX_MODULES);
useEffect(() => {
@ -84,82 +83,65 @@ export function AddToolControls({ onAdd }) {
return lockBodyScroll();
}, [open]);
useEffect(() => {
if (!quickOpen) return undefined;
function handlePointerDown(event) {
if (!controlsRef.current?.contains(event.target)) setQuickOpen(false);
}
function handleKeyDown(event) {
if (event.key === "Escape") setQuickOpen(false);
}
document.addEventListener("pointerdown", handlePointerDown);
document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("pointerdown", handlePointerDown);
document.removeEventListener("keydown", handleKeyDown);
};
}, [quickOpen]);
function addTool(type) {
onAdd(type);
setOpen(false);
setQuickOpen(false);
}
return (
<>
<div
className="tool-add-controls"
ref={controlsRef}
onMouseLeave={() => setQuickOpen(false)}
onFocusCapture={(event) => {
if (event.target.closest(".tool-add-quick-toggle")) setQuickOpen(true);
}}
onBlurCapture={(event) => {
if (!event.currentTarget.contains(event.relatedTarget)) setQuickOpen(false);
}}
aria-label="Ajouter un outil"
>
<button
className="primary tool-add-modal-button"
type="button"
onClick={() => {
setQuickOpen(false);
setOpen(true);
}}
onClick={() => setOpen(true)}
>
Ajouter un outil
</button>
<button
className={`primary tool-add-quick-toggle ${quickOpen ? "active" : ""}`}
type="button"
onMouseEnter={() => setQuickOpen(true)}
onClick={() => setQuickOpen((value) => !value)}
aria-label="Afficher l'ajout rapide"
aria-expanded={quickOpen}
title="Ajout rapide"
>
<Icon name="dropdown" />
</button>
<div className={`tool-quick-add ${quickOpen ? "is-open" : ""}`} aria-label="Ajout rapide">
{modules.map(([type, module]) => (
<CompactDropdown
className="tool-add-quick-dropdown"
menuClassName="tool-quick-add"
label="Ajout rapide"
openOnHover
closeOnMouseLeave
renderTrigger={({ open: quickOpen, toggle }) => (
<button
key={type}
className="tool-quick-add-button"
className={`primary tool-add-quick-toggle ${quickOpen ? "active" : ""}`}
type="button"
onClick={() => onAdd(type)}
aria-label={`Ajouter ${module.label}`}
title={module.label}
onClick={toggle}
aria-label="Afficher l'ajout rapide"
aria-expanded={quickOpen}
title="Ajout rapide"
>
<span className="module-icon" aria-hidden="true">
<span className={`module-icon-svg module-icon-${module.icon}`} />
</span>
<Icon name="dropdown" />
</button>
))}
</div>
)}
>
{({ close }) => (
<>
{modules.map(([type, module]) => (
<button
key={type}
className="tool-quick-add-button"
type="button"
onClick={() => {
onAdd(type);
close();
}}
aria-label={`Ajouter ${module.label}`}
title={module.label}
>
<span className="module-icon" aria-hidden="true">
<span className={`module-icon-svg module-icon-${module.icon}`} />
</span>
</button>
))}
</>
)}
</CompactDropdown>
</div>
{open && createPortal(
<div className="tool-add-modal-root" role="dialog" aria-modal="true" aria-labelledby="tool-add-modal-title">