chris 1f51504de9 Add story writer app with editor, auth, export, and polish features
- React + TipTap editor with formatting toolbar (bold, italic, underline,
  strikethrough, alignment, highlight, scene breaks)
- Custom image node view with resize and alignment controls; server-side
  WebP conversion via sharp
- Express + SQLite backend with JWT auth and admin user management
- Export to PDF, EPUB, and ODT
- Five themes (Midnight, Gothic Night, Enchanted Forest, Aged Manuscript,
  Neon Noir); Lora body font for readability
- Writing streak, daily word goal, milestones, and Ollama writing prompts
- Docker Compose setup for self-hosted deployment behind NPMplus

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:47:55 -04:00

27 lines
768 B
JavaScript

import { createContext, useContext, useState, useCallback } from 'react'
const Ctx = createContext(null)
export function ToastProvider({ children }) {
const [toasts, setToasts] = useState([])
const addToast = useCallback((message, type = 'info') => {
const id = Date.now() + Math.random()
setToasts(p => [...p, { id, message, type }])
setTimeout(() => setToasts(p => p.filter(t => t.id !== id)), 4000)
}, [])
return (
<Ctx.Provider value={addToast}>
{children}
<div className="toast-container" aria-live="polite">
{toasts.map(t => (
<div key={t.id} className={`toast toast--${t.type}`}>{t.message}</div>
))}
</div>
</Ctx.Provider>
)
}
export function useToast() { return useContext(Ctx) }