forked from akai/readest
fix(reader): show full bookmark ribbon in scrolled mode header (#4365)
In scrolled mode, SectionInfo paints a solid `bg-base-100` `notch-area` mask over the top safe-area strip at z-10. The Ribbon was also z-10 but rendered earlier in the DOM, so the equal-z mask painted over the ribbon's upper (unsafe-area) half — only the lower 44px showed. In paginated mode the mask has no background, so the ribbon showed fully. Raise the ribbon to z-20 so the whole ribbon stays visible above the mask, and mark it pointer-events-none so taps still fall through to the notch mask's scroll-to-top handler. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render } from '@testing-library/react';
|
||||
import Ribbon from '@/app/reader/components/Ribbon';
|
||||
|
||||
vi.mock('@/store/themeStore', () => ({
|
||||
useThemeStore: () => ({ safeAreaInsets: { top: 48, right: 0, bottom: 0, left: 0 } }),
|
||||
}));
|
||||
|
||||
describe('Ribbon', () => {
|
||||
it('stacks above the scrolled-mode notch mask so the full ribbon stays visible', () => {
|
||||
// In scrolled mode SectionInfo paints a `bg-base-100` `notch-area` mask over the
|
||||
// top safe-area strip at z-10. The ribbon renders earlier in the DOM, so it must
|
||||
// sit on a higher layer than z-10 or its upper (unsafe-area) half gets covered.
|
||||
const { container } = render(<Ribbon width='5%' />);
|
||||
const ribbon = container.querySelector('.ribbon') as HTMLElement;
|
||||
|
||||
expect(ribbon).not.toBeNull();
|
||||
expect(ribbon.classList.contains('z-10')).toBe(false);
|
||||
expect(ribbon.classList.contains('z-20')).toBe(true);
|
||||
// Decorative only: taps must fall through to the notch mask's scroll-to-top.
|
||||
expect(ribbon.classList.contains('pointer-events-none')).toBe(true);
|
||||
});
|
||||
|
||||
it('spans the safe-area inset plus the header bar height', () => {
|
||||
const { container } = render(<Ribbon width='5%' />);
|
||||
const ribbon = container.querySelector('.ribbon') as HTMLElement;
|
||||
|
||||
expect(ribbon.style.height).toBe('92px'); // 48px safe-area top + 44px header bar
|
||||
});
|
||||
});
|
||||
@@ -9,9 +9,13 @@ interface RibbonProps {
|
||||
const Ribbon: React.FC<RibbonProps> = ({}) => {
|
||||
const { safeAreaInsets } = useThemeStore();
|
||||
|
||||
// z-20 keeps the ribbon above the scrolled-mode `notch-area` mask (z-10 in
|
||||
// SectionInfo) so its upper safe-area half isn't covered.
|
||||
return (
|
||||
<div
|
||||
className={clsx('ribbon absolute inset-0 z-10 flex w-8 justify-center sm:w-6')}
|
||||
className={clsx(
|
||||
'ribbon pointer-events-none absolute inset-0 z-20 flex w-8 justify-center sm:w-6',
|
||||
)}
|
||||
style={{
|
||||
height: `${(safeAreaInsets?.top || 0) + 44}px`,
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user