Numerals: Eastern (۱۲۳) or Western (123) in the display settings; the server sends pages with the chosen digits (scripts and styles untouched) and script-drawn numbers follow. Settings button lines up with the other icons
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e04ed0d4af
commit
3305a514ba
@ -29,6 +29,7 @@ import Icon from '../components/Icon.astro';
|
|||||||
if (t) document.documentElement.dataset.theme = t;
|
if (t) document.documentElement.dataset.theme = t;
|
||||||
const pal = localStorage.getItem('divan-palette'); // sepia when unset
|
const pal = localStorage.getItem('divan-palette'); // sepia when unset
|
||||||
if (pal) document.documentElement.dataset.palette = pal;
|
if (pal) document.documentElement.dataset.palette = pal;
|
||||||
|
if (document.cookie.includes('divan-digits=latn')) document.documentElement.dataset.digits = 'latn'; // Western numerals
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
@ -66,6 +67,8 @@ import Icon from '../components/Icon.astro';
|
|||||||
<button type="button" data-palette={v} title={name} aria-label={name} style={`--a: ${a}; --b: ${b}`}><span></span>{name}</button>
|
<button type="button" data-palette={v} title={name} aria-label={name} style={`--a: ${a}; --b: ${b}`}><span></span>{name}</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<p>ہندسے</p>
|
||||||
|
<div class="seg"><button type="button" data-digits="">۱۲۳ مشرقی</button><button type="button" data-digits="latn">123 مغربی</button></div>
|
||||||
<p>روشنی</p>
|
<p>روشنی</p>
|
||||||
<div class="seg">
|
<div class="seg">
|
||||||
<button type="button" data-theme-pick="light"><Icon name="sun" size={16} /> روشن</button>
|
<button type="button" data-theme-pick="light"><Icon name="sun" size={16} /> روشن</button>
|
||||||
@ -122,15 +125,32 @@ import Icon from '../components/Icon.astro';
|
|||||||
panel.querySelectorAll('[data-font]').forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.font === on.font)));
|
panel.querySelectorAll('[data-font]').forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.font === on.font)));
|
||||||
panel.querySelectorAll('[data-palette]').forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.palette === on.palette)));
|
panel.querySelectorAll('[data-palette]').forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.palette === on.palette)));
|
||||||
panel.querySelectorAll('[data-theme-pick]').forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.themePick === on.theme)));
|
panel.querySelectorAll('[data-theme-pick]').forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.themePick === on.theme)));
|
||||||
|
panel.querySelectorAll('[data-digits]').forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.digits === (root.dataset.digits ?? ''))));
|
||||||
};
|
};
|
||||||
panel.addEventListener('click', (e) => {
|
panel.addEventListener('click', (e) => {
|
||||||
const b = e.target.closest('button'); if (!b) return;
|
const b = e.target.closest('button'); if (!b) return;
|
||||||
if (b.dataset.font) { root.classList.toggle('nastaliq', b.dataset.font === 'nastaliq'); store('divan-font', b.dataset.font); }
|
if (b.dataset.font) { root.classList.toggle('nastaliq', b.dataset.font === 'nastaliq'); store('divan-font', b.dataset.font); }
|
||||||
if (b.dataset.palette != null) { if (b.dataset.palette) root.dataset.palette = b.dataset.palette; else delete root.dataset.palette; store('divan-palette', b.dataset.palette); }
|
if (b.dataset.palette != null) { if (b.dataset.palette) root.dataset.palette = b.dataset.palette; else delete root.dataset.palette; store('divan-palette', b.dataset.palette); }
|
||||||
|
if (b.dataset.digits != null) {
|
||||||
|
// numerals: a cookie, so the server sends pages with them; switching back to Eastern reloads the page
|
||||||
|
document.cookie = `divan-digits=${b.dataset.digits}; path=/; max-age=${b.dataset.digits ? 31536000 : 0}; samesite=lax`;
|
||||||
|
if (!b.dataset.digits) { delete root.dataset.digits; location.reload(); return; }
|
||||||
|
root.dataset.digits = 'latn'; westernDigits(document.body);
|
||||||
|
}
|
||||||
if (b.dataset.themePick != null) { if (b.dataset.themePick) root.dataset.theme = b.dataset.themePick; else delete root.dataset.theme; store('divan-theme', b.dataset.themePick); }
|
if (b.dataset.themePick != null) { if (b.dataset.themePick) root.dataset.theme = b.dataset.themePick; else delete root.dataset.theme; store('divan-theme', b.dataset.themePick); }
|
||||||
marks();
|
marks();
|
||||||
|
|
||||||
});
|
});
|
||||||
document.addEventListener('click', (e) => { if (panel.open && !panel.contains(e.target)) panel.open = false; }); // close when clicking elsewhere
|
document.addEventListener('click', (e) => { if (panel.open && !panel.contains(e.target)) panel.open = false; }); // close when clicking elsewhere
|
||||||
|
// Western numerals also in what scripts add later (word sidebar, page numbers, suggestions)
|
||||||
|
function westernDigits(node) {
|
||||||
|
const walk = document.createTreeWalker(node, NodeFilter.SHOW_TEXT);
|
||||||
|
for (let t = walk.nextNode(); t; t = walk.nextNode()) if (/[۰-۹]/.test(t.data)) t.data = t.data.replace(/[۰-۹]/g, (d) => String(d.charCodeAt(0) - 0x6f0));
|
||||||
|
}
|
||||||
|
new MutationObserver((list) => {
|
||||||
|
if (root.dataset.digits !== 'latn') return;
|
||||||
|
for (const m of list) for (const n of m.addedNodes) n.nodeType === 3 ? westernDigits(n.parentNode) : n.nodeType === 1 && westernDigits(n);
|
||||||
|
}).observe(document.body, { childList: true, subtree: true });
|
||||||
marks();
|
marks();
|
||||||
// Urdu on-screen keyboard, Gboard/Windows Urdu layout
|
// Urdu on-screen keyboard, Gboard/Windows Urdu layout
|
||||||
const BASE = [[...'طصھدٹپتبجح'], [...'مورنلہاکی'], [...'قفےسشغع']];
|
const BASE = [[...'طصھدٹپتبجح'], [...'مورنلہاکی'], [...'قفےسشغع']];
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
// The signed-in reader (or null) for every page, from the session cookie
|
// The signed-in reader (or null) for every page, from the session cookie; and the reader's numerals: pages are
|
||||||
|
// written with Eastern Arabic (Urdu) digits, and a reader who chose Western digits (cookie divan-digits=latn, set in
|
||||||
|
// the display settings) gets them in the page as sent, so nothing flashes
|
||||||
import { defineMiddleware } from 'astro:middleware';
|
import { defineMiddleware } from 'astro:middleware';
|
||||||
import { auth, COOKIE } from './lib/auth';
|
import { auth, COOKIE } from './lib/auth';
|
||||||
|
|
||||||
@ -10,5 +12,11 @@ export const onRequest = defineMiddleware(async (ctx, next) => {
|
|||||||
if (r.ok) ctx.locals.user = r.data.user;
|
if (r.ok) ctx.locals.user = r.data.user;
|
||||||
else if (r.status === 401) ctx.cookies.delete(COOKIE, { path: '/' }); // expired or signed out elsewhere
|
else if (r.status === 401) ctx.cookies.delete(COOKIE, { path: '/' }); // expired or signed out elsewhere
|
||||||
}
|
}
|
||||||
return next();
|
const res = await next();
|
||||||
|
if (ctx.cookies.get('divan-digits')?.value !== 'latn' || !res.headers.get('content-type')?.includes('text/html')) return res;
|
||||||
|
// text only: scripts and styles are left alone (the page's own scripts look for Eastern digits)
|
||||||
|
const html = (await res.text()).split(/(<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>)/)
|
||||||
|
.map((part, i) => (i % 2 ? part : part.replace(/[۰-۹]/g, (d) => String(d.charCodeAt(0) - 0x6f0)))).join('');
|
||||||
|
const headers = new Headers(res.headers); headers.delete('content-length');
|
||||||
|
return new Response(html, { status: res.status, statusText: res.statusText, headers });
|
||||||
});
|
});
|
||||||
|
|||||||
@ -496,7 +496,7 @@ h1 + .muted { text-align: center; margin-top: 0; }
|
|||||||
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
||||||
.icon-btn.small { width: 30px; height: 30px; }
|
.icon-btn.small { width: 30px; height: 30px; }
|
||||||
/* display settings in the header: a button and its panel (font, palette swatches, light/dark/automatic) */
|
/* display settings in the header: a button and its panel (font, palette swatches, light/dark/automatic) */
|
||||||
.display-menu { position: relative; }
|
.display-menu { position: relative; display: flex; } /* no line box: lines up with the other header icons */
|
||||||
.display-menu > summary { list-style: none; }
|
.display-menu > summary { list-style: none; }
|
||||||
.display-menu > summary::-webkit-details-marker { display: none; }
|
.display-menu > summary::-webkit-details-marker { display: none; }
|
||||||
.display-menu[open] > summary { border-color: var(--brand); color: var(--brand); }
|
.display-menu[open] > summary { border-color: var(--brand); color: var(--brand); }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user