From e86782bf383d79cea84a51d4934328914a0a0b46 Mon Sep 17 00:00:00 2001 From: Richard Roberson Date: Sat, 22 Nov 2025 15:18:46 -0700 Subject: [PATCH] feat: improve document list and self-hosting clarity - Introduce a toggleable grid/list view for the document list, enhancing organization and display flexibility. This involved updates across `DocumentList`, `DocumentFolder`, `DocumentListItem`, and `SortControls`. - Add a new `CodeBlock` component and integrate detailed Docker-based self-hosting instructions into the footer. - Enhance privacy policy popover with clearer details on Deepinfra usage and strongly recommend self-hosting for secure experience. - Implement conditional rendering and feature gating based on the `isDev` environment variable, differentiating features between the production demo and self-hosted instances. Affected components include `page.tsx`, `DocumentSettings.tsx`, `SettingsModal.tsx`, and `config.ts`. - Clarify that advanced features like audiobook export and word-by-word highlighting via `whisper.cpp` are exclusive to self-hosted setups and are disabled in the demo. - Expand the list of supported document types on the homepage to include MD and TXT. - Integrate new `ListIcon`, `GridIcon`, and `CopyIcon` to support UI enhancements. - Add a custom `xs` breakpoint in `tailwind.config.ts` for improved responsive design. --- src/app/page.tsx | 8 +- src/components/CodeBlock.tsx | 32 ++++++++ src/components/DocumentSettings.tsx | 20 ++--- src/components/EPUBViewer.tsx | 13 ++-- src/components/Footer.tsx | 79 +++++++++++++++++--- src/components/SettingsModal.tsx | 2 +- src/components/doclist/DocumentFolder.tsx | 9 ++- src/components/doclist/DocumentList.tsx | 42 ++++++----- src/components/doclist/DocumentListItem.tsx | 8 +- src/components/doclist/SortControls.tsx | 83 ++++++++++++++------- src/components/icons/Icons.tsx | 52 +++++++++++++ src/types/config.ts | 11 ++- src/types/documents.ts | 1 + tailwind.config.ts | 3 + 14 files changed, 279 insertions(+), 84 deletions(-) create mode 100644 src/components/CodeBlock.tsx diff --git a/src/app/page.tsx b/src/app/page.tsx index 286c7e5..24a4558 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,7 @@ import { HomeContent } from '@/components/HomeContent'; import { SettingsModal } from '@/components/SettingsModal'; -// Home page redesigned for fullscreen layout: hero + document area. +const isDev = process.env.NEXT_PUBLIC_NODE_ENV !== 'production' || process.env.NODE_ENV == null; export default function Home() { return ( @@ -10,9 +10,9 @@ export default function Home() {

OpenReader WebUI

-

- Bring your own text-to-speech API. - Read & listen to PDF, EPUB & HTML documents with high quality voices. +

+ Open source document reader web app {isDev ? 'self-hosted server' : 'demo'}. + Read & listen to PDF, EPUB, MD, and TXT documents with high quality text to speech voices.

diff --git a/src/components/CodeBlock.tsx b/src/components/CodeBlock.tsx new file mode 100644 index 0000000..a887c96 --- /dev/null +++ b/src/components/CodeBlock.tsx @@ -0,0 +1,32 @@ +'use client'; + +import { useState } from 'react'; +import { CopyIcon, CheckIcon } from '@/components/icons/Icons'; + +export function CodeBlock({ children }: { children: string }) { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + await navigator.clipboard.writeText(children); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( +
+
+        {children}
+      
+ +
+ ); +} diff --git a/src/components/DocumentSettings.tsx b/src/components/DocumentSettings.tsx index f78d482..515d300 100644 --- a/src/components/DocumentSettings.tsx +++ b/src/components/DocumentSettings.tsx @@ -141,16 +141,18 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: { leaveTo="opacity-0 scale-95" > - {isDev && !html &&
+ {!html &&
} @@ -352,18 +354,18 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: { updateConfigKey('pdfWordHighlightEnabled', e.target.checked) } - className="form-checkbox h-4 w-4 text-accent rounded border-muted disabled:opacity-50" + className="form-checkbox h-4 w-4 text-accent rounded border-muted disabled:opacity-50 disabled:cursor-not-allowed" /> Word-by-word

- Highlight individual words using audio timestamps generated by whisper.cpp + Highlight individual words using audio timestamps generated by whisper.cpp {!isDev && '(requires self-hosted)'}

@@ -389,18 +391,18 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: { updateConfigKey('epubWordHighlightEnabled', e.target.checked) } - className="form-checkbox h-4 w-4 text-accent rounded border-muted disabled:opacity-50" + className="form-checkbox h-4 w-4 text-accent rounded border-muted disabled:opacity-50 disabled:cursor-not-allowed" /> Word-by-word

- Highlight individual words using audio timestamps generated by whisper.cpp + Highlight individual words using audio timestamps generated by whisper.cpp {!isDev && '(requires self-hosted)'}

diff --git a/src/components/EPUBViewer.tsx b/src/components/EPUBViewer.tsx index 7289538..3c38034 100644 --- a/src/components/EPUBViewer.tsx +++ b/src/components/EPUBViewer.tsx @@ -156,18 +156,21 @@ export function EPUBViewer({ className = '' }: EPUBViewerProps) { {isTocOpen && tocRef.current && tocRef.current.length > 0 && (
Skip to chapters
-
+
{tocRef.current.map((item, index) => ( diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx index b81abaa..8b0182b 100644 --- a/src/components/Footer.tsx +++ b/src/components/Footer.tsx @@ -1,10 +1,14 @@ import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react' import { GithubIcon } from '@/components/icons/Icons' +import { CodeBlock } from '@/components/CodeBlock' + +const isDev = process.env.NEXT_PUBLIC_NODE_ENV !== 'production' || process.env.NODE_ENV == null; + export function Footer() { return ( -