feat: wire up recent tools tracking + favorites pin menu in bottom toolbar
Tracks last 2 sidebar tools used and shows them at the right end of the bottom toolbar. [+] button opens a grouped menu to pin up to 4 favorite tools. Pins and recents persist in localStorage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d988e0b112
commit
acc0faca01
|
|
@ -3960,6 +3960,132 @@
|
|||
syncBottomToolbar();
|
||||
});
|
||||
|
||||
// ── Recent tools + Favorites (+) menu ──
|
||||
const recentToolsEl = document.getElementById("recent-tools");
|
||||
const recentSep = document.getElementById("recent-sep");
|
||||
const toolPlusMenu = document.getElementById("tool-plus-menu");
|
||||
const toolPlusBtn = document.getElementById("tool-plus");
|
||||
|
||||
// Recent tools: track last 2 sidebar tools used (not basic canvas tools)
|
||||
let recentTools = JSON.parse(localStorage.getItem("rspace_recent_tools") || "[]");
|
||||
// Pinned favorites
|
||||
let pinnedTools = JSON.parse(localStorage.getItem("rspace_pinned_tools") || "[]");
|
||||
|
||||
// Tool registry: maps sidebar button IDs to display info
|
||||
const sidebarToolRegistry = {};
|
||||
document.querySelectorAll("#toolbar .toolbar-dropdown button").forEach(btn => {
|
||||
sidebarToolRegistry[btn.id] = {
|
||||
id: btn.id,
|
||||
label: btn.textContent.trim(),
|
||||
title: btn.title || btn.textContent.trim(),
|
||||
};
|
||||
});
|
||||
// Add direct sidebar buttons too
|
||||
["new-feed", "toggle-memory", "toggle-hide-forgotten", "feed-toggle"].forEach(id => {
|
||||
const btn = document.getElementById(id);
|
||||
if (btn) sidebarToolRegistry[id] = { id, label: btn.textContent.trim(), title: btn.title || btn.textContent.trim() };
|
||||
});
|
||||
|
||||
function trackRecentTool(toolId) {
|
||||
if (!toolId || !sidebarToolRegistry[toolId]) return;
|
||||
// Don't track if it's already pinned
|
||||
if (pinnedTools.includes(toolId)) return;
|
||||
recentTools = recentTools.filter(t => t !== toolId);
|
||||
recentTools.unshift(toolId);
|
||||
recentTools = recentTools.slice(0, 2);
|
||||
localStorage.setItem("rspace_recent_tools", JSON.stringify(recentTools));
|
||||
renderRecentTools();
|
||||
}
|
||||
|
||||
function renderRecentTools() {
|
||||
recentToolsEl.innerHTML = "";
|
||||
// Show pinned first, then recent (excluding pinned)
|
||||
const shown = [...pinnedTools, ...recentTools.filter(t => !pinnedTools.includes(t))].slice(0, 4);
|
||||
if (shown.length > 0) recentSep.style.display = "";
|
||||
else recentSep.style.display = "none";
|
||||
|
||||
for (const toolId of shown) {
|
||||
const info = sidebarToolRegistry[toolId];
|
||||
if (!info) continue;
|
||||
const btn = document.createElement("button");
|
||||
btn.className = "recent-tool-btn";
|
||||
btn.title = info.title;
|
||||
btn.textContent = info.label.split(" ")[0]; // emoji only
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
document.getElementById(toolId)?.click();
|
||||
});
|
||||
recentToolsEl.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
// Track clicks on sidebar tool buttons
|
||||
document.querySelectorAll("#toolbar .toolbar-dropdown button, #toolbar-panel-body button").forEach(btn => {
|
||||
btn.addEventListener("click", () => trackRecentTool(btn.id));
|
||||
});
|
||||
// Intercept panel button clicks for tracking (cloned dynamically)
|
||||
document.getElementById("toolbar-panel-body")?.addEventListener("click", (e) => {
|
||||
const btn = e.target.closest("button");
|
||||
if (btn && btn.id) trackRecentTool(btn.id);
|
||||
});
|
||||
|
||||
// [+] menu: show all sidebar tools, allow pinning
|
||||
toolPlusBtn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
toolPlusMenu.classList.toggle("open");
|
||||
if (toolPlusMenu.classList.contains("open")) renderPlusMenu();
|
||||
});
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!e.target.closest(".tool-plus-wrap")) {
|
||||
toolPlusMenu.classList.remove("open");
|
||||
}
|
||||
});
|
||||
|
||||
function renderPlusMenu() {
|
||||
toolPlusMenu.innerHTML = "";
|
||||
|
||||
// Group tools by their toolbar group
|
||||
const groups = document.querySelectorAll("#toolbar .toolbar-group");
|
||||
for (const group of groups) {
|
||||
const toggle = group.querySelector(".toolbar-group-toggle");
|
||||
const dropdown = group.querySelector(".toolbar-dropdown");
|
||||
if (!toggle || !dropdown) continue;
|
||||
|
||||
const heading = document.createElement("div");
|
||||
heading.className = "menu-heading";
|
||||
heading.textContent = toggle.textContent.trim();
|
||||
toolPlusMenu.appendChild(heading);
|
||||
|
||||
for (const origBtn of dropdown.querySelectorAll("button")) {
|
||||
const toolId = origBtn.id;
|
||||
if (!toolId) continue;
|
||||
const info = sidebarToolRegistry[toolId];
|
||||
if (!info) continue;
|
||||
|
||||
const btn = document.createElement("button");
|
||||
btn.className = pinnedTools.includes(toolId) ? "pinned" : "";
|
||||
btn.innerHTML = `<span>${info.label}</span><span class="pin-icon">📌</span>`;
|
||||
btn.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
if (pinnedTools.includes(toolId)) {
|
||||
pinnedTools = pinnedTools.filter(t => t !== toolId);
|
||||
} else {
|
||||
pinnedTools.push(toolId);
|
||||
if (pinnedTools.length > 4) pinnedTools.shift();
|
||||
}
|
||||
localStorage.setItem("rspace_pinned_tools", JSON.stringify(pinnedTools));
|
||||
renderRecentTools();
|
||||
renderPlusMenu();
|
||||
});
|
||||
toolPlusMenu.appendChild(btn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initial render
|
||||
renderRecentTools();
|
||||
|
||||
// Whiteboard pointer handlers on the SVG overlay
|
||||
wbOverlay.addEventListener("pointerdown", (e) => {
|
||||
if (!wbTool || wbTool === "eraser") {
|
||||
|
|
|
|||
Loading…
Reference in New Issue