fix(web): lecteur mobile — compacter la barre du lecteur sur téléphone (wrap flex, libellés secondaires masqués, navigation/plein écran en icônes, select de mode réductible) pour éliminer le rognage à droite (bug #40)
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { ArrowLeft, ArrowRight } from "lucide-react";
|
||||
import { ArrowLeft, ArrowRight, Maximize2, Minimize2 } from "lucide-react";
|
||||
import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
|
||||
import { ErrorRibbon } from "../components/ui";
|
||||
import { navigate } from "../router";
|
||||
@ -189,9 +189,9 @@ export function ReaderShell({ title, backHref, error, onRetry, controls, zoomCon
|
||||
setHeaderVisible(true);
|
||||
}}
|
||||
>
|
||||
<button className="ghost-button" onClick={() => navigate(backHref)}>
|
||||
<button className="ghost-button reader-back-button" onClick={() => navigate(backHref)} aria-label="Retour">
|
||||
<ArrowLeft size={17} />
|
||||
Retour
|
||||
<span>Retour</span>
|
||||
</button>
|
||||
<strong className="reader-title">{title}</strong>
|
||||
<span className="reader-position">{controls.positionLabel}</span>
|
||||
@ -204,12 +204,12 @@ export function ReaderShell({ title, backHref, error, onRetry, controls, zoomCon
|
||||
</select>
|
||||
</label>
|
||||
)}
|
||||
<button className="ghost-button" onClick={controls.onPrevious} disabled={!controls.canPrevious}>
|
||||
<button className="ghost-button reader-nav-button reader-previous-button" onClick={controls.onPrevious} disabled={!controls.canPrevious} aria-label="Page precedente">
|
||||
<ArrowLeft size={16} />
|
||||
Precedent
|
||||
<span>Precedent</span>
|
||||
</button>
|
||||
<button className="ghost-button" onClick={controls.onNext} disabled={!controls.canNext}>
|
||||
Suivant
|
||||
<button className="ghost-button reader-nav-button reader-next-button" onClick={controls.onNext} disabled={!controls.canNext} aria-label="Page suivante">
|
||||
<span>Suivant</span>
|
||||
<ArrowRight size={16} />
|
||||
</button>
|
||||
{zoomControls && (
|
||||
@ -226,8 +226,9 @@ export function ReaderShell({ title, backHref, error, onRetry, controls, zoomCon
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<button className="ghost-button reader-fullscreen-toggle" onClick={() => void toggleFullscreen()} aria-pressed={fullscreenActive}>
|
||||
{fullscreenActive ? "Quitter le plein écran" : "Plein écran"}
|
||||
<button className="ghost-button reader-fullscreen-toggle" onClick={() => void toggleFullscreen()} aria-pressed={fullscreenActive} aria-label={fullscreenActive ? "Quitter le plein écran" : "Plein écran"}>
|
||||
{fullscreenActive ? <Minimize2 size={16} /> : <Maximize2 size={16} />}
|
||||
<span>{fullscreenActive ? "Quitter le plein écran" : "Plein écran"}</span>
|
||||
</button>
|
||||
</header>
|
||||
{error && (
|
||||
|
||||
@ -222,6 +222,15 @@ describe("reader runtime helpers", () => {
|
||||
expect(verticalContent).toContain("align-self: start");
|
||||
});
|
||||
|
||||
it("lets the mobile reader toolbar wrap instead of overflowing horizontally", () => {
|
||||
const styles = readFileSync(new URL("../styles/app.css", import.meta.url), "utf8");
|
||||
|
||||
expect(styles).toContain(".reader-topbar {\n gap: 8px;\n flex-wrap: wrap;");
|
||||
expect(styles).toContain("overflow: hidden");
|
||||
expect(styles).toContain(".reader-back-button span,\n .reader-nav-button span,\n .reader-fullscreen-toggle span,\n .reader-mode-control > span");
|
||||
expect(styles).toContain(".reader-mode-control select {\n width: 100%;");
|
||||
});
|
||||
|
||||
it("detects fullscreen support and active fullscreen element", () => {
|
||||
const fullscreenElement = { requestFullscreen: () => Promise.resolve() } as unknown as HTMLElement;
|
||||
const regularElement = {} as HTMLElement;
|
||||
|
||||
@ -1282,6 +1282,78 @@ main.app-main-reader .reader-page {
|
||||
|
||||
.reader-topbar {
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
align-content: start;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.reader-back-button,
|
||||
.reader-nav-button,
|
||||
.reader-fullscreen-toggle {
|
||||
width: 34px;
|
||||
min-width: 34px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.reader-back-button {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.reader-title {
|
||||
order: 2;
|
||||
flex: 1 1 120px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.reader-position {
|
||||
order: 3;
|
||||
min-width: 78px;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.reader-fullscreen-toggle {
|
||||
order: 4;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.reader-mode-control {
|
||||
order: 5;
|
||||
flex: 1 1 132px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.reader-mode-control select {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.reader-previous-button {
|
||||
order: 6;
|
||||
}
|
||||
|
||||
.reader-next-button {
|
||||
order: 7;
|
||||
}
|
||||
|
||||
.reader-zoom-controls {
|
||||
order: 8;
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.reader-zoom-label {
|
||||
min-width: 46px;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.reader-back-button span,
|
||||
.reader-nav-button span,
|
||||
.reader-fullscreen-toggle span,
|
||||
.reader-mode-control > span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.reader-zoom-reset {
|
||||
|
||||
Reference in New Issue
Block a user