diff --git a/web/src/components/Icon.astro b/web/src/components/Icon.astro new file mode 100644 index 00000000..71611e9d --- /dev/null +++ b/web/src/components/Icon.astro @@ -0,0 +1,39 @@ +--- +// Icons (Lucide, ISC licence; https://lucide.dev): drawn with currentColor, so they take the colour of their button +// or link. Decorative: the button or link carries the words (aria-label/title, or its text). +const { name, size = 20 } = Astro.props as { name: keyof typeof PATHS; size?: number }; +const PATHS = { + admin: '', + edit: '', + bookmark: '', + // the word book: a book; the letter ع is laid over it as text (.glyph-icon), which every browser draws the same + words: '', + user: '', + login: '', + logout: '', + theme: '', + font: '', + tag: '', + arrange: '', + history: '', + upload: '', + download: '', + check: '', + close: '', + undo: '', + send: '', + save: '', + full: '', + next: '', // points left: forward in a right-to-left page + prev: '', + trash: '', + key: '', + image: '', + plus: '', + settings: '', + sun: '', + moon: '', + external: '', +}; +--- + diff --git a/web/src/components/LibraryNav.astro b/web/src/components/LibraryNav.astro index 9afb2990..47f30db2 100644 --- a/web/src/components/LibraryNav.astro +++ b/web/src/components/LibraryNav.astro @@ -1,9 +1,10 @@ --- -// tabs between the reader's bookmarks and their word book (kept separate) -const { current } = Astro.props as { current: 'bookmarks' | 'words' }; +// tabs of the reader's own space: saved texts, favourite writers, the word book (kept separate), profile +const { current } = Astro.props as { current: 'bookmarks' | 'writers' | 'words' }; --- diff --git a/web/src/components/Seg.astro b/web/src/components/Seg.astro index 95275948..4576db74 100644 --- a/web/src/components/Seg.astro +++ b/web/src/components/Seg.astro @@ -3,4 +3,4 @@ const { s } = Astro.props as { s: [string, string, string?][] }; --- {s.map(([t, k, d]) => (k === 'mark' ? {t} : k === 'pen' ? {t} - : k === 'bmk' ? {t} : t))} + : k === 'bmk' ? {t} : t))} diff --git a/web/src/layouts/Base.astro b/web/src/layouts/Base.astro index 5fb512d6..ec139c2d 100644 --- a/web/src/layouts/Base.astro +++ b/web/src/layouts/Base.astro @@ -8,6 +8,7 @@ import '../styles/global.css'; interface Props { title?: string; description?: string; q?: string } const { title, description = 'اردو کی کلاسیکی شاعری اور نثر', q = '' } = Astro.props; const fullTitle = title ? `${title} · دیوان` : 'دیوان · اردو کی کلاسیکی شاعری اور نثر'; +import Icon from '../components/Icon.astro'; --- @@ -18,7 +19,7 @@ const fullTitle = title ? `${title} · دیوان` : 'دیوان · اردو ک @@ -43,17 +47,43 @@ const fullTitle = title ? `${title} · دیوان` : 'دیوان · اردو ک -
- {Astro.locals.user?.role === 'admin' && } - {['mod-l2', 'mod-l1', 'admin'].includes(Astro.locals.user?.role ?? '') && } - {Astro.locals.user && } - {Astro.locals.user && } +
+ ? + : } +
+ +
+

خط

+
+

رنگ

+
+ {[['', 'سپیا', '#fbf6ea', '#bf3f2a'], ['teal', 'فیروزی', '#e2f0ee', '#0b4f6c'], ['lapis', 'نیلگوں', '#e6ebf8', '#1d3b8b'], + ['green', 'سبز', '#e5eede', '#1f5d3a'], ['rose', 'گلابی', '#f5e6ea', '#6b2c5e']].map(([v, name, a, b]) => ( + + ))} +
+

ہندسے

+
+

روشنی

+
+ + + +
+
+
+ {Astro.locals.user && ( +
+ + +
+ )} + @@ -87,14 +117,41 @@ const fullTitle = title ? `${title} · دیوان` : 'دیوان · اردو ک diff --git a/web/src/lib/pdfreader.ts b/web/src/lib/pdfreader.ts index 48db1ab3..04c481ff 100644 --- a/web/src/lib/pdfreader.ts +++ b/web/src/lib/pdfreader.ts @@ -57,7 +57,7 @@ export async function pdfReader(root: HTMLElement) { const full = root.querySelector('.pdf-full')!; const toggle = () => (document.fullscreenElement ? document.exitFullscreen() : root.requestFullscreen()).catch(() => {}); full.onclick = toggle; - document.addEventListener('fullscreenchange', () => { full.textContent = document.fullscreenElement === root ? 'واپس' : 'پوری اسکرین'; show(page); }); + document.addEventListener('fullscreenchange', () => { full.title = document.fullscreenElement === root ? 'پوری اسکرین سے واپس (F)' : 'پوری اسکرین (F)'; show(page); }); // a click on the half the book turns towards goes forward pagesBox.onclick = (e) => { const left = e.clientX < pagesBox.getBoundingClientRect().left + pagesBox.clientWidth / 2; step(left === rtl ? 1 : -1); }; document.addEventListener('keydown', (e) => { diff --git a/web/src/middleware.ts b/web/src/middleware.ts index d2ff4d2d..d0d91be4 100644 --- a/web/src/middleware.ts +++ b/web/src/middleware.ts @@ -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 { 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; 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(/(|)/) + .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 }); }); diff --git a/web/src/pages/[...path].astro b/web/src/pages/[...path].astro index 2d70d5b2..73b476ee 100644 --- a/web/src/pages/[...path].astro +++ b/web/src/pages/[...path].astro @@ -82,6 +82,7 @@ const ebookCount = page.type === 'poet' ? ((await api(`/api/ebooks?poet=$ const tagTarget = page.type === 'poem' ? `work/${poemId}` : `category/${page.category?.id}`; 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; +import Icon from '../components/Icon.astro'; --- {page.type !== 'poet' && ( @@ -95,8 +96,8 @@ const title = page.type === 'poem' ? page.poem.title : page.type === 'poet' ? pa {page.type === 'poet' && ( <>

{page.poet.name}

-
{arrange && <>
- ترتیب کا تاریخچہ}{tagCan && <>
}
+
{arrange && <>
+ }{tagCan && <>
}

{years(page.poet)}

{page.poet.description &&
{page.poet.description}
} @@ -106,8 +107,8 @@ const title = page.type === 'poem' ? page.poem.title : page.type === 'poet' ? pa <>

{page.category.title}

-
{arrange && <>
- ترتیب کا تاریخچہ}{tagCan && <>
}
+
{arrange && <>
+ }{tagCan && <>
}
)} @@ -135,8 +136,8 @@ const title = page.type === 'poem' ? page.poem.title : page.type === 'poet' ? pa

)}
- {modCan.edit && <>
- تاریخچہ}{tagCan && <>
}
+ {modCan.edit && <>
+ }{tagCan && <>
} {page.poem.radif != null &&

{page.poem.radif ? `ردیف: ${page.poem.radif}` : 'غیر مردف'}

}
diff --git a/web/src/pages/[poet]/ebooks.astro b/web/src/pages/[poet]/ebooks.astro index 5945f4ea..ca197746 100644 --- a/web/src/pages/[poet]/ebooks.astro +++ b/web/src/pages/[poet]/ebooks.astro @@ -18,11 +18,12 @@ const cover = (b: any) => (b.has_cover ? `/ebooks/cover/${b.id}` : b.kind === 'a const token = Astro.locals.user ? Astro.cookies.get(COOKIE)?.value : undefined; const mayAdd = token && ['mod-l2', 'mod-l1', 'admin'].includes(Astro.locals.user!.role) && (await asUser(token, `/api/mod/can?category=${page.category.id}`)).data.ebooks; +import Icon from '../../components/Icon.astro'; ---

ای بکس

- {mayAdd &&

ای بک شامل کریں

} + {mayAdd &&

ای بک شامل کریں

}