First commit

This commit is contained in:
2026-09-30 01:49:35 +02:00
commit 6edd03aace
109 changed files with 27020 additions and 0 deletions

View 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 }
}