Spaces:
Sleeping
Sleeping
| import { STATE } from '../core/State.js'; | |
| import { updateThreadColor, updateThreadVisibility } from '../visualizer/ThreadManager.js'; | |
| import { updateHUD } from './HUD.js'; | |
| export function updateThreadListUI() { | |
| const ul = document.getElementById('thread-list-ul'); | |
| if (!ul) return; | |
| ul.innerHTML = ''; | |
| STATE.threads.forEach((t, index) => { | |
| const li = document.createElement('li'); | |
| li.className = 'list-item'; | |
| if (t.isGhost) { | |
| li.style.borderColor = 'var(--color-brand-secondary)'; | |
| li.style.boxShadow = '0 0 8px oklch(from var(--color-brand-secondary) l c h / 0.2)'; | |
| } | |
| const isFocused = STATE.focusedThreads.has(index); | |
| const isHidden = STATE.hiddenThreads.has(index); | |
| const hex = '#' + t.color.getHexString(); | |
| li.innerHTML = ` | |
| <div style="display:flex; align-items:center; gap:8px; overflow:hidden;"> | |
| <input type="color" class="thread-color-picker" data-index="${index}" value="${hex}" style="width:16px; height:16px; border:none; padding:0; background:none; cursor:pointer; flex-shrink:0;"> | |
| <span style="font-weight:700; color:${hex}; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:110px; font-size: var(--font-size-small);">${t.label} <span style="font-size:9px; opacity:0.5;">ID: ${t.tokenID || 0}</span></span> | |
| </div> | |
| <div style="display:flex; gap:6px; align-items:center; flex-shrink:0;"> | |
| <span id="thread-val-${index}" style="font-family: var(--font-mono); font-size: var(--font-size-small); color: var(--color-neutral-400); width:35px; text-align:right; font-weight: 500;">0.00</span> | |
| <button class="btn-focus btn btn-secondary" data-index="${index}" style=" | |
| background: ${isFocused ? 'var(--color-semantic-success)' : 'oklch(from var(--color-neutral-50) l c h / 0.04)'}; | |
| color: ${isFocused ? 'var(--color-neutral-950)' : 'var(--color-semantic-success)'}; | |
| border-color: ${isFocused ? 'var(--color-semantic-success)' : 'oklch(from var(--color-neutral-50) l c h / 0.08)'}; | |
| font-size:10px; width:22px; height:22px; min-height:22px; display:flex; align-items:center; justify-content:center; padding:0; | |
| " title="Focus">🎯</button> | |
| <button class="btn-hide btn btn-secondary" data-index="${index}" style=" | |
| background: ${isHidden ? 'var(--color-semantic-error)' : 'oklch(from var(--color-neutral-50) l c h / 0.04)'}; | |
| color: ${isHidden ? 'var(--color-neutral-50)' : 'var(--color-neutral-400)'}; | |
| border-color: ${isHidden ? 'var(--color-semantic-error)' : 'oklch(from var(--color-neutral-50) l c h / 0.08)'}; | |
| font-size:10px; width:22px; height:22px; min-height:22px; display:flex; align-items:center; justify-content:center; padding:0; | |
| " title="Toggle Visibility">👁️</button> | |
| </div> | |
| `; | |
| ul.appendChild(li); | |
| }); | |
| // Attach color picker event listeners | |
| ul.querySelectorAll('.thread-color-picker').forEach(input => { | |
| input.oninput = (e) => { | |
| const idx = parseInt(e.target.dataset.index); | |
| const hex = e.target.value; | |
| const thread = STATE.threads[idx]; | |
| if (thread) { | |
| updateThreadColor(thread, hex); | |
| } | |
| }; | |
| }); | |
| // Focus state button listener | |
| ul.querySelectorAll('.btn-focus').forEach(btn => { | |
| btn.onclick = (e) => { | |
| const idx = parseInt(e.currentTarget.dataset.index); | |
| if (STATE.focusedThreads.has(idx)) { | |
| STATE.focusedThreads.delete(idx); | |
| } else { | |
| STATE.focusedThreads.add(idx); | |
| } | |
| updateThreadListUI(); | |
| updateThreadVisibility(); | |
| }; | |
| }); | |
| // Visibility state button listener | |
| ul.querySelectorAll('.btn-hide').forEach(btn => { | |
| btn.onclick = (e) => { | |
| const idx = parseInt(e.currentTarget.dataset.index); | |
| if (STATE.hiddenThreads.has(idx)) { | |
| STATE.hiddenThreads.delete(idx); | |
| } else { | |
| STATE.hiddenThreads.add(idx); | |
| } | |
| updateThreadListUI(); | |
| updateThreadVisibility(); | |
| }; | |
| }); | |
| } | |
| export function displayHunterResults(matches) { | |
| const container = document.getElementById('hunter-results'); | |
| if (!container) return; | |
| container.innerHTML = ''; | |
| if (matches.length === 0) { | |
| container.innerHTML = '<li class="list-item" style="color: var(--color-neutral-400); justify-content: center; font-size: var(--font-size-small);">No matches found.</li>'; | |
| return; | |
| } | |
| matches.forEach(m => { | |
| const li = document.createElement('li'); | |
| li.className = 'list-item'; | |
| li.style.cssText = ` | |
| cursor: pointer; font-family: var(--font-mono); font-size: var(--font-size-small); | |
| `; | |
| li.innerHTML = ` | |
| <span style="font-weight: 700; color: var(--color-brand-primary);">DIM ${m.index}</span> | |
| <span style="color: var(--color-neutral-50); font-weight: 600;">${m.value.toFixed(3)}</span> | |
| `; | |
| li.onclick = () => { | |
| STATE.currentSelectedIndex = m.index; | |
| updateHUD(); | |
| }; | |
| li.onmouseover = () => { | |
| li.style.backgroundColor = 'oklch(from var(--color-brand-primary) l c h / 0.1)'; | |
| li.style.borderColor = 'var(--color-brand-primary)'; | |
| }; | |
| li.onmouseout = () => { | |
| li.style.backgroundColor = 'oklch(from var(--color-neutral-50) l c h / 0.02)'; | |
| li.style.borderColor = 'oklch(from var(--color-neutral-50) l c h / 0.04)'; | |
| }; | |
| container.appendChild(li); | |
| }); | |
| } | |
| export function renderDemoBadge(containerTarget, customMessage) { | |
| const el = typeof containerTarget === 'string' ? document.querySelector(containerTarget) : containerTarget; | |
| if (!el) return; | |
| const msg = customMessage || 'DEMO MODE (READ-ONLY) — This action is disabled in the public demo to ensure stability.'; | |
| const badgeHtml = ` | |
| <div style="margin-top: 12px; padding: 10px 14px; background: oklch(from var(--color-brand-primary) l c h / 0.08); border: 1px solid oklch(from var(--color-brand-primary) l c h / 0.3); border-radius: var(--border-radius-medium, 6px); color: var(--color-neutral-100); font-size: 0.75rem; line-height: 1.4; display: flex; align-items: center; gap: 8px;"> | |
| <span style="font-size: 1rem; flex-shrink: 0;">🔒</span> | |
| <span>${msg}</span> | |
| </div> | |
| `; | |
| el.insertAdjacentHTML('beforeend', badgeHtml); | |
| } | |