Explorateur épinglable : panneau fixe ou flottant au-dessus du schéma
- Bouton punaise (barre de recherche de l'explorateur) : épinglé = colonne fixe redimensionnable (comportement actuel) ; désépinglé = panneau masqué qui s'ouvre par-dessus le canevas. - Désépinglé : ouverture par le bouton ☰ ou en survolant le bord gauche ; fermeture à l'ouverture d'un schéma, au clic hors du panneau, par Échap, ou en quittant le panneau s'il a été ouvert par survol. Il revient seul quand le schéma est fermé ou qu'aucun n'est ouvert. - À la bascule, le défilement du canevas est compensé : le schéma ne bouge pas à l'écran (zoom conservé, pas de recadrage). - Choix mémorisé par navigateur (localStorage drawerPinned). Sur mobile, l'explorateur reste un tiroir et le bouton est masqué. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XR9aSZwC3Ssajfy1R7SLPo
This commit is contained in:
1 parent
ffb5ff1311
commit
a5fddba9a0
4 files changed
+66
-4
No files matched your search
@@ -137,6 +137,7 @@ Sans `id_token_hint`, Keycloak demande de confirmer la déconnexion ; `OIDC_LOGO
|
|||||||
- **Lien direct** : l'URL `http://hôte:8080/#/dossier/schema.excalidraw` ouvre le schéma.
|
- **Lien direct** : l'URL `http://hôte:8080/#/dossier/schema.excalidraw` ouvre le schéma.
|
||||||
- **Bibliothèque** Excalidraw : persistée côté serveur, partagée entre tous les schémas.
|
- **Bibliothèque** Excalidraw : persistée côté serveur, partagée entre tous les schémas.
|
||||||
- **Largeur de l'explorateur** (bureau) : glisser la poignée entre l'explorateur et le canevas ; flèches ←/→ au clavier quand elle a le focus (Maj : pas plus grand), double-clic pour revenir à 330 px. Mémorisée par navigateur.
|
- **Largeur de l'explorateur** (bureau) : glisser la poignée entre l'explorateur et le canevas ; flèches ←/→ au clavier quand elle a le focus (Maj : pas plus grand), double-clic pour revenir à 330 px. Mémorisée par navigateur.
|
||||||
|
- **Explorateur épinglé ou flottant** (bureau) : la punaise à droite de la recherche bascule entre panneau fixe à côté du schéma (par défaut) et panneau masqué, qui s'ouvre par-dessus le schéma avec le bouton ☰ ou en survolant le bord gauche de la fenêtre. Il se referme à l'ouverture d'un schéma, au clic à côté, avec `Échap`, ou dès que le pointeur le quitte s'il a été ouvert par survol. À la bascule, le schéma reste en place à l'écran. Choix mémorisé par navigateur ; sur mobile, l'explorateur reste un tiroir.
|
||||||
- **Style** : l'explorateur et la barre du haut reprennent les couleurs, la police, les rayons et les tailles de boutons d'Excalidraw (jetons `--ex-*` en tête de `styles.css`), en clair comme en sombre.
|
- **Style** : l'explorateur et la barre du haut reprennent les couleurs, la police, les rayons et les tailles de boutons d'Excalidraw (jetons `--ex-*` en tête de `styles.css`), en clair comme en sombre.
|
||||||
- **Mise à jour d'Excalidraw** : quand la version publiée sur le canal choisi (voir *Paramètres*) diffère de celle embarquée, une icône apparaît à droite de la barre du haut ; un clic ouvre les paramètres sur la commande de reconstruction (voir *Mettre à jour Excalidraw*).
|
- **Mise à jour d'Excalidraw** : quand la version publiée sur le canal choisi (voir *Paramètres*) diffère de celle embarquée, une icône apparaît à droite de la barre du haut ; un clic ouvre les paramètres sur la commande de reconstruction (voir *Mettre à jour Excalidraw*).
|
||||||
- **Mode clair/sombre** : bouton ☀/☾ à droite de la barre du haut ; s'applique à l'interface et au canevas Excalidraw, reste synchronisé avec le choix du menu d'Excalidraw. Mémorisé par navigateur.
|
- **Mode clair/sombre** : bouton ☀/☾ à droite de la barre du haut ; s'applique à l'interface et au canevas Excalidraw, reste synchronisé avec le choix du menu d'Excalidraw. Mémorisé par navigateur.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import type { DragEvent, KeyboardEvent, MouseEvent } from "react";
|
import type { DragEvent, KeyboardEvent, MouseEvent, ReactNode } from "react";
|
||||||
import {
|
import {
|
||||||
api,
|
api,
|
||||||
ApiError,
|
ApiError,
|
||||||
@@ -62,6 +62,8 @@ interface Props {
|
|||||||
onHistory: (path: string) => void;
|
onHistory: (path: string) => void;
|
||||||
/** Affiche les liens de partage d'un schéma. */
|
/** Affiche les liens de partage d'un schéma. */
|
||||||
onShare: (path: string) => void;
|
onShare: (path: string) => void;
|
||||||
|
/** Contenu ajouté au bout de la barre de recherche (bouton d'épinglage du panneau). */
|
||||||
|
toolbarEnd?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
type View = "list" | "grid";
|
type View = "list" | "grid";
|
||||||
@@ -88,7 +90,7 @@ const initialView = (): View => {
|
|||||||
const canMoveInto = (path: string, targetDir: string) =>
|
const canMoveInto = (path: string, targetDir: string) =>
|
||||||
dirname(path) !== targetDir && targetDir !== path && !targetDir.startsWith(path + "/");
|
dirname(path) !== targetDir && targetDir !== path && !targetDir.startsWith(path + "/");
|
||||||
|
|
||||||
export function Explorer({ current, refreshKey, onOpen, onMoved, onDeleted, onHistory, onShare }: Props) {
|
export function Explorer({ current, refreshKey, onOpen, onMoved, onDeleted, onHistory, onShare, toolbarEnd }: Props) {
|
||||||
const [dir, setDir] = useState(() => (current ? dirname(current) : ""));
|
const [dir, setDir] = useState(() => (current ? dirname(current) : ""));
|
||||||
const [entries, setEntries] = useState<Entry[]>([]);
|
const [entries, setEntries] = useState<Entry[]>([]);
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
@@ -642,6 +644,7 @@ export function Explorer({ current, refreshKey, onOpen, onMoved, onDeleted, onHi
|
|||||||
<button className="icon-btn" onClick={refresh} title="Rafraîchir" aria-label="Rafraîchir">
|
<button className="icon-btn" onClick={refresh} title="Rafraîchir" aria-label="Rafraîchir">
|
||||||
<RefreshIcon />
|
<RefreshIcon />
|
||||||
</button>
|
</button>
|
||||||
|
{toolbarEnd}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="filters" role="group" aria-label="Filtres">
|
<div className="filters" role="group" aria-label="Filtres">
|
||||||
|
|||||||
@@ -200,6 +200,9 @@ export const EyeIcon = icon(
|
|||||||
</>,
|
</>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** Punaise : panneau épinglé ou flottant (comme le bouton d'ancrage des panneaux d'Excalidraw). */
|
||||||
|
export const PinIcon = icon(<path d="M15 4.5l-4 4-4 1.5-1.5 1.5 7 7 1.5-1.5 1.5-4 4-4M9 15l-4.5 4.5M14.5 4 20 9.5" />);
|
||||||
|
|
||||||
export const LogoutIcon = icon(
|
export const LogoutIcon = icon(
|
||||||
<>
|
<>
|
||||||
<path d="M14 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2v-2" />
|
<path d="M14 8V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2v-2" />
|
||||||
|
|||||||
+57
-2
@@ -245,6 +245,10 @@ button.danger:hover:not(:disabled) {
|
|||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
.app.instant,
|
||||||
|
.app.instant .drawer {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Poignée de redimensionnement, à cheval sur la bordure de l'explorateur. */
|
/* Poignée de redimensionnement, à cheval sur la bordure de l'explorateur. */
|
||||||
.splitter {
|
.splitter {
|
||||||
@@ -258,7 +262,7 @@ button.danger:hover:not(:disabled) {
|
|||||||
cursor: col-resize;
|
cursor: col-resize;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
}
|
}
|
||||||
.drawer-open .splitter {
|
.pinned.drawer-open .splitter {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.splitter::after {
|
.splitter::after {
|
||||||
@@ -546,6 +550,56 @@ li.active > .row {
|
|||||||
height: var(--ex-btn);
|
height: var(--ex-btn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Explorateur non épinglé (bureau) : panneau flottant sur le canevas ------ */
|
||||||
|
|
||||||
|
.peek-edge {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
.app.unpinned,
|
||||||
|
.app.unpinned.drawer-open {
|
||||||
|
grid-template-columns: 0 1fr;
|
||||||
|
}
|
||||||
|
.unpinned .drawer {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 20;
|
||||||
|
top: var(--topbar-h);
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: var(--drawer-w);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
visibility: hidden;
|
||||||
|
transition:
|
||||||
|
transform 0.15s ease,
|
||||||
|
visibility 0.15s;
|
||||||
|
box-shadow: var(--ex-shadow-island);
|
||||||
|
}
|
||||||
|
.unpinned.drawer-open .drawer {
|
||||||
|
transform: none;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
/* Clic hors du panneau : le referme sans agir sur le schéma. */
|
||||||
|
.unpinned.drawer-open .backdrop {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 15;
|
||||||
|
inset: var(--topbar-h) 0 0 0;
|
||||||
|
}
|
||||||
|
/* Bord gauche sensible au survol pour faire apparaître le panneau. */
|
||||||
|
.unpinned .peek-edge {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 16;
|
||||||
|
top: var(--topbar-h);
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
.unpinned .peek-edge:hover {
|
||||||
|
background: linear-gradient(to right, var(--accent-soft), transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* --- Mobile : l'explorateur devient un tiroir superposé -------------------- */
|
/* --- Mobile : l'explorateur devient un tiroir superposé -------------------- */
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
@@ -585,7 +639,8 @@ li.active > .row {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.splitter,
|
.splitter,
|
||||||
.drawer-open .splitter {
|
.pinned.drawer-open .splitter,
|
||||||
|
.pin-btn {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.row .name {
|
.row .name {
|
||||||
|
|||||||
Reference in new issue
Block a user