From 2ff10f781f776643e446d7f100481d1ead9233e4 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Wed, 7 Jan 2026 16:18:57 +0100 Subject: [PATCH] feat(annotator): support vertical layout for annotation editor (#2882) --- .../public/locales/ar/translation.json | 3 +- .../public/locales/bn/translation.json | 3 +- .../public/locales/bo/translation.json | 3 +- .../public/locales/de/translation.json | 3 +- .../public/locales/el/translation.json | 3 +- .../public/locales/es/translation.json | 3 +- .../public/locales/fa/translation.json | 3 +- .../public/locales/fr/translation.json | 3 +- .../public/locales/hi/translation.json | 3 +- .../public/locales/id/translation.json | 3 +- .../public/locales/it/translation.json | 3 +- .../public/locales/ja/translation.json | 3 +- .../public/locales/ko/translation.json | 3 +- .../public/locales/ms/translation.json | 3 +- .../public/locales/nl/translation.json | 3 +- .../public/locales/pl/translation.json | 3 +- .../public/locales/pt/translation.json | 3 +- .../public/locales/ru/translation.json | 3 +- .../public/locales/si/translation.json | 3 +- .../public/locales/sv/translation.json | 3 +- .../public/locales/ta/translation.json | 3 +- .../public/locales/th/translation.json | 3 +- .../public/locales/tr/translation.json | 3 +- .../public/locales/uk/translation.json | 3 +- .../public/locales/vi/translation.json | 3 +- .../public/locales/zh-CN/translation.json | 3 +- .../public/locales/zh-TW/translation.json | 3 +- .../components/annotator/AnnotationNotes.tsx | 22 +++++--- .../components/annotator/AnnotationPopup.tsx | 7 ++- .../annotator/AnnotationRangeEditor.tsx | 54 +++++++++++++------ .../reader/components/annotator/Annotator.tsx | 1 + .../components/annotator/QuickActionMenu.tsx | 19 ++++++- .../app/reader/hooks/useAnnotationEditor.ts | 10 ++-- 33 files changed, 137 insertions(+), 57 deletions(-) diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index 7599f034..a595f99a 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -874,5 +874,6 @@ "Annotations": "التعليقات التوضيحية", "Show Results": "عرض النتائج", "Clear search": "مسح البحث", - "Clear search history": "مسح سجل البحث" + "Clear search history": "مسح سجل البحث", + "Quick action disabled": "الإجراء السريع معطل" } diff --git a/apps/readest-app/public/locales/bn/translation.json b/apps/readest-app/public/locales/bn/translation.json index c299d227..64e5809f 100644 --- a/apps/readest-app/public/locales/bn/translation.json +++ b/apps/readest-app/public/locales/bn/translation.json @@ -834,5 +834,6 @@ "Annotations": "টীকা", "Show Results": "ফলাফল দেখুন", "Clear search": "অনুসন্ধান সাফ করুন", - "Clear search history": "অনুসন্ধান ইতিহাস সাফ করুন" + "Clear search history": "অনুসন্ধান ইতিহাস সাফ করুন", + "Quick action disabled": "দ্রুত কার্যক্রম অক্ষম" } diff --git a/apps/readest-app/public/locales/bo/translation.json b/apps/readest-app/public/locales/bo/translation.json index 26fc83ec..3c820551 100644 --- a/apps/readest-app/public/locales/bo/translation.json +++ b/apps/readest-app/public/locales/bo/translation.json @@ -824,5 +824,6 @@ "Annotations": "མཆན།", "Show Results": "འབྲས་བུ་སྟོན།", "Clear search": "འཚོལ་བཤེར་གཙང་སེལ།", - "Clear search history": "འཚོལ་བཤེར་ལོ་རྒྱུས་གཙང་སེལ།" + "Clear search history": "འཚོལ་བཤེར་ལོ་རྒྱུས་གཙང་སེལ།", + "Quick action disabled": "མྱུར་མགྱོགས་བྱ་འགུལ་བཀག་འགོག" } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 5a8c3a66..b0e3004b 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -834,5 +834,6 @@ "Annotations": "Anmerkungen", "Show Results": "Ergebnisse anzeigen", "Clear search": "Suche löschen", - "Clear search history": "Suchverlauf löschen" + "Clear search history": "Suchverlauf löschen", + "Quick action disabled": "Schnellaktion deaktiviert" } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index d8df8e59..a077b700 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -834,5 +834,6 @@ "Annotations": "Σχολιασμοί", "Show Results": "Εμφάνιση αποτελεσμάτων", "Clear search": "Εκκαθάριση αναζήτησης", - "Clear search history": "Εκκαθάριση ιστορικού αναζήτησης" + "Clear search history": "Εκκαθάριση ιστορικού αναζήτησης", + "Quick action disabled": "Η γρήγορη ενέργεια απενεργοποιήθηκε" } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index a0729204..cfd67965 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -844,5 +844,6 @@ "Annotations": "Anotaciones", "Show Results": "Mostrar resultados", "Clear search": "Borrar búsqueda", - "Clear search history": "Borrar historial de búsqueda" + "Clear search history": "Borrar historial de búsqueda", + "Quick action disabled": "Acción rápida desactivada" } diff --git a/apps/readest-app/public/locales/fa/translation.json b/apps/readest-app/public/locales/fa/translation.json index 35808068..0314a921 100644 --- a/apps/readest-app/public/locales/fa/translation.json +++ b/apps/readest-app/public/locales/fa/translation.json @@ -834,5 +834,6 @@ "Annotations": "یادداشت‌ها", "Show Results": "نمایش نتایج", "Clear search": "پاک کردن جستجو", - "Clear search history": "پاک کردن تاریخچه جستجو" + "Clear search history": "پاک کردن تاریخچه جستجو", + "Quick action disabled": "عملکرد سریع غیرفعال است" } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 247c78ca..0179918d 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -844,5 +844,6 @@ "Annotations": "Annotations", "Show Results": "Afficher les résultats", "Clear search": "Effacer la recherche", - "Clear search history": "Effacer l'historique de recherche" + "Clear search history": "Effacer l'historique de recherche", + "Quick action disabled": "Action rapide désactivée" } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index 389a5972..8779e008 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -834,5 +834,6 @@ "Annotations": "टिप्पणियाँ", "Show Results": "परिणाम दिखाएं", "Clear search": "खोज साफ़ करें", - "Clear search history": "खोज इतिहास साफ़ करें" + "Clear search history": "खोज इतिहास साफ़ करें", + "Quick action disabled": "त्वरित क्रिया अक्षम" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index 855fdf2b..d6d58a80 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -824,5 +824,6 @@ "Annotations": "Anotasi", "Show Results": "Tampilkan Hasil", "Clear search": "Hapus pencarian", - "Clear search history": "Hapus riwayat pencarian" + "Clear search history": "Hapus riwayat pencarian", + "Quick action disabled": "Tindakan cepat dinonaktifkan" } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index ebc624d9..f89e7c45 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -844,5 +844,6 @@ "Annotations": "Annotazioni", "Show Results": "Mostra risultati", "Clear search": "Cancella ricerca", - "Clear search history": "Cancella cronologia ricerche" + "Clear search history": "Cancella cronologia ricerche", + "Quick action disabled": "Azione rapida disattivata" } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index 46eb3a4d..5d523132 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -824,5 +824,6 @@ "Annotations": "注釈", "Show Results": "結果を表示", "Clear search": "検索をクリア", - "Clear search history": "検索履歴をクリア" + "Clear search history": "検索履歴をクリア", + "Quick action disabled": "クイックアクション無効" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index de5f5e96..00ae6b8d 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -824,5 +824,6 @@ "Annotations": "주석", "Show Results": "결과 표시", "Clear search": "검색 지우기", - "Clear search history": "검색 기록 지우기" + "Clear search history": "검색 기록 지우기", + "Quick action disabled": "빠른 작업 비활성화됨" } diff --git a/apps/readest-app/public/locales/ms/translation.json b/apps/readest-app/public/locales/ms/translation.json index bf16e31b..998f60f9 100644 --- a/apps/readest-app/public/locales/ms/translation.json +++ b/apps/readest-app/public/locales/ms/translation.json @@ -824,5 +824,6 @@ "Annotations": "Anotasi", "Show Results": "Tunjukkan Hasil", "Clear search": "Kosongkan carian", - "Clear search history": "Kosongkan sejarah carian" + "Clear search history": "Kosongkan sejarah carian", + "Quick action disabled": "Tindakan pantas dilumpuhkan" } diff --git a/apps/readest-app/public/locales/nl/translation.json b/apps/readest-app/public/locales/nl/translation.json index d6b1e5c0..8fe2219e 100644 --- a/apps/readest-app/public/locales/nl/translation.json +++ b/apps/readest-app/public/locales/nl/translation.json @@ -834,5 +834,6 @@ "Annotations": "Aantekeningen", "Show Results": "Resultaten tonen", "Clear search": "Zoekopdracht wissen", - "Clear search history": "Zoekgeschiedenis wissen" + "Clear search history": "Zoekgeschiedenis wissen", + "Quick action disabled": "Snelle actie uitgeschakeld" } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index 184bb48a..711d2edc 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -854,5 +854,6 @@ "Annotations": "Adnotacje", "Show Results": "Pokaż wyniki", "Clear search": "Wyczyść wyszukiwanie", - "Clear search history": "Wyczyść historię wyszukiwania" + "Clear search history": "Wyczyść historię wyszukiwania", + "Quick action disabled": "Szybka akcja wyłączona" } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 0ab0f90d..00f6ae58 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -844,5 +844,6 @@ "Annotations": "Anotações", "Show Results": "Mostrar resultados", "Clear search": "Limpar pesquisa", - "Clear search history": "Limpar histórico de pesquisa" + "Clear search history": "Limpar histórico de pesquisa", + "Quick action disabled": "Ação rápida desativada" } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 6824a924..3c903027 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -854,5 +854,6 @@ "Annotations": "Аннотации", "Show Results": "Показать результаты", "Clear search": "Очистить поиск", - "Clear search history": "Очистить историю поиска" + "Clear search history": "Очистить историю поиска", + "Quick action disabled": "Быстрое действие отключено" } diff --git a/apps/readest-app/public/locales/si/translation.json b/apps/readest-app/public/locales/si/translation.json index 225836c8..9518d5f8 100644 --- a/apps/readest-app/public/locales/si/translation.json +++ b/apps/readest-app/public/locales/si/translation.json @@ -834,5 +834,6 @@ "Annotations": "අනුසටහන්", "Show Results": "ප්‍රතිඵල පෙන්වන්න", "Clear search": "සෙවුම හිස් කරන්න", - "Clear search history": "සෙවුම් ඉතිහාසය හිස් කරන්න" + "Clear search history": "සෙවුම් ඉතිහාසය හිස් කරන්න", + "Quick action disabled": "ඉක්මන් ක්‍රියාව අක්‍රීයයි" } diff --git a/apps/readest-app/public/locales/sv/translation.json b/apps/readest-app/public/locales/sv/translation.json index b5f913b6..b5a5c2f3 100644 --- a/apps/readest-app/public/locales/sv/translation.json +++ b/apps/readest-app/public/locales/sv/translation.json @@ -834,5 +834,6 @@ "Annotations": "Anteckningar", "Show Results": "Visa resultat", "Clear search": "Rensa sökning", - "Clear search history": "Rensa sökhistorik" + "Clear search history": "Rensa sökhistorik", + "Quick action disabled": "Snabbåtgärd inaktiverad" } diff --git a/apps/readest-app/public/locales/ta/translation.json b/apps/readest-app/public/locales/ta/translation.json index 3f45eabf..5bdf0b89 100644 --- a/apps/readest-app/public/locales/ta/translation.json +++ b/apps/readest-app/public/locales/ta/translation.json @@ -834,5 +834,6 @@ "Annotations": "சிறுகுறிப்புகள்", "Show Results": "முடிவுகளைக் காட்டு", "Clear search": "தேடலை அழி", - "Clear search history": "தேடல் வரலாற்றை அழி" + "Clear search history": "தேடல் வரலாற்றை அழி", + "Quick action disabled": "விரைவு செயல் முடக்கப்பட்டது" } diff --git a/apps/readest-app/public/locales/th/translation.json b/apps/readest-app/public/locales/th/translation.json index 076eeb75..eccbee45 100644 --- a/apps/readest-app/public/locales/th/translation.json +++ b/apps/readest-app/public/locales/th/translation.json @@ -824,5 +824,6 @@ "Annotations": "คำอธิบายประกอบ", "Show Results": "แสดงผลลัพธ์", "Clear search": "ล้างการค้นหา", - "Clear search history": "ล้างประวัติการค้นหา" + "Clear search history": "ล้างประวัติการค้นหา", + "Quick action disabled": "ปิดใช้งานการดำเนินการด่วน" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 9ace0f94..9cdfcd95 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -834,5 +834,6 @@ "Annotations": "Açıklamalar", "Show Results": "Sonuçları Göster", "Clear search": "Aramayı temizle", - "Clear search history": "Arama geçmişini temizle" + "Clear search history": "Arama geçmişini temizle", + "Quick action disabled": "Hızlı eylem devre dışı" } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index 626b71a8..26619847 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -854,5 +854,6 @@ "Annotations": "Анотації", "Show Results": "Показати результати", "Clear search": "Очистити пошук", - "Clear search history": "Очистити історію пошуку" + "Clear search history": "Очистити історію пошуку", + "Quick action disabled": "Швидку дію вимкнено" } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index 91a6efc2..53935074 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -824,5 +824,6 @@ "Annotations": "Chú thích", "Show Results": "Hiển thị kết quả", "Clear search": "Xóa tìm kiếm", - "Clear search history": "Xóa lịch sử tìm kiếm" + "Clear search history": "Xóa lịch sử tìm kiếm", + "Quick action disabled": "Đã tắt thao tác nhanh" } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index 82b26839..cb2bf330 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -824,5 +824,6 @@ "Annotations": "注释", "Show Results": "显示结果", "Clear search": "清除搜索", - "Clear search history": "清除搜索历史" + "Clear search history": "清除搜索历史", + "Quick action disabled": "快捷操作已禁用" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index cd45bafe..af5757da 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -824,5 +824,6 @@ "Annotations": "註解", "Show Results": "顯示結果", "Clear search": "清除搜尋", - "Clear search history": "清除搜尋歷史" + "Clear search history": "清除搜尋歷史", + "Quick action disabled": "快捷操作已停用" } diff --git a/apps/readest-app/src/app/reader/components/annotator/AnnotationNotes.tsx b/apps/readest-app/src/app/reader/components/annotator/AnnotationNotes.tsx index aeed6a96..3c011a6e 100644 --- a/apps/readest-app/src/app/reader/components/annotator/AnnotationNotes.tsx +++ b/apps/readest-app/src/app/reader/components/annotator/AnnotationNotes.tsx @@ -1,4 +1,5 @@ import clsx from 'clsx'; +import dayjs from 'dayjs'; import React, { useMemo } from 'react'; import { BookNote } from '@/types/book'; import { useEnv } from '@/context/EnvContext'; @@ -11,6 +12,7 @@ interface AnnotationNotesProps { bookKey: string; isVertical: boolean; notes: BookNote[]; + toolsVisible: boolean; triangleDir: 'up' | 'down' | 'left' | 'right'; popupWidth: number; popupHeight: number; @@ -21,6 +23,7 @@ const AnnotationNotes: React.FC = ({ bookKey, isVertical, notes, + toolsVisible, triangleDir, popupWidth, popupHeight, @@ -31,7 +34,7 @@ const AnnotationNotes: React.FC = ({ const { setHoveredBookKey } = useReaderStore(); const { setSideBarVisible } = useSidebarStore(); const config = getConfig(bookKey); - const maxSize = useResponsiveSize(150); + const maxSize = useResponsiveSize(250); const sortedNotes = useMemo(() => { return [...notes].sort((a, b) => b.updatedAt - a.updatedAt); @@ -59,15 +62,15 @@ const AnnotationNotes: React.FC = ({ style={{ ...(isVertical ? { - right: `${triangleDir === 'left' ? `${popupWidth + 16}px` : undefined}`, - left: `${triangleDir === 'right' ? `${popupWidth + 16}px` : undefined}`, + right: triangleDir === 'left' ? `${toolsVisible ? popupWidth + 16 : 0}px` : undefined, + left: triangleDir === 'right' ? `${toolsVisible ? popupWidth + 16 : 0}px` : undefined, height: `${popupHeight}px`, maxWidth: `${maxSize}px`, overflowX: 'auto', } : { - top: triangleDir === 'up' ? undefined : `${popupHeight + 16}px`, - bottom: triangleDir === 'up' ? `${popupHeight + 16}px` : undefined, + top: triangleDir === 'down' ? `${toolsVisible ? popupHeight + 16 : 0}px` : undefined, + bottom: triangleDir === 'up' ? `${toolsVisible ? popupHeight + 16 : 0}px` : undefined, width: `${popupWidth}px`, maxHeight: `${maxSize}px`, overflowY: 'auto', @@ -76,7 +79,7 @@ const AnnotationNotes: React.FC = ({ }} >
= ({ : {} } > - {note.note} +
+ {note.note} + + {dayjs(note.createdAt).fromNow()} + +
)} diff --git a/apps/readest-app/src/app/reader/components/annotator/AnnotationPopup.tsx b/apps/readest-app/src/app/reader/components/annotator/AnnotationPopup.tsx index 51d820b9..a529e51a 100644 --- a/apps/readest-app/src/app/reader/components/annotator/AnnotationPopup.tsx +++ b/apps/readest-app/src/app/reader/components/annotator/AnnotationPopup.tsx @@ -54,7 +54,10 @@ const AnnotationPopup: React.FC = ({ minHeight={isVertical ? popupWidth : popupHeight} position={position} trianglePosition={trianglePosition} - className='selection-popup bg-gray-600 text-white' + className={clsx( + 'selection-popup bg-gray-600 text-white', + notes.length > 0 && 'bg-transparent', + )} triangleClassName='text-gray-600' onDismiss={onDismiss} > @@ -63,6 +66,7 @@ const AnnotationPopup: React.FC = ({ className={clsx( 'selection-buttons flex h-full w-full items-center justify-between p-2', isVertical ? 'flex-col overflow-y-auto' : 'flex-row overflow-x-auto', + notes.length > 0 && 'hidden', )} style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }} > @@ -85,6 +89,7 @@ const AnnotationPopup: React.FC = ({ bookKey={bookKey} isVertical={isVertical} notes={notes} + toolsVisible={false} triangleDir={trianglePosition.dir!} popupWidth={isVertical ? popupHeight : popupWidth} popupHeight={isVertical ? popupWidth : popupHeight} diff --git a/apps/readest-app/src/app/reader/components/annotator/AnnotationRangeEditor.tsx b/apps/readest-app/src/app/reader/components/annotator/AnnotationRangeEditor.tsx index 0b22cef9..d22f9c63 100644 --- a/apps/readest-app/src/app/reader/components/annotator/AnnotationRangeEditor.tsx +++ b/apps/readest-app/src/app/reader/components/annotator/AnnotationRangeEditor.tsx @@ -4,11 +4,13 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { BookNote, HighlightColor } from '@/types/book'; import { Point, TextSelection } from '@/utils/sel'; import { useSettingsStore } from '@/store/settingsStore'; +import { useResponsiveSize } from '@/hooks/useResponsiveSize'; import { useAnnotationEditor } from '../../hooks/useAnnotationEditor'; import { getHighlightColorHex } from '../../utils/annotatorUtil'; interface HandleProps { position: Point; + isVertical: boolean; type: 'start' | 'end'; color: string; onDragStart: () => void; @@ -18,6 +20,7 @@ interface HandleProps { const Handle: React.FC = ({ position, + isVertical, type, color, onDragStart, @@ -25,6 +28,9 @@ const Handle: React.FC = ({ onDragEnd, }) => { const isDragging = useRef(false); + const size = useResponsiveSize(24); + const circleRadius = useResponsiveSize(8); + const stemHeight = useResponsiveSize(12); const handlePointerDown = useCallback( (e: React.PointerEvent) => { @@ -59,16 +65,22 @@ const Handle: React.FC = ({ [onDragEnd], ); - const size = 24; - const circleRadius = 8; - const stemHeight = 8; - return (
= ({ height={size + stemHeight} viewBox={`0 0 ${size} ${size + stemHeight}`} className={clsx(type === 'start' && 'rotate-180')} - style={{ transform: type === 'start' ? 'rotate(180deg)' : undefined }} + style={{ + transform: isVertical + ? type === 'start' + ? 'rotate(270deg)' + : 'rotate(90deg)' + : type === 'start' + ? 'rotate(180deg)' + : undefined, + }} > {/* Stem/line */} = ({ interface AnnotationRangeEditorProps { bookKey: string; + isVertical: boolean; annotation: BookNote; selection: TextSelection; handleColor: HighlightColor; @@ -113,6 +134,7 @@ interface AnnotationRangeEditorProps { const AnnotationRangeEditor: React.FC = ({ bookKey, + isVertical, annotation, selection, handleColor, @@ -137,7 +159,7 @@ const AnnotationRangeEditor: React.FC = ({ initializedRef.current = true; const range = selection.range; - const positions = getHandlePositionsFromRange(range); + const positions = getHandlePositionsFromRange(range, isVertical); if (positions) { setTimeout(() => { setCurrentStart(positions.start); @@ -146,7 +168,7 @@ const AnnotationRangeEditor: React.FC = ({ startRef.current = positions.start; endRef.current = positions.end; } - }, [annotation, selection, getHandlePositionsFromRange]); + }, [annotation, selection, isVertical, getHandlePositionsFromRange]); useEffect(() => { if (!handlePositions || draggingRef.current) return; @@ -172,24 +194,24 @@ const AnnotationRangeEditor: React.FC = ({ (point: Point) => { setCurrentStart(point); startRef.current = point; - handleAnnotationRangeChange(point, endRef.current, true); + handleAnnotationRangeChange(point, endRef.current, isVertical, true); }, - [handleAnnotationRangeChange], + [isVertical, handleAnnotationRangeChange], ); const handleEndDrag = useCallback( (point: Point) => { setCurrentEnd(point); endRef.current = point; - handleAnnotationRangeChange(startRef.current, point, true); + handleAnnotationRangeChange(startRef.current, point, isVertical, true); }, - [handleAnnotationRangeChange], + [isVertical, handleAnnotationRangeChange], ); const handleDragEnd = useCallback(() => { draggingRef.current = null; - handleAnnotationRangeChange(startRef.current, endRef.current, false); - }, [handleAnnotationRangeChange]); + handleAnnotationRangeChange(startRef.current, endRef.current, isVertical, false); + }, [isVertical, handleAnnotationRangeChange]); if (currentStart.x === 0 && currentStart.y === 0) { return null; @@ -199,6 +221,7 @@ const AnnotationRangeEditor: React.FC = ({
= ({ /> = ({ bookKey }) => { {editingAnnotation && editingAnnotation.color && selection && ( = ({ const handleActionClick = (action: AnnotationToolType) => { onActionSelect(action); + if (selectedAction === action) { + eventDispatcher.dispatch('toast', { + type: 'info', + timeout: 2000, + message: _('Quick action disabled'), + }); + } else { + eventDispatcher.dispatch('toast', { + type: 'info', + timeout: 2000, + message: _(annotationToolQuickActions.find((btn) => btn.type === action)?.tooltip || ''), + }); + } + setIsDropdownOpen?.(false); }; return ( @@ -41,7 +55,8 @@ const QuickActionMenu: React.FC = ({ key={button.type} label={_(button.label)} tooltip={_(button.tooltip)} - Icon={selectedAction === button.type ? MdCheck : button.Icon} + buttonClass={selectedAction === button.type ? 'bg-base-300/85' : ''} + Icon={button.Icon} onClick={() => handleActionClick(button.type)} /> ))} diff --git a/apps/readest-app/src/app/reader/hooks/useAnnotationEditor.ts b/apps/readest-app/src/app/reader/hooks/useAnnotationEditor.ts index bd25aeb5..24926061 100644 --- a/apps/readest-app/src/app/reader/hooks/useAnnotationEditor.ts +++ b/apps/readest-app/src/app/reader/hooks/useAnnotationEditor.ts @@ -34,7 +34,7 @@ export const useAnnotationEditor = ({ const [handlePositions, setHandlePositions] = useState(null); const getHandlePositionsFromRange = useCallback( - (range: Range): HandlePositions | null => { + (range: Range, isVertical: boolean): HandlePositions | null => { const gridFrame = document.querySelector(`#gridcell-${bookKey}`); if (!gridFrame) return null; @@ -48,11 +48,11 @@ export const useAnnotationEditor = ({ return { start: { - x: frameRect.left + firstRect.left, + x: frameRect.left + (isVertical ? firstRect.right : firstRect.left), y: frameRect.top + firstRect.top, }, end: { - x: frameRect.left + lastRect.right, + x: frameRect.left + (isVertical ? lastRect.left : lastRect.right), y: frameRect.top + lastRect.bottom, }, }; @@ -61,7 +61,7 @@ export const useAnnotationEditor = ({ ); const handleAnnotationRangeChange = useCallback( - async (startPoint: Point, endPoint: Point, isDragging: boolean) => { + async (startPoint: Point, endPoint: Point, isVertical: boolean, isDragging: boolean) => { if (!editingAnnotationRef.current || !view) return; const contents = view.renderer.getContents(); @@ -132,7 +132,7 @@ export const useAnnotationEditor = ({ return; } - const newPositions = getHandlePositionsFromRange(newRange); + const newPositions = getHandlePositionsFromRange(newRange, isVertical); if (newPositions) { setHandlePositions(newPositions); }