Files
eranos/src/lib/localDrafts.ts
T
Chad Curtis fa34922cce refactor: harden article editor — encryption, mobile UX, deduplication, source toggle
- Encrypt drafts with NIP-44 via NIP-37 (kind 31234) instead of
  plaintext kind 30024
- Fix slug auto-generation overwriting manual edits
- Guard auto-save state setters against unmount
- Deduplicate save logic, load handlers, tag extraction, and types
  via shared ArticleFields/parseArticleEvent helpers
- Replace derived state (wordCount/readingTime) with useMemo
- Mobile UX: sticky toolbar, touch-friendly header image swap,
  adaptive tooltips (pointer:fine only), FAB bottom clearance,
  responsive editor min-height
- Editor placeholder: hide on focus, handle trailing whitespace
- Tighten editor padding and paragraph spacing
- Add raw markdown source toggle (Eye/EyeOff) in toolbar
- Shrink slug/tag fields, consistent sizing
2026-04-02 03:48:10 -05:00

77 lines
2.2 KiB
TypeScript

import type { Draft } from '@/hooks/useDrafts';
const DRAFTS_KEY = 'article-drafts';
/** Save a draft to localStorage. Returns the draft ID or null on failure. */
export function saveDraft(draft: Omit<Draft, 'id' | 'updatedAt'> & { id?: string }): string | null {
try {
const stored = localStorage.getItem(DRAFTS_KEY);
const drafts: Draft[] = stored ? JSON.parse(stored) : [];
const existingIndex = draft.id
? drafts.findIndex(d => d.id === draft.id)
: drafts.findIndex(d => d.slug === draft.slug);
const newDraft: Draft = {
...draft,
id: draft.id || (existingIndex >= 0 ? drafts[existingIndex].id : crypto.randomUUID()),
updatedAt: Date.now(),
};
if (existingIndex >= 0) {
drafts[existingIndex] = newDraft;
} else {
drafts.unshift(newDraft);
}
// Keep only the 20 most recent drafts
const trimmedDrafts = drafts.slice(0, 20);
localStorage.setItem(DRAFTS_KEY, JSON.stringify(trimmedDrafts));
return newDraft.id;
} catch (error) {
console.error('Failed to save draft:', error);
return null;
}
}
/** Delete a draft by slug from localStorage. */
export function deleteDraftBySlug(slug: string): void {
try {
const stored = localStorage.getItem(DRAFTS_KEY);
if (!stored) return;
const drafts: Draft[] = JSON.parse(stored);
const filtered = drafts.filter(d => d.slug !== slug);
localStorage.setItem(DRAFTS_KEY, JSON.stringify(filtered));
} catch (error) {
console.error('Failed to delete draft:', error);
}
}
/** Delete a draft by id from localStorage. Returns the remaining drafts. */
export function deleteLocalDraftById(id: string): Draft[] {
try {
const stored = localStorage.getItem(DRAFTS_KEY);
if (!stored) return [];
const drafts: Draft[] = JSON.parse(stored);
const filtered = drafts.filter(d => d.id !== id);
localStorage.setItem(DRAFTS_KEY, JSON.stringify(filtered));
return filtered;
} catch (error) {
console.error('Failed to delete draft:', error);
return [];
}
}
/** Get all local drafts. */
export function getLocalDrafts(): Draft[] {
try {
const stored = localStorage.getItem(DRAFTS_KEY);
return stored ? JSON.parse(stored) : [];
} catch {
return [];
}
}