Converge reader navigation buttons
This commit is contained in:
parent
d2d06e15b6
commit
fdceed6067
4 changed files with 23 additions and 21 deletions
|
|
@ -20,6 +20,7 @@ import { RateLimitBanner } from '@/components/auth/RateLimitBanner';
|
||||||
import { useAuthRateLimit } from '@/contexts/AuthRateLimitContext';
|
import { useAuthRateLimit } from '@/contexts/AuthRateLimitContext';
|
||||||
import { useFeatureFlag } from '@/contexts/RuntimeConfigContext';
|
import { useFeatureFlag } from '@/contexts/RuntimeConfigContext';
|
||||||
import { useUnmountCleanupRef } from '@/hooks/useUnmountCleanupRef';
|
import { useUnmountCleanupRef } from '@/hooks/useUnmountCleanupRef';
|
||||||
|
import { buttonClass } from '@/components/ui';
|
||||||
import { useEpubDocument } from './useEpubDocument';
|
import { useEpubDocument } from './useEpubDocument';
|
||||||
|
|
||||||
export default function EPUBPage() {
|
export default function EPUBPage() {
|
||||||
|
|
@ -173,9 +174,9 @@ export default function EPUBPage() {
|
||||||
<p className="text-danger mb-4">{error}</p>
|
<p className="text-danger mb-4">{error}</p>
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center px-3 py-1 bg-surface text-foreground rounded-lg hover:bg-accent-wash transition duration-base ease-standard hover:text-accent"
|
className={buttonClass({ variant: 'secondary', size: 'md', className: 'gap-2' })}
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4 mr-2 text-soft" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4 text-soft" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
</svg>
|
</svg>
|
||||||
Back to Documents
|
Back to Documents
|
||||||
|
|
@ -190,10 +191,10 @@ export default function EPUBPage() {
|
||||||
left={
|
left={
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-line bg-surface text-foreground text-xs hover:bg-accent-wash transition duration-base ease-standard hover:text-accent"
|
className={buttonClass({ variant: 'secondary', size: 'sm', className: 'gap-2' })}
|
||||||
aria-label="Back to documents"
|
aria-label="Back to documents"
|
||||||
>
|
>
|
||||||
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3 h-3" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
</svg>
|
</svg>
|
||||||
Documents
|
Documents
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import { AudiobookExportModal } from '@/components/AudiobookExportModal';
|
||||||
import { useAuthRateLimit } from '@/contexts/AuthRateLimitContext';
|
import { useAuthRateLimit } from '@/contexts/AuthRateLimitContext';
|
||||||
import { useFeatureFlag } from '@/contexts/RuntimeConfigContext';
|
import { useFeatureFlag } from '@/contexts/RuntimeConfigContext';
|
||||||
import { useUnmountCleanupRef } from '@/hooks/useUnmountCleanupRef';
|
import { useUnmountCleanupRef } from '@/hooks/useUnmountCleanupRef';
|
||||||
|
import { buttonClass } from '@/components/ui';
|
||||||
import type { TTSAudiobookChapter } from '@/types/tts';
|
import type { TTSAudiobookChapter } from '@/types/tts';
|
||||||
import type { AudiobookGenerationSettings } from '@/types/client';
|
import type { AudiobookGenerationSettings } from '@/types/client';
|
||||||
import { useHtmlDocument } from './useHtmlDocument';
|
import { useHtmlDocument } from './useHtmlDocument';
|
||||||
|
|
@ -160,9 +161,9 @@ export default function HTMLPage() {
|
||||||
<p className="text-danger mb-4">{error}</p>
|
<p className="text-danger mb-4">{error}</p>
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center px-3 py-1 bg-surface text-foreground rounded-lg hover:bg-accent-wash transition duration-base ease-standard hover:text-accent"
|
className={buttonClass({ variant: 'secondary', size: 'md', className: 'gap-2' })}
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
</svg>
|
</svg>
|
||||||
Back to Documents
|
Back to Documents
|
||||||
|
|
@ -177,10 +178,10 @@ export default function HTMLPage() {
|
||||||
left={
|
left={
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-line bg-surface text-foreground text-xs hover:bg-accent-wash transition duration-base ease-standard hover:text-accent"
|
className={buttonClass({ variant: 'secondary', size: 'sm', className: 'gap-2' })}
|
||||||
aria-label="Back to documents"
|
aria-label="Back to documents"
|
||||||
>
|
>
|
||||||
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3 h-3" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
</svg>
|
</svg>
|
||||||
Documents
|
Documents
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import { RateLimitBanner } from '@/components/auth/RateLimitBanner';
|
||||||
import { useAuthRateLimit } from '@/contexts/AuthRateLimitContext';
|
import { useAuthRateLimit } from '@/contexts/AuthRateLimitContext';
|
||||||
import { useFeatureFlag } from '@/contexts/RuntimeConfigContext';
|
import { useFeatureFlag } from '@/contexts/RuntimeConfigContext';
|
||||||
import { LoadingSpinner } from '@/components/Spinner';
|
import { LoadingSpinner } from '@/components/Spinner';
|
||||||
|
import { buttonClass } from '@/components/ui';
|
||||||
import {
|
import {
|
||||||
FORCE_REPARSE_CONFIRM_MESSAGE,
|
FORCE_REPARSE_CONFIRM_MESSAGE,
|
||||||
FORCE_REPARSE_CONFIRM_TEXT,
|
FORCE_REPARSE_CONFIRM_TEXT,
|
||||||
|
|
@ -255,9 +256,9 @@ export default function PDFViewerPage() {
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
onClick={handleBackToDocuments}
|
onClick={handleBackToDocuments}
|
||||||
className="inline-flex items-center px-3 py-1 bg-surface text-foreground rounded-lg hover:bg-accent-wash transition duration-base ease-standard hover:text-accent"
|
className={buttonClass({ variant: 'secondary', size: 'md', className: 'gap-2' })}
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4 mr-2 text-soft" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4 text-soft" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
</svg>
|
</svg>
|
||||||
Back to Documents
|
Back to Documents
|
||||||
|
|
@ -384,10 +385,10 @@ export default function PDFViewerPage() {
|
||||||
<Link
|
<Link
|
||||||
href="/app"
|
href="/app"
|
||||||
onClick={handleBackToDocuments}
|
onClick={handleBackToDocuments}
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-line bg-surface text-foreground text-xs hover:bg-accent-wash transition duration-base ease-standard hover:text-accent"
|
className={buttonClass({ variant: 'secondary', size: 'sm', className: 'gap-2' })}
|
||||||
aria-label="Back to documents"
|
aria-label="Back to documents"
|
||||||
>
|
>
|
||||||
<svg className="w-3 h-3 mr-2" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-3 h-3" fill="currentColor" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||||
</svg>
|
</svg>
|
||||||
Documents
|
Documents
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { useEPUBTheme, getThemeStyles } from '@/hooks/epub/useEPUBTheme';
|
||||||
import { useEPUBResize } from '@/hooks/epub/useEPUBResize';
|
import { useEPUBResize } from '@/hooks/epub/useEPUBResize';
|
||||||
import { DotsVerticalIcon, ChevronLeftIcon, ChevronRightIcon } from '@/components/icons/Icons';
|
import { DotsVerticalIcon, ChevronLeftIcon, ChevronRightIcon } from '@/components/icons/Icons';
|
||||||
import type { EpubDocumentState } from '@/app/(app)/epub/[id]/useEpubDocument';
|
import type { EpubDocumentState } from '@/app/(app)/epub/[id]/useEpubDocument';
|
||||||
|
import { ToolbarButton } from '@/components/ui';
|
||||||
|
|
||||||
const ReactReader = dynamic(() => import('react-reader').then(mod => mod.ReactReader), {
|
const ReactReader = dynamic(() => import('react-reader').then(mod => mod.ReactReader), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
|
|
@ -160,36 +161,34 @@ export function EPUBViewer({ className = '', epubState }: EPUBViewerProps) {
|
||||||
<div className={`h-full flex flex-col relative z-0 ${className}`} ref={containerRef}>
|
<div className={`h-full flex flex-col relative z-0 ${className}`} ref={containerRef}>
|
||||||
<div className="flex items-center justify-between px-2 py-1 border-b border-line-soft bg-surface text-xs text-soft">
|
<div className="flex items-center justify-between px-2 py-1 border-b border-line-soft bg-surface text-xs text-soft">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<button
|
<ToolbarButton
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setIsTocOpen(open => !open)}
|
onClick={() => setIsTocOpen(open => !open)}
|
||||||
className="inline-flex items-center py-1 px-1 rounded-md border border-line bg-surface text-foreground text-xs hover:bg-accent-wash transition duration-base ease-standard transform hover:text-accent"
|
|
||||||
aria-label={isTocOpen ? 'Hide chapters' : 'Show chapters'}
|
aria-label={isTocOpen ? 'Hide chapters' : 'Show chapters'}
|
||||||
|
className="px-1"
|
||||||
>
|
>
|
||||||
<DotsVerticalIcon className="w-4 h-4" />
|
<DotsVerticalIcon className="w-4 h-4" />
|
||||||
</button>
|
</ToolbarButton>
|
||||||
<button
|
<ToolbarButton
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleLocationChanged('prev')}
|
onClick={() => handleLocationChanged('prev')}
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-line bg-surface text-foreground text-xs hover:bg-accent-wash transition duration-base ease-standard transform hover:text-accent"
|
|
||||||
aria-label="Previous section"
|
aria-label="Previous section"
|
||||||
>
|
>
|
||||||
<ChevronLeftIcon className="w-4 h-4" />
|
<ChevronLeftIcon className="w-4 h-4" />
|
||||||
</button>
|
</ToolbarButton>
|
||||||
</div>
|
</div>
|
||||||
{currDocPages !== undefined && typeof currDocPage === 'number' && (
|
{currDocPages !== undefined && typeof currDocPage === 'number' && (
|
||||||
<span className="px-2 tabular-nums">
|
<span className="px-2 tabular-nums">
|
||||||
{currDocPage} / {currDocPages}
|
{currDocPage} / {currDocPages}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<button
|
<ToolbarButton
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleLocationChanged('next')}
|
onClick={() => handleLocationChanged('next')}
|
||||||
className="inline-flex items-center py-1 px-2 rounded-md border border-line bg-surface text-foreground text-xs hover:bg-accent-wash transition duration-base ease-standard transform hover:text-accent"
|
|
||||||
aria-label="Next section"
|
aria-label="Next section"
|
||||||
>
|
>
|
||||||
<ChevronRightIcon className="w-4 h-4" />
|
<ChevronRightIcon className="w-4 h-4" />
|
||||||
</button>
|
</ToolbarButton>
|
||||||
</div>
|
</div>
|
||||||
{isTocOpen && tocRef.current && tocRef.current.length > 0 && (
|
{isTocOpen && tocRef.current && tocRef.current.length > 0 && (
|
||||||
<div className="border-b border-line-soft bg-background text-xs overflow-y-auto max-h-64 p-2">
|
<div className="border-b border-line-soft bg-background text-xs overflow-y-auto max-h-64 p-2">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue