feat: visual polish & UX — fade-in, theme toggle, scroll-to-top, footer, cursor, badge
- Add FadeIn component (IntersectionObserver scroll-reveal + load animation) - Add dark/light theme toggle (useSyncExternalStore + localStorage) - Add scroll-to-top button (appears after 300px scroll) - Add configurable footer with social links (gallery.yaml) - Add crosshair cursor on photo grid items - Add 'X photos' count badge on subpage cover images - Add light theme color palette in tokens.css
This commit is contained in:
52
lib/cache.ts
52
lib/cache.ts
@@ -4,42 +4,42 @@
|
||||
*/
|
||||
|
||||
interface CacheEntry<T> {
|
||||
data: T;
|
||||
expiresAt: number;
|
||||
data: T;
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
class MemoryCache {
|
||||
private store = new Map<string, CacheEntry<unknown>>();
|
||||
private maxEntries = 200;
|
||||
private store = new Map<string, CacheEntry<unknown>>();
|
||||
private maxEntries = 200;
|
||||
|
||||
get<T>(key: string): T | null {
|
||||
const entry = this.store.get(key);
|
||||
if (!entry) return null;
|
||||
get<T>(key: string): T | null {
|
||||
const entry = this.store.get(key);
|
||||
if (!entry) return null;
|
||||
|
||||
if (Date.now() > entry.expiresAt) {
|
||||
this.store.delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
return entry.data as T;
|
||||
if (Date.now() > entry.expiresAt) {
|
||||
this.store.delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
set<T>(key: string, data: T, ttlMs: number): void {
|
||||
// Evict oldest entries if at capacity
|
||||
if (this.store.size >= this.maxEntries) {
|
||||
const firstKey = this.store.keys().next().value;
|
||||
if (firstKey) this.store.delete(firstKey);
|
||||
}
|
||||
return entry.data as T;
|
||||
}
|
||||
|
||||
this.store.set(key, {
|
||||
data,
|
||||
expiresAt: Date.now() + ttlMs,
|
||||
});
|
||||
set<T>(key: string, data: T, ttlMs: number): void {
|
||||
// Evict oldest entries if at capacity
|
||||
if (this.store.size >= this.maxEntries) {
|
||||
const firstKey = this.store.keys().next().value;
|
||||
if (firstKey) this.store.delete(firstKey);
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.store.clear();
|
||||
}
|
||||
this.store.set(key, {
|
||||
data,
|
||||
expiresAt: Date.now() + ttlMs,
|
||||
});
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.store.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export const cache = new MemoryCache();
|
||||
|
||||
Reference in New Issue
Block a user