mobile: fix annotator tools in iOS browsers (#239)

* chore: disable PWA in dev mode for better performance

* mobile: fix annotator tools in iOS browsers
This commit is contained in:
Huang Xin
2025-01-24 13:30:42 +01:00
committed by GitHub
parent 18dfd73bed
commit 942524c110
5 changed files with 36 additions and 27 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
import withPWA from 'next-pwa';
const isDev = process.env['NODE_ENV'] === 'development';
const appPlatform = process.env['NEXT_PUBLIC_APP_PLATFORM'];
/** @type {import('next').NextConfig} */
@@ -22,7 +23,7 @@ const nextConfig = {
export default withPWA({
dest: 'public',
disable: appPlatform !== 'web',
disable: isDev || appPlatform !== 'web',
register: true,
skipWaiting: true,
})(nextConfig);
@@ -4,6 +4,7 @@ import PopupButton from './PopupButton';
import HighlightOptions from './HighlightOptions';
import { Position } from '@/utils/sel';
import { HighlightColor, HighlightStyle } from '@/types/book';
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
interface AnnotationPopupProps {
buttons: Array<{ tooltipText: string; Icon: React.ElementType; onClick: () => void }>;
@@ -17,8 +18,8 @@ interface AnnotationPopupProps {
onHighlight: (update?: boolean) => void;
}
const highlightOptionsHeightPx = 28;
const highlightOptionsPaddingPx = 16;
const OPTIONS_HEIGHT_PIX = 28;
const OPTIONS_PADDING_PIX = 16;
const AnnotationPopup: React.FC<AnnotationPopupProps> = ({
buttons,
@@ -31,6 +32,8 @@ const AnnotationPopup: React.FC<AnnotationPopupProps> = ({
popupHeight,
onHighlight,
}) => {
const highlightOptionsHeightPx = useResponsiveSize(OPTIONS_HEIGHT_PIX);
const highlightOptionsPaddingPx = useResponsiveSize(OPTIONS_PADDING_PIX);
return (
<div>
<Popup
@@ -35,7 +35,6 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const { settings } = useSettingsStore();
const { getConfig, saveConfig, getBookData, updateBooknotes } = useBookDataStore();
const { getProgress, getView, getViewsById, getViewSettings } = useReaderStore();
const { isNotebookPinned, isNotebookVisible } = useNotebookStore();
const { setNotebookVisible, setNotebookNewAnnotation } = useNotebookStore();
useNotesSync(bookKey);
@@ -48,6 +47,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const isShowingPopup = useRef(false);
const isTextSelected = useRef(false);
const isClickToShowPopup = useRef(false);
const [selection, setSelection] = useState<TextSelection | null>();
const [showAnnotPopup, setShowAnnotPopup] = useState(false);
const [showWiktionaryPopup, setShowWiktionaryPopup] = useState(false);
@@ -86,8 +86,12 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
setSelection({ key: bookKey, text: sel.toString(), range: sel.getRangeAt(0), index });
}
};
const handleTouchmove = () => {
setShowAnnotPopup(false);
};
if (bookData.book?.format !== 'PDF') {
detail.doc?.addEventListener('pointerup', handlePointerup);
detail.doc?.addEventListener('touchmove', handleTouchmove);
}
};
@@ -116,6 +120,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const annotation = annotations.find((annotation) => annotation.cfi === cfi);
if (!annotation) return;
const selection = { key: bookKey, annotated: true, text: annotation.text ?? '', range, index };
isClickToShowPopup.current = true;
setSelectedStyle(annotation.style!);
setSelectedColor(annotation.color!);
setSelection(selection);
@@ -140,12 +145,16 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
useEffect(() => {
const handleSingleClick = (): boolean => {
if (isClickToShowPopup.current) {
isClickToShowPopup.current = false;
return true;
}
if (isTextSelected.current) {
view?.deselect();
isTextSelected.current = false;
handleDismissPopupAndSelection();
return true;
}
if (showAnnotPopup || isShowingPopup.current) {
handleDismissPopup();
return true;
}
return false;
@@ -229,7 +238,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
});
const { booknotes: annotations = [] } = config;
if (selection) navigator.clipboard.writeText(selection.text);
if (selection) navigator.clipboard?.writeText(selection.text);
const cfi = view?.getCFI(selection.index, selection.range);
if (!cfi) return;
const annotation: BookNote = {
@@ -363,14 +372,6 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
return (
<div>
{(showAnnotPopup || showWiktionaryPopup || showWikipediaPopup || showDeepLPopup) &&
(!isNotebookVisible || isNotebookPinned) && (
<div
className='fixed inset-0'
onClick={handleDismissPopupAndSelection}
onContextMenu={handleDismissPopup}
/>
)}
{showWiktionaryPopup && trianglePosition && dictPopupPosition && (
<WiktionaryPopup
word={selection?.text as string}
@@ -25,7 +25,9 @@ const HighlightOptions: React.FC<HighlightOptionsProps> = ({
const globalReadSettings = settings.globalReadSettings;
const [selectedStyle, setSelectedStyle] = React.useState<HighlightStyle>(_selectedStyle);
const [selectedColor, setSelectedColor] = React.useState<HighlightColor>(_selectedColor);
const iconSize16 = useResponsiveSize(16);
const size16 = useResponsiveSize(16);
const size18 = useResponsiveSize(18);
const size28 = useResponsiveSize(28);
const handleSelectStyle = (style: HighlightStyle) => {
globalReadSettings.highlightStyle = style;
@@ -42,18 +44,19 @@ const HighlightOptions: React.FC<HighlightOptionsProps> = ({
onHandleHighlight(true);
};
return (
<div className='highlight-options absolute flex h-7 items-center justify-between' style={style}>
<div className='flex h-7 gap-2'>
<div className='highlight-options absolute flex items-center justify-between' style={style}>
<div className='flex gap-2' style={{ height: size28 }}>
{styles.map((style) => (
<button
key={style}
onClick={() => handleSelectStyle(style)}
className={`flex h-7 min-h-7 w-7 items-center justify-center rounded-full bg-gray-700 p-0`}
className={`flex items-center justify-center rounded-full bg-gray-700 p-0`}
style={{ width: size28, height: size28, minHeight: size28 }}
>
<div
style={{ width: size16, height: style === 'squiggly' ? size18 : size16 }}
className={clsx(
'w-4 p-0 text-center leading-none',
style === 'highlight' ? 'h-4' : 'h-5',
style === 'highlight' &&
(selectedStyle === 'highlight' ? `bg-${selectedColor}-400` : `bg-gray-300`),
(style === 'underline' || style === 'squiggly') &&
@@ -74,18 +77,19 @@ const HighlightOptions: React.FC<HighlightOptionsProps> = ({
))}
</div>
<div className='flex h-7 items-center justify-center gap-2 rounded-3xl bg-gray-700 px-2'>
<div
className='flex items-center justify-center gap-2 rounded-3xl bg-gray-700 px-2'
style={{ height: size28 }}
>
{colors.map((color) => (
<button
key={color}
onClick={() => handleSelectColor(color)}
className={clsx(
`h-4 w-4 rounded-full p-0`,
selectedColor !== color && `bg-${color}-400`,
)}
style={{ width: size16, height: size16 }}
className={clsx(`rounded-full p-0`, selectedColor !== color && `bg-${color}-400`)}
>
{selectedColor === color && (
<FaCheckCircle size={iconSize16} className={clsx(`fill-${color}-400`)} />
<FaCheckCircle size={size16} className={clsx(`fill-${color}-400`)} />
)}
</button>
))}