Files
readest/apps/readest-app/src/app/reader/components/ViewMenu.tsx
T
Huang Xin 693c79c9b7 fix: remove seldomly used option to invert colors in dark mode (#548)
This option is hard to understand and explain. Most hardcoded color
in dark mode that affects readability has already been fixed in the
reader so there is no necessity to have this option.
2025-03-09 17:02:01 +01:00

154 lines
5.0 KiB
TypeScript

import clsx from 'clsx';
import React, { useEffect } from 'react';
import { useState } from 'react';
import { BiMoon, BiSun } from 'react-icons/bi';
import { TbSunMoon } from 'react-icons/tb';
import { MdZoomOut, MdZoomIn, MdCheck } from 'react-icons/md';
import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL, ZOOM_STEP } from '@/services/constants';
import { useEnv } from '@/context/EnvContext';
import { useThemeStore } from '@/store/themeStore';
import { useReaderStore } from '@/store/readerStore';
import { useTranslation } from '@/hooks/useTranslation';
import { ThemeMode } from '@/styles/themes';
import { getStyles } from '@/utils/style';
import { getMaxInlineSize } from '@/utils/config';
import { tauriHandleToggleFullScreen } from '@/utils/window';
import MenuItem from '@/components/MenuItem';
interface ViewMenuProps {
bookKey: string;
setIsDropdownOpen?: (open: boolean) => void;
onSetSettingsDialogOpen: (open: boolean) => void;
}
const ViewMenu: React.FC<ViewMenuProps> = ({
bookKey,
setIsDropdownOpen,
onSetSettingsDialogOpen,
}) => {
const _ = useTranslation();
const { appService } = useEnv();
const { getView, getViews, getViewSettings, setViewSettings } = useReaderStore();
const viewSettings = getViewSettings(bookKey)!;
const { themeMode, themeCode, setThemeMode } = useThemeStore();
const [isScrolledMode, setScrolledMode] = useState(viewSettings!.scrolled);
const [zoomLevel, setZoomLevel] = useState(viewSettings!.zoomLevel!);
const zoomIn = () => setZoomLevel((prev) => Math.min(prev + ZOOM_STEP, MAX_ZOOM_LEVEL));
const zoomOut = () => setZoomLevel((prev) => Math.max(prev - ZOOM_STEP, MIN_ZOOM_LEVEL));
const resetZoom = () => setZoomLevel(100);
const toggleScrolledMode = () => setScrolledMode(!isScrolledMode);
const openFontLayoutMenu = () => {
setIsDropdownOpen?.(false);
onSetSettingsDialogOpen(true);
};
const cycleThemeMode = () => {
const nextMode: ThemeMode =
themeMode === 'auto' ? 'light' : themeMode === 'light' ? 'dark' : 'auto';
setThemeMode(nextMode);
};
const handleFullScreen = () => {
tauriHandleToggleFullScreen();
setIsDropdownOpen?.(false);
};
useEffect(() => {
getViews().forEach((view) => {
view.renderer.setStyles?.(getStyles(viewSettings!));
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [themeCode]);
useEffect(() => {
viewSettings!.scrolled = isScrolledMode;
getView(bookKey)?.renderer.setAttribute('flow', isScrolledMode ? 'scrolled' : 'paginated');
getView(bookKey)?.renderer.setAttribute(
'max-inline-size',
`${getMaxInlineSize(viewSettings)}px`,
);
getView(bookKey)?.renderer.setStyles?.(getStyles(viewSettings!));
setViewSettings(bookKey, viewSettings!);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isScrolledMode]);
useEffect(() => {
const view = getView(bookKey);
if (!view) return;
viewSettings!.zoomLevel = zoomLevel;
setViewSettings(bookKey, viewSettings!);
view.renderer.setStyles?.(getStyles(viewSettings!));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [zoomLevel]);
return (
<div
tabIndex={0}
className='view-menu dropdown-content bgcolor-base-200 dropdown-right no-triangle border-base-200 z-20 mt-1 w-72 border shadow-2xl'
>
<div className={clsx('flex items-center justify-between rounded-md')}>
<button
onClick={zoomOut}
className={clsx(
'hover:bg-base-300 text-base-content rounded-full p-2',
zoomLevel <= MIN_ZOOM_LEVEL && 'btn-disabled text-gray-400',
)}
>
<MdZoomOut />
</button>
<button
className={clsx(
'hover:bg-base-300 text-base-content h-8 min-h-8 w-[50%] rounded-md p-1 text-center',
)}
onClick={resetZoom}
>
{zoomLevel}%
</button>
<button
onClick={zoomIn}
className={clsx(
'hover:bg-base-300 text-base-content rounded-full p-2',
zoomLevel >= MAX_ZOOM_LEVEL && 'btn-disabled text-gray-400',
)}
>
<MdZoomIn />
</button>
</div>
<hr className='border-base-300 my-1' />
<MenuItem label={_('Font & Layout')} shortcut='Shift+F' onClick={openFontLayoutMenu} />
<MenuItem
label={_('Scrolled Mode')}
shortcut='Shift+J'
icon={isScrolledMode ? <MdCheck /> : undefined}
onClick={toggleScrolledMode}
/>
<hr className='border-base-300 my-1' />
{appService?.hasRoundedWindow && (
<MenuItem label={_('Fullscreen')} onClick={handleFullScreen} />
)}
<MenuItem
label={
themeMode === 'dark'
? _('Dark Mode')
: themeMode === 'light'
? _('Light Mode')
: _('Auto Mode')
}
icon={themeMode === 'dark' ? <BiMoon /> : themeMode === 'light' ? <BiSun /> : <TbSunMoon />}
onClick={cycleThemeMode}
/>
</div>
);
};
export default ViewMenu;