diff --git a/apps/readest-app/src/app/reader/components/SectionInfo.tsx b/apps/readest-app/src/app/reader/components/SectionInfo.tsx index 05b8eabd..1702ae16 100644 --- a/apps/readest-app/src/app/reader/components/SectionInfo.tsx +++ b/apps/readest-app/src/app/reader/components/SectionInfo.tsx @@ -68,8 +68,8 @@ const SectionInfo: React.FC = ({ } : { top: `${topInset}px`, - insetInlineStart: `calc(${horizontalGap / 2}% + ${contentInsets.left}px)`, - width: `calc(100% - ${contentInsets.left + contentInsets.right}px)`, + paddingInlineStart: `calc(${horizontalGap / 2}% + ${contentInsets.left}px)`, + width: '100%', } } > diff --git a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx index 13a79bb3..7facf9ae 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx @@ -11,7 +11,7 @@ import { BookSearchConfig, BookSearchResult } from '@/types/book'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; import { debounce } from '@/utils/debounce'; import { isCJKStr } from '@/utils/lang'; -import { createRejecttFilter } from '@/utils/node'; +import { createRejectFilter } from '@/utils/node'; import Dropdown from '@/components/Dropdown'; import SearchOptions from './SearchOptions'; @@ -127,7 +127,7 @@ const SearchBar: React.FC = ({ ...searchConfig, index, query: term, - acceptNode: createRejecttFilter({ + acceptNode: createRejectFilter({ tags: primaryLang.startsWith('ja') ? ['rt'] : [], }), }); diff --git a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx index 1c0e81ba..f99dc784 100644 --- a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx +++ b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx @@ -208,6 +208,30 @@ const TTSControl: React.FC = ({ bookKey, gridInsets }) => { viewSettings.ttsLocation = cfi || ''; setViewSettings(bookKey, viewSettings); } + + if (!view.renderer.scrolled) { + view.renderer.scrollToAnchor(range); + } else { + const rect = range.getBoundingClientRect(); + const { start, size, viewSize, sideProp } = view.renderer; + const positionStart = rect[sideProp === 'height' ? 'y' : 'x'] + viewSettings.marginTopPx; + const positionEnd = rect[sideProp === 'height' ? 'height' : 'width'] + positionStart; + const offsetStart = view.book.dir === 'rtl' ? viewSize - positionStart : positionStart; + const offsetEnd = view.book.dir === 'rtl' ? viewSize - positionEnd : positionEnd; + + const showHeader = viewSettings.showHeader; + const showFooter = viewSettings.showFooter; + const showBarsOnScroll = viewSettings.showBarsOnScroll; + const headerScrollOverlap = showHeader && showBarsOnScroll ? 44 : 0; + const footerScrollOverlap = showFooter && showBarsOnScroll ? 44 : 0; + const scrollingOverlap = viewSettings.scrollingOverlap; + const endInNextView = offsetEnd > start + size - footerScrollOverlap - scrollingOverlap; + const startInPrevView = offsetStart < start + headerScrollOverlap + scrollingOverlap; + if (endInNextView || startInPrevView) { + const scrollTo = offsetStart - headerScrollOverlap - scrollingOverlap; + view.renderer.scrollToAnchor(scrollTo / viewSize); + } + } }; ttsController.addEventListener('tts-speak-mark', handleSpeakMark); diff --git a/apps/readest-app/src/services/tts/TTSController.ts b/apps/readest-app/src/services/tts/TTSController.ts index b9149e55..2910e597 100644 --- a/apps/readest-app/src/services/tts/TTSController.ts +++ b/apps/readest-app/src/services/tts/TTSController.ts @@ -3,7 +3,7 @@ import { AppService } from '@/types/system'; import { parseSSMLMarks } from '@/utils/ssml'; import { Overlayer } from 'foliate-js/overlayer.js'; import { TTSGranularity, TTSHighlightOptions, TTSMark, TTSVoice } from './types'; -import { createRejecttFilter } from '@/utils/node'; +import { createRejectFilter } from '@/utils/node'; import { WebSpeechClient } from './WebSpeechClient'; import { NativeTTSClient } from './NativeTTSClient'; import { EdgeTTSClient } from './EdgeTTSClient'; @@ -85,13 +85,6 @@ export class TTSController extends EventTarget { const { style, color } = options; overlayer?.remove(HIGHLIGHT_KEY); overlayer?.add(HIGHLIGHT_KEY, range, Overlayer[style], { color }); - const rect = range.getBoundingClientRect(); - const { start, size, viewSize, sideProp } = this.view.renderer; - const position = rect[sideProp === 'height' ? 'y' : 'x'] + 88; - const offset = this.view.book.dir === 'rtl' ? viewSize - position : position; - if (!this.view.renderer.scrolled || offset < start || offset > start + size) { - this.view.renderer.scrollToAnchor(range); - } }; } @@ -109,7 +102,7 @@ export class TTSController extends EventTarget { const highlightOptions: TTSHighlightOptions = { style: 'highlight', color: 'gray' }; await this.view.initTTS( granularity, - createRejecttFilter({ + createRejectFilter({ tags: ['rt', 'sup'], contents: [{ tag: 'a', content: /^\d+$/ }], }), diff --git a/apps/readest-app/src/utils/node.ts b/apps/readest-app/src/utils/node.ts index ca871d4e..536c2f22 100644 --- a/apps/readest-app/src/utils/node.ts +++ b/apps/readest-app/src/utils/node.ts @@ -1,4 +1,4 @@ -export const createRejecttFilter = ({ +export const createRejectFilter = ({ tags = [], classes = [], attributes = [],