divan/reader/index.html
Anas Rashid 5f2b779e89 Public home page, Naskh default font, no poet photos
- home page is public: no redirect to login/admin import; flat poet list until century
  groups exist (upstream needed a pinned 'popular poets' group, which Divan never has, so
  the home page always redirected); public 'being prepared' notice when there are no poets
- Naskh is the default font, Nastaliq the option (site and static reader)
- poet/writer photos hidden everywhere (CSS on /poet/image/), poet page photos tab removed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:59:20 +02:00

152 lines
8.6 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="ur-PK" dir="rtl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>دیوان · قاری</title>
<meta name="description" content="دیوان کا سادہ قاری: اردو کی کلاسیکی شاعری اور نثر، براہِ راست divan-data سے۔">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Nastaliq+Urdu:wght@400..700&family=Noto+Naskh+Arabic:wght@400..700&display=swap" rel="stylesheet">
<style>
/* Divan static reader: no server, reads the divan-data static API (ganjoor-data layout). */
:root {
--bg: #faf7f0; --card: #ffffff; --ink: #2b2620; --muted: #7a6f60; --line: #e6dfd2; --accent: #8a5a19;
--font: 'Noto Naskh Arabic', 'Noto Nastaliq Urdu', serif; --lh: 2;
}
@media (prefers-color-scheme: dark) {
:root { --bg: #17140f; --card: #211d17; --ink: #ece4d6; --muted: #a89c88; --line: #3a3328; --accent: #d9a55a; }
}
html.nastaliq { --font: 'Noto Nastaliq Urdu', 'Noto Naskh Arabic', serif; --lh: 2.5; }
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--ink); font-family: var(--font); line-height: var(--lh); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
header { display: flex; align-items: center; gap: 16px; padding: 8px 16px; border-bottom: 1px solid var(--line); background: var(--card); position: sticky; top: 0; z-index: 1; }
header h1 { margin: 0; font-size: 1.8rem; font-weight: 700; }
header .grow { flex: 1; }
button { font: inherit; background: none; color: var(--ink); border: 1px solid var(--line); border-radius: 20px; padding: 0 14px; cursor: pointer; }
main { max-width: 860px; margin: 0 auto; padding: 16px; }
.crumbs { color: var(--muted); font-size: .95rem; }
.crumbs a + a::before, .crumbs a + span::before { content: " « "; color: var(--muted); }
input[type=search] { width: 100%; font: inherit; padding: 4px 14px; border: 1px solid var(--line); border-radius: 22px; background: var(--card); color: var(--ink); }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px; margin-top: 16px; }
.grid a, .list a { display: block; background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 4px 14px; }
.list { display: grid; gap: 6px; margin-top: 12px; }
.years { color: var(--muted); font-size: .85rem; }
.intro { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 8px 16px; white-space: pre-line; }
.poem { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 16px; margin-top: 12px; }
.b { display: grid; grid-template-columns: 1fr 1fr; gap: 0 32px; margin: 4px 0 12px; }
.b p { margin: 0; }
.b p:last-child { text-align: left; }
.s { text-align: center; margin: 0; }
.para { text-align: justify; margin: 0 0 12px; }
.source { color: var(--muted); font-size: .85rem; margin-top: 16px; }
@media (max-width: 600px) { .b { grid-template-columns: 1fr; } .b p:last-child { text-align: right; padding-right: 32px; } }
.msg { color: var(--muted); text-align: center; padding: 32px; }
</style>
<script>try { if (localStorage.getItem('divan-font') === 'nastaliq') document.documentElement.classList.add('nastaliq'); } catch (e) {}</script>
</head>
<body>
<header>
<h1><a href="#/">دیوان</a></h1>
<span class="grow"></span>
<button id="font" type="button" title="خط بدلیں">نسخ</button>
</header>
<main id="app"><p class="msg">لوڈ ہو رہا ہے…</p></main>
<script>
// Data source: ?data=<base url> (e.g. ?data=data/ when served next to a divan-data checkout), else the public CDN.
var DATA = new URLSearchParams(location.search).get('data') || 'https://cdn.jsdelivr.net/gh/anas-rashid/divan-data@main/';
var app = document.getElementById('app');
var cache = {};
function get(path) {
if (!cache[path]) cache[path] = fetch(DATA + path).then(function (r) { if (!r.ok) throw new Error(r.status + ' ' + path); return r.json(); });
return cache[path];
}
function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
function ud(n) { return String(n).replace(/[0-9]/g, function (d) { return '۰۱۲۳۴۵۶۷۸۹'[d]; }); }
function years(p) {
var b = p.ValidBirthDate ? ud(p.BirthYearInLHijri) : '', d = p.ValidDeathDate ? ud(p.DeathYearInLHijri) : '';
return b || d ? (b || '؟') + ' – ' + (d || '؟') + ' ھ' : '';
}
function link(url, text) { return '<a href="#' + esc(url) + '">' + esc(text) + '</a>'; }
function crumbs(fullTitle, fullUrl) {
// FullTitle "poet » cat » ... » poem" lines up with FullUrl segments "/p1/cat/.../sh9"
var titles = fullTitle.split(' » '), segs = fullUrl.split('/').filter(Boolean), out = [link('/', 'سرورق')];
titles.forEach(function (t, i) {
var u = '/' + segs.slice(0, i + 1).join('/');
out.push(i < titles.length - 1 ? link(u, t) : '<span>' + esc(t) + '</span>');
});
return '<div class="crumbs">' + out.join('') + '</div>';
}
function home() {
return get('manifest.json').then(function (m) {
app.innerHTML = '<input type="search" id="q" placeholder="شاعر تلاش کریں (' + ud(m.PoetsCount) + ' شعرا، ' + ud(m.PoemsCount) + ' تخلیقات)">' +
'<div class="grid" id="poets"></div>';
var box = document.getElementById('poets');
function render(q) {
box.innerHTML = m.Poets.filter(function (p) { return !q || p.Nickname.indexOf(q) >= 0; })
.map(function (p) { return link(p.FullUrl, p.Nickname); }).join('');
}
render('');
document.getElementById('q').oninput = function (e) { render(e.target.value.trim()); };
});
}
function category(url) {
var slug = url.split('/')[1];
return Promise.all([get('poets' + url + '/_cat.json'), get('poets/' + slug + '/poet.json')]).then(function (r) {
var c = r[0], poet = r[1], isRoot = c.ParentId == null;
var html = isRoot
? '<div class="crumbs">' + link('/', 'سرورق') + '<span>' + esc(poet.Nickname) + '</span></div><h2>' + esc(poet.Name) + ' <span class="years">' + years(poet) + '</span></h2>' +
(poet.Description ? '<div class="intro">' + esc(poet.Description) + '</div>' : '')
: '<h2>' + esc(c.Title) + '</h2>';
if (!isRoot) {
// breadcrumb for a sub-category: walk up via FullUrl
var segs = url.split('/').filter(Boolean);
html = '<div class="crumbs">' + link('/', 'سرورق') + link('/' + segs[0], poet.Nickname) +
segs.slice(1).map(function (s, i) { return i < segs.length - 2 ? link('/' + segs.slice(0, i + 2).join('/'), '…') : '<span>' + esc(c.Title) + '</span>'; }).join('') + '</div>' + html;
}
html += '<div class="list">' + c.ChildCats.map(function (x) { return link(x.FullUrl, '📚 ' + x.Title); }).join('') +
c.Poems.map(function (x) { return link(x.FullUrl, x.Title); }).join('') + '</div>';
app.innerHTML = html;
});
}
function poem(url) {
return get('poets' + url + '.json').then(function (p) {
var html = crumbs(p.FullTitle, p.FullUrl) + '<h2>' + esc(p.Title) + '</h2><div class="poem">', pair = [];
p.Verses.forEach(function (v) {
if (v.Position === 'Right') pair = [v.Text];
else if (v.Position === 'Left') { html += '<div class="b"><p>' + esc(pair[0] || '') + '</p><p>' + esc(v.Text) + '</p></div>'; pair = []; }
else if (v.Position === 'Paragraph') html += '<p class="para">' + esc(v.Text) + '</p>';
else html += '<p class="s">' + esc(v.Text) + '</p>';
});
html += '</div>';
if (p.SourceUrl) html += '<div class="source">ماخذ: <a href="' + esc(p.SourceUrl) + '" target="_blank" rel="noopener">' + esc(p.SourceName || 'ویکی ماخذ') + '</a></div>';
app.innerHTML = html;
});
}
function route() {
var url = decodeURIComponent(location.hash.replace(/^#/, '')) || '/';
var view = url === '/' ? home() : /\/sh\d+$/.test(url) ? poem(url) : category(url);
view.then(function () { window.scrollTo(0, 0); }).catch(function (e) { app.innerHTML = '<p class="msg">نہیں مل سکا: ' + esc(e.message) + '</p>'; });
}
window.addEventListener('hashchange', route);
route();
var fontBtn = document.getElementById('font');
fontBtn.textContent = document.documentElement.classList.contains('nastaliq') ? 'نستعلیق' : 'نسخ';
fontBtn.onclick = function () {
var nastaliq = document.documentElement.classList.toggle('nastaliq');
try { localStorage.setItem('divan-font', nastaliq ? 'nastaliq' : 'naskh'); } catch (e) {}
fontBtn.textContent = nastaliq ? 'نستعلیق' : 'نسخ';
};
</script>
</body>
</html>