From 7972de19090e05f5d6387d7547db080320893c3b Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Sun, 28 Jun 2026 22:13:42 +0800 Subject: [PATCH] fix(eink): render Customize Toolbar preview as bordered surface, not black bar (#4839) (#4841) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Customize Toolbar sub-page shows a content-width preview of the live selection popup, copying its bg-gray-600 text-white styling. Unlike the real reader popup (which gets its e-ink chrome from .popup-container in globals.css), the preview Zone is a plain div with no e-ink override, so under [data-eink='true'] the dark fill survived and the row painted as an unreadable solid black bar. Scope the dark fill to non-e-ink (not-eink:bg-gray-600 not-eink:text-white) and let eink-bordered render the preview in e-ink as the popup's e-ink chrome: a base-100 surface with a 1px base-content border. The chip icons already invert to base-content via the global [data-eink] button rule. Also fall the empty-state hint back to base-content in e-ink so it stays legible once the surface turns base-100. Verified via computed styles under [data-eink]: background oklch(1 0 0) (white), 1px oklch(0.2 0 0) border, dark icons — matching the reader's annotation toolbar. Co-authored-by: Claude Opus 4.8 (1M context) --- .../AnnotationToolbarCustomizerEink.test.tsx | 58 +++++++++++++++++++ .../settings/AnnotationToolbarCustomizer.tsx | 15 ++++- 2 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 apps/readest-app/src/__tests__/components/settings/AnnotationToolbarCustomizerEink.test.tsx diff --git a/apps/readest-app/src/__tests__/components/settings/AnnotationToolbarCustomizerEink.test.tsx b/apps/readest-app/src/__tests__/components/settings/AnnotationToolbarCustomizerEink.test.tsx new file mode 100644 index 00000000..9c8a5eaf --- /dev/null +++ b/apps/readest-app/src/__tests__/components/settings/AnnotationToolbarCustomizerEink.test.tsx @@ -0,0 +1,58 @@ +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { render, cleanup } from '@testing-library/react'; + +/** + * Regression guard for issue #4839 (display error under e-ink mode). + * + * The Customize Toolbar sub-page renders a content-width *preview* of the live + * selection popup. The preview surface uses `bg-gray-600 text-white` to mirror + * the real popup — but unlike the real popup (which earns its e-ink treatment + * from `.popup-container` in globals.css), the preview Zone is a plain div. With + * no e-ink override, the dark fill survives under `[data-eink='true']` and the + * whole row paints as an unreadable solid black bar. + * + * Invariant: the toolbar preview must carry `eink-bordered`, so e-ink swaps the + * dark fill for a `base-100` surface with a 1px `base-content` border — matching + * how the annotation toolbar renders in the reader. + */ + +vi.mock('@/context/EnvContext', () => ({ + useEnv: () => ({ envConfig: {}, appService: {} }), +})); + +vi.mock('@/hooks/useTranslation', () => ({ + useTranslation: () => (s: string) => s, +})); + +vi.mock('@/store/readerStore', () => ({ + useReaderStore: () => ({ getViewSettings: () => undefined }), +})); + +vi.mock('@/store/settingsStore', () => ({ + useSettingsStore: () => ({ + settings: { globalViewSettings: { annotationToolbarItems: undefined } }, + }), +})); + +vi.mock('@/helpers/settings', () => ({ + saveViewSettings: vi.fn(), +})); + +vi.mock('@/utils/share', () => ({ + canShareText: () => true, +})); + +import AnnotationToolbarCustomizer from '@/components/settings/AnnotationToolbarCustomizer'; + +afterEach(() => { + cleanup(); +}); + +describe('AnnotationToolbarCustomizer e-ink toolbar preview', () => { + it('marks the toolbar preview eink-bordered so e-ink swaps the dark fill for a bordered base-100 surface', () => { + const { container } = render( {}} />); + const toolbarPreview = container.querySelector('.selection-popup') as HTMLElement; + expect(toolbarPreview).not.toBeNull(); + expect(toolbarPreview.classList.contains('eink-bordered')).toBe(true); + }); +}); diff --git a/apps/readest-app/src/components/settings/AnnotationToolbarCustomizer.tsx b/apps/readest-app/src/components/settings/AnnotationToolbarCustomizer.tsx index 812c6c5f..ca32ab49 100644 --- a/apps/readest-app/src/components/settings/AnnotationToolbarCustomizer.tsx +++ b/apps/readest-app/src/components/settings/AnnotationToolbarCustomizer.tsx @@ -113,14 +113,23 @@ const Zone: React.FC<{ 'flex min-h-12 flex-wrap items-center gap-2 rounded-lg p-2', isToolbar ? // A faithful, content-width preview of the real popup, start-aligned - // with the Available row below it. - 'selection-popup bg-gray-600 text-white w-fit max-w-full' + // with the Available row below it. Off e-ink it mirrors the popup's + // dark fill; in e-ink the dark fill is dropped entirely and + // `eink-bordered` renders it as the popup's e-ink chrome instead + // (.popup-container): a base-100 surface with a 1px base-content + // border, so it doesn't paint as a solid black bar (#4839). + 'selection-popup eink-bordered w-fit max-w-full not-eink:bg-gray-600 not-eink:text-white' : 'bg-base-200/60', )} > {items.length === 0 ? ( {emptyHint}