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>
36 lines
1.5 KiB
TypeScript
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))]
|
|
}
|