Architecture
Handoff : refonte de la lecture du Corpus (ISNAD)
Sur cette page
Overview#
Refonte de l'expérience de lecture du corpus dans isnad-app-fr (Next.js App Router + Supabase + Tailwind).
Trois problèmes rapportés par le propriétaire du produit :
- « Pas facile à lire » — la page d'un livre (
/[locale]/corpus/[collectionId]/books/[bookId]) est un unique flux vertical de chapitres, sans repère de position. - Aucun menu de navigation latéral qui mette en évidence le chapitre / sous-chapitre en cours de lecture, y compris pendant le défilement.
- Mélange arabe / français sur des pages censées être monolingues, et aucun réglage de police pour le lecteur (3 choix demandés).
Le paquet contient deux fichiers de design : la reconstitution 1:1 de l'état actuel, et la refonte proposée (bureau FR clair, bureau AR sombre RTL, mobile FR).
About the Design Files#
Les fichiers .dc.html de ce paquet sont des références de design réalisées en HTML — des prototypes qui
montrent l'apparence et le comportement visés. Ce n'est pas du code de production à copier. Le travail
consiste à recréer ces écrans dans l'environnement existant du dépôt : React 18 / Next.js App Router,
composants clients 'use client', Tailwind avec les jetons HSL de src/app/globals.css, i18n via
useLocale() de src/lib/i18n.tsx, données via src/lib/supabaseClient.ts.
Les prototypes utilisent des styles inline et des polices chargées depuis Google Fonts ; dans le dépôt, il faut
passer par les classes Tailwind / globals.css et next/font/google (src/lib/fonts.ts).
Fidelity#
Haute fidélité (hifi). Couleurs, tailles de police, graisses, interlignes, épaisseurs de filets et rythme vertical sont définitifs et repris des jetons réels du dépôt. À recréer au pixel avec les classes Tailwind existantes. Seules exceptions, à remplacer par des données réelles :
- les libellés des chapitres 02 à 06 (« Le mérite de la foi », « Le devoir de transmettre »,
« Les premiers auditeurs », « La dictée et la lecture », « Les recensions divergentes ») sont provisoires —
utiliser
chapters.title_fr; - les numéros
SB-HD0002…SB-HD0022et les compteurs de hadiths sont illustratifs ; - les seules lignes réellement issues du dépôt (fixtures
supabase/tests/fixtures/) sont : collections 10 (صحيح البخاري/ Ṣaḥīḥ al-Bukhārī) et 15 (صحيح مسلم/ Ṣaḥīḥ Muslim) ; livres 92 (كتاب بدء الوحي/ Révélation), 56 (كتاب الجهاد/ Jihad), 95 (كتاب الفتن/ Épreuves) ; chapitre 104 (باب بدء الوحي/ Début de la révélation) ; hadithSB-HD0001et sa chaîne (al-Ḥumaydī → Sufyān → Yaḥyā ibn Saʿīd → ʿUmar ibn al-Khaṭṭāb).
Screens / Views#
A. Atelier de lecture — bureau, français, thème clair (option 1a)#
Route cible : /[locale]/corpus/[collectionId]/books/[bookId] (remplace la page actuelle).
Objet : lire un livre entier chapitre par chapitre sans perdre sa position, avec la chaîne de transmission
lisible à côté du texte.
Layout
Colonne pleine hauteur, hors <main> actuel (l'atelier prend la hauteur de la fenêtre ; le
max-w-6xl px-5 py-12 du layout ne doit pas s'appliquer à cette route — prévoir un layout de route
dédié, ou un <main> sans padding pour ce segment).
┌ barre d'atelier (hauteur 51px, border-bottom 1px, bg card) ────────────────┐
│ logo ISNAD · fil d'Ariane · [Français|العربية] · thème │
├──────────────┬───────────────────────────────┬──────────────────────────────┤
│ rail gauche │ colonne de lecture │ panneau isnād │
│ 312px fixe │ minmax(0,1fr) │ 332px fixe │
│ overflow │ en-tête collant + zone │ overflow-y auto │
│ interne │ défilante │ │
└──────────────┴───────────────────────────────┴──────────────────────────────┘
- Grille :
grid-template-columns: 312px minmax(0,1fr) 332px, hauteur =100dvh - 51px. - Séparations :
border-inline-end/border-inline-start1pxhsl(var(--border))(propriétés logiques obligatoires — le rail passe à droite en RTL sans code conditionnel). - Les trois colonnes défilent indépendamment (
min-height:0sur chaque piste, sinon leoverflow-y:autone fonctionne pas dans une grille).
Rail gauche (312px)
Trois blocs empilés en flex-direction:column :
-
En-tête de livre — padding
20px 20px 16px,border-bottom1pxhsl(var(--border) / .7):- kicker
LIVRE 1 SUR 97: Inter 600, 10px,letter-spacing:.18em,hsl(var(--primary)); - titre
Révélation: Newsreader 400, 22px,line-height:1.2, marge haute 10px ; - méta
6 chapitres · 22 hadiths · 18 identifiés: Inter 400, 12px,hsl(var(--muted-foreground)), chiffres entabular-nums; - champ de filtre :
border1pxhsl(var(--border)),radius 4px, padding7px 10px, fondhsl(var(--background)), icône loupe Lucide 13px, placeholder « Filtrer les chapitres » (12,5px). Filtre en clair sur le titre français ET surtitle_ar(un chercheur tape en arabe).
- kicker
-
Table des matières —
flex:1; overflow-y:auto, padding12px 12px 16px:- kicker
TABLE DES MATIÈRES: Inter 600, 10px,letter-spacing:.16em,hsl(var(--muted-foreground)); - ligne de chapitre :
display:flex; gap:10px; border-radius:4px; padding:10px 12px; numéro Inter 400 11pxtabular-numshsl(var(--muted-foreground)), titre Inter 400 13,5px, méta (6 hadiths) Inter 400 10,5pxhsl(var(--muted-foreground)); - ligne active : fond
hsl(var(--accent) / .7), titre Inter 500hsl(var(--accent-foreground)), méta suffixée « · en lecture », et une barre verticaleposition:absolute; inset-block:8px; inset-inline-start:0; width:2px; border-radius:999px; background:hsl(var(--primary)); - sous-liste du chapitre actif uniquement :
margin-inline-start:30px,border-inline-start:1px solid hsl(var(--primary) / .35),padding-inline-start:12px; chaque entréeHadith n · titre courtInter 400 12,5px,padding:5px 0; le hadith en cours de lecture enhsl(var(--primary)), les autres enhsl(var(--muted-foreground)).
- kicker
-
Réglages de lecture —
border-top1px, padding16px 20px 18px, fondhsl(var(--muted) / .5):- kicker
RÉGLAGES DE LECTURE(même style que ci-dessus, couleur primary) ; - libellé « Police du texte source » Inter 400 11px, puis 3 boutons en
flex; gap:6px, chacunflex:1,border1px,radius 4px,padding:8px 6px, centré : échantillon « أبجد » à 19px dans la police proposée + libellé 9,5px ; sélection =border-color:hsl(var(--primary))+ fondhsl(var(--accent) / .8); - libellé « Taille » + 3 boutons
Petit | Moyen | Grand(Inter 12px, 500 si actif,padding:6px).
- kicker
Colonne de lecture
- En-tête collant (
position:sticky; top:0; z-index:3), fondhsl(var(--background) / .94)+backdrop-filter: blur(8px),border-bottom1px :- ligne
padding:11px 32px 10px: à gaucheCH. 01(Inter 11pxtabular-numsprimary) + titre du chapitre courant (Newsreader 15px,text-overflow:ellipsis) ; à droite42 % du livre(Inter 11pxtabular-numsmuted) ; - barre de progression : piste 2px
hsl(var(--border) / .6), remplissagehsl(var(--primary)),transition: width .12s linear.
- ligne
- Zone défilante :
overflow-y:auto,padding: 64px 32px 680px(la marge basse donne au dernier chapitre la place d'atteindre le seuil de détection — voir « Scroll-spy »), contenu centrémax-width:684px. - En-tête de livre : kicker
ṢAḤĪḤ AL-BUKHĀRĪ · LIVRE 1, h1 Newsreader 400 40px/1.1, chapeau Inter 15px/1.7 muted,border-bottom1px,padding-bottom:28px. - Section de chapitre — une par chapitre,
padding-top:44px(56px pour les suivantes), attributsdata-ch,data-num,data-title(le scroll-spy les lit) :- titre :
<h2>Newsreader 400 26px/1.25, précédé du numéro (Inter 13pxtabular-numsprimary,margin-inline-end:10px) ; à droite le compteur « 6 hadiths » (Inter 11,5px muted) ;border-bottom1px,padding-bottom:12px; - ligne « Titre source :
باب بدء الوحي» — Inter 12px muted + Amiri 15pxdir="rtl"à 75 % d'opacité. C'est la seule place de l'arabe côté interface française (voir « Règle monolingue »).
- titre :
- Fiche de hadith dépliée :
border1pxhsl(var(--border)),radius 4px, fondhsl(var(--card)),overflow:hidden:- barre de titre : fond
hsl(var(--muted) / .5),border-bottom1px,padding:12px 20px; « Hadith 1 » Newsreader 15pxtabular-nums+ cléSB-HD0001en mono 10,5px muted ; à droite deux étiquettes : « 4 maillons identifiés » (bordurehsl(var(--primary) / .45), textehsl(var(--accent-foreground)), 10px 500) et « Traduction FR à venir » (bordure tiretéehsl(var(--border)), texte muted) ; - corps : kicker
TEXTE SOURCE · ARABE(Inter 600 9,5pxletter-spacing:.16emmuted), puis le matndir="rtl",text-align:justify, police et taille pilotées par les réglages (défaut Amiri 21px /line-height:2.05) ; - pied :
border-top1px, fondhsl(var(--background) / .7), kickerCHAÎNE DE TRANSMISSION · DU PLUS ANCIEN AU RECUEIL, puis la chaîne horizontale (ci-dessous).
- barre de titre : fond
- Fiche repliée (divulgation progressive) : ligne
display:flex; justify-content:space-between,padding:15px 4px,border-bottom1pxhsl(var(--border) / .7); « Hadith 2 » Newsreader 14px + clé mono 10,5px ; à droite « 3 maillons · 2 identifiés », trois pastilles d'état de 7px, et l'action « Déplier » enhsl(var(--primary)).
Visualisation de la chaîne (horizontale, dans la fiche)
display:flex, un flex:1 par maillon, dernier élément flex:none; width:112px (le recueil).
Chaque maillon :
- pastille 9px (
border-radius:999px) + filet horizontal 1pxhsl(var(--border))vers le maillon suivant ; - nom translittéré Newsreader 14px (lien vers
/[locale]/narrators/[id]) ; - méta Inter 10,5px muted :
Gén. 5 · thiqa · ʿanʿana— la formule de transmission ambiguë (ʿanʿana) est coloréehsl(41 56% 36%), les formules explicites (ḥaddathanā) restent muted.
Ordre : chronologique, du Compagnon vers le recueil (inverse de l'ordre position en base, qui part du
compilateur). En RTL, l'ordre visuel se renverse naturellement — ne pas re-trier en JS.
Couleurs de pastille : Compagnon hsl(41 56% 46%) (or) · narrateur identifié et gradé
hsl(var(--primary)) · mention non résolue = cercle 7–9px avec border: 1px dashed hsl(var(--muted-foreground))
et fond transparent · recueil = carré border-radius:2px hsl(var(--foreground)).
Panneau isnād (332px)
Version verticale détaillée du même isnād, padding:22px, fond hsl(var(--card) / .55) :
- ouvert par défaut sur grand écran (décision du propriétaire du produit) ; l'état replié/ouvert est
mémorisé dans
localStoragecomme les réglages de lecture ; - kicker
ISNĀD · HADITH 1+ action « Masquer » (Inter 11px muted) ; - grille
grid-template-columns: 22px 1fr: colonne de gauche = pastille 11px + filet vertical 1pxhsl(var(--border))enflex:1(le connecteur se dessine tout seul, aucun SVG) ; - par maillon : nom translittéré Newsreader 16px (lien), nom arabe Amiri 15px à 55 % d'opacité,
puis des étiquettes 10px 500 (
thiqa · gén. 5,ʿanʿana) ; - sous une étiquette
ʿanʿana, une note Inter 11px/1.6 muted reprenant le texte déjà présent danssrc/lib/i18n-data.ts(entrée « ʿanʿana » : formule grammaticalement ambiguë, n'atteste pas explicitement une audition directe) — ne pas réécrire ce texte, le lire depuist(); - bas de panneau :
border-top1px puis une légende des trois états de pastille.
B. Même atelier en arabe, thème sombre, RTL (option 1b)#
Route : /ar/corpus/.... dir="rtl" sur <html> (déjà en place dans [locale]/layout.tsx).
Différences structurelles (pas seulement des libellés traduits) :
- le rail passe à droite, la progression se remplit de droite à gauche : obtenu gratuitement si tout le
positionnement utilise
inset-inline-start/end,border-inline-*,margin-inline-*; - chiffres indo-arabes partout :
٧ أبواب · ٢٢ حديثًا,الكتاب ١ من ٩٧—Intl.NumberFormat('ar')(le dépôt fait déjàtoLocaleString(locale === 'ar' ? 'ar' : 'fr')danscorpus/page.tsx) ; - vocabulaire des ṭabaqāt :
الطبقة ١ · صحابي,ثقة,عنعنة,المصنَّف; - titres de l'interface en Amiri (
font-serif-ar), textes courants en Noto Sans Arabic (font-sans-ar) ; aucun mot latin sauf la clé documentaireSB-HD0001, qui reste en mono ; - les 3 polices proposées sont des naskh : Amiri / Noto Sans Arabic / Scheherazade New — pas des équivalents latins ;
- couleurs = bloc
.darkdeglobals.css(voir « Design Tokens »).
C. Mobile, français (option 1c)#
Cible 390 × 844. Le rail ne peut pas rester affiché :
- barre haute collante
border-bottom1px, fondhsl(var(--card)): bouton menu (Lucide, 30×30,border1px,radius 6px, icône primary) + bloc deux lignes (CH. 1 · RÉVÉLATIONInter 10px primary / titre Newsreader 15px tronqué) + bouton Aa (34×30, bordurehsl(var(--primary) / .5), textehsl(var(--accent-foreground))) qui ouvre les réglages ; dessous, la même barre de progression de 2px ; - corps : « Hadith 1 » + clé, kicker
TEXTE SOURCE · ARABE, matn Amiri 19px/2 justifié, puis la chaîne verticale (pastille 9px + nom Newsreader 14px + méta 10,5px) ; - feuille de table des matières rappelable :
border-radius:16px 16px 0 0,border-top1px,box-shadow: 0 -18px 40px -30px hsl(var(--surface-shadow)), poignée 40×4pxradius 999px, kickerCHAPITRES · LIVRE 1, lignes de 9px de padding vertical ; la ligne active reprend exactement la mise en surbrillance du rail (border-inline-start:2px solid hsl(var(--primary)), fondhsl(var(--accent) / .55), Inter 500 13,5px) et affiche1/6; - toutes les cibles tactiles ≥ 44px de haut.
Interactions & Behavior#
Scroll-spy (le cœur de la demande)#
Le conteneur défilant est la colonne de lecture, pas la fenêtre (overflow-y:auto).
const SPY_OFFSET = 140; // px sous le haut du conteneur
const sections = Array.from(el.querySelectorAll('[data-ch]')) as HTMLElement[];
const max = el.scrollHeight - el.clientHeight;
const pos = Math.min(el.scrollTop, max);
let active = 0;
sections.forEach((s, i) => { if (s.offsetTop - SPY_OFFSET <= pos) active = i; });
if (pos >= max - 2) active = sections.length - 1; // verrou de fin
const ratio = max > 0 ? Math.min(1, Math.max(0, pos / max)) : 0;
Points durs constatés pendant le prototypage — ne pas les réintroduire :
- mesurer sur
offsetTop(stable) et non surgetBoundingClientRect().topau montage : avant la mise en page, tous les rectangles valent 0 et c'est le dernier chapitre qui gagne. Première mesure dans un doublerequestAnimationFrame(ouIntersectionObserver), et sortie immédiate si!el.clientHeight; - le ratio et le verrou de fin doivent utiliser le même
scrollHeight - clientHeight; tout autre dénominateur (l'étendue de la dernière section, par exemple) déclenche le verrou trop tôt et rend les chapitres intermédiaires inatteignables ; - il faut assez de marge basse (
padding-bottom≈ une hauteur de fenêtre) pour que le dernier chapitre franchisse le seuil en défilant, et non seulement par le verrou de fin.
Écouteur { passive: true }, setState seulement si l'index change ou si le ratio bouge de plus de 0,5 %,
retrait de l'écouteur au démontage. Un clic sur une entrée de la table des matières défile vers la section
(el.scrollTo({ top: section.offsetTop - SPY_OFFSET, behavior: 'smooth' }) — ne pas utiliser
scrollIntoView, et respecter prefers-reduced-motion).
Réglages de lecture#
- Police du texte source arabe : 3 valeurs
amiri | noto | scheherazade→ appliquées au matn, aux titres source et aux noms arabes du panneau isnād. - Police du texte français : 3 valeurs
newsreader | garamond | inter→ appliquées à la prose de la colonne de lecture (titres de livre et de chapitre, chapeaux, paragraphes), pas à l'interface (rail, en-tête collant, étiquettes, méta restent en Inter). Registre voulu : liseuse, moderne et minimaliste — Newsreader (défaut, celui de l'app), EB Garamond (lecture longue), Inter (écran). Ajouter EB Garamond àsrc/lib/fonts.ts(next/font/google, subsetlatin, variable--font-reading-latin). Implémentation : une seule déclarationfont-familysur le conteneur de prose (max-width:684px) et les titres/paragraphes qui héritent — ne pas figer de famille dans leur raccourcifont:. - Taille :
petit | moyen | grand= 18 / 21 / 25 px, interlignes 1.95 / 2.05 / 2.1. - Persistance en
localStoragesur le modèle desrc/lib/theme.tsx(clés distinctes, p. ex.isnad.reading.font/isnad.reading.size), lues dans un script d'initialisation commesrc/lib/theme-script.tspour éviter le flash au premier rendu. - Implémentation : poser un attribut
data-reading-font/data-reading-sizesur le conteneur et laisserglobals.cssrésoudre--font-reading/--size-reading— pas de style inline par élément. Scheherazade Newdoit être ajouté àsrc/lib/fonts.ts(next/font/google, subsetarabic, variable--font-naskh-alt).
Règle monolingue#
Règle à appliquer partout dans le segment corpus :
L'interface est dans une seule langue, celle de la route. L'autre écriture n'apparaît que comme citation de source explicitement étiquetée.
Concrètement, en fr :
- ne plus laisser
title_argagner surtitle_fr— le code actuel fait l'inverse (danscorpus/[collectionId]/page.tsx, la classe passe àtext-right font-serif-ardès quebook.title_arexiste, et la valeur affichée retombe surtitle_aravanttitle_fr) ; attendu : enfr, affichertitle_fr; sititle_frest nul, laisser le titre arabe tel quel (décision du propriétaire du produit) — endir="rtl", en Amiri, précédé de la mention « Titre source », jamais remplacé par un numéro ; - la carte de recueil n'empile plus les deux titres (retirer la branche
collection.name_ar && locale !== 'ar'decorpus/page.tsx) ; l'étagère OpenITI expose le titre translittéré, l'arabe passe en ligne « titre source » ; - le matn arabe reste affiché (la traduction n'est pas en base) mais sous un kicker
TEXTE SOURCE · ARABEet accompagné de l'étiquette « Traduction FR à venir » ; - les noms de narrateurs utilisent
full_name_fr(translittération) ; l'arabe figure en regard, à 55 % d'opacité, dans le panneau isnād seulement.
En ar : symétrique, aucun mot latin hors clés documentaires.
États#
- Chargement : squelettes de lignes dans le rail (6 lignes de 44px) et une fiche de hadith fantôme ; ne jamais afficher un livre vide pendant le chargement.
- Erreur : conserver le comportement actuel (
reportLoadError+ messaget('loadError')+ bouton « Réessayer » qui incrémente unreloadNonce) — une panne ne doit pas se présenter comme un livre vide. - Vide :
t('corpusEmpty'). - Survol : lignes de la table des matières → fond
hsl(var(--muted) / .55)(classe.surface-interactiveexistante) ; liens de narrateur → soulignement. - Focus clavier : anneau existant
:focus-visible { outline: 2px solid hsl(var(--ring)); outline-offset: 2px }— ne pas le redéfinir. La table des matières est un<nav>avec une liste de liens ; l'ordre de tabulation suit l'ordre de lecture. prefers-reduced-motion: supprimer le défilement animé et la transition de la barre de progression (globals.cssa déjà un bloc de ce type pour.book-spine).
Responsive#
- ≥ 1280px : trois colonnes.
- 1024–1279px : panneau isnād replié en tiroir (bouton « Isnād » dans l'en-tête collant).
- 768–1023px : rail replié en tiroir, colonne de lecture pleine largeur.
- < 768px : disposition mobile (écran C).
State Management#
Composant client unique (ReadingWorkspace), état local :
| État | Type | Source / déclencheur |
|---|---|---|
activeChapterIndex | number | scroll-spy sur la colonne de lecture |
scrollRatio | number 0→1 | même écouteur ; alimente la barre et « n % du livre » |
expandedHadithIds | Set<number> | clic sur « Déplier » (divulgation progressive) |
selectedHadithId | `number | null` |
tocFilter | string | champ de filtre (titre FR et title_ar) |
readingFont | `'amiri' | 'noto' |
readingSize | `'petit' | 'moyen' |
railOpen / isnadOpen | boolean | tiroirs sous 1280px |
Données#
Une seule requête suffit pour la page (elle existe déjà dans
corpus/[collectionId]/books/[bookId]/page.tsx) : chapters filtrés par book_id, ordonnés par
chapter_number, avec les hadiths imbriqués (id, chapter_id, hadith_number, hadith_number_raw, source_key, text_ar, text_fr).
À compléter pour l'atelier :
books:title_fr,title_ar,source_sequence_number, et le total de livres du recueil (compteur « LIVRE 1 SUR 97 ») ;- chaînes :
hadith_chains(id, chain_number, hadith_chain_nodes(id, position, narrator_id, mention_ar, transmission_term_ar))— déjà utilisé par la fiche hadith ; - grades et générations des narrateurs cités :
narrators(id, full_name_fr, full_name_ar, grade_tier, generation_rank)(voirsrc/lib/grade-tiers.ts,src/lib/tabaqa.ts) ; - la formule de transmission (
ḥaddathanā/ʿanʿana) vient detransmission_term_ardu maillon ; les libellés explicatifs existent danssrc/lib/i18n-data.ts.
Charger les chaînes des hadiths repliés à la demande (au dépliage) pour ne pas alourdir un livre de plusieurs centaines de hadiths ; ne charger que la chaîne du hadith sélectionné pour le panneau de droite.
Design Tokens#
Tous repris de src/app/globals.css (HSL brut, notation Tailwind hsl(var(--x) / <alpha-value>)) —
ne pas coder de hex en dur.
Clair (:root)#
| Jeton | Valeur | Emploi dans la refonte |
|---|---|---|
--background | 39 39% 94% | fond de la colonne de lecture |
--foreground | 36 8% 10% | texte courant, pastille « recueil » |
--card | 39 35% 97% | barre d'atelier, fiche de hadith, feuille mobile |
--border | 40 28% 80% | tous les filets, connecteurs, pistes |
--muted | 39 24% 90% | bloc réglages, barre de titre de fiche |
--muted-foreground | 31 7% 45% | méta, kickers secondaires |
--primary | 146 15% 38% | kickers, barre active, pastilles de narrateur, progression |
--accent | 143 17% 86% | fond de la ligne active, étiquettes sélectionnées |
--accent-foreground | 146 18% 27% | texte sur fond accent |
--ring | 146 18% 38% | anneau de focus |
--surface-shadow | 170 30% 10% | ombre de la feuille mobile |
Sombre (.dark)#
--background 150 8% 8% · --foreground 39 24% 90% · --card 145 7% 11% · --border 45 9% 22% ·
--muted 145 6% 15% · --muted-foreground 38 8% 65% · --primary 162 34% 58% ·
--accent 169 19% 15% · --accent-foreground 158 16% 90%.
Couleur ajoutée#
Une seule : l'or des Compagnons et des formules de transmission ambiguës —
hsl(41 56% 46%) en clair, hsl(41 56% 56%) en sombre, texte hsl(41 56% 30%) / hsl(41 56% 72%).
À déclarer comme jeton (--sahabi / --sahabi-foreground) dans globals.css, pas en dur.
Typographie#
| Rôle | Police | Variable | Tailles utilisées |
|---|---|---|---|
| Titres latins | Newsreader | --font-serif | 40 / 26 / 22 / 16 / 15 / 14 px |
| Interface latine | Inter | --font-sans | 15 / 13,5 / 12,5 / 12 / 11,5 / 11 / 10,5 / 10 / 9,5 px |
| Titres arabes | Amiri | --font-serif-ar | 40 / 24 / 21 / 19 / 17 / 15 px |
| Interface arabe | Noto Sans Arabic | --font-sans-ar | 12,5 / 11,5 / 11 / 10,5 px |
| Naskh alternatif | Scheherazade New | à ajouter | texte source au choix du lecteur |
| Clés documentaires | mono système | — | 10,5 px, letter-spacing:.04em |
Kickers : Inter 600, 9,5–10px, letter-spacing:.16em à .18em, en majuscules.
Chiffres : font-variant-numeric: tabular-nums sur tous les compteurs, numéros de chapitre et pourcentages.
Interlignes du matn : 1.95 / 2.05 / 2.1 selon la taille choisie (le .arabic-reading actuel est à 2.05).
Espacement et rayons#
Padding de rail 20px · lignes de table des matières 10px 12px · fiche 26px 28px ·
colonne de lecture 64px 32px 680px · écart entre sections de chapitre 56px ·
rayons : 4px (cartes, boutons, champs), 6px (boutons mobiles), 16px (feuille), 999px (pastilles, pilules).
Ombres : uniquement celles de tailwind.config.ts (shadow-card, shadow-elevated) ; l'atelier n'en
utilise qu'une, celle de la feuille mobile.
Assets#
- Marque ISNAD : composant existant
src/components/Logo.tsx(LogoMark+Logo), inchangé. - Icônes : Lucide (loupe, menu, soleil/lune) — le dépôt les dessine actuellement en SVG inline dans
ThemeToggle.tsx/NavBar.tsx; garder la même approche ou passer àlucide-react, mais pas les deux. - Aucune image : la refonte n'ajoute aucun visuel. Les connecteurs de chaîne sont des
divde 1px, pas des SVG. - Polices : Inter, Newsreader, Amiri, Noto Sans Arabic déjà chargées par
src/lib/fonts.ts; ajouter Scheherazade New.
Files#
Dans ce paquet :
| Fichier | Contenu |
|---|---|
Corpus - etat actuel.dc.html | reconstitution 1:1 des 4 écrans actuels (/fr/corpus, /fr/corpus/10, …/books/92, fiche hadith en thème sombre), avec sous chaque écran le constat de ce qui bloque |
Corpus - refonte lecture.dc.html | la refonte : 1a bureau FR clair interactif (scroll-spy, 3 polices, 3 tailles réellement fonctionnels), 1b bureau AR sombre RTL, 1c mobile FR |
support.js | runtime des deux fichiers de design (ouvrir les .dc.html directement dans un navigateur) |
Dans le dépôt isnad-app-fr, fichiers concernés :
| Fichier | Action |
|---|---|
src/app/[locale]/corpus/[collectionId]/books/[bookId]/page.tsx | remplacé par l'atelier de lecture |
src/app/[locale]/corpus/[collectionId]/page.tsx | règle monolingue sur les titres de livres ; rail réutilisable |
src/app/[locale]/corpus/page.tsx | règle monolingue sur les cartes de recueil et l'étagère OpenITI |
src/app/[locale]/corpus/[collectionId]/books/[bookId]/hadiths/[hadithId]/page.tsx | la fiche hadith reprend la chaîne visualisée (aujourd'hui une ligne à flèches) |
src/app/globals.css | jetons --sahabi, --font-reading, --size-reading ; classes de l'atelier |
src/lib/fonts.ts | ajout de Scheherazade New |
src/lib/i18n-data.ts | libellés : réglages de lecture, polices, tailles, « titre source », « n % du livre », « Déplier », légende des pastilles |
src/lib/theme.tsx / src/lib/theme-script.ts | modèle de persistance à dupliquer pour les réglages de lecture |
tailwind.config.ts | inchangé sauf si les nouveaux jetons doivent être exposés en classes |
Décisions arrêtées (propriétaire du produit, 2026-09-13)#
- Chapitres sans
title_fr: laisser le titre arabe tel quel, étiqueté « Titre source ». Pas de substitution par un numéro documentaire, pas de libellé inventé. - Panneau isnād : ouvert par défaut sur grand écran (≥ 1280px), repliable et état mémorisé.
- Choix de police pour le texte français : oui, trois faces, registre liseuse moderne et minimaliste (Newsreader / EB Garamond / Inter). Voir « Réglages de lecture ».