Refactor layout accommodation using traffic light status

This commit is contained in:
chrox
2024-11-12 13:39:41 +01:00
parent 26ca5849aa
commit ebe28dcd66
10 changed files with 74 additions and 52 deletions
@@ -4,8 +4,7 @@ import { FaSearch } from 'react-icons/fa';
import { PiPlus } from 'react-icons/pi';
import { PiSelectionAllDuotone } from 'react-icons/pi';
import { useEnv } from '@/context/EnvContext';
import useFullScreen from '@/hooks/useFullScreen';
import useTrafficLight from '@/hooks/useTrafficLight';
import WindowButtons from '@/components/WindowButtons';
interface LibraryHeaderProps {
@@ -19,8 +18,7 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
onImportBooks,
onToggleSelectMode,
}) => {
const { appService } = useEnv();
const { isFullScreen } = useFullScreen();
const { isTrafficLightVisible } = useTrafficLight();
const headerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
@@ -55,7 +53,7 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
ref={headerRef}
className={clsx(
'titlebar fixed z-10 w-full bg-gray-100 py-2 pr-6',
isFullScreen ? 'pl-2' : 'pl-16',
isTrafficLightVisible ? 'pl-16' : 'pl-2',
)}
>
<div className='flex items-center justify-between'>
@@ -93,14 +91,15 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
</button>
</div>
</div>
{!appService?.isNativeWindow && (
<WindowButtons
headerRef={headerRef}
onMinimize={handleMinimize}
onToggleMaximize={handleToggleMaximize}
onClose={handleClose}
/>
)}
<WindowButtons
headerRef={headerRef}
showMinimize={!isTrafficLightVisible}
showMaximize={!isTrafficLightVisible}
showClose={!isTrafficLightVisible}
onMinimize={handleMinimize}
onToggleMaximize={handleToggleMaximize}
onClose={handleClose}
/>
</div>
</div>
);
@@ -3,7 +3,7 @@ import React, { useRef, useState } from 'react';
import { PiDotsThreeVerticalBold } from 'react-icons/pi';
import { useReaderStore } from '@/store/readerStore';
import useFullScreen from '@/hooks/useFullScreen';
import useTrafficLight from '@/hooks/useTrafficLight';
import WindowButtons from '@/components/WindowButtons';
import Dropdown from '@/components/Dropdown';
import SidebarToggler from './SidebarToggler';
@@ -29,7 +29,7 @@ const HeaderBar: React.FC<HeaderBarProps> = ({
onSetSettingsDialogOpen,
}) => {
const headerRef = useRef<HTMLDivElement>(null);
const { isFullScreen } = useFullScreen();
const { isTrafficLightVisible } = useTrafficLight();
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const { hoveredBookKey, isSideBarVisible, setHoveredBookKey } = useReaderStore();
@@ -43,7 +43,7 @@ const HeaderBar: React.FC<HeaderBarProps> = ({
ref={headerRef}
className={clsx(
`header-bar absolute top-0 z-10 flex h-11 w-full items-center pr-4`,
!isFullScreen && isTopLeft && !isSideBarVisible ? 'pl-16' : 'pl-4',
isTrafficLightVisible && isTopLeft && !isSideBarVisible ? 'pl-16' : 'pl-4',
`shadow-xs bg-base-100 rounded-window-top-right transition-opacity duration-300`,
!isSideBarVisible && 'rounded-window-top-left',
isHoveredAnim && 'hover-bar-anim',
@@ -1,7 +1,9 @@
import { useReaderStore } from '@/store/readerStore';
import clsx from 'clsx';
import React from 'react';
import { useReaderStore } from '@/store/readerStore';
import useTrafficLight from '@/hooks/useTrafficLight';
interface SectionInfoProps {
chapter?: string;
gapLeft: string;
@@ -9,11 +11,12 @@ interface SectionInfoProps {
const SectionInfo: React.FC<SectionInfoProps> = ({ chapter, gapLeft }) => {
const { isSideBarVisible } = useReaderStore();
const { isTrafficLightVisible } = useTrafficLight();
return (
<div
className={clsx(
'pageinfo absolute right-0 top-0 flex items-end',
isSideBarVisible ? 'h-[30px]' : 'h-[44px]',
isTrafficLightVisible && !isSideBarVisible ? 'h-[44px]' : 'h-[30px]',
)}
style={{ left: gapLeft }}
>
@@ -4,7 +4,7 @@ import { GiBookshelf } from 'react-icons/gi';
import { FiSearch } from 'react-icons/fi';
import { MdOutlineMenu, MdOutlinePushPin, MdPushPin } from 'react-icons/md';
import useFullScreen from '@/hooks/useFullScreen';
import useTrafficLight from '@/hooks/useTrafficLight';
import Dropdown from '@/components/Dropdown';
import BookMenu from './BookMenu';
@@ -14,12 +14,12 @@ const SidebarHeader: React.FC<{
onOpenSplitView: () => void;
handleTogglePin: () => void;
}> = ({ isPinned, onGoToLibrary, onOpenSplitView, handleTogglePin }) => {
const { isFullScreen } = useFullScreen();
const { isTrafficLightVisible } = useTrafficLight();
return (
<div
className={clsx(
'sidebar-header flex h-11 items-center justify-between pr-2',
isFullScreen ? 'pl-1.5' : 'pl-20',
isTrafficLightVisible ? 'pl-20' : 'pl-1.5',
)}
>
<div className='flex items-center'>
@@ -70,7 +70,11 @@ const WindowButtons: React.FC<WindowButtonsProps> = ({
return (
<div
ref={parentRef}
className={clsx('window-buttons ml-6 flex h-8 items-center justify-end space-x-2', className)}
className={clsx(
'window-buttons flex h-8 items-center justify-end space-x-2 pl-6',
showClose || showMaximize || showMinimize ? 'visible' : 'hidden',
className,
)}
>
{showMinimize && (
<button
@@ -1,27 +0,0 @@
import { useEffect, useState } from 'react';
const useFullScreen = () => {
const [isFullScreen, setIsFullScreen] = useState(false);
const handleSwitchFullScreen = async () => {
const { getCurrentWindow } = await import('@tauri-apps/api/window');
const currentWindow = getCurrentWindow();
currentWindow.listen('will-enter-fullscreen', () => {
console.log('Window entered fullscreen');
setIsFullScreen(true);
});
currentWindow.listen('will-exit-fullscreen', () => {
console.log('Window exited fullscreen');
setIsFullScreen(false);
});
};
useEffect(() => {
handleSwitchFullScreen();
}, []);
return { isFullScreen };
};
export default useFullScreen;
@@ -0,0 +1,43 @@
import { useEffect, useState } from 'react';
import { useEnv } from '@/context/EnvContext';
/**
* Custom hook to get the visibility of the traffic light (window control buttons on macOS)
* based on the fullscreen state of the application window.
*
* @returns {Object} An object containing:
* - `isTrafficLightVisible` (boolean): A state indicating whether the traffic light is visible.
*/
const useTrafficLight = () => {
const { appService } = useEnv();
const [isTrafficLightVisible, setVisible] = useState(appService?.hasTrafficLight ?? false);
let unlistenEnterFullScreen: () => void;
let unlistenExitFullScreen: () => void;
const handleSwitchFullScreen = async () => {
const { getCurrentWindow } = await import('@tauri-apps/api/window');
const currentWindow = getCurrentWindow();
const isFullscreen = await currentWindow.isFullscreen();
if (appService?.hasTrafficLight) setVisible(!isFullscreen);
unlistenEnterFullScreen = await currentWindow.listen('will-enter-fullscreen', () => {
if (appService?.hasTrafficLight) setVisible(false);
});
unlistenExitFullScreen = await currentWindow.listen('will-exit-fullscreen', () => {
if (appService?.hasTrafficLight) setVisible(true);
});
};
useEffect(() => {
handleSwitchFullScreen();
return () => {
unlistenEnterFullScreen?.();
unlistenExitFullScreen?.();
};
}, []);
return { isTrafficLightVisible };
};
export default useTrafficLight;
+1 -1
View File
@@ -26,7 +26,7 @@ import {
export abstract class BaseAppService implements AppService {
localBooksDir: string = '';
abstract isAppDataSandbox: boolean;
abstract isNativeWindow: boolean;
abstract hasTrafficLight: boolean;
abstract fs: FileSystem;
abstract resolvePath(fp: string, base: BaseDir): { baseDir: number; base: BaseDir; fp: string };
@@ -115,7 +115,7 @@ export const nativeFileSystem: FileSystem = {
export class NativeAppService extends BaseAppService {
fs = nativeFileSystem;
isAppDataSandbox = isMobile;
isNativeWindow = osType() === 'macos';
hasTrafficLight = osType() === 'macos';
override resolvePath(fp: string, base: BaseDir): { baseDir: number; base: BaseDir; fp: string } {
return resolvePath(fp, base);
+1 -1
View File
@@ -18,7 +18,7 @@ export interface FileSystem {
export interface AppService {
fs: FileSystem;
isNativeWindow: boolean;
hasTrafficLight: boolean;
isAppDataSandbox: boolean;
selectDirectory(title: string): Promise<string>;