Use bookID in path in Web version
This commit is contained in:
@@ -7,7 +7,7 @@ const internalHost = process.env.TAURI_DEV_HOST || 'localhost';
|
||||
const nextConfig = {
|
||||
// Ensure Next.js uses SSG instead of SSR
|
||||
// https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
|
||||
output: 'export',
|
||||
output: process.env['NEXT_PUBLIC_APP_PLATFORM'] === 'web' ? undefined : 'output',
|
||||
// Note: This feature is required to use the Next.js Image component in SSG mode.
|
||||
// See https://nextjs.org/docs/messages/export-image-api for different workarounds.
|
||||
images: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@readest/readest-app",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "dotenv -e .env.tauri -- next dev",
|
||||
|
||||
@@ -11,6 +11,7 @@ import Image from 'next/image';
|
||||
import { Book, BooksGroup } from '@/types/book';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useLibraryStore } from '@/store/libraryStore';
|
||||
import { navigateToReader } from '@/utils/nav';
|
||||
import Alert from '@/components/Alert';
|
||||
import Spinner from '@/components/Spinner';
|
||||
|
||||
@@ -68,7 +69,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({ libraryBooks, isSelectMode, onImp
|
||||
setClickedImage(id);
|
||||
setTimeout(() => setClickedImage(null), 300);
|
||||
setTimeout(() => setLoading(true), 200);
|
||||
router.push(`/reader?ids=${id}`);
|
||||
navigateToReader(router, [id]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,7 +81,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({ libraryBooks, isSelectMode, onImp
|
||||
|
||||
const openSelectedBooks = () => {
|
||||
setTimeout(() => setLoading(true), 200);
|
||||
router.push(`/reader?ids=${selectedBooks.join(',')}`);
|
||||
navigateToReader(router, selectedBooks);
|
||||
};
|
||||
|
||||
const confirmDelete = () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useRouter } from 'next/navigation';
|
||||
|
||||
import { Book } from '@/types/book';
|
||||
import { AppService } from '@/types/system';
|
||||
import { navigateToReader } from '@/utils/nav';
|
||||
import { parseOpenWithFiles } from '@/helpers/cli';
|
||||
import { isTauriAppPlatform } from '@/services/environment';
|
||||
import { FILE_ACCEPT_FORMATS, SUPPORTED_FILE_EXTS } from '@/services/constants';
|
||||
@@ -47,7 +48,7 @@ const LibraryPage = () => {
|
||||
|
||||
console.log('Opening books:', bookIds);
|
||||
if (bookIds.length > 0) {
|
||||
router.push(`/reader?ids=${bookIds.join(',')}`);
|
||||
navigateToReader(router, bookIds);
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { navigateToLibrary } from '@/utils/nav';
|
||||
|
||||
import Spinner from '@/components/Spinner';
|
||||
|
||||
@@ -9,7 +10,7 @@ const HomePage = () => {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
router.push('/library');
|
||||
navigateToLibrary(router);
|
||||
}, [router]);
|
||||
|
||||
return <Spinner loading={true} />;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import Reader from '../components/Reader';
|
||||
|
||||
export default async function Page({ params }: { params: Promise<{ ids: string }> }) {
|
||||
const ids = decodeURIComponent((await params).ids);
|
||||
return <Reader ids={ids} />;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { useEffect, Suspense, useRef } from 'react';
|
||||
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useLibraryStore } from '@/store/libraryStore';
|
||||
|
||||
import ReaderContent from './ReaderContent';
|
||||
import { AboutWindow } from '@/components/AboutWindow';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
|
||||
const Reader: React.FC<{ ids?: string }> = ({ ids }) => {
|
||||
const { envConfig } = useEnv();
|
||||
const { settings, setSettings } = useSettingsStore();
|
||||
const { library, setLibrary } = useLibraryStore();
|
||||
const isInitiating = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitiating.current) return;
|
||||
isInitiating.current = true;
|
||||
const initLibrary = async () => {
|
||||
const appService = await envConfig.getAppService();
|
||||
const settings = await appService.loadSettings();
|
||||
setSettings(settings);
|
||||
setLibrary(await appService.loadLibraryBooks());
|
||||
};
|
||||
|
||||
initLibrary();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
library.length > 0 &&
|
||||
settings.globalReadSettings && (
|
||||
<div className='reader-page bg-base-100 text-base-content min-h-screen select-none'>
|
||||
<Suspense>
|
||||
<ReaderContent ids={ids} settings={settings} />
|
||||
<AboutWindow />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default Reader;
|
||||
@@ -13,6 +13,8 @@ import { SystemSettings } from '@/types/settings';
|
||||
import { parseOpenWithFiles } from '@/helpers/cli';
|
||||
import { tauriHandleClose } from '@/utils/window';
|
||||
import { uniqueId } from '@/utils/misc';
|
||||
import { navigateToLibrary } from '@/utils/nav';
|
||||
import { BOOK_IDS_SEPARATOR } from '@/services/constants';
|
||||
|
||||
import useBooksManager from '../hooks/useBooksManager';
|
||||
import useBookShortcuts from '../hooks/useBookShortcuts';
|
||||
@@ -21,7 +23,7 @@ import SideBar from './sidebar/SideBar';
|
||||
import Notebook from './notebook/Notebook';
|
||||
import BooksGrid from './BooksGrid';
|
||||
|
||||
const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) => {
|
||||
const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ ids, settings }) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const { envConfig } = useEnv();
|
||||
@@ -40,7 +42,8 @@ const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) =>
|
||||
if (isInitiating.current) return;
|
||||
isInitiating.current = true;
|
||||
|
||||
const initialIds = (searchParams.get('ids') || '').split(',').filter(Boolean);
|
||||
const bookIds = ids || searchParams.get('ids') || '';
|
||||
const initialIds = bookIds.split(BOOK_IDS_SEPARATOR).filter(Boolean);
|
||||
const initialBookKeys = initialIds.map((id) => `${id}-${uniqueId()}`);
|
||||
setBookKeys(initialBookKeys);
|
||||
const uniqueIds = new Set<string>();
|
||||
@@ -72,7 +75,7 @@ const ReaderContent: React.FC<{ settings: SystemSettings }> = ({ settings }) =>
|
||||
|
||||
const saveSettingsAndGoToLibrary = () => {
|
||||
saveSettings(envConfig, settings);
|
||||
router.replace('/library');
|
||||
navigateToLibrary(router);
|
||||
};
|
||||
|
||||
const handleCloseBooks = () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSidebarStore } from '@/store/sidebarStore';
|
||||
import { uniqueId } from '@/utils/misc';
|
||||
import { useParallelViewStore } from '@/store/parallelViewStore';
|
||||
import { navigateToReader } from '@/utils/nav';
|
||||
|
||||
const useBooksManager = () => {
|
||||
const router = useRouter();
|
||||
@@ -18,11 +19,9 @@ const useBooksManager = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldUpdateSearchParams) {
|
||||
const ids = bookKeys.map((key) => key.split('-')[0]).join(',');
|
||||
const ids = bookKeys.map((key) => key.split('-')[0]!);
|
||||
if (ids) {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set('ids', ids);
|
||||
router.replace(`?${params.toString()}`, { scroll: false });
|
||||
navigateToReader(router, ids, searchParams.toString(), { scroll: false });
|
||||
}
|
||||
setShouldUpdateSearchParams(false);
|
||||
}
|
||||
|
||||
@@ -1,46 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { useEffect, Suspense, useRef } from 'react';
|
||||
import Reader from './components/Reader';
|
||||
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useLibraryStore } from '@/store/libraryStore';
|
||||
|
||||
import ReaderContent from './components/ReaderContent';
|
||||
import { AboutWindow } from '@/components/AboutWindow';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
|
||||
const ReaderPage = () => {
|
||||
const { envConfig } = useEnv();
|
||||
const { settings, setSettings } = useSettingsStore();
|
||||
const { library, setLibrary } = useLibraryStore();
|
||||
const isInitiating = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitiating.current) return;
|
||||
isInitiating.current = true;
|
||||
const initLibrary = async () => {
|
||||
const appService = await envConfig.getAppService();
|
||||
const settings = await appService.loadSettings();
|
||||
setSettings(settings);
|
||||
setLibrary(await appService.loadLibraryBooks());
|
||||
};
|
||||
|
||||
initLibrary();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return (
|
||||
library.length > 0 &&
|
||||
settings.globalReadSettings && (
|
||||
<div className='reader-page bg-base-100 text-base-content min-h-screen select-none'>
|
||||
<Suspense>
|
||||
<ReaderContent settings={settings} />
|
||||
<AboutWindow />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ReaderPage;
|
||||
export default function Page() {
|
||||
return <Reader />;
|
||||
}
|
||||
|
||||
@@ -78,3 +78,5 @@ export const SANS_SERIF_FONTS = ['Roboto', 'Noto Sans', 'Open Sans', 'Helvetica'
|
||||
export const MONOSPACE_FONTS = ['Fira Code', 'Lucida Console', 'Consolas', 'Courier New'];
|
||||
|
||||
export const ONE_COLUMN_MAX_INLINE_SIZE = 9999;
|
||||
|
||||
export const BOOK_IDS_SEPARATOR = '+';
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { isWebAppPlatform } from '@/services/environment';
|
||||
import { BOOK_IDS_SEPARATOR } from '@/services/constants';
|
||||
|
||||
export const navigateToReader = (
|
||||
router: ReturnType<typeof useRouter>,
|
||||
bookIds: string[],
|
||||
queryParams?: string,
|
||||
navOptions?: { scroll?: boolean },
|
||||
) => {
|
||||
const ids = bookIds.join(BOOK_IDS_SEPARATOR);
|
||||
if (isWebAppPlatform()) {
|
||||
router.push(`/reader/${ids}${queryParams ? `?${queryParams}` : ''}`, navOptions);
|
||||
} else {
|
||||
const params = new URLSearchParams(queryParams || '');
|
||||
params.set('ids', ids);
|
||||
router.push(`/reader?${params.toString()}`, navOptions);
|
||||
}
|
||||
};
|
||||
|
||||
export const navigateToLibrary = (router: ReturnType<typeof useRouter>) => {
|
||||
router.push('/library');
|
||||
};
|
||||
Reference in New Issue
Block a user