mirror of
https://github.com/readest/readest.git
synced 2026-07-09 16:00:16 +00:00
fix(reader): keep running header/footer readable over light PDFs in dark mode (#4901) (#4911)
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (rust) (push) Waiting to run
Publish Docker image / build (linux/amd64, ubuntu-latest) (push) Waiting to run
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm) (push) Waiting to run
Publish Docker image / merge (push) Blocked by required conditions
PR checks / rust_lint (push) Waiting to run
PR checks / build_web_app (push) Waiting to run
PR checks / test_web_app (1) (push) Waiting to run
PR checks / test_web_app (2) (push) Waiting to run
PR checks / test_extensions (push) Waiting to run
PR checks / build_tauri_app (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Deploy to vercel on merge / build_and_deploy (push) Waiting to run
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (rust) (push) Waiting to run
Publish Docker image / build (linux/amd64, ubuntu-latest) (push) Waiting to run
Publish Docker image / build (linux/arm64, ubuntu-24.04-arm) (push) Waiting to run
Publish Docker image / merge (push) Blocked by required conditions
PR checks / rust_lint (push) Waiting to run
PR checks / build_web_app (push) Waiting to run
PR checks / test_web_app (1) (push) Waiting to run
PR checks / test_web_app (2) (push) Waiting to run
PR checks / test_extensions (push) Waiting to run
PR checks / build_tauri_app (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Deploy to vercel on merge / build_and_deploy (push) Waiting to run
The running section title and page-number footer used text-neutral-content, which is a light color in dark mode. A light-mode PDF stays white under a dark theme (invertImgColorInDark defaults to false), so the light text sat on the white page and became unreadable. Blend the header/footer text against whatever is behind it using mix-blend-mode: difference with a fixed white/75 anchor, so it inverts to dark on a light page and stays light on a dark margin. white/75 matches the former neutral-content brightness over the dark theme, so reflowable books look unchanged. E-ink keeps its plain base-content text; StatusInfo and the sticky progress bar manage their own colors and are left untouched. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8c91ad411c
commit
2b524439bf
4 changed files with 85 additions and 1 deletions
|
|
@ -68,3 +68,27 @@ describe('SectionInfo notch mask', () => {
|
|||
expect(notch.classList.contains('bg-base-100')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('SectionInfo contrast against the page (#4901)', () => {
|
||||
// A light-mode PDF shown under a dark theme keeps its white page, but the
|
||||
// running header text was themed for the dark UI (neutral-content, light)
|
||||
// and became unreadable on the white page. mix-blend-mode: difference makes
|
||||
// the text invert against whatever is actually behind it (the page or the
|
||||
// themed margin), so it stays legible over any background.
|
||||
it('blends the section title against the background in non-eink mode', () => {
|
||||
const { container } = render(<SectionInfo {...baseProps} isEink={false} />);
|
||||
const info = container.querySelector('.sectioninfo') as HTMLElement;
|
||||
|
||||
expect(info.classList.contains('mix-blend-difference')).toBe(true);
|
||||
expect(info.classList.contains('text-white/75')).toBe(true);
|
||||
// The theme-fixed neutral color is what made it unreadable on a white page.
|
||||
expect(info.classList.contains('text-neutral-content')).toBe(false);
|
||||
});
|
||||
|
||||
it('does not blend in eink mode (base-content text on the e-ink page)', () => {
|
||||
const { container } = render(<SectionInfo {...baseProps} isEink={true} />);
|
||||
const info = container.querySelector('.sectioninfo') as HTMLElement;
|
||||
|
||||
expect(info.classList.contains('mix-blend-difference')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -286,3 +286,51 @@ describe('ProgressBar — sticky progress bar', () => {
|
|||
expect(container.querySelector('.sticky-progress-bar')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('ProgressBar — contrast against the page (#4901)', () => {
|
||||
// A light-mode PDF under a dark theme keeps its white page while the footer
|
||||
// progress text stayed themed for the dark UI (neutral-content, light) and
|
||||
// became unreadable over the white page. Blending the text spans against the
|
||||
// real backdrop keeps the page number and remaining-pages text legible on
|
||||
// any background. StatusInfo (clock/battery) is intentionally left alone — it
|
||||
// manages its own blend against the battery glyph.
|
||||
it('blends the progress and remaining text against the background in non-eink mode', () => {
|
||||
currentViewSettings = {
|
||||
...baseSettings,
|
||||
isEink: false,
|
||||
showRemainingPages: true,
|
||||
showRemainingTime: false,
|
||||
progressInfoMode: 'all',
|
||||
} as ViewSettings;
|
||||
currentProgress = makeProgress(2, 5);
|
||||
currentBookData = { isFixedLayout: false };
|
||||
currentRenderer = { page: 1, pages: 4 };
|
||||
|
||||
const { container } = renderProgressBar();
|
||||
|
||||
const progress = container.querySelector('.progress-info') as HTMLElement;
|
||||
const remaining = container.querySelector('.remaining-info') as HTMLElement;
|
||||
expect(progress.classList.contains('mix-blend-difference')).toBe(true);
|
||||
expect(progress.classList.contains('text-white/75')).toBe(true);
|
||||
expect(remaining.classList.contains('mix-blend-difference')).toBe(true);
|
||||
expect(remaining.classList.contains('text-white/75')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not blend in eink mode', () => {
|
||||
currentViewSettings = {
|
||||
...baseSettings,
|
||||
isEink: true,
|
||||
showRemainingPages: true,
|
||||
showRemainingTime: false,
|
||||
progressInfoMode: 'all',
|
||||
} as ViewSettings;
|
||||
currentProgress = makeProgress(2, 5);
|
||||
currentBookData = { isFixedLayout: false };
|
||||
currentRenderer = { page: 1, pages: 4 };
|
||||
|
||||
const { container } = renderProgressBar();
|
||||
|
||||
const progress = container.querySelector('.progress-info') as HTMLElement;
|
||||
expect(progress.classList.contains('mix-blend-difference')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -287,6 +287,9 @@ const ProgressBar: React.FC<ProgressBarProps> = ({
|
|||
'remaining-info whitespace-nowrap text-start',
|
||||
!stickyBarActive && 'flex-1',
|
||||
showStatusInfo && 'overflow-hidden',
|
||||
// Keep the text legible on any backdrop (e.g. a light PDF page
|
||||
// under a dark theme, #4901); blend it against what's behind.
|
||||
!isEink && 'text-white/75 mix-blend-difference',
|
||||
)}
|
||||
>
|
||||
{viewSettings.showRemainingTime ? (
|
||||
|
|
@ -346,6 +349,9 @@ const ProgressBar: React.FC<ProgressBarProps> = ({
|
|||
className={clsx(
|
||||
'progress-info items-center overflow-hidden whitespace-nowrap text-end tabular-nums',
|
||||
!stickyBarActive && 'flex-1',
|
||||
// Keep the page number legible on any backdrop (e.g. a light PDF
|
||||
// page under a dark theme, #4901); blend it against what's behind.
|
||||
!isEink && 'text-white/75 mix-blend-difference',
|
||||
)}
|
||||
>
|
||||
{(progressBarMode === 'all' || progressBarMode.includes('progress')) && (
|
||||
|
|
|
|||
|
|
@ -75,7 +75,13 @@ const SectionInfo: React.FC<SectionInfoProps> = ({
|
|||
<div
|
||||
className={clsx(
|
||||
'sectioninfo absolute flex items-center overflow-hidden font-sans',
|
||||
isEink ? 'text-sm font-normal' : 'text-neutral-content text-xs font-light',
|
||||
// A light-mode PDF stays white under a dark theme, so the themed
|
||||
// neutral-content title was unreadable on the page (#4901). Blend the
|
||||
// text against whatever is actually behind it (page or margin) so it
|
||||
// stays legible on any background. text-white/75 matches the previous
|
||||
// neutral-content brightness over the dark theme, so nothing changes
|
||||
// for reflowable books. E-ink keeps its plain base-content text.
|
||||
isEink ? 'text-sm font-normal' : 'text-white/75 mix-blend-difference text-xs font-light',
|
||||
isVertical ? 'writing-vertical-rl max-h-[85%]' : 'top-0',
|
||||
)}
|
||||
role='none'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue