- Notes: a glyph below each couplet's bookmark opens a note box (filled gold when the couplet or a phrase in it has a note; the note shows on hover). Selected text gets نوٹ in the selection menu; a highlighted phrase with a note shows the note glyph and opens its note (with "remove highlight"). API: POST /api/library/note {poemId, couplet, phrase?, note} (bookmarks if needed; empty clears the note), notes in /api/library/state; tests added
- Confirm dialog in Urdu (destructive answer in red, named for what it does) in place of the browser's English confirm(); forms use data-confirm
- Toasts for "done" messages; errors stay by the form and nudge; a submitting button shows a spinner
- Motion: page cross-fade (View Transitions) with the logo held; couplets rise in on load; bookmark and note glyphs pop; the word sidebar slides in; menus and folding sections open smoothly; all off with reduced motion
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 lines
1.3 KiB
TypeScript
24 lines
1.3 KiB
TypeScript
// Browser -> API for the bookmark buttons and the word book: the reader's session cookie becomes the Bearer token.
|
|
// JSON posts from other sites are refused: the Origin must be this site (and SameSite cookies are not sent).
|
|
import type { APIRoute } from 'astro';
|
|
import { asUser, COOKIE } from '../../lib/auth';
|
|
|
|
const json = (data: unknown, status = 200) => new Response(JSON.stringify(data), { status, headers: { 'content-type': 'application/json' } });
|
|
|
|
export const POST: APIRoute = async ({ request, cookies, url }) => {
|
|
const origin = request.headers.get('origin');
|
|
if (origin && new URL(origin).host !== url.host) return json({ error: 'forbidden' }, 403);
|
|
const token = cookies.get(COOKIE)?.value;
|
|
if (!token) return json({ error: 'لاگ ان کریں' }, 401);
|
|
const body = await request.json().catch(() => ({}));
|
|
const r = await asUser(token, 'note' in body ? '/api/library/note' : '/api/library/toggle', body); // {note, poemId, couplet, phrase?}: a note
|
|
return json(r.data, r.status);
|
|
};
|
|
|
|
export const GET: APIRoute = async ({ cookies, url }) => {
|
|
const token = cookies.get(COOKIE)?.value;
|
|
if (!token) return json({ error: 'لاگ ان کریں' }, 401);
|
|
const r = await asUser(token, `/api/library/state?word=${encodeURIComponent(url.searchParams.get('word') ?? '')}`);
|
|
return json(r.data, r.status);
|
|
};
|