mobile: responsive font size in UI (#227)

This commit is contained in:
Huang Xin
2025-01-23 10:36:03 +01:00
committed by GitHub
parent 369d894557
commit 475bab24c5
10 changed files with 43 additions and 21 deletions
@@ -2,6 +2,7 @@ import React from 'react';
import { MdCheck } from 'react-icons/md';
import { useSettingsStore } from '@/store/settingsStore';
import { useTranslation } from '@/hooks/useTranslation';
import { useDefaultIconSize } from '@/hooks/useResponsiveSize';
interface DialogMenuProps {
toggleDropdown?: () => void;
@@ -9,6 +10,7 @@ interface DialogMenuProps {
const DialogMenu: React.FC<DialogMenuProps> = ({ toggleDropdown }) => {
const _ = useTranslation();
const iconSize = useDefaultIconSize();
const { isFontLayoutSettingsGlobal, setFontLayoutSettingsGlobal } = useSettingsStore();
const handleToggleGlobal = () => {
@@ -26,7 +28,7 @@ const DialogMenu: React.FC<DialogMenuProps> = ({ toggleDropdown }) => {
onClick={handleToggleGlobal}
>
<div className='flex items-center'>
<span style={{ minWidth: '20px' }}>
<span style={{ minWidth: `${iconSize}px` }}>
{isFontLayoutSettingsGlobal && <MdCheck className='text-base-content' />}
</span>
<div
@@ -3,7 +3,7 @@ import React from 'react';
import { FiChevronUp, FiChevronLeft } from 'react-icons/fi';
import { MdCheck } from 'react-icons/md';
import { useTranslation } from '@/hooks/useTranslation';
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
import { useDefaultIconSize, useResponsiveSize } from '@/hooks/useResponsiveSize';
interface DropdownProps {
family?: string;
@@ -24,6 +24,7 @@ const FontDropdown: React.FC<DropdownProps> = ({
}) => {
const _ = useTranslation();
const iconSize16 = useResponsiveSize(16);
const defaultIconSize = useDefaultIconSize();
return (
<div className='dropdown dropdown-top'>
<button
@@ -40,7 +41,7 @@ const FontDropdown: React.FC<DropdownProps> = ({
{options.map((option) => (
<li key={option} onClick={() => onSelect(option)}>
<div className='flex items-center px-0'>
<span style={{ minWidth: '20px' }}>
<span style={{ minWidth: `${defaultIconSize}px` }}>
{selected === option && <MdCheck className='text-base-content' />}
</span>
<span style={{ fontFamily: onGetFontFamily(option, family ?? '') }}>{option}</span>
@@ -50,7 +51,7 @@ const FontDropdown: React.FC<DropdownProps> = ({
{moreOptions && moreOptions.length > 0 && (
<li className='dropdown dropdown-left dropdown-top'>
<div className='flex items-center px-0'>
<span style={{ minWidth: '20px' }}>
<span style={{ minWidth: `${iconSize16}px` }}>
<FiChevronLeft size={iconSize16} />
</span>
<span>{_('System Fonts')}</span>
@@ -65,7 +66,7 @@ const FontDropdown: React.FC<DropdownProps> = ({
{moreOptions.map((option) => (
<li key={option} onClick={() => onSelect(option)}>
<div className='flex items-center px-2'>
<span style={{ minWidth: '20px' }}>
<span style={{ minWidth: `${defaultIconSize}px` }}>
{selected === option && <MdCheck className='text-base-content' />}
</span>
<span style={{ fontFamily: onGetFontFamily(option, family ?? '') }}>
@@ -135,7 +135,7 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
>
<div className='relative p-1'>
<textarea
className='textarea textarea-ghost h-48 w-full border-0 p-3 !outline-none'
className='textarea textarea-ghost h-48 w-full border-0 p-3 text-base !outline-none sm:text-sm'
placeholder={_('Enter your custom CSS here...')}
spellCheck='false'
value={draftStylesheet}
@@ -68,8 +68,8 @@ const SidebarContent: React.FC<{
<>
<div
className={clsx(
'sidebar-content flex min-h-0 flex-grow flex-col',
'font-sans text-sm font-normal shadow-inner',
'sidebar-content flex min-h-0 flex-grow flex-col shadow-inner',
'font-sans text-base font-normal sm:text-sm',
)}
>
<div
@@ -29,7 +29,7 @@ const SidebarHeader: React.FC<{
isTrafficLightVisible ? 'pl-20' : 'pl-1.5',
)}
>
<div className='flex items-center gap-x-4'>
<div className='flex items-center gap-x-8'>
<button
onClick={onClose}
className={'btn btn-ghost btn-circle flex h-6 min-h-6 w-6 hover:bg-transparent sm:hidden'}
@@ -2,6 +2,7 @@ import React from 'react';
import { MdCheck } from 'react-icons/md';
import { BookSearchConfig } from '@/types/book';
import { useTranslation } from '@/hooks/useTranslation';
import { useDefaultIconSize } from '@/hooks/useResponsiveSize';
interface SearchOptionsProps {
searchConfig: BookSearchConfig;
@@ -21,7 +22,7 @@ const Option: React.FC<OptionProps> = ({ label, isActive, onClick }) => (
onClick={onClick}
>
<div className='flex items-center'>
<span style={{ minWidth: '20px' }}>
<span style={{ minWidth: `${useDefaultIconSize()}px` }}>
{isActive && <MdCheck className='text-base-content' />}
</span>
<span className='ml-2'>{label}</span>
@@ -183,9 +183,13 @@ const TTSControl = () => {
throttle(async (rate: number) => {
const ttsController = ttsControllerRef.current;
if (ttsController) {
await ttsController.stop();
await ttsController.setRate(rate);
await ttsController.start();
if (ttsController.state === 'playing') {
await ttsController.stop();
await ttsController.setRate(rate);
await ttsController.start();
} else {
await ttsController.setRate(rate);
}
}
}, 3000),
[],
@@ -196,9 +200,13 @@ const TTSControl = () => {
throttle(async (voice: string) => {
const ttsController = ttsControllerRef.current;
if (ttsController) {
await ttsController.stop();
await ttsController.setVoice(voice);
await ttsController.start();
if (ttsController.state === 'playing') {
await ttsController.stop();
await ttsController.setVoice(voice);
await ttsController.start();
} else {
await ttsController.setVoice(voice);
}
}
}, 3000),
[],
@@ -6,7 +6,7 @@ import { MdPlayCircle, MdPauseCircle, MdFastRewind, MdFastForward, MdStop } from
import { RiVoiceAiFill } from 'react-icons/ri';
import { MdCheck } from 'react-icons/md';
import { TTSVoice } from '@/services/tts';
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
import { useDefaultIconSize, useResponsiveSize } from '@/hooks/useResponsiveSize';
type TTSPanelProps = {
bookKey: string;
@@ -43,6 +43,7 @@ const TTSPanel = ({
const [rate, setRate] = useState(viewSettings?.ttsRate ?? 1.0);
const [selectedVoice, setSelectedVoice] = useState(viewSettings?.ttsVoice ?? '');
const defaultIconSize = useDefaultIconSize();
const iconSize32 = useResponsiveSize(32);
const iconSize48 = useResponsiveSize(48);
@@ -144,10 +145,10 @@ const TTSPanel = ({
onClick={() => !voice.disabled && handleSelectVoice(voice.id)}
>
<div className='flex items-center px-2'>
<span style={{ minWidth: '20px' }}>
<span style={{ minWidth: `${defaultIconSize}px` }}>
{selectedVoice === voice.id && <MdCheck className='text-base-content' />}
</span>
<span className={clsx('text-sm', voice.disabled && 'text-gray-400')}>
<span className={clsx('text-base sm:text-sm', voice.disabled && 'text-gray-400')}>
{voice.name}
</span>
</div>
+4 -2
View File
@@ -1,5 +1,6 @@
import clsx from 'clsx';
import React from 'react';
import { useDefaultIconSize } from '@/hooks/useResponsiveSize';
interface MenuItemProps {
label: string;
@@ -22,6 +23,7 @@ const MenuItem: React.FC<MenuItemProps> = ({
children,
onClick,
}) => {
const iconSize = useDefaultIconSize();
const menuButton = (
<button
className={clsx(
@@ -32,10 +34,10 @@ const MenuItem: React.FC<MenuItemProps> = ({
disabled={disabled}
>
<div className='flex items-center'>
{!noIcon && <span style={{ minWidth: '20px' }}>{icon}</span>}
{!noIcon && <span style={{ minWidth: `${iconSize}px` }}>{icon}</span>}
<span className={clsx('ml-2 max-w-32 truncate', labelClass)}>{label}</span>
</div>
{shortcut && <span className='text-neutral-content text-sm'>{shortcut}</span>}
{shortcut && <span className='text-neutral-content hidden text-sm sm:flex'>{shortcut}</span>}
</button>
);
+7
View File
@@ -164,6 +164,13 @@ foliate-view {
font-weight: 400;
}
@media (max-width: 768px) {
.dropdown-content,
.settings-content {
font-size: 16px;
}
}
.config-item {
@apply flex h-14 items-center justify-between p-4;
@apply hover:bg-base-100/50;