First commit
This commit is contained in:
56
frontend/app/composables/useRecentlyViewed.ts
Normal file
56
frontend/app/composables/useRecentlyViewed.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
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<ViewedArticle[]>('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 }
|
||||
}
|
||||
Reference in New Issue
Block a user