mirror of
https://github.com/penpot/penpot.git
synced 2026-08-19 19:28:36 +00:00
✨ Add overview mode: fold containers at or beyond a depth
"fold >= depth" number input (root = 0, empty = off, localStorage): every combo whose container sits at that IsChildOf depth or deeper collapses, giving a top-of-file overview (e.g. 2 folds the containers hanging from a Page). Composes with fold-unchanged — depth folds first, changed ancestor paths are then drilled open. Derived fold state overrides manual folds while active. Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>
This commit is contained in:
parent
b882b97d21
commit
bd712bb7fa
@ -165,6 +165,11 @@ Graph Console
|
|||||||
title="collapse every container that holds no changed elements">
|
title="collapse every container that holds no changed elements">
|
||||||
<input type="checkbox" id="graph-diff-fold" /> fold unchanged
|
<input type="checkbox" id="graph-diff-fold" /> fold unchanged
|
||||||
</label>
|
</label>
|
||||||
|
<label style="margin-left: 1em; font-size: 12px; font-weight: normal;"
|
||||||
|
title="overview mode: collapse every container at or beyond this depth from the root (root = 0; empty = off)">
|
||||||
|
fold ≥ depth: <input type="number" id="graph-depth-fold" min="0" max="99"
|
||||||
|
style="width: 3em;" />
|
||||||
|
</label>
|
||||||
<label style="margin-left: 1em; font-size: 12px; font-weight: normal;">
|
<label style="margin-left: 1em; font-size: 12px; font-weight: normal;">
|
||||||
layout: <select id="graph-layout-select"></select>
|
layout: <select id="graph-layout-select"></select>
|
||||||
</label>
|
</label>
|
||||||
@ -511,6 +516,15 @@ Graph Console
|
|||||||
return localStorage.getItem("graph-diff-fold") === "1";
|
return localStorage.getItem("graph-diff-fold") === "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overview mode: null = off, else collapse containers at depth ≥ value
|
||||||
|
// (root = depth 0, so e.g. 2 folds the containers hanging from a Page).
|
||||||
|
function depthFoldValue() {
|
||||||
|
const raw = localStorage.getItem("graph-depth-fold");
|
||||||
|
if (raw == null || raw === "") return null;
|
||||||
|
const v = parseInt(raw, 10);
|
||||||
|
return Number.isFinite(v) && v >= 0 ? v : null;
|
||||||
|
}
|
||||||
|
|
||||||
// One-shot pulse rings on age-0 marks, placed ~post-render (positions
|
// One-shot pulse rings on age-0 marks, placed ~post-render (positions
|
||||||
// are sampled once; pulses don't track pan/zoom during their ~1.2 s).
|
// are sampled once; pulses don't track pan/zoom during their ~1.2 s).
|
||||||
function pulseAt(canvasPoint, color, sizePx) {
|
function pulseAt(canvasPoint, color, sizePx) {
|
||||||
@ -688,21 +702,36 @@ Graph Console
|
|||||||
if ((childrenOf[n.id] || []).length && parentOf[n.id]) hasCombo[n.id] = true;
|
if ((childrenOf[n.id] || []).length && parentOf[n.id]) hasCombo[n.id] = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Diff-fold: derive fold state from the live marks instead of the
|
// Derived fold state (overrides manual double-click folds while on):
|
||||||
// instance — every combo collapses except those on an ancestor path
|
// overview mode collapses every combo at depth ≥ the limit (all of
|
||||||
// of (or being) a changed element, so changes stand out of the
|
// them when only diff-fold is on), then diff-fold re-opens the
|
||||||
// unchanged mass. Manual double-click fold state is ignored while on.
|
// ancestor paths of changed elements — combined, that reads as
|
||||||
if (diffFold && withCombos) {
|
// "overview, with changes drilled open".
|
||||||
|
const depthLimit = depthFoldValue();
|
||||||
|
if (withCombos && (diffFold || depthLimit != null)) {
|
||||||
|
const depthOf = {};
|
||||||
|
const depth = function (id) {
|
||||||
|
if (depthOf[id] != null) return depthOf[id];
|
||||||
|
const p = parentOf[id];
|
||||||
|
depthOf[id] = p ? depth(p) + 1 : 0;
|
||||||
|
return depthOf[id];
|
||||||
|
};
|
||||||
collapsedIds = new Set();
|
collapsedIds = new Set();
|
||||||
Object.keys(hasCombo).forEach(function (id) { collapsedIds.add(comboIdFor(id)); });
|
Object.keys(hasCombo).forEach(function (id) {
|
||||||
liveMarkedNodeIds().forEach(function (id) {
|
if (depthLimit == null || depth(id) >= depthLimit) {
|
||||||
if (hasCombo[id]) collapsedIds.delete(comboIdFor(id));
|
collapsedIds.add(comboIdFor(id));
|
||||||
let p = parentOf[id];
|
|
||||||
while (p) {
|
|
||||||
if (hasCombo[p]) collapsedIds.delete(comboIdFor(p));
|
|
||||||
p = parentOf[p];
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (diffFold) {
|
||||||
|
liveMarkedNodeIds().forEach(function (id) {
|
||||||
|
if (hasCombo[id]) collapsedIds.delete(comboIdFor(id));
|
||||||
|
let p = parentOf[id];
|
||||||
|
while (p) {
|
||||||
|
if (hasCombo[p]) collapsedIds.delete(comboIdFor(p));
|
||||||
|
p = parentOf[p];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const combos = [];
|
const combos = [];
|
||||||
nodes.forEach(function (n) {
|
nodes.forEach(function (n) {
|
||||||
@ -1041,7 +1070,8 @@ Graph Console
|
|||||||
}
|
}
|
||||||
if (anywayBtn) anywayBtn.style.display = "none";
|
if (anywayBtn) anywayBtn.style.display = "none";
|
||||||
graphViewStatus.textContent = graphStatusText(data) + filterNote;
|
graphViewStatus.textContent = graphStatusText(data) + filterNote;
|
||||||
renderGraph(toG6Data(shown, collapsedComboIds(), foldEnabled() || diffFoldEnabled(),
|
renderGraph(toG6Data(shown, collapsedComboIds(),
|
||||||
|
foldEnabled() || diffFoldEnabled() || depthFoldValue() != null,
|
||||||
LAYOUTS[currentLayoutName()] == null, diffFoldEnabled()));
|
LAYOUTS[currentLayoutName()] == null, diffFoldEnabled()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1552,6 +1582,16 @@ Graph Console
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const depthFoldInput = document.getElementById("graph-depth-fold");
|
||||||
|
if (depthFoldInput) {
|
||||||
|
const v = depthFoldValue();
|
||||||
|
depthFoldInput.value = v == null ? "" : String(v);
|
||||||
|
depthFoldInput.addEventListener("change", function () {
|
||||||
|
localStorage.setItem("graph-depth-fold", depthFoldInput.value);
|
||||||
|
renderCurrent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const layoutSelect = document.getElementById("graph-layout-select");
|
const layoutSelect = document.getElementById("graph-layout-select");
|
||||||
if (layoutSelect) {
|
if (layoutSelect) {
|
||||||
Object.keys(LAYOUTS).forEach(function (name) {
|
Object.keys(LAYOUTS).forEach(function (name) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user