feat(kanban): sidebar edge zone now toggles (open + close)
The 32px left drag zone now also closes the sidebar when it is open. Symmetric behaviour: dwell ≥400ms while dragging closes if open / opens if closed. To prevent a drag that starts with the pointer already inside the sidebar (e.g. dragging a sidebar card itself) from immediately auto- closing, the close action requires the pointer to have left the strip at least once after the drag started. So: - closed + drag-to-edge -> opens (unchanged). - open + drag a card out, then move the card back to the edge -> closes. - open + drag a sidebar card directly to the board -> nothing happens. After a successful toggle the dwell flag resets, so the user must leave the strip and re-enter to trigger another action. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+24
-8
@@ -193,6 +193,12 @@ export function App() {
|
|||||||
}
|
}
|
||||||
let timer: number | null = null;
|
let timer: number | null = null;
|
||||||
let inside = false;
|
let inside = false;
|
||||||
|
// Para evitar que un drag iniciado dentro del sidebar abierto dispare un
|
||||||
|
// cierre inmediato, exigimos que el puntero haya salido de la franja al
|
||||||
|
// menos una vez tras empezar el drag. Asi: abrir = entrar a la franja
|
||||||
|
// tras empezar fuera (que ya pasaba); cerrar = salir de la franja y
|
||||||
|
// volver a entrar.
|
||||||
|
let hasLeftStrip = false;
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
if (timer !== null) {
|
if (timer !== null) {
|
||||||
window.clearTimeout(timer);
|
window.clearTimeout(timer);
|
||||||
@@ -203,16 +209,26 @@ export function App() {
|
|||||||
const nowInside = ev.clientX <= DRAG_EDGE_WIDTH;
|
const nowInside = ev.clientX <= DRAG_EDGE_WIDTH;
|
||||||
if (nowInside === inside) return;
|
if (nowInside === inside) return;
|
||||||
inside = nowInside;
|
inside = nowInside;
|
||||||
setEdgeArmed(nowInside);
|
// El brillo visible solo cuando "armable": fuera-y-luego-dentro (open
|
||||||
if (nowInside) {
|
// siempre) o dentro con sidebar cerrado (open trigger).
|
||||||
if (navOpenRef.current) return; // already open, nothing to do
|
const armable = nowInside && (!navOpenRef.current || hasLeftStrip);
|
||||||
clear();
|
setEdgeArmed(armable);
|
||||||
timer = window.setTimeout(() => {
|
if (!nowInside) {
|
||||||
setNavOpen(true);
|
hasLeftStrip = true;
|
||||||
}, DRAG_EDGE_HOVER_MS);
|
|
||||||
} else {
|
|
||||||
clear();
|
clear();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// nowInside = true
|
||||||
|
if (!armable) return;
|
||||||
|
clear();
|
||||||
|
const willOpen = !navOpenRef.current;
|
||||||
|
timer = window.setTimeout(() => {
|
||||||
|
setNavOpen(willOpen);
|
||||||
|
// Tras toggle, resetea el flag para no encadenar otra accion sin
|
||||||
|
// que el usuario salga + vuelva.
|
||||||
|
hasLeftStrip = false;
|
||||||
|
setEdgeArmed(false);
|
||||||
|
}, DRAG_EDGE_HOVER_MS);
|
||||||
};
|
};
|
||||||
document.addEventListener("mousemove", onMove);
|
document.addEventListener("mousemove", onMove);
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user