fix: feed view DOM restore + toolbar cleanup

Save/restore DOM child order when toggling feed view so element
positions revert correctly on exit. Remove unused Feed and Connect
toolbar buttons (connect mode still works via 'A' key). Rename
Memory panel to Recent Changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-03 14:39:08 -08:00
parent 59b1ae2d05
commit 24cc3ffe95
1 changed files with 23 additions and 87 deletions

View File

@ -1809,8 +1809,7 @@
<span class="toolbar-sep"></span> <span class="toolbar-sep"></span>
<button id="new-feed" title="New Feed from another layer">🔄 Feed</button> <button id="toggle-memory" title="Recent Changes">💭 Recent Changes</button>
<button id="toggle-memory" title="Forgotten rSpaces">💭 Memory</button>
<button id="toggle-hide-forgotten" title="Hide forgotten items">👁 Hide Faded</button> <button id="toggle-hide-forgotten" title="Hide forgotten items">👁 Hide Faded</button>
<button id="feed-toggle" title="Toggle feed view">📋 Feed View</button> <button id="feed-toggle" title="Toggle feed view">📋 Feed View</button>
@ -1857,9 +1856,6 @@
<button class="tool-btn" id="tool-text" title="Note (T)"> <button class="tool-btn" id="tool-text" title="Note (T)">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 7 4 4 20 4 20 7"/><line x1="12" y1="4" x2="12" y2="20"/><line x1="8" y1="20" x2="16" y2="20"/></svg> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 7 4 4 20 4 20 7"/><line x1="12" y1="4" x2="12" y2="20"/><line x1="8" y1="20" x2="16" y2="20"/></svg>
</button> </button>
<button class="tool-btn" id="tool-arrow" title="Connect (A)">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="5" y1="19" x2="19" y2="5"/><polyline points="12 5 19 5 19 12"/></svg>
</button>
<span class="tool-sep"></span> <span class="tool-sep"></span>
<button class="tool-btn" id="tool-eraser" title="Eraser (E)"> <button class="tool-btn" id="tool-eraser" title="Eraser (E)">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 20H7L3 16a1 1 0 010-1.4l9.6-9.6a1 1 0 011.4 0l7 7a1 1 0 010 1.4L15 20"/><line x1="18" y1="13" x2="11" y2="6"/></svg> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 20H7L3 16a1 1 0 010-1.4l9.6-9.6a1 1 0 011.4 0l7 7a1 1 0 010 1.4L15 20"/><line x1="18" y1="13" x2="11" y2="6"/></svg>
@ -1877,7 +1873,7 @@
<div id="memory-panel"> <div id="memory-panel">
<div id="memory-panel-header"> <div id="memory-panel-header">
<h3>💭 Memory</h3> <h3>💭 Recent Changes</h3>
<span class="count" id="memory-count">0</span> <span class="count" id="memory-count">0</span>
</div> </div>
<div id="memory-list"></div> <div id="memory-list"></div>
@ -3359,7 +3355,6 @@
if (pendingTool) clearPendingTool(); if (pendingTool) clearPendingTool();
if (connectMode) { if (connectMode) {
connectMode = false; connectMode = false;
newArrowBtn?.classList.remove("active");
canvas.classList.remove("connect-mode"); canvas.classList.remove("connect-mode");
if (connectSource) { connectSource.classList.remove("connect-source"); connectSource = null; } if (connectSource) { connectSource.classList.remove("connect-source"); connectSource = null; }
} }
@ -3377,7 +3372,7 @@
else if (key === "c") { document.getElementById("tool-circle")?.click(); } else if (key === "c") { document.getElementById("tool-circle")?.click(); }
else if (key === "s") { document.getElementById("tool-sticky")?.click(); } else if (key === "s") { document.getElementById("tool-sticky")?.click(); }
else if (key === "t") { document.getElementById("tool-text")?.click(); } else if (key === "t") { document.getElementById("tool-text")?.click(); }
else if (key === "a") { document.getElementById("tool-arrow")?.click(); } else if (key === "a") { toggleConnectMode(); }
else if (key === "e") { document.getElementById("tool-eraser")?.click(); } else if (key === "e") { document.getElementById("tool-eraser")?.click(); }
}); });
@ -3733,71 +3728,20 @@
} }
// Feed shape — pull live data from another layer/module // Feed shape — pull live data from another layer/module
document.getElementById("new-feed").addEventListener("click", () => {
// Prompt for source module (simple for now — will get a proper UI)
const modules = ["notes", "funds", "vote", "choices", "wallet", "data", "work", "network", "trips"];
const sourceModule = prompt("Feed from which rApp?\n\n" + modules.join(", "), "notes");
if (!sourceModule || !modules.includes(sourceModule)) return;
// Pick flow kind based on module defaults
const moduleFlowKinds = {
funds: "economic", wallet: "economic", trips: "economic",
vote: "governance", choices: "governance",
network: "trust",
data: "attention",
notes: "data", work: "data",
};
const flowKind = moduleFlowKinds[sourceModule] || "data";
setPendingTool("folk-feed", {
sourceModule,
sourceLayer: "layer-" + sourceModule,
feedId: "",
flowKind,
maxItems: 10,
refreshInterval: 30000,
__postCreate: (shape) => {
// Auto-register a LayerFlow in Automerge if layers exist
if (sync.getLayers) {
const layers = sync.getLayers();
const currentLayer = layers.find(l => l.moduleId === "rspace") || layers[0];
const sourceLayer = layers.find(l => l.moduleId === sourceModule);
if (currentLayer && sourceLayer) {
const flowId = `flow-auto-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
sync.addFlow({
id: flowId,
kind: flowKind,
sourceLayerId: sourceLayer.id,
targetLayerId: currentLayer.id,
targetShapeId: shape.id,
label: sourceModule + " feed",
strength: 0.5,
active: true,
});
}
// Also ensure source module has a layer (add if missing)
if (!sourceLayer) {
sync.addLayer({
id: "layer-" + sourceModule,
moduleId: sourceModule,
label: sourceModule,
order: layers.length,
color: "",
visible: true,
createdAt: Date.now(),
});
}
}
},
});
});
// Arrow connection mode // Arrow connection mode
let connectMode = false; let connectMode = false;
let connectSource = null; let connectSource = null;
const newArrowBtn = document.getElementById("tool-arrow"); function toggleConnectMode() {
if (wbTool) setWbTool(null);
if (pendingTool) clearPendingTool();
connectMode = !connectMode;
canvas.classList.toggle("connect-mode", connectMode);
if (!connectMode && connectSource) {
connectSource.classList.remove("connect-source");
connectSource = null;
}
if (typeof syncBottomToolbar === "function") syncBottomToolbar();
}
// Handle shape clicks for connection mode // Handle shape clicks for connection mode
canvas.addEventListener("click", (e) => { canvas.addEventListener("click", (e) => {
@ -3830,7 +3774,6 @@
connectSource.classList.remove("connect-source"); connectSource.classList.remove("connect-source");
connectSource = null; connectSource = null;
connectMode = false; connectMode = false;
newArrowBtn.classList.remove("active");
canvas.classList.remove("connect-mode"); canvas.classList.remove("connect-mode");
if (typeof syncBottomToolbar === "function") syncBottomToolbar(); if (typeof syncBottomToolbar === "function") syncBottomToolbar();
} }
@ -3878,7 +3821,7 @@
const map = { pencil: "tool-pencil", line: "tool-line", rect: "tool-rect", circle: "tool-circle", eraser: "tool-eraser" }; const map = { pencil: "tool-pencil", line: "tool-line", rect: "tool-rect", circle: "tool-circle", eraser: "tool-eraser" };
document.getElementById(map[wbTool])?.classList.add("active"); document.getElementById(map[wbTool])?.classList.add("active");
} else if (connectMode) { } else if (connectMode) {
document.getElementById("tool-arrow")?.classList.add("active"); // Connect mode active (no toolbar button — toggled via 'A' key)
} else if (pendingTool) { } else if (pendingTool) {
// Check if pending tool maps to a bottom toolbar button // Check if pending tool maps to a bottom toolbar button
if (pendingTool.tagName === "folk-markdown" && pendingTool.props?.__postCreate) { if (pendingTool.tagName === "folk-markdown" && pendingTool.props?.__postCreate) {
@ -3898,7 +3841,6 @@
if (pendingTool) clearPendingTool(); if (pendingTool) clearPendingTool();
if (connectMode) { if (connectMode) {
connectMode = false; connectMode = false;
newArrowBtn.classList.remove("active");
canvas.classList.remove("connect-mode"); canvas.classList.remove("connect-mode");
if (connectSource) { connectSource.classList.remove("connect-source"); connectSource = null; } if (connectSource) { connectSource.classList.remove("connect-source"); connectSource = null; }
} }
@ -3947,19 +3889,6 @@
syncBottomToolbar(); syncBottomToolbar();
}); });
document.getElementById("tool-arrow").addEventListener("click", () => {
if (wbTool) setWbTool(null);
if (pendingTool) clearPendingTool();
connectMode = !connectMode;
newArrowBtn.classList.toggle("active", connectMode);
canvas.classList.toggle("connect-mode", connectMode);
if (!connectMode && connectSource) {
connectSource.classList.remove("connect-source");
connectSource = null;
}
syncBottomToolbar();
});
// ── Recent tools + Favorites (+) menu ── // ── Recent tools + Favorites (+) menu ──
const recentToolsEl = document.getElementById("recent-tools"); const recentToolsEl = document.getElementById("recent-tools");
const recentSep = document.getElementById("recent-sep"); const recentSep = document.getElementById("recent-sep");
@ -3981,7 +3910,7 @@
}; };
}); });
// Add direct sidebar buttons too // Add direct sidebar buttons too
["new-feed", "toggle-memory", "toggle-hide-forgotten", "feed-toggle"].forEach(id => { ["toggle-memory", "toggle-hide-forgotten", "feed-toggle"].forEach(id => {
const btn = document.getElementById(id); const btn = document.getElementById(id);
if (btn) sidebarToolRegistry[id] = { id, label: btn.textContent.trim(), title: btn.title || btn.textContent.trim() }; if (btn) sidebarToolRegistry[id] = { id, label: btn.textContent.trim(), title: btn.title || btn.textContent.trim() };
}); });
@ -5130,6 +5059,7 @@
// ── Feed Mode ── // ── Feed Mode ──
let feedMode = false; let feedMode = false;
let feedSortKey = 'y'; let feedSortKey = 'y';
let feedOriginalOrder = [];
const feedToggleBtn = document.getElementById('feed-toggle'); const feedToggleBtn = document.getElementById('feed-toggle');
const feedSortBar = document.getElementById('feed-sort-bar'); const feedSortBar = document.getElementById('feed-sort-bar');
const feedSortSelect = document.getElementById('feed-sort'); const feedSortSelect = document.getElementById('feed-sort');
@ -5140,7 +5070,13 @@
feedToggleBtn.classList.toggle('active', feedMode); feedToggleBtn.classList.toggle('active', feedMode);
feedSortBar.classList.toggle('hidden', !feedMode); feedSortBar.classList.toggle('hidden', !feedMode);
if (feedMode) { if (feedMode) {
// Save original DOM order before reordering
feedOriginalOrder = [...canvasContent.children];
sortFeedShapes(feedSortKey); sortFeedShapes(feedSortKey);
} else {
// Restore original DOM order
for (const el of feedOriginalOrder) canvasContent.appendChild(el);
feedOriginalOrder = [];
} }
} }