mirror of
https://github.com/R0m1k3/FlowReader.git
synced 2026-10-19 21:28:10 +02:00
- Service worker activates new versions immediately (skipWaiting + clientsClaim). In prompt mode a waiting worker kept serving the previous build to tabs that never send SKIP_WAITING, so the old UI hit the new API and showed "Aucun contenu disponible" on every article. Pages already controlled get a reload toast; lazy chunks missing after a deploy reload once. - Reader opens as a large card above the dimmed grid: close with ✕, Escape or a click beside it; previous/next arrows on the sides (desktop) and a bottom bar with the next title (all sizes). - Remove search, the focus banner and decorative headers; plain sentence- case labels instead of tracked capitals; quieter dashboard header. - Fix horizontal overflow of cards and reader navigation on phones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
74 lines
2.8 KiB
TypeScript
74 lines
2.8 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
||
|
||
const GROUPS: { title: string; keys: [string, string][] }[] = [
|
||
{
|
||
title: 'Liste',
|
||
keys: [
|
||
['j / k', 'Article suivant / précédent'],
|
||
['o · Entrée', 'Ouvrir l’article'],
|
||
['m', 'Marquer lu / non lu'],
|
||
['s · f', 'Favori'],
|
||
['v', 'Ouvrir l’original'],
|
||
['u', 'Basculer Non lus / Tous'],
|
||
['r', 'Actualiser les flux'],
|
||
],
|
||
},
|
||
{
|
||
title: 'Lecture',
|
||
keys: [
|
||
['Espace', 'Défiler, puis article suivant'],
|
||
['j · → / k · ←', 'Article suivant / précédent'],
|
||
['+ / -', 'Taille du texte'],
|
||
['Échap', 'Fermer l’article'],
|
||
],
|
||
},
|
||
];
|
||
|
||
export function ShortcutsHelp({ onClose }: { onClose: () => void }) {
|
||
const ref = useRef<HTMLDivElement>(null);
|
||
|
||
useEffect(() => {
|
||
ref.current?.focus();
|
||
const onKey = (e: KeyboardEvent) => {
|
||
if (e.key === 'Escape' || e.key === '?') {
|
||
e.stopImmediatePropagation();
|
||
onClose();
|
||
}
|
||
};
|
||
window.addEventListener('keydown', onKey, true);
|
||
return () => window.removeEventListener('keydown', onKey, true);
|
||
}, [onClose]);
|
||
|
||
return (
|
||
<div className="fixed inset-0 z-[60] flex items-center justify-center p-4 bg-nature-dark/50 animate-fade-in" onClick={onClose}>
|
||
<div
|
||
ref={ref}
|
||
tabIndex={-1}
|
||
role="dialog"
|
||
aria-modal="true"
|
||
aria-labelledby="shortcuts-title"
|
||
className="surface-card w-full max-w-lg p-7 outline-none animate-rise"
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
<h2 id="shortcuts-title" className="text-2xl font-serif text-paper-white mb-5">Raccourcis clavier</h2>
|
||
<div className="grid sm:grid-cols-2 gap-6">
|
||
{GROUPS.map((g) => (
|
||
<section key={g.title}>
|
||
<h3 className="text-sm font-semibold text-paper-white mb-3">{g.title}</h3>
|
||
<dl className="space-y-2 text-sm">
|
||
{g.keys.map(([k, label]) => (
|
||
<div key={k} className="flex items-center justify-between gap-3">
|
||
<dt className="text-paper-muted">{label}</dt>
|
||
<dd className="kbd shrink-0">{k}</dd>
|
||
</div>
|
||
))}
|
||
</dl>
|
||
</section>
|
||
))}
|
||
</div>
|
||
<button onClick={onClose} className="btn-ghost w-full mt-6">Fermer</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|