Files
hamlab/web/src/railorder.ts
T
Mitchell-JohnsonandClaude Fable 5.1 7e3e916f25 Arrange the rail: drag pages into your own order, kept with the account
The close cross on a detail pane is drawn, not a glyph, and sits in no box.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 19:59:25 -07:00

36 lines
1.5 KiB
TypeScript

// The order of the pages in the rail is the account's: kept here for instant use and saved
// with the UI prefs, so it follows the login. Pages the saved order doesn't name (added since)
// go after the ones it does, in their built-in order.
import { useEffect, useState } from 'react'
const KEY = 'hamlab.rail'
export function getRailOrder(): string[] {
try { const v = JSON.parse(localStorage.getItem(KEY) ?? '[]'); return Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [] } catch { return [] }
}
export function setRailOrder(ids: string[], save = true) {
localStorage.setItem(KEY, JSON.stringify(ids))
window.dispatchEvent(new Event('hamlab:rail'))
if (save) import('./accents').then((m) => m.savePrefs())
}
export function resetRailOrder() { localStorage.removeItem(KEY); window.dispatchEvent(new Event('hamlab:rail')); import('./accents').then((m) => m.savePrefs()) }
export function useRailOrder(): string[] {
const [order, setOrder] = useState(getRailOrder)
useEffect(() => {
const h = () => setOrder(getRailOrder())
window.addEventListener('hamlab:rail', h)
return () => window.removeEventListener('hamlab:rail', h)
}, [])
return order
}
export function orderBy<T extends { id: string }>(items: T[], order: string[]): T[] {
const by = new Map(items.map((g) => [g.id, g]))
const named = order.map((id) => by.get(id)).filter((g): g is T => !!g)
const seen = new Set(named.map((g) => g.id))
return [...named, ...items.filter((g) => !seen.has(g.id))]
}