Moderators' guide: how to write Divan text with all the tags #57

Merged
anas merged 1 commits from feature/mod-guide into main 2026-10-08 22:44:15 +00:00
5 changed files with 197 additions and 10 deletions

View File

@ -0,0 +1,17 @@
---
// Divan text rendered like the site (moderation preview, guide examples): headings, paragraphs, couplets with
// their labels, lines and stanzas; dictionary links underlined, footnotes numbered, variants marked
import { parse } from '../../../api/src/divantext.ts';
const { text } = Astro.props as { text: string };
const doc = parse(text);
let n = 0;
const notes: string[] = [];
const line = (l: any) => { l.notes.forEach((x: string) => notes.push(x)); return l; };
---
<article class="poem preview">
{doc.blocks.map((b: any) => b.type === 'heading' ? (b.level > 2 ? <h4 class="mod-h sub">{b.text}</h4> : <h3 class="mod-h">{b.text}</h3>)
: b.type === 'para' ? <p class="para">{line(b.line).text}{b.line.notes.map(() => <sup>{++n}</sup>)}</p>
: b.type === 'couplet' ? <div class="couplet" data-mark={b.label}>{b.lines.map((l: any) => <p>{line(l).text}{l.notes.map(() => <sup>{++n}</sup>)}</p>)}</div>
: <div class={b.type === 'stanza' ? 'stanza' : ''}>{b.lines.map((l: any) => <p class="single">{line(l).text}{l.notes.map(() => <sup>{++n}</sup>)}</p>)}</div>)}
{notes.length > 0 && <ol class="preview-notes">{notes.map((x) => <li>{x}</li>)}</ol>}
</article>

View File

@ -1,7 +1,8 @@
---
const { current } = Astro.props as { current?: 'queue' | 'log' };
const { current } = Astro.props as { current?: 'queue' | 'log' | 'guide' };
---
<nav class="admin-nav">
<a href="/mod" aria-current={current === 'queue' ? 'page' : undefined}>موڈریشن</a>
<a href="/mod?log=1" aria-current={current === 'log' ? 'page' : undefined}>سرگرمی</a>
<a href="/mod/guide" aria-current={current === 'guide' ? 'page' : undefined}>رہنمائی</a>
</nav>

View File

@ -0,0 +1,156 @@
---
// رہنمائی: how moderators write Divan text with all its tags, Urdu spelling rules, summaries and review.
// Open to everyone (future contributors can read it); every example is rendered by the site's own parser.
import Base from '../../layouts/Base.astro';
import ModNav from '../../components/ModNav.astro';
import DivanPreview from '../../components/DivanPreview.astro';
const ex = {
header: `{{دیوان
| عنوان = چپکے چپکے رات دن آنسو بہانا یاد ہے
| شاعر = حسرت موہانی
| صنف = غزل
| ردیف = یاد ہے
| قافیہ = بہانا، زمانا
| ماخذ = ویکی ماخذ
| ماخذ_ربط = https://ur.wikisource.org/…
}}`,
ghazal: `<poem>
چپکے چپکے رات دن آنسو بہانا یاد ہے
ہم کو اب تک عاشقی کا وہ زمانا یاد ہے
باہزاراں اضطراب و صدہزاراں اشتیاق
تجھ سے وہ پہلے پہل دل کا لگانا یاد ہے
بار بار اٹھنا اسی جانب نگاہ شوق کا
اور ترا غرفے سے وہ آنکھیں لڑانا یاد ہے
</poem>`,
stanza: `<poem>
وہ نبیوں میں رحمت لقب پانے والا
مرادیں غریبوں کی بر لانے والا
مصیبت میں غیروں کے کام آنے والا
وہ اپنے پرائے کا غم کھانے والا
فقیروں کا ملجا ضعیفوں کا ماویٰ
یتیموں کا والی غلاموں کا مولیٰ
</poem>`,
prose: `== آب حیات ==
=== زبان اردو کی تاریخ ===
اتنی بات ہر شخص جانتا ہے کہ ہمارے اُردو زبان برج بھاشا سے نکلی ہے اور "برج بھاشا" خاص ہندوستانی زبان ہے۔ لیکن وہ ایسی زبان نہیں کہ دنیا کے پردے پر ہندوستان کے ساتھ آئی ہو۔ اس کی عمر آٹھ سو برس سے زیادہ نہیں ہے اور برج کا سبزہ زار اس کا وطن ہے۔`,
labels: `<poem>
{{مطلع}} دل ناداں تجھے ہوا کیا ہے
آخر اس درد کی دوا کیا ہے
{{مقطع}} میں نے مانا کہ کچھ نہیں غالبؔ
مفت ہاتھ آئے تو برا کیا ہے
</poem>`,
links: `<poem>
دل [[ناداں]] تجھے ہوا کیا ہے
آخر اس درد کی [[دوا]] کیا ہے<ref>دوا: علاج۔</ref>
ہم ہیں [[مشتاق]] اور وہ [[لغت:بیزار|بے زار]]
یا الٰہی یہ {{نسخہ|ماجرا|ماجرہ|ماخذ=کسی دوسرے نسخے کا نام}} کیا ہے
</poem>`,
};
const TAGS: [string, string, string][] = [
['{{دیوان | … }}', 'کلام کا خاکہ: عنوان، شاعر یا مصنف، صنف، ردیف، قافیہ، بحر، ماخذ', 'ہر کلام کے شروع میں، ایک بار'],
['<poem> … </poem>', 'شاعری کا حصہ', 'منظوم کلام کے گرد'],
['دو سطریں', 'شعر (دو مصرعے)', 'اشعار کے درمیان ایک خالی سطر'],
['ایک سطر', 'اکیلا مصرع', 'آگے پیچھے خالی سطر'],
['تین یا زیادہ سطریں', 'بند (مسدس، مخمس، رباعی وغیرہ)', 'بند کے درمیان خالی سطر نہیں'],
['== عنوان ==', 'باب کا عنوان', 'نثر میں، الگ سطر پر'],
['=== عنوان ===', 'ذیلی عنوان', 'باب کے اندر'],
['خالی سطر سے الگ متن', 'نثر کا پیراگراف', '<poem> کے باہر'],
['{{مطلع}} {{حسن مطلع}} {{مقطع}}', 'شعر کی نشانی', 'شعر کی پہلی سطر کے شروع میں، صرف درستی کے لیے'],
['[[لفظ]]', 'لفظ کا لغت سے ربط', 'جب لفظ لغت میں اسی شکل میں ہو'],
['[[لغت:دیوانہ|دیوانے]]', 'لغت سے ربط، لفظ کی بدلی ہوئی شکل کے ساتھ', 'پہلے لغت کی شکل، پھر متن کی شکل'],
['<ref> … </ref>', 'حاشیہ', 'جس لفظ یا سطر کے بعد ہو، وہیں'],
['{{نسخہ|متن|دوسرا متن|ماخذ=…}}', 'نسخوں کا فرق: پہلا متن دکھایا جاتا ہے', 'ماخذ ضرور لکھیں'],
];
---
<Base title="رہنمائی: دیوان میں لکھنے کا طریقہ">
<h1>دیوان میں لکھنے کا طریقہ</h1>
{Astro.locals.user && ['mod-l2', 'mod-l1', 'admin'].includes(Astro.locals.user.role) && <ModNav current="guide" />}
<div class="guide">
<p>
دیوان کا ہر کلام <strong>دیوان متن</strong> میں لکھا جاتا ہے: سادہ اردو سطریں اور چند نشانیاں جو بتاتی ہیں کہ کیا شعر ہے، کیا مصرع، کیا بند،
کیا باب کا عنوان اور کیا پیراگراف۔ یہی متن جائزے کے بعد شائع ہوتا ہے اور دیوان کے کھلے ڈیٹا میں ہر تبدیلی سطر بہ سطر محفوظ رہتی ہے۔
ہر مثال کے ساتھ اس کا پیش نظارہ وہی ہے جو سائٹ پر دکھائی دے گا۔
</p>
<h2>نشانیوں کا خلاصہ</h2>
<table class="admin-table guide-table">
<thead><tr><th>لکھیں</th><th>مطلب</th><th>کہاں اور کیسے</th></tr></thead>
<tbody>{TAGS.map(([t, m, w]) => <tr><td><code dir="rtl">{t}</code></td><td>{m}</td><td>{w}</td></tr>)}</tbody>
</table>
<h2>۱۔ کلام کا خاکہ</h2>
<p>
ہر کلام <code dir="auto">{'{{دیوان'}</code> سے شروع ہوتا ہے اور ہر معلومات اپنی سطر پر <code dir="auto">| نام = قدر</code> کی صورت میں لکھی جاتی ہے۔
نثر کے لیے <code dir="auto">شاعر</code> کی جگہ <code dir="auto">مصنف</code> لکھیں۔ ردیف اور قافیہ خود بخود بھی معلوم کیے جاتے ہیں؛ یہاں صرف درست صورت لکھیں۔
</p>
<div class="example"><pre dir="rtl">{ex.header}</pre></div>
<h2>۲۔ غزل: شعر اور مصرعے</h2>
<p>
شاعری <code dir="auto">{'<poem>'}</code> اور <code dir="auto">{'</poem>'}</code> کے درمیان۔ ہر مصرع اپنی سطر پر، شعر کے دو مصرعے ساتھ ساتھ،
اور ہر شعر کے بعد <strong>ایک خالی سطر</strong>۔ مقطع میں تخلص پر تخلص کا نشان <code dir="auto">ؔ</code> لگائیں (حسرتؔ، غالبؔ)، مقطع خود پہچانا جائے گا۔
(مثال: حسرت موہانی کی غزل کے پہلے تین اشعار)
</p>
<div class="example"><pre dir="rtl">{ex.ghazal}</pre><DivanPreview text={ex.ghazal} /></div>
<h2>۳۔ بند: مسدس، مخمس، رباعی</h2>
<p>تین یا زیادہ مصرعے بغیر خالی سطر کے ایک بند بنتے ہیں۔ بندوں کے درمیان ایک خالی سطر چھوڑیں۔ (مثال: حالی کی مسدس)</p>
<div class="example"><pre dir="rtl">{ex.stanza}</pre><DivanPreview text={ex.stanza} /></div>
<h2>۴۔ نثر: باب، ذیلی عنوان اور پیراگراف</h2>
<p>
نثر <code dir="auto">{'<poem>'}</code> کے باہر لکھی جاتی ہے۔ ہر پیراگراف کے بعد ایک خالی سطر۔ باب کا عنوان <code dir="auto">== عنوان ==</code>
اور ذیلی عنوان <code dir="auto">=== عنوان ===</code>، دونوں الگ سطر پر۔ (مثال: محمد حسین آزاد کی "آب حیات"؛ کتاب کا نام باب کے عنوان کی طرح اور "زبان اردو کی تاریخ" ذیلی عنوان کی طرح)
</p>
<div class="example"><pre dir="rtl">{ex.prose}</pre><DivanPreview text={ex.prose} /></div>
<h2>۵۔ مطلع اور مقطع کی نشانی</h2>
<p>
مطلع، مقطع اور ردیف عام طور پر خود معلوم ہو جاتے ہیں۔ اگر کہیں غلط ہوں تو شعر کی پہلی سطر کے شروع میں
<code dir="auto">{'{{مطلع}}'}</code>، <code dir="auto">{'{{حسن مطلع}}'}</code> یا <code dir="auto">{'{{مقطع}}'}</code> لکھ دیں۔
</p>
<div class="example"><pre dir="rtl">{ex.labels}</pre><DivanPreview text={ex.labels} /></div>
<h2>۶۔ لغت کا ربط، حاشیہ اور نسخوں کا فرق</h2>
<ul>
<li><code dir="auto">[[لفظ]]</code> لفظ کو لغت سے جوڑتا ہے۔ اگر متن میں لفظ کی بدلی ہوئی شکل ہو تو پہلے لغت کی شکل، پھر متن کی: <code dir="auto">[[لغت:بیزار|بے زار]]</code>۔ ہر لفظ پر ربط نہ لگائیں؛ صرف مشکل یا کم معروف الفاظ پر۔</li>
<li><code dir="auto">{'<ref>…</ref>'}</code> حاشیہ ہے؛ جس لفظ یا سطر سے متعلق ہو اسی کے بعد لکھیں۔ پیش نظارہ میں اس کا نمبر اور نیچے متن دکھایا جاتا ہے۔</li>
<li><code dir="auto">{'{{نسخہ|متن|دوسرا متن|ماخذ=…}}'}</code> دو نسخوں کا فرق ہے؛ پہلا متن کلام میں دکھایا جاتا ہے۔ دوسرے نسخے کا نام ضرور لکھیں۔</li>
</ul>
<div class="example"><pre dir="rtl">{ex.links}</pre><DivanPreview text={ex.links} /></div>
<h2>۷۔ املا اور رموزِ اوقاف</h2>
<ul>
<li><strong>اردو حروف</strong>: <code dir="auto">ی</code> (عربی <code dir="auto">ي</code> نہیں)، <code dir="auto">ک</code> (عربی <code dir="auto">ك</code> نہیں)، <code dir="auto">ہ</code> اور دو چشمی <code dir="auto">ھ</code> کا فرق رکھیں (کہ، کھ)، <code dir="auto">ے</code> اپنی جگہ۔</li>
<li><strong>رموز</strong>: ختمہ <code dir="auto">۔</code>، سکتہ <code dir="auto">،</code>، سوالیہ <code dir="auto">؟</code>، وقفہ <code dir="auto">؛</code>۔ انگریزی <code dir="auto">. , ?</code> نہیں۔</li>
<li><strong>اعداد</strong>: اردو ہندسے <code dir="auto">۱۲۳</code>۔</li>
<li><strong>اعراب</strong>: زیر، زبر، پیش صرف جہاں ماخذ میں ہوں یا معنی بدلیں (مثلاً اضافت: دلِ ناداں)۔</li>
<li><strong>مرکب الفاظ</strong>: بے‌ثبوت، نا‌امید جیسے الفاظ کو ایک لفظ رکھنے کے لیے درمیان میں "زیرو وِڈتھ نان جوائنر" (ZWNJ) استعمال کریں، خالی جگہ نہیں۔</li>
<li><strong>فاصلے</strong>: الفاظ کے درمیان ایک ہی خالی جگہ؛ سطر کے شروع یا آخر میں نہیں۔</li>
<li>متن ماخذ کے مطابق رکھیں؛ اپنی طرف سے الفاظ نہ بدلیں۔ ماخذ مختلف ہوں تو <code dir="auto">{'{{نسخہ}}'}</code> استعمال کریں۔</li>
</ul>
<h2>۸۔ ترمیم کا خلاصہ</h2>
<ul>
<li>ہر مسودے کے ساتھ مختصر خلاصہ لکھیں کہ کیا بدلا اور کیوں: "دوسرے شعر کا مصرع نسخۂ … کے مطابق درست کیا"۔</li>
<li>ایک مسودے میں ایک ہی قسم کی تبدیلی رکھیں تاکہ جائزہ آسان ہو۔</li>
<li>ماخذ کا حوالہ دیں: کتاب، ایڈیشن، صفحہ۔</li>
</ul>
<h2>۹۔ جائزہ اور اشاعت</h2>
<ol>
<li>موڈریٹر (L2) مسودہ بنا کر <strong>جائزے کے لیے بھیجتا</strong> ہے۔</li>
<li>سینئر موڈریٹر (L1) جس کے پاس اس شاعر یا کتاب کی اجازت ہو، تبدیلیاں (سرخ: ہٹائی گئی، سبز: نئی) دیکھ کر <strong>منظور</strong> کرتا ہے، یا وجہ لکھ کر <strong>واپس</strong> یا <strong>مسترد</strong> کرتا ہے۔ واپس آیا مسودہ درست کر کے دوبارہ بھیجیں۔</li>
<li>ایڈمن <strong>شائع</strong> کرتا ہے: نیا ورژن نمبر ملتا ہے، کلام سائٹ پر فوراً بدل جاتا ہے، اور دیوان کے کھلے ڈیٹا میں آپ کے عوامی نام کے ساتھ محفوظ ہو جاتا ہے۔</li>
<li>L1 کا اپنا مسودہ سیدھا ایڈمن کو جاتا ہے؛ ایڈمن کی اپنی ترمیم فوراً شائع ہوتی ہے۔</li>
<li>اگر جائزے کے دوران کلام کا نیا ورژن شائع ہو جائے تو پرانا مسودہ شائع نہیں ہو سکتا؛ اسے تازہ متن پر دوبارہ بنائیں۔</li>
</ol>
</div>
</Base>

View File

@ -5,7 +5,7 @@ import ModNav from '../../../components/ModNav.astro';
import { asUser, COOKIE } from '../../../lib/auth';
import { STATUS, EVENT, when } from '../../../lib/mod';
import { ud } from '../../../lib/urdu';
import { parse } from '../../../../../api/src/divantext.ts';
import DivanPreview from '../../../components/DivanPreview.astro';
const me = Astro.locals.user;
if (!me) return Astro.redirect(`/signin?next=${Astro.url.pathname}`);
@ -22,7 +22,6 @@ if (Astro.request.method === 'POST') {
const res = await asUser(token, `/api/mod/revisions/${id}`);
if (!res.ok) return new Response(res.data.error ?? 'نہیں ملا', { status: res.status });
const { revision: rev, diff, changes, events, may } = res.data;
const doc = parse(rev.content);
const acts = ([['approve', 'منظور کریں'], ['return', 'واپس بھیجیں'], ['reject', 'مسترد کریں'], ['publish', 'شائع کریں']] as const).filter(([a]) => may[a]);
---
<Base title={`مسودہ: ${rev.work_title}`}>
@ -43,7 +42,7 @@ const acts = ([['approve', 'منظور کریں'], ['return', 'واپس بھیج
<label class="mod-text">متن (دیوان متن)
<textarea name="content" id="mod-content" data-urdu rows="22" dir="rtl" spellcheck="false">{rev.content}</textarea>
</label>
<p class="muted note">شعر کے دو مصرعے الگ سطروں پر، اشعار کے درمیان خالی سطر۔ <code>== باب ==</code> عنوان، <code>[[لفظ]]</code> لغت کا ربط، <code>&lt;ref&gt;…&lt;/ref&gt;</code> حاشیہ۔</p>
<p class="muted note">شعر کے دو مصرعے الگ سطروں پر، اشعار کے درمیان خالی سطر۔ <code>== باب ==</code> عنوان، <code>[[لفظ]]</code> لغت کا ربط، <code>&lt;ref&gt;…&lt;/ref&gt;</code> حاشیہ۔ <a href="/mod/guide" target="_blank">لکھنے کا مکمل طریقہ</a></p>
<div class="filter-actions">
<button type="button" class="in-box-btn" data-urdu-rom="mod-content" title="رومن حروف سے اردو">اب</button>
<button type="button" class="in-box-btn" data-urdu-kb="mod-content" title="اردو کی بورڈ">کی بورڈ</button>
@ -64,12 +63,7 @@ const acts = ([['approve', 'منظور کریں'], ['return', 'واپس بھیج
<section class="lib-section">
<h2>پیش نظارہ</h2>
<article class="poem">
{doc.blocks.map((b: any) => b.type === 'heading' ? <h3 class="mod-h">{b.text}</h3>
: b.type === 'para' ? <p class="para">{b.line.text}</p>
: b.type === 'couplet' ? <div class="couplet" data-mark={b.label}>{b.lines.map((l: any) => <p>{l.text}</p>)}</div>
: b.lines.map((l: any) => <p class="single">{l.text}</p>))}
</article>
<DivanPreview text={rev.content} />
</section>
{acts.length > 0 && (

View File

@ -327,3 +327,22 @@ h1 + .muted { text-align: center; margin-top: 0; }
.inline-form { display: inline; }
.mod-edit-btn, .save-like { font: inherit; font-size: .85rem; padding: 1px 14px; border: 1.5px solid var(--gold); border-radius: 999px; background: var(--inner); color: var(--ink); cursor: pointer; }
.mod-history { font-size: .85rem; margin-inline-start: 6px; }
/* moderators' guide */
.guide { max-width: 900px; margin: 0 auto; line-height: 2; }
.guide h2 { font-size: 1.15rem; color: var(--brand); text-align: start; margin-top: 28px; }
.guide code { font-family: inherit; background: var(--inner); border: 1px solid var(--gold-light); border-radius: 6px; padding: 0 6px; unicode-bidi: plaintext; display: inline-block; } /* Latin tags read left to right, Urdu right to left */
.guide-table td:first-child { white-space: nowrap; }
.example { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: start; margin: 10px 0; }
.example pre { unicode-bidi: plaintext; margin: 0; padding: 12px 14px; background: var(--inner); border: 1px solid var(--border); border-radius: 10px; white-space: pre-wrap;
font-family: 'Noto Naskh Arabic', serif; font-size: .95rem; line-height: 1.9; }
.example:has(> pre:only-child) { grid-template-columns: 1fr; }
.preview { margin: 0; padding: 12px 16px; }
.preview .couplet { font-size: 1rem; grid-template-columns: 1fr; }
.preview .couplet p, .preview .couplet p + p { text-align: center; }
.preview .stanza { margin: 6px 0 12px; }
.preview .stanza p, .preview .single { text-align: center; margin: 0; }
.preview .mod-h.sub { font-size: 1rem; text-align: center; color: var(--lapis); }
.preview sup { color: var(--brand); font-size: .7em; }
.preview-notes { font-size: .85rem; border-top: 1px dashed var(--gold-light); margin-top: 8px; padding-top: 6px; }
@media (max-width: 760px) { .example { grid-template-columns: 1fr; } }