feat(canvas): add first-time forgotten shapes explainer tooltip

Shows a one-time onboarding tooltip when users first encounter a faded
(forgotten) shape. Explains right-click to remember/forget permanently,
the Hide Forgotten toggle in profile menu, and highlights the Collective
Memory graph as a prototype feature. Persisted via localStorage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-25 16:09:05 -07:00
parent 5f853322b0
commit 1a422f06ac
1 changed files with 123 additions and 0 deletions

View File

@ -1406,6 +1406,84 @@
display: none !important;
}
/* First-time forgotten explainer tooltip */
#forgotten-explainer {
display: none;
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%);
background: var(--rs-bg-surface, #1e293b);
border: 1px solid var(--rs-border, rgba(255,255,255,0.1));
border-radius: 14px;
padding: 20px 24px;
max-width: 420px;
width: calc(100vw - 32px);
box-shadow: 0 12px 40px rgba(0,0,0,0.5);
z-index: 300000;
color: var(--rs-text-primary, #e2e8f0);
font-size: 0.85rem;
line-height: 1.55;
animation: explainer-slide-up 0.35s ease-out;
}
@keyframes explainer-slide-up {
from { opacity: 0; transform: translateX(-50%) translateY(20px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
#forgotten-explainer.visible { display: block; }
#forgotten-explainer h4 {
margin: 0 0 10px;
font-size: 0.95rem;
color: var(--rs-text-primary, #e2e8f0);
}
#forgotten-explainer p {
margin: 0 0 8px;
color: var(--rs-text-secondary, #94a3b8);
}
#forgotten-explainer .tip-row {
display: flex;
align-items: flex-start;
gap: 8px;
margin-bottom: 6px;
}
#forgotten-explainer .tip-icon {
flex-shrink: 0;
font-size: 1rem;
line-height: 1.4;
}
#forgotten-explainer .tip-label {
font-size: 0.82rem;
color: var(--rs-text-secondary, #94a3b8);
}
#forgotten-explainer .tip-label strong {
color: var(--rs-text-primary, #e2e8f0);
}
#forgotten-explainer .proto-badge {
display: inline-block;
font-size: 0.68rem;
padding: 1px 6px;
border-radius: 4px;
background: rgba(124,58,237,0.15);
color: #a78bfa;
margin-left: 4px;
vertical-align: middle;
}
#forgotten-explainer .dismiss-btn {
display: block;
margin: 14px auto 0;
padding: 7px 20px;
background: rgba(20,184,166,0.12);
border: 1px solid rgba(20,184,166,0.25);
color: #14b8a6;
border-radius: 8px;
font-size: 0.82rem;
font-weight: 600;
cursor: pointer;
}
#forgotten-explainer .dismiss-btn:hover {
background: rgba(20,184,166,0.2);
}
/* Cross-space shape styling — colored border + source badge */
.rspace-cross-space-shape {
outline: 2px dashed rgba(99, 102, 241, 0.5) !important;
@ -2128,6 +2206,24 @@
<!-- Hidden button for JS toggle reference (injected into identity dropdown) -->
<button id="toggle-hide-forgotten" style="display:none" title="Hide forgotten items"></button>
<div id="forgotten-explainer">
<h4>👻 Faded shapes are "forgotten"</h4>
<p>When you or others close a shape, it doesn't disappear — it fades. This is <strong>collective memory</strong>.</p>
<div class="tip-row">
<span class="tip-icon">🖱</span>
<span class="tip-label"><strong>Right-click</strong> a faded shape to <strong>Remember</strong> it (restore) or <strong>Forget permanently</strong> (delete)</span>
</div>
<div class="tip-row">
<span class="tip-icon">👁</span>
<span class="tip-label">Toggle <strong>Hide Forgotten</strong> in your profile menu to show/hide faded shapes</span>
</div>
<div class="tip-row">
<span class="tip-icon">🔮</span>
<span class="tip-label">The <strong>Collective Memory</strong> graph <span class="proto-badge">prototype</span> visualizes what the group remembers vs. forgets</span>
</div>
<button class="dismiss-btn" id="forgotten-explainer-dismiss">Got it</button>
</div>
<div id="memory-panel">
<div id="memory-panel-header">
<h3>💭 Recent Changes</h3>
@ -6068,6 +6164,33 @@ Use real coordinates, YYYY-MM-DD dates, ISO currency codes. Ask clarifying quest
if (memoryPanel.classList.contains("open")) renderMemoryPanel();
});
// First-time forgotten explainer tooltip
{
const SEEN_KEY = 'rspace_forgotten_explainer_seen';
let explainerShown = false;
function showForgottenExplainer() {
if (explainerShown || localStorage.getItem(SEEN_KEY)) return;
explainerShown = true;
// Delay slightly so the faded shape is visible first
setTimeout(() => {
const el = document.getElementById('forgotten-explainer');
if (el) el.classList.add('visible');
}, 800);
}
document.getElementById('forgotten-explainer-dismiss')?.addEventListener('click', () => {
localStorage.setItem(SEEN_KEY, '1');
const el = document.getElementById('forgotten-explainer');
if (el) el.classList.remove('visible');
});
sync.addEventListener("shape-state-changed", (e) => {
if (e.detail?.state === 'forgotten') showForgottenExplainer();
});
sync.addEventListener("shape-forgotten", () => showForgottenExplainer());
}
// Re-dispatch comment-pins-changed on window so header bell can update
sync.addEventListener("comment-pins-changed", () => {
window.dispatchEvent(new CustomEvent("comment-pins-changed"));