- Icon component (Lucide shapes, ISC), currentColor, decorative (the control keeps its words in aria-label/title).
- Colour roles: --action (primary, filled), --ok (approve, publish), --danger (log out, delete, reject); .btn variants
and .icon-btn; light and dark.
- Header: admin, moderation, saved, word book, account/sign in, font, theme as icons; log out in red.
- Review: save/send filled, approve/publish green, return plain, reject red, with icons. Account: save, log out, password,
delete. Reading pages: edit, history, arrange, tag. E-books: add, download, covers; the reader's controls as icons.
- نشانات is now محفوظ شدہ; favourite writers have their own page, پسندیدہ لکھاری (/writers).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ای بکس card beside the poet's books and genres on every poet page; /<poet>/ebooks with tabs
پی ڈی ایف (PDF) / ای پب (ePUB) / یونیکوڈ متن (Unicode) (+ آرکائیو when present) and a grid of covers.
- Covers: made in the moderator's browser from a PDF's first page (pdf.js) or an EPUB's cover (epub.js); archive.org's
thumbnail; a styled card for text; or the moderator's own image. سرورق بنائیں on existing books.
- PDF reader (pdf.js) reading right to left: next page to the left (button, ← key, left half), facing pages with the
cover alone then 2|3; left to right for LTR books; full screen (F); opens in a new tab; byte-range requests.
- Page bookmarks in the reader's library (kind 'page'), listed in نشانات and opening at that page.
- Details: writer as printed, co-authors (linked to poets on the site, who list the book too; new names kept as text),
language, reading direction (RTL/LTR), extra tags (on tag pages), source, copyright, note; in upload and review.
- Word lookup and selection menu only on reading text, not menus, buttons or tabs.
- Schema: the library kind check lists 'page' where it is defined (it was re-added without it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ebooks permission (create, per poet); the upload button only for L2/L1 moderators with it (and admins).
- Files kept by SHA-256 in DIVAN_FILES_DIR (ab/cd/<sha>.<ext>; one copy per file), up to 100 MB, kind read from
the bytes; details in PostgreSQL indexed by poet and trigram (title, text of text books); search shows e-books.
- An upload is a revision (entity 'ebook') through L2 -> L1 -> admin; unpublished files only for moderators;
approved details committed to divan-data (divan/<poet>/ebooks/<id>.txt).
- ای بکس on the poet page; /ebook/<id>: PDF in the browser viewer, EPUB with epub.js, text, archive.org embed.
- README: e-books and the file store (attach growable block storage or an S3 bucket via rclone).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Types موضوع، صنف، بحر، شخصیت، مقام، دور and free ٹیگ; a work's tag may be on one couplet (شعر n, from 1).
- Tagging is a revision (tags-category / tags-work) through the L2 -> L1 -> admin pipeline with the new 'tags'
permission; publishing writes divan-data/divan/<url>.tags, commits it and updates the site; the import reloads them.
- Pages show tag chips (couplet tags under the couplet); /tag/<type>/<name> lists what carries a tag; /tags lists all.
- Search: tag:عشق / ٹیگ:"حب الوطنی" filters works (tagged work, couplet or book), matching tags shown as a group.
- Tag editor rows with suggestions, Urdu keyboard and Roman typing.
- Tests run one file at a time (they share Ghalib's ghazals); the library test picks a ghazal with three couplets.
- Mod buttons sit in a div (a form closes a p, which broke the row).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The keyboard finds its box again by id when a page redraws it (Base.astro), so it keeps typing into the
name box after a poet is added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- home_sections: chosen-poets sections (مقبول شعرا) and century sections (every poet born in that Hijri century,
so new poets appear on their own); first use seeds the layout the home page had.
- New content type 'site' for grants (scope all, action edit); admins always. Changes apply at once and are audited.
- /mod/site editor (tab سرورق): names, ↑ ↓, remove, sort, add/remove/order poets with the Urdu name box.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Its own permission (arrange), separate from editing; same L2 -> L1 -> admin pipeline as a work's text
(revisions with entity 'order'), one line per item; only the order counts and every item stays listed.
- Publishing writes divan-data/divan/<url>.order, commits it and updates the site's positions.
- ترتیب دیں on poet and book/section pages; a sortable list (drag, ↑ ↓, اول, آخر); /mod/order/:id history.
- An unchanged arrangement is not kept, as with texts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- کوڈ in the toolbar: the Divan text next to the editor (stacked on phones), updated as you type; the سورس tab still edits it.
- A draft is only listed (my drafts, history, activity) once its text differs from the text it started from;
saving it unchanged drops it (compared as Divan text, so layout-only differences don't count) and says so;
submitting an unchanged returned draft is refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- web/src/lib/editor.ts (Tiptap 3 MIT core): verse units of misras (1 = مصرع, 2 = شعر, 3+ = بند, as in
Divan text) with مطلع/حسن مطلع/مقطع labels, prose paragraphs, chapter headings and sub-headings, a
dictionary-link mark, footnotes and variant readings; Enter adds a misra (or moves into the next
empty one), Enter on an empty misra starts a new unit.
- Revision page: editor and source tabs over the same text, the work's data points as rows, a
toolbar (couplet, paragraph, headings, labels, dictionary link, footnote, variant, undo/redo,
Roman typing, Urdu keyboard). Saving always sends Divan text.
- Divan text: inline segments keep where links, footnotes and variants sit; toText writes a
document back. All 11,087 works round-trip unchanged through toText and through the editor.
- The Urdu keyboard and Roman typing type into rich editors; the reader's word sidebar and
selection menu stay out of editors.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/mod/guide, open to all: the tag summary table; the work header; ghazal couplets (Hasrat Mohani);
stanzas (Hali's musaddas); prose chapters and sub-headings (Muhammad Husain Azad's Aab-e-Hayat);
matla/maqta labels; dictionary links, footnotes and variant readings; Urdu letters, punctuation,
digits, diacritics, ZWNJ compounds and spacing; edit summaries; the L2 -> L1 -> admin review.
Every example shows its source beside the site's own rendering (shared DivanPreview component,
also used on the revision page). Linked from the moderation tabs and the editor.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- api/src/git.ts: each published version is a commit in the divan-data checkout (queued, one at a
time): the moderator as author by public name with a placeholder email, the summary and version
in the message, Reviewed-by / Approved-by / Divan-Revision / Divan-Version trailers;
DIVAN_GIT_PUSH=1 pushes. The commit id is kept with the revision.
- Privacy fix: published files and commits carry public names (profile name, else 'موڈریٹر <id>'),
never email addresses (divan-data is public).
- Poem pages: 'دیوان کا ورژن …' with who edited, reviewed and published, the date, and a link to
the commit diff (DIVAN_DATA_COMMIT_URL).
- deploy/sync.sh: pull --rebase so publishing commits are kept.
- Admins are super moderators (documented).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- revisions (a work's Divan text, summary, status, author/reviewer/publisher, the text it started from)
and revision_events (who did what, with comments): the review thread and the moderation log.
- API (api/src/moderation.ts): what a moderator may do on a work, queue, drafts (one open draft per
person and work), save, submit, approve, return/reject (reason required), publish; history; log.
Rules come from the IAM grants: L2 drafts, an L1 covering the work reviews, an admin publishes; L1
drafts go to the admin, admin drafts publish directly. Publishing numbers the version, writes it
to divan-data (owned.ts) and updates the site; a draft based on an older version is refused (409).
- Line diff (api/src/diff.ts) against the text a draft started from.
- Site: ترمیم کریں / تاریخچہ on works, /mod (queue, activity log), /mod/rev/<id> (editor with the Urdu
keyboard and Roman typing, diff, preview, actions, timeline), /mod/work/<id> (versions).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Results in groups: شعرا و ادبا (by name or pen name, with years, work counts and a 'search in their
works' link), کتابیں اور ابواب (books/chapters by title), and کلام (content).
- Content pages: numbered pagination (first, last, two either side, gaps) and 'نتائج ۴۱–۶۰ از ۸۱۱۶'.
- Author filter: chips for the authors the results come from, with counts; tick one or several to
narrow; a name box finds any other poet/writer, with the Urdu keyboard and Roman-to-Urdu typing.
The keyboard and Roman typing now work on any input marked data-urdu, not only the search box.
- API: poet=1,2 (several), authors with counts, poets and books on page 1 (api/src/search.ts).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner request. Saved state: filled accent-coloured glyph, bold accent text and border, light accent
tint; the label follows the state on load and on click. The selection menu's phrase option and the
couplet bookmark's label use the same words.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner reference: a Flaticon bookmark pack (similar, not the same). Drawn here, so no third-party
licence or attribution; grey outline when not set, filled brand colour when set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Material Design 'bookmark' / 'bookmark_border' (Apache-2.0) drawn as a CSS mask so it follows the
theme; replaces the 🔖 emoji on bookmark buttons, couplet bookmarks, bookmarked phrases, contents
lists and cards, and the نشانات tab.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner direction: the word collection is separate from bookmarks, and bookmarks use the bookmark
glyph, not hearts.
- 🔖 نشان buttons on poet, book/chapter (new) and poem pages; contents lists and cards show 🔖.
- /library (نشانات): bookmarked poets, books and chapters, poems, couplets, phrases.
- /words (ذخیرۂ الفاظ): the word book on its own page; tabs between the two; header links.
- Word button: 'ذخیرۂ الفاظ میں ڈالیں' (+), 'ذخیرۂ الفاظ میں ہے' (✓) once added.
- API: library kind 'category' (books and chapters) in toggle, state, marks and the list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner request: words are not favourites. The sidebar button reads '+ ذخیرۂ الفاظ میں' and turns
into '✓' once added; the selection menu has '+ لفظ'; the library section is ذخیرۂ الفاظ.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Select any part of a couplet or paragraph and press نشان (selection menu): the phrase is
bookmarked and shown underlined with a small 🔖, also across the two misras; clicking it removes
the bookmark (with a confirmation). Listed in the library as نشان زدہ عبارتیں.
- Contents lists show ♥ on favourite works and 🔖 on works holding bookmarks; book/section cards and
poet cards (home) show 🔖 when they hold any. API: GET /api/library/marks; phrases in state and
library; phrase kind validated against the couplet's text.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Save (♡) poets and works, bookmark (🔖) couplets and paragraphs, save words from the word sidebar
or the selection menu (with the couplet they came from); notes on items.
- /library (میری لائبریری): the reader's name and bio, then favourite poets, works, bookmarked
couplets and saved words, each with its full path (poet » book » section » work) and a link to
the couplet (#cN anchors on poem pages); saved words open the word sidebar.
- API (api/src/library.ts), JSON + Bearer tokens so mobile apps (#44) can use it; deleting an
account deletes its library. Signed-out readers are sent to sign-in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Readers write their full name and a short bio (Urdu or any text) on /account; the name heads the
account page and the header shows the first name. API: POST /api/auth/profile (trimmed, control
characters dropped, 100 and 1,000 characters).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Roles: reader, mod-l2, mod-l1, admin. Grants: scope (all, poet, book/section with everything in
it, one work) x content (poets, books, works, dictionary) x actions (create, edit, delete,
arrange); dictionary grants are site-wide. can() in api/src/permissions.ts is the one check.
- Admin API and pages: role dropdown on /admin; /admin/user/:id lists a moderator's grants, adds
them (target by poet id or page link) and revokes them; demoting a moderator clears their grants;
grant and revoke go to the audit log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- API (api/src/admin.ts, admins only): user list and search; password reset generates a temporary
password shown once and ends the user's sessions; disable/enable (ends sessions, blocks sign-in);
roles reader/admin; delete; an admin cannot disable, demote or delete themself. Every action is
written to audit_log (kept when users are deleted).
- First admin from the server: npm run make-admin -- <email> (after signing up).
- Site: /admin (users) and /admin/audit; 'ایڈمن' link in the header for admins.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- API (api/src/auth.ts): scrypt password hashes; random session tokens stored only as SHA-256;
30-day sliding sessions; rate limits on sign-in (per IP and per email) and sign-up; changing the
password signs out other devices; deleting the account removes its data.
- Site: /signup, /signin (returns to the page the reader came from), /account; header link; plain
forms, no JavaScript needed. Session in an HTTP-only, SameSite=Lax cookie (Secure over HTTPS).
- CSRF: Astro's origin check, with the site's hostnames listed (SITE_HOSTS) so its own form posts
pass and other sites' are refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Selecting reading text shows a menu by the selection: معنی (word sidebar, single words),
تلاش (search Divan, phrases quoted), کاپی (text with poet, title and link), شیئر (link to the
page with the selection highlighted via ?hl=; native share sheet where available), قرآن
(tanzil.net), گوگل. Escape or clearing the selection closes it; no layout shift.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Panel folds the extras (more meanings, examples, long etymologies, long word lists). 175 MB in PostgreSQL.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- readings: one spelling, different short vowels (ملک: مَلَک، مَلِک، مِلک، مُلک), each with form,
transliteration, IPA, audio and meanings
- always: same consonants with other long vowels (consonant-skeleton regex)
- not found: inflection stems (آنکھوں -> آنکھ, جاتے -> جانا), prefix regex, trigram similarity
- Persian/Arabic words with no Urdu entry: Urdu translations via English first, then English, then
their own language; filler glosses (especially, usually…) dropped
- punctuation, dashes and spaces dropped from selected words and lookup keys; clean titles
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- en.wiktionary entries via kaikki.org (meanings, IPA, transliteration, audio, etymology, synonyms)
- ur./fa./ar.wiktionary dumps for meanings in each language (incl. more Urdu entry formats)
- English->Urdu pivot table from Urdu entries' glosses and ur.wiktionary's English entries
- dict-sync.ts: re-imports sources when upstream publishes new files, applies daily recent changes;
run from deploy/sync.sh
- lookups now read the database (2-7 ms) instead of calling Wikimedia live
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>