import { createCard } from './components/Card.js';
import { renderProgressMap as renderProgressMapEl } from './components/ProgressMap.js';
import { attachTypeahead } from './components/HandleTypeahead.js';
import { createElement, RefreshCw, UserPlus, UserMinus, Sprout, ArrowRight } from 'lucide';
const ARROW_RIGHT_HTML = createElement(ArrowRight, { width: 16, height: 16, 'stroke-width': 2, class: 'inline align-text-bottom ml-1' }).outerHTML;
const ICON_MAP = { follow: UserPlus, unfollow: UserMinus, seed: Sprout, refresh: RefreshCw };
export function iconHtml(type, size = 14) {
const node = ICON_MAP[type];
if (!node) return '';
return createElement(node, { width: size, height: size, 'stroke-width': 2, class: 'inline align-text-bottom' }).outerHTML;
}
export const KEYS = ['a', 's', 'd', 'f'];
export const secretBtns = `—
[r] refresh / [b] back / [n] next`;
export function showLoading(msg) {
document.getElementById('login-screen').style.display = 'none';
document.getElementById('discover-screen').style.display = 'none';
const ls = document.getElementById('loading-screen');
ls.style.display = 'block';
ls.textContent = msg || 'loading…';
}
export function showDiscover() {
document.getElementById('login-screen').style.display = 'none';
document.getElementById('loading-screen').style.display = 'none';
document.getElementById('discover-screen').style.display = 'block';
}
export function setStatus(msg) {
document.getElementById('status').innerHTML = msg;
}
export function updateFollowCounter(count) {
const el = document.getElementById('follow-counter');
if (el) el.textContent = `${count.toLocaleString()} following`;
}
export function setUndoVisible(visible) {
const hint = document.getElementById('z-hint');
if (hint) hint.style.display = visible ? 'block' : 'none';
}
export function setSmallOnlyChecked(checked) {
const el = document.getElementById('small-only-toggle');
if (el) el.checked = checked;
}
export function setBackVisible(visible) {
const btn = document.getElementById('back-btn');
if (btn) btn.style.display = visible ? '' : 'none';
}
export function setForwardVisible(visible) {
const btn = document.getElementById('forward-btn');
if (btn) btn.style.display = visible ? '' : 'none';
}
export function showLoginError(msg) {
document.getElementById('login-error').textContent = msg || '';
}
export function showError(msg) {
document.getElementById('error').textContent = msg || '';
}
export function setRefreshSpinnerVisible(visible) {
const el = document.getElementById('refresh-spinner');
if (el) el.style.display = visible ? 'flex' : 'none';
}
export function setGridDimmed(dimmed) {
const classList = document.getElementById('grid').classList;
if (dimmed) {
classList.add('opacity-40', 'pointer-events-none');
} else {
classList.remove('opacity-40', 'pointer-events-none');
}
}
export function highlightCard(index) {
const card = document.getElementById('grid').children[index];
if (!card) return () => {};
card.classList.add('outline', 'outline-4', 'outline-offset-4', 'outline-black', 'dark:outline-gray-600');
return () => card.classList.remove('outline', 'outline-4', 'outline-offset-4', 'outline-black', 'dark:outline-gray-600');
}
export function renderGrid(candidates, onSelect, followingSet) {
const grid = document.getElementById('grid');
grid.innerHTML = '';
candidates.forEach((p, i) => {
const followed = followingSet?.has(p.did) ?? false;
const card = createCard(p, KEYS[i], followed ? null : () => onSelect(i), followed);
grid.appendChild(card);
});
}
export function renderProgressMap(timelineEvents, myAvatar, cursor) {
renderProgressMapEl(document.getElementById('progress-map'), timelineEvents, myAvatar, cursor);
}
export function setLoginLoading(isLoading) {
const btn = document.getElementById('login-btn');
btn.disabled = isLoading;
btn.innerHTML = isLoading ? 'redirecting…' : `enter tunnel${ARROW_RIGHT_HTML}`;
if (isLoading) showLoginError('');
}
export function bindEvents({ onLogin, onLogout, onKeySelect, onRefresh, onBack, onForward, onUndo, onSmallOnlyToggle }) {
const smallToggle = document.getElementById('small-only-toggle');
if (smallToggle && onSmallOnlyToggle) {
smallToggle.addEventListener('change', () => {
onSmallOnlyToggle(smallToggle.checked);
smallToggle.blur();
});
}
setLoginLoading(false);
const handleInput = document.getElementById('handle');
document.getElementById('login-btn').addEventListener('click', () => {
onLogin(handleInput.value.trim());
});
attachTypeahead(handleInput, document.getElementById('handle-typeahead'), {
onSubmit: v => onLogin(v),
});
document.getElementById('logout-btn').addEventListener('click', onLogout);
document.addEventListener('click', e => {
if (e.target.id === 'refresh-btn' && onRefresh) onRefresh();
if (e.target.id === 'back-btn' && onBack) onBack();
if (e.target.id === 'forward-btn' && onForward) onForward();
if (e.target.id === 'new-seed-btn' && onForward) onForward();
if (e.target.id === 'undo-btn' && onUndo) onUndo();
if (e.target.id === 'undo-btn-bottom' && onUndo) onUndo();
});
document.addEventListener('keydown', e => {
if (e.target.tagName === 'INPUT') return;
if (e.key === 'r') {
if (onRefresh) onRefresh();
return;
}
if (e.key === 'b') {
if (onBack) onBack();
return;
}
if (e.key === 'n') {
if (onForward) onForward();
return;
}
if (e.key === 'z') {
if (onUndo) onUndo();
return;
}
const i = KEYS.indexOf(e.key);
if (i !== -1) {
onKeySelect(i);
}
});
}