Newer
Older
navi-1 / client / js / sidebar.js
@Eugene Sukhodolskiy Eugene Sukhodolskiy on 8 Apr 2 KB Pin sessions + larger code font
/** Sidebar DOM helpers. */

function esc(str) {
  return String(str ?? '')
    .replace(/&/g, '&amp;').replace(/</g, '&lt;')
    .replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}

function timeLabel(iso) {
  if (!iso) return '';
  const d = new Date(iso);
  if (isNaN(d)) return '';
  const diff = Date.now() - d;
  if (diff < 60_000)     return 'just now';
  if (diff < 3_600_000)  return `${Math.floor(diff / 60_000)}m ago`;
  if (diff < 86_400_000) return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
  return d.toLocaleDateString();
}

export function renderProfiles(selectEl, profiles) {
  selectEl.innerHTML = profiles
    .map(p => `<option value="${esc(p.id)}">${esc(p.name)}</option>`)
    .join('');
}

export function renderSessions(listEl, sessions, currentId, { onSelect, onDelete, onPin }) {
  if (!sessions.length) {
    listEl.innerHTML = '<div class="empty-sessions">No conversations yet</div>';
    return;
  }

  listEl.innerHTML = sessions.map(s => {
    const active   = s.session_id === currentId ? ' active' : '';
    const pinned   = s.pinned ? ' pinned' : '';
    const preview  = esc(s.preview || 'No messages yet');
    const name     = esc(s.profile_name || s.profile_id);
    const time     = timeLabel(s.last_active);
    const pinIcon  = s.pinned ? '📌' : '📍';
    const pinTitle = s.pinned ? 'Unpin' : 'Pin';
    return `
      <div class="session-item${active}${pinned}" data-id="${s.session_id}">
        <div class="s-body">
          <div class="s-profile">${s.pinned ? '📌 ' : ''}${name}</div>
          <div class="s-preview">${preview}</div>
          <div class="s-time">${time}</div>
        </div>
        <div class="s-actions">
          <button class="btn-pin"    data-id="${s.session_id}" data-pinned="${s.pinned}" title="${pinTitle}">${pinIcon}</button>
          <button class="btn-delete" data-id="${s.session_id}" title="Delete">×</button>
        </div>
      </div>`;
  }).join('');

  listEl.querySelectorAll('.session-item').forEach(el =>
    el.addEventListener('click', () => onSelect(el.dataset.id))
  );
  listEl.querySelectorAll('.btn-pin').forEach(btn =>
    btn.addEventListener('click', e => {
      e.stopPropagation();
      onPin(btn.dataset.id, btn.dataset.pinned !== 'true');
    })
  );
  listEl.querySelectorAll('.btn-delete').forEach(btn =>
    btn.addEventListener('click', e => { e.stopPropagation(); onDelete(btn.dataset.id); })
  );
}

export function updateChatHeader(headerEl, profileId, profileName) {
  headerEl.innerHTML = profileId
    ? `<span class="profile-badge">${esc(profileId)}</span> ${esc(profileName || profileId)}`
    : 'Select a profile and start a new chat';
}