{bm}
{bm}
---
// Poet (/p238), category (/p238/shaeri/c641) and poem (/p238/shaeri/c641/sh6556) pages
import Base from '../layouts/Base.astro';
import Seg from '../components/Seg.astro';
import { api } from '../lib/api';
import { asUser, COOKIE } from '../lib/auth';
import { phraseParts, phraseRe } from '../lib/phrases';
import { ud, years, highlighter, parts } from '../lib/urdu';
const url = '/' + (Astro.params.path ?? '');
const page = await api(`/api/page?url=${encodeURIComponent(url)}`);
if (!page) return new Response(null, { status: 404, statusText: 'Not found' });
// group verses into couplets / single lines / paragraphs for rendering
type Verse = { position: string; couplet: number; text: string };
const blocks: { kind: 'couplet' | 'single' | 'para'; lines: string[]; c: number; mark?: string }[] = [];
if (page.type === 'poem') {
const { matla, maqta } = page.poem;
for (const v of page.verses as Verse[]) {
if (v.position === 'Right') blocks.push({ kind: 'couplet', lines: [v.text], c: v.couplet,
mark: v.couplet === matla ? 'مطلع' : v.couplet === maqta ? 'مقطع' : undefined });
else if (v.position === 'Left' && blocks.at(-1)?.kind === 'couplet' && blocks.at(-1)!.lines.length === 1) blocks.at(-1)!.lines.push(v.text);
else if (v.position === 'Paragraph') blocks.push({ kind: 'para', lines: [v.text], c: v.couplet });
else blocks.push({ kind: 'single', lines: [v.text], c: v.couplet });
}
}
// pen name (marked ؔ in the text) set apart; split() with a capture group puts matches at odd indexes
// ?hl= (from search results) marks the searched words on the page; segments: [text, 'mark' | 'pen' | '']
const hlq = Astro.url.searchParams.get('hl') ?? '';
const re = highlighter(hlq);
// bookmarked phrases first ('bmk', carrying what to un-bookmark), then search hits, then the pen name
type Mark = { part: string; save: string };
const show = (line: string, marks: Mark[] = []): [string, string, string?][] => {
const plain = (text: string) => parts(text, re).flatMap((s, i): [string, string][] =>
i % 2 ? [[s, 'mark']] : s.split(/(\S*\u0614\S*)/).map((t, j) => [t, j % 2 ? 'pen' : '']));
if (!marks.length) return plain(line);
const bm = new RegExp(`(${marks.map((m) => phraseRe(m.part).source).join('|')})`, 'u');
return line.split(bm).flatMap((s, i): [string, string, string?][] =>
i % 2 ? [[s, 'bmk', marks.find((m) => phraseRe(m.part).test(s))?.save]] : plain(s));
};
// contents of a divan grouped by radif letter ("ردیف الف … ی"); ے is filed under ی as in printed divans
const LETTER = (l: string) => (l === 'ا' ? 'الف' : l === 'ے' ? 'ی' : l);
const groups: { letter: string | null; poems: any[] }[] = [];
for (const p of page.poems ?? []) {
const l = p.radif_letter ? LETTER(p.radif_letter) : null;
if (groups.at(-1)?.letter !== l || !groups.length) groups.push({ letter: l, poems: [] });
groups.at(-1)!.poems.push(p);
}
const crumbs = page.breadcrumbs ?? [];
// what the signed-in reader has bookmarked on this page (poet, book/chapter, poem, couplets, phrases)
const token = Astro.locals.user ? Astro.cookies.get(COOKIE)?.value : undefined;
const poetId = page.poet?.id, poemId = page.type === 'poem' ? page.poem.id : undefined;
const categoryId = page.type === 'category' ? page.category.id : undefined;
const saved = token ? (await asUser(token, `/api/library/state?poet=${poetId ?? ''}&category=${categoryId ?? ''}&poem=${poemId ?? ''}`)).data
: { poet: false, category: false, poem: false, couplets: [], phrases: [] };
// on contents pages: which works are bookmarked or hold bookmarks, and which books/chapters do
const marks = token && page.type !== 'poem' ? (await asUser(token, '/api/library/marks')).data : { poems: {}, categories: [] };
const glyph = (poemId: number) => (marks.poems[poemId]?.fav ? ' mark-fav' : '') + (marks.poems[poemId]?.bm ? ' mark-bm' : '');
// the marked part of each line of a block, for its bookmarked phrases
const lineMarks = (c: number, lines: string[]) => {
const out: Mark[][] = lines.map(() => []);
for (const p of saved.phrases.filter((x: any) => x.couplet === c)) {
const save = JSON.stringify({ kind: 'phrase', poemId, couplet: c, phrase: p.phrase });
phraseParts(lines, p.phrase).forEach((part, i) => part && out[i].push({ part, save }));
}
return out;
};
const label = (on: unknown) => (on ? 'محفوظ شدہ' : 'محفوظ کریں'); // bookmark buttons
// moderators who may edit this work get edit and history links
const modCan = token && poemId && ['mod-l2', 'mod-l1', 'admin'].includes(Astro.locals.user?.role ?? '')
? (await asUser(token, `/api/mod/can?poem=${poemId}`)).data : { edit: false };
const bookmark = (c: number) => JSON.stringify({ kind: 'couplet', poemId, couplet: c });
const title = page.type === 'poem' ? page.poem.title : page.type === 'poet' ? page.poet.nickname : page.category.title;
---
{years(page.poet)}
{page.poet.description &&«{hlq}» نمایاں · تلاش کے نتائج · نشان ہٹائیں
)}{modCan.edit && <>
تاریخچہ>} {page.poem.radif != null &&{page.poem.radif ? `ردیف: ${page.poem.radif}` : 'غیر مردف'}
}{bm}
{bm}
کسی لفظ کو منتخب کریں تو اس کے معنی اور تلفظ ساتھ نظر آئیں گے۔
{page.divan && (دیوان کا ورژن {ud(page.divan.version)} · ترمیم: {page.divan.by}{page.divan.reviewedBy && <> · جائزہ: {page.divan.reviewedBy}>} · اشاعت: {page.divan.publishedBy} · {new Date(page.divan.at).toISOString().slice(0, 10)} {page.divan.commit_url && <> · تبدیلی دیکھیں>}
)} {page.poem.source_url && (ماخذ: ویکی ماخذ · {page.poet && {page.poet.nickname}}
)} > )} {re && }