Paramètres : choix du canal d'Excalidraw (stable ou préversion)
- Dialogue « Paramètres » (icône engrenage) : sections Apparence (titre, logo) et Excalidraw (canal latest/next, versions publiées, commande de reconstruction ; rappel qu'Excalidraw est compilé dans l'image). - L'icône de mise à jour suit le canal choisi et compare par égalité (les numéros next sont inférieurs à la dernière stable) ; elle ouvre les paramètres sur la section Excalidraw. - Compatibilité avec le canal next : la prop excalidrawAPI y devient onExcalidrawAPI, les deux sont passées (image next construite et testée). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019EuvvuTv7AUc8ksDHv8VKx
This commit is contained in:
1 parent
7da52b6755
commit
88f7750577
9 files changed
+361
-255
No files matched your search
+33
-13
@@ -15,11 +15,11 @@ import type {
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
import type { OrderedExcalidrawElement } from "@excalidraw/excalidraw/element/types";
|
||||
import { api, ApiError, basename, stripExt, type Settings } from "./api";
|
||||
import { CustomizeDialog, DEFAULT_TITLE } from "./CustomizeDialog";
|
||||
import { Explorer } from "./Explorer";
|
||||
import { CloseIcon, MenuIcon, MoonIcon, SaveIcon, SettingsIcon, SunIcon } from "./icons";
|
||||
import { CloseIcon, MenuIcon, MoonIcon, SaveIcon, SettingsIcon, SunIcon, UpdateIcon } from "./icons";
|
||||
import { Splitter } from "./Splitter";
|
||||
import { UpdateBadge } from "./UpdateBadge";
|
||||
import { SettingsDialog, DEFAULT_TITLE } from "./SettingsDialog";
|
||||
import { pendingVersion, useUpdateStatus } from "./update";
|
||||
import { storeThumb } from "./thumbs";
|
||||
|
||||
type Theme = "light" | "dark";
|
||||
@@ -87,8 +87,10 @@ export default function App() {
|
||||
const [loadError, setLoadError] = useState<string | null>(null);
|
||||
const [drawerWidth, setDrawerWidth] = useState(initialDrawerWidth);
|
||||
const [resizing, setResizing] = useState(false);
|
||||
const [settings, setSettings] = useState<Settings>({ title: "", logo: "" });
|
||||
const [customizing, setCustomizing] = useState(false);
|
||||
const [settings, setSettings] = useState<Settings>({ title: "", logo: "", channel: "latest" });
|
||||
const updateStatus = useUpdateStatus();
|
||||
const pending = pendingVersion(updateStatus, settings.channel);
|
||||
const [customizing, setCustomizing] = useState<false | "all" | "excalidraw">(false);
|
||||
|
||||
const excalidraw = useRef<ExcalidrawImperativeAPI | null>(null);
|
||||
const pathRef = useRef<string | null>(null); // schéma ouvert (survit aux renommages)
|
||||
@@ -219,9 +221,12 @@ export default function App() {
|
||||
|
||||
openRef.current = openFile;
|
||||
|
||||
const onApi = useCallback((ex: ExcalidrawImperativeAPI) => {
|
||||
const onApi = useCallback((ex: ExcalidrawImperativeAPI | null) => {
|
||||
excalidraw.current = ex;
|
||||
}, []);
|
||||
// La prop s'appelle excalidrawAPI jusqu'à la 0.18 et onExcalidrawAPI sur le canal
|
||||
// next : on passe les deux pour que l'image se construise avec l'un ou l'autre.
|
||||
const apiProps = { excalidrawAPI: onApi, onExcalidrawAPI: onApi } as object;
|
||||
|
||||
// --- Effets globaux --------------------------------------------------------
|
||||
|
||||
@@ -347,7 +352,7 @@ export default function App() {
|
||||
>
|
||||
<MenuIcon />
|
||||
</button>
|
||||
<button className="brand" title="Personnaliser le titre et le logo" onClick={() => setCustomizing(true)}>
|
||||
<button className="brand" title="Paramètres" onClick={() => setCustomizing("all")}>
|
||||
{settings.logo && <img className="logo" src={api.logoUrl(settings.logo)} alt="" />}
|
||||
<span className="brand-title">{appTitle}</span>
|
||||
</button>
|
||||
@@ -384,7 +389,16 @@ export default function App() {
|
||||
</>
|
||||
)}
|
||||
<div className="topbar-tools">
|
||||
<UpdateBadge />
|
||||
{pending && (
|
||||
<button
|
||||
className="icon-btn update-btn"
|
||||
title={`Excalidraw ${pending} disponible (installée : ${__EXCALIDRAW_VERSION__}) — reconstruire l'image`}
|
||||
aria-label={`Mise à jour d'Excalidraw disponible : ${pending}`}
|
||||
onClick={() => setCustomizing("excalidraw")}
|
||||
>
|
||||
<UpdateIcon />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
className="icon-btn"
|
||||
aria-label={theme === "dark" ? "Passer en mode clair" : "Passer en mode sombre"}
|
||||
@@ -395,9 +409,9 @@ export default function App() {
|
||||
</button>
|
||||
<button
|
||||
className="icon-btn"
|
||||
aria-label="Personnaliser le titre et le logo"
|
||||
title="Personnaliser"
|
||||
onClick={() => setCustomizing(true)}
|
||||
aria-label="Paramètres"
|
||||
title="Paramètres (titre, logo, version d'Excalidraw)"
|
||||
onClick={() => setCustomizing("all")}
|
||||
>
|
||||
<SettingsIcon />
|
||||
</button>
|
||||
@@ -430,7 +444,7 @@ export default function App() {
|
||||
// Remontage complet à chaque ouverture : historique et état propres.
|
||||
key={scene.id}
|
||||
initialData={{ ...scene.initialData, libraryItems: library }}
|
||||
excalidrawAPI={onApi}
|
||||
{...apiProps}
|
||||
onChange={onChange}
|
||||
onLibraryChange={onLibraryChange}
|
||||
theme={theme}
|
||||
@@ -448,7 +462,13 @@ export default function App() {
|
||||
</main>
|
||||
|
||||
{customizing && (
|
||||
<CustomizeDialog settings={settings} onChange={setSettings} onClose={() => setCustomizing(false)} />
|
||||
<SettingsDialog
|
||||
settings={settings}
|
||||
update={updateStatus}
|
||||
focusExcalidraw={customizing === "excalidraw"}
|
||||
onChange={setSettings}
|
||||
onClose={() => setCustomizing(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user