export interface ViewedArticle { slug: string title: string viewedAt: number } const STORAGE_KEY = 'mathew-recently-viewed' const MAX_ENTRIES = 8 let loaded = false function readStored(): ViewedArticle[] { try { const raw = localStorage.getItem(STORAGE_KEY) return raw ? (JSON.parse(raw) as ViewedArticle[]) : [] } catch { /* ignore corrupt storage */ return [] } } /** * Tracks which articles the visitor has opened, in `localStorage`, so the * sidebar can offer a "recently viewed" list. Shared across pages via * `useState`, so it updates live as you browse without extra fetches. */ export function useRecentlyViewed() { const viewed = useState('recently-viewed', () => []) /* read the saved history once, after mount, so the server render and the client hydration both start from an empty list */ onMounted(() => { if (loaded) return loaded = true const stored = readStored() if (stored.length) viewed.value = stored }) function record(article: { slug: string; title: string }) { /* merge with what's already saved so recording before the list has loaded (e.g. deep-linking straight to an article) can't clobber it */ const base = viewed.value.length ? viewed.value : readStored() viewed.value = [ { ...article, viewedAt: Date.now() }, ...base.filter((v) => v.slug !== article.slug), ].slice(0, MAX_ENTRIES) loaded = true try { localStorage.setItem(STORAGE_KEY, JSON.stringify(viewed.value)) } catch { /* private mode etc. — history just won't persist */ } } return { viewed, record } }