@pressy-pub/components 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/content/index.d.ts +41 -0
- package/dist/content/index.js +368 -0
- package/dist/content/index.js.map +1 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.js +2618 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Reader.tsx","../src/Navigation.tsx","../src/TextShare.tsx","../src/OfflineIndicator.tsx","../src/TableOfContents.tsx","../src/Paywall.tsx","../src/ThemeSwitcher.tsx","../src/DownloadBook.tsx","../src/BookProgress.tsx"],"sourcesContent":["import { ComponentChildren, ComponentType } from \"preact\";\nimport { useState, useEffect, useRef, useCallback } from \"preact/hooks\";\n\nimport { Navigation } from \"./Navigation.js\";\nimport { TextShare } from \"./TextShare.js\";\nimport { OfflineIndicator } from \"./OfflineIndicator.js\";\n\nexport interface ProgressData {\n page: number;\n totalPages: number;\n scrollPosition: number;\n}\n\nexport interface ChapterMapData {\n chapterMap: Record<\n string,\n () => Promise<{\n default: ComponentType<{ components?: Record<string, unknown> }>;\n }>\n >;\n chapterOrder: string[];\n}\n\nexport interface ReaderProps {\n children: ComponentChildren;\n title: string;\n bookTitle?: string;\n chapterSlug?: string;\n prevChapter?: { slug: string; title: string };\n nextChapter?: { slug: string; title: string };\n showDropCap?: boolean;\n paginationMode?: \"scroll\" | \"paginated\";\n onSaveProgress?: (data: ProgressData) => void;\n onRestoreProgress?: () => Promise<ProgressData | null>;\n bookProgressPercent?: number;\n initialContent?: ComponentType<{ components?: Record<string, unknown> }>;\n chapterMapData?: ChapterMapData;\n currentChapterSlug?: string;\n allChapters?: Array<{ slug: string; title: string; wordCount?: number }>;\n bookBasePath?: string;\n onChapterChange?: (slug: string, page: number, totalPages: number) => void;\n mdxComponents?: Record<string, unknown>;\n}\n\nexport function Reader({\n children,\n bookTitle,\n prevChapter,\n nextChapter,\n showDropCap = true,\n paginationMode = \"scroll\",\n onSaveProgress,\n onRestoreProgress,\n bookProgressPercent,\n initialContent,\n chapterMapData,\n currentChapterSlug,\n allChapters,\n bookBasePath,\n onChapterChange,\n mdxComponents,\n}: ReaderProps) {\n if (paginationMode === \"paginated\") {\n return (\n <PaginatedReader\n bookTitle={bookTitle}\n prevChapter={prevChapter}\n nextChapter={nextChapter}\n showDropCap={showDropCap}\n onSaveProgress={onSaveProgress}\n onRestoreProgress={onRestoreProgress}\n bookProgressPercent={bookProgressPercent}\n initialContent={initialContent}\n chapterMapData={chapterMapData}\n currentChapterSlug={currentChapterSlug}\n allChapters={allChapters}\n bookBasePath={bookBasePath}\n onChapterChange={onChapterChange}\n mdxComponents={mdxComponents}\n >\n {children}\n </PaginatedReader>\n );\n }\n\n return (\n <ScrollReader\n prevChapter={prevChapter}\n nextChapter={nextChapter}\n showDropCap={showDropCap}\n onSaveProgress={onSaveProgress}\n onRestoreProgress={onRestoreProgress}\n >\n {children}\n </ScrollReader>\n );\n}\n\n// ── Scroll Reader ────────────────────────────────────────────\n\ninterface ScrollReaderProps {\n children: ComponentChildren;\n prevChapter?: { slug: string; title: string };\n nextChapter?: { slug: string; title: string };\n showDropCap: boolean;\n onSaveProgress?: (data: ProgressData) => void;\n onRestoreProgress?: () => Promise<ProgressData | null>;\n}\n\nfunction ScrollReader({\n children,\n prevChapter,\n nextChapter,\n showDropCap,\n onSaveProgress,\n onRestoreProgress,\n}: ScrollReaderProps) {\n const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Restore scroll position on mount\n useEffect(() => {\n if (!onRestoreProgress) return;\n onRestoreProgress().then((data) => {\n if (data && data.scrollPosition > 0) {\n window.scrollTo(0, data.scrollPosition);\n }\n });\n }, []);\n\n // Save scroll position (debounced)\n useEffect(() => {\n if (!onSaveProgress) return;\n\n const handleScroll = () => {\n if (saveTimerRef.current) clearTimeout(saveTimerRef.current);\n saveTimerRef.current = setTimeout(() => {\n onSaveProgress({\n page: 0,\n totalPages: 0,\n scrollPosition: window.scrollY,\n });\n }, 500);\n };\n\n window.addEventListener(\"scroll\", handleScroll, { passive: true });\n return () => {\n window.removeEventListener(\"scroll\", handleScroll);\n if (saveTimerRef.current) clearTimeout(saveTimerRef.current);\n };\n }, [onSaveProgress]);\n\n // Save on page unload\n useEffect(() => {\n if (!onSaveProgress) return;\n\n const handleUnload = () => {\n onSaveProgress({\n page: 0,\n totalPages: 0,\n scrollPosition: window.scrollY,\n });\n };\n\n window.addEventListener(\"beforeunload\", handleUnload);\n return () => window.removeEventListener(\"beforeunload\", handleUnload);\n }, [onSaveProgress]);\n\n return (\n <div class=\"pressy-reader\">\n <main class=\"pressy-reader-main\">\n <article\n class={`pressy-prose ${showDropCap ? \"\" : \"no-drop-cap\"}`}\n data-drop-cap={showDropCap}\n >\n {children}\n </article>\n </main>\n\n <TextShare />\n <Navigation prev={prevChapter} next={nextChapter} />\n <OfflineIndicator />\n\n <style>{SCROLL_STYLES}</style>\n </div>\n );\n}\n\n// ── Paginated Reader ──────────────────────────────────────────\n\ninterface LoadedChapter {\n slug: string;\n title: string;\n Content: ComponentType<{ components?: Record<string, unknown> }>;\n}\n\ninterface ChapterPageRange {\n slug: string;\n startPage: number;\n endPage: number;\n}\n\ninterface PaginatedReaderProps {\n children: ComponentChildren;\n bookTitle?: string;\n prevChapter?: { slug: string; title: string };\n nextChapter?: { slug: string; title: string };\n showDropCap: boolean;\n onSaveProgress?: (data: ProgressData) => void;\n onRestoreProgress?: () => Promise<ProgressData | null>;\n bookProgressPercent?: number;\n initialContent?: ComponentType<{ components?: Record<string, unknown> }>;\n chapterMapData?: ChapterMapData;\n currentChapterSlug?: string;\n allChapters?: Array<{ slug: string; title: string; wordCount?: number }>;\n bookBasePath?: string;\n onChapterChange?: (slug: string, page: number, totalPages: number) => void;\n mdxComponents?: Record<string, unknown>;\n}\n\nfunction ChapterDivider({ title }: { title: string }) {\n return (\n <div class=\"pressy-chapter-divider\">\n <h2 class=\"pressy-chapter-divider-title\">{title}</h2>\n </div>\n );\n}\n\nfunction PaginatedReader({\n children,\n bookTitle,\n prevChapter,\n nextChapter,\n showDropCap,\n onSaveProgress,\n onRestoreProgress,\n bookProgressPercent,\n initialContent,\n chapterMapData,\n currentChapterSlug,\n allChapters,\n bookBasePath,\n onChapterChange,\n mdxComponents,\n}: PaginatedReaderProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const viewportRef = useRef<HTMLDivElement>(null);\n const articleRef = useRef<HTMLElement>(null);\n const [currentPage, setCurrentPage] = useState(0);\n const [totalPages, setTotalPages] = useState(1);\n const hasRestoredRef = useRef(false);\n const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Multi-chapter state\n const [loadedChapters, setLoadedChapters] = useState<LoadedChapter[]>([]);\n const [chapterRanges, setChapterRanges] = useState<ChapterPageRange[]>([]);\n const [activeChapterSlug, setActiveChapterSlug] = useState(\n currentChapterSlug || \"\"\n );\n const preloadingRef = useRef<Set<string>>(new Set());\n\n // Whether we're in multi-chapter mode\n const isMultiChapter = !!(\n chapterMapData &&\n initialContent &&\n currentChapterSlug &&\n allChapters\n );\n\n // Initialize loaded chapters\n useEffect(() => {\n if (isMultiChapter && initialContent && currentChapterSlug) {\n const chapterInfo = allChapters!.find(\n (ch) => ch.slug === currentChapterSlug\n );\n setLoadedChapters([\n {\n slug: currentChapterSlug,\n title: chapterInfo?.title || currentChapterSlug,\n Content: initialContent,\n },\n ]);\n setActiveChapterSlug(currentChapterSlug);\n }\n }, []); // Only on mount\n\n // Settings panel state\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [activeTheme, setActiveTheme] = useState<string>(() => {\n if (typeof localStorage !== \"undefined\") {\n return localStorage.getItem(\"pressy-theme\") || \"light\";\n }\n return \"light\";\n });\n const [fontScale, setFontScale] = useState<number>(() => {\n if (typeof localStorage !== \"undefined\") {\n const saved = localStorage.getItem(\"pressy-font-size\");\n return saved ? parseFloat(saved) : 1.0;\n }\n return 1.0;\n });\n\n const applyFontScale = useCallback((scale: number) => {\n if (scale === 1.0) {\n document.documentElement.style.removeProperty(\"--font-size-base\");\n } else {\n document.documentElement.style.setProperty(\n \"--font-size-base\",\n `calc(clamp(1rem, 0.875rem + 0.5vw, 1.25rem) * ${scale})`\n );\n }\n }, []);\n\n // Apply saved font scale on mount\n useEffect(() => {\n if (fontScale !== 1.0) {\n applyFontScale(fontScale);\n }\n }, []);\n\n const handleThemeChange = useCallback((theme: string) => {\n setActiveTheme(theme);\n localStorage.setItem(\"pressy-theme\", theme);\n const resolved =\n theme === \"system\"\n ? window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\"\n : theme;\n document.documentElement.setAttribute(\"data-theme\", resolved);\n }, []);\n\n // Drag/swipe state\n const [isDragging, setIsDragging] = useState(false);\n const [dragOffset, setDragOffset] = useState(0);\n const [chapterHint, setChapterHint] = useState<\"next\" | \"prev\" | null>(null);\n\n // Touch tracking refs (avoid re-renders during drag)\n const touchStartXRef = useRef(0);\n const touchStartYRef = useRef(0);\n const lastTouchXRef = useRef(0);\n const lastTouchTimeRef = useRef(0);\n const velocityRef = useRef(0);\n const isSwipingRef = useRef(false);\n const isDraggingRef = useRef(false);\n\n // Build page-to-chapter map after recalculating pages\n const updateChapterRanges = useCallback(() => {\n if (!isMultiChapter) return;\n const article = articleRef.current;\n const viewport = viewportRef.current;\n if (!article || !viewport) return;\n\n const viewportWidth = viewport.clientWidth;\n if (viewportWidth === 0) return;\n\n const sections = article.querySelectorAll(\".pressy-chapter-section\");\n const ranges: ChapterPageRange[] = [];\n\n sections.forEach((section) => {\n const slug = section.getAttribute(\"data-chapter-slug\") || \"\";\n const sectionLeft = (section as HTMLElement).offsetLeft;\n const sectionWidth = (section as HTMLElement).scrollWidth;\n const startPage = Math.floor(sectionLeft / viewportWidth);\n const endPage = Math.max(\n startPage,\n Math.ceil((sectionLeft + sectionWidth) / viewportWidth) - 1\n );\n ranges.push({ slug, startPage, endPage });\n });\n\n setChapterRanges(ranges);\n }, [isMultiChapter]);\n\n // Calculate page count and set column-width to match viewport\n const recalculatePages = useCallback(() => {\n const article = articleRef.current;\n const viewport = viewportRef.current;\n if (!article || !viewport) return;\n\n const viewportWidth = viewport.clientWidth;\n if (viewportWidth === 0) return;\n\n // Set column-width to viewport width so each column = one page\n article.style.columnWidth = `${viewportWidth}px`;\n\n // Force synchronous layout recalculation\n void article.scrollWidth;\n\n const total = Math.max(1, Math.round(article.scrollWidth / viewportWidth));\n setTotalPages(total);\n\n // Clamp current page if now out of bounds (e.g. after resize)\n setCurrentPage((prev) => Math.min(prev, total - 1));\n\n // Update chapter ranges for multi-chapter mode\n updateChapterRanges();\n }, [updateChapterRanges]);\n\n // Font size change handler (defined after recalculatePages)\n const handleFontSizeChange = useCallback(\n (delta: number) => {\n setFontScale((prev) => {\n const next =\n Math.round(Math.max(0.8, Math.min(1.5, prev + delta)) * 10) / 10;\n localStorage.setItem(\"pressy-font-size\", String(next));\n applyFontScale(next);\n setTimeout(() => recalculatePages(), 100);\n return next;\n });\n },\n [applyFontScale, recalculatePages]\n );\n\n // Recalculate on mount and on resize via ResizeObserver\n useEffect(() => {\n const viewport = viewportRef.current;\n if (!viewport) return;\n\n // Delay initial calculation to let fonts and content render\n const initialTimer = setTimeout(recalculatePages, 50);\n\n const observer = new ResizeObserver(() => {\n recalculatePages();\n });\n observer.observe(viewport);\n\n return () => {\n clearTimeout(initialTimer);\n observer.disconnect();\n };\n }, [recalculatePages]);\n\n // Recalculate when loaded chapters change\n useEffect(() => {\n if (loadedChapters.length > 0) {\n // Delay to let new content render\n const timer = setTimeout(recalculatePages, 50);\n return () => clearTimeout(timer);\n }\n }, [loadedChapters.length, recalculatePages]);\n\n // Recalculate when images finish loading\n useEffect(() => {\n const article = articleRef.current;\n if (!article) return;\n\n const images = article.querySelectorAll(\"img\");\n if (images.length === 0) return;\n\n const onLoad = () => recalculatePages();\n images.forEach((img) => {\n if (!img.complete) {\n img.addEventListener(\"load\", onLoad);\n img.addEventListener(\"error\", onLoad);\n }\n });\n\n return () => {\n images.forEach((img) => {\n img.removeEventListener(\"load\", onLoad);\n img.removeEventListener(\"error\", onLoad);\n });\n };\n }, [recalculatePages, loadedChapters.length]);\n\n // Check ?page=last query param for backward navigation\n useEffect(() => {\n const params = new URLSearchParams(window.location.search);\n if (params.get(\"page\") === \"last\" && totalPages > 1) {\n setCurrentPage(totalPages - 1);\n hasRestoredRef.current = true;\n // Clean up the URL\n const url = new URL(window.location.href);\n url.searchParams.delete(\"page\");\n history.replaceState(null, \"\", url.pathname);\n }\n }, [totalPages]);\n\n // Apply translateX — combines page position + drag offset\n useEffect(() => {\n const article = articleRef.current;\n const viewport = viewportRef.current;\n if (!article || !viewport) return;\n\n const baseOffset = currentPage * viewport.clientWidth;\n const totalOffset = baseOffset - dragOffset;\n\n if (isDragging) {\n // During drag: no transition, immediate response\n article.style.transition = \"none\";\n } else {\n // Snap animation: smooth ease-out\n article.style.transition =\n \"transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)\";\n }\n\n article.style.transform = `translateX(-${totalOffset}px)`;\n }, [currentPage, dragOffset, isDragging]);\n\n // Manage focusability: elements on off-screen pages get tabindex=\"-1\"\n // so tab navigation can't reach them and cause layout shifts.\n // Uses getBoundingClientRect which accounts for the CSS transform.\n useEffect(() => {\n const article = articleRef.current;\n const viewport = viewportRef.current;\n if (!article || !viewport) return;\n\n const viewportRect = viewport.getBoundingClientRect();\n\n const focusable = article.querySelectorAll<HTMLElement>(\n \"a[href], button, input, select, textarea, [tabindex]\"\n );\n\n focusable.forEach((el) => {\n const elRect = el.getBoundingClientRect();\n const onCurrentPage =\n elRect.left >= viewportRect.left - 1 &&\n elRect.right <= viewportRect.right + 1;\n\n if (onCurrentPage) {\n const original = el.getAttribute(\"data-original-tabindex\");\n if (original !== null) {\n if (original === \"\") {\n el.removeAttribute(\"tabindex\");\n } else {\n el.setAttribute(\"tabindex\", original);\n }\n el.removeAttribute(\"data-original-tabindex\");\n }\n } else {\n if (!el.hasAttribute(\"data-original-tabindex\")) {\n el.setAttribute(\n \"data-original-tabindex\",\n el.getAttribute(\"tabindex\") || \"\"\n );\n }\n el.setAttribute(\"tabindex\", \"-1\");\n }\n });\n }, [currentPage, totalPages]);\n\n // Preload next chapter when within 2 pages of chapter end\n useEffect(() => {\n if (!isMultiChapter || !chapterMapData || chapterRanges.length === 0)\n return;\n\n const activeRange = chapterRanges.find((r) => r.slug === activeChapterSlug);\n if (!activeRange) return;\n\n const pagesFromEnd = activeRange.endPage - currentPage;\n if (pagesFromEnd > 2) return;\n\n // Find the next chapter to preload\n const { chapterOrder, chapterMap } = chapterMapData;\n const lastLoadedSlug = loadedChapters[loadedChapters.length - 1]?.slug;\n const lastLoadedIdx = chapterOrder.indexOf(lastLoadedSlug);\n if (lastLoadedIdx === -1 || lastLoadedIdx >= chapterOrder.length - 1)\n return;\n\n const nextSlug = chapterOrder[lastLoadedIdx + 1];\n if (preloadingRef.current.has(nextSlug)) return;\n if (loadedChapters.some((ch) => ch.slug === nextSlug)) return;\n\n preloadingRef.current.add(nextSlug);\n\n const loader = chapterMap[nextSlug];\n if (!loader) return;\n\n loader()\n .then((mod) => {\n const Content = mod.default;\n const chapterInfo = allChapters!.find((ch) => ch.slug === nextSlug);\n setLoadedChapters((prev) => {\n if (prev.some((ch) => ch.slug === nextSlug)) return prev;\n return [\n ...prev,\n {\n slug: nextSlug,\n title: chapterInfo?.title || nextSlug,\n Content,\n },\n ];\n });\n })\n .catch(() => {\n // Dynamic import failed — will fall back to full-page navigation\n preloadingRef.current.delete(nextSlug);\n });\n }, [\n currentPage,\n activeChapterSlug,\n chapterRanges,\n isMultiChapter,\n chapterMapData,\n loadedChapters,\n allChapters,\n ]);\n\n // Detect chapter boundary crossings and update URL / active chapter\n useEffect(() => {\n if (!isMultiChapter || chapterRanges.length === 0 || !bookBasePath) return;\n\n const currentRange = chapterRanges.find(\n (r) => currentPage >= r.startPage && currentPage <= r.endPage\n );\n if (!currentRange || currentRange.slug === activeChapterSlug) return;\n\n const prevSlug = activeChapterSlug;\n setActiveChapterSlug(currentRange.slug);\n\n // Update URL\n const newPath = `${bookBasePath}/${currentRange.slug}`;\n history.replaceState(null, \"\", newPath);\n\n // Update document title\n const chapterInfo = allChapters?.find(\n (ch) => ch.slug === currentRange.slug\n );\n if (chapterInfo) {\n document.title = document.title.replace(\n /^[^|]+/,\n chapterInfo.title + \" \"\n );\n }\n\n // Notify parent about chapter change (saves progress for the chapter being left)\n if (onChapterChange && prevSlug) {\n const prevRange = chapterRanges.find((r) => r.slug === prevSlug);\n if (prevRange) {\n const prevTotalPages = prevRange.endPage - prevRange.startPage + 1;\n onChapterChange(prevSlug, prevTotalPages - 1, prevTotalPages);\n }\n }\n }, [\n currentPage,\n chapterRanges,\n activeChapterSlug,\n isMultiChapter,\n bookBasePath,\n allChapters,\n onChapterChange,\n ]);\n\n // Save progress when page changes (debounced) — save relative to active chapter\n useEffect(() => {\n if (!onSaveProgress || !hasRestoredRef.current) return;\n\n if (saveTimerRef.current) clearTimeout(saveTimerRef.current);\n saveTimerRef.current = setTimeout(() => {\n if (isMultiChapter && chapterRanges.length > 0) {\n const activeRange = chapterRanges.find(\n (r) => r.slug === activeChapterSlug\n );\n if (activeRange) {\n const chapterPage = currentPage - activeRange.startPage;\n const chapterTotalPages =\n activeRange.endPage - activeRange.startPage + 1;\n onSaveProgress({\n page: chapterPage,\n totalPages: chapterTotalPages,\n scrollPosition: 0,\n });\n }\n } else {\n onSaveProgress({\n page: currentPage,\n totalPages,\n scrollPosition: 0,\n });\n }\n }, 300);\n\n return () => {\n if (saveTimerRef.current) clearTimeout(saveTimerRef.current);\n };\n }, [\n currentPage,\n totalPages,\n onSaveProgress,\n isMultiChapter,\n chapterRanges,\n activeChapterSlug,\n ]);\n\n // Save progress on page unload\n useEffect(() => {\n if (!onSaveProgress) return;\n\n const handleUnload = () => {\n if (isMultiChapter && chapterRanges.length > 0) {\n const activeRange = chapterRanges.find(\n (r) => r.slug === activeChapterSlug\n );\n if (activeRange) {\n const chapterPage = currentPage - activeRange.startPage;\n const chapterTotalPages =\n activeRange.endPage - activeRange.startPage + 1;\n onSaveProgress({\n page: chapterPage,\n totalPages: chapterTotalPages,\n scrollPosition: 0,\n });\n }\n } else {\n onSaveProgress({\n page: currentPage,\n totalPages,\n scrollPosition: 0,\n });\n }\n };\n\n window.addEventListener(\"beforeunload\", handleUnload);\n return () => window.removeEventListener(\"beforeunload\", handleUnload);\n }, [\n currentPage,\n totalPages,\n onSaveProgress,\n isMultiChapter,\n chapterRanges,\n activeChapterSlug,\n ]);\n\n // Determine the effective last chapter slug for rubber-band / next chapter hint\n const effectiveNextChapter = (() => {\n if (!isMultiChapter || !chapterMapData) return nextChapter;\n const { chapterOrder } = chapterMapData;\n const lastLoadedSlug = loadedChapters[loadedChapters.length - 1]?.slug;\n const lastLoadedIdx = chapterOrder.indexOf(lastLoadedSlug);\n // If we haven't loaded the last chapter in the book yet, no next chapter hint needed\n // (preloading will seamlessly add the next chapter)\n if (lastLoadedIdx < chapterOrder.length - 1) return undefined;\n // All chapters loaded — navigate to book table of contents\n if (bookBasePath) return { slug: bookBasePath, title: \"Table of Contents\" };\n return nextChapter;\n })();\n\n // Determine the effective prev chapter for backward navigation\n const effectivePrevChapter = (() => {\n if (!isMultiChapter || !chapterMapData) return prevChapter;\n const { chapterOrder } = chapterMapData;\n const firstLoadedSlug = loadedChapters[0]?.slug;\n const firstLoadedIdx = chapterOrder.indexOf(firstLoadedSlug);\n // If the first loaded chapter is the first chapter of the book\n if (firstLoadedIdx <= 0) return prevChapter;\n // There's a previous chapter in the book — navigate to it via page load\n const prevSlug = chapterOrder[firstLoadedIdx - 1];\n const prevInfo = allChapters?.find((ch) => ch.slug === prevSlug);\n return {\n slug: `${bookBasePath}/${prevSlug}?page=last`,\n title: prevInfo?.title || prevSlug,\n };\n })();\n\n const goToPage = useCallback(\n (page: number) => {\n const clamped = Math.max(0, Math.min(page, totalPages - 1));\n setCurrentPage(clamped);\n },\n [totalPages]\n );\n\n const goNext = useCallback(() => {\n if (currentPage >= totalPages - 1) {\n // At the last page — navigate to next chapter if available\n if (effectiveNextChapter) {\n window.location.href = effectiveNextChapter.slug;\n }\n return;\n }\n goToPage(currentPage + 1);\n }, [currentPage, totalPages, effectiveNextChapter, goToPage]);\n\n const goPrev = useCallback(() => {\n if (currentPage <= 0) {\n // At the first page — navigate to prev chapter if available\n if (effectivePrevChapter) {\n window.location.href = effectivePrevChapter.slug;\n }\n return;\n }\n goToPage(currentPage - 1);\n }, [currentPage, effectivePrevChapter, goToPage]);\n\n // Footer visibility — hidden by default, shown on interaction\n const [footerVisible, setFooterVisible] = useState(false);\n const footerTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const showFooterTemporarily = useCallback(() => {\n setFooterVisible(true);\n if (footerTimerRef.current) clearTimeout(footerTimerRef.current);\n footerTimerRef.current = setTimeout(() => setFooterVisible(false), 3000);\n }, []);\n\n // Double-tap fullscreen (mobile middle-third)\n const lastMiddleTapRef = useRef(0);\n const middleTapTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const toggleFullscreen = useCallback(() => {\n if (document.fullscreenElement) {\n document.exitFullscreen();\n } else {\n document.documentElement.requestFullscreen().catch(() => {\n // Fullscreen not supported or denied\n });\n }\n }, []);\n\n // Tap-to-turn: clicking left/right thirds of the screen turns pages.\n // Uses a click handler on the container so interactive content (links,\n // footnotes, buttons) naturally gets priority via event bubbling.\n const handleContainerClick = useCallback(\n (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n\n // Clicks inside the settings panel or on interactive elements — don't turn pages\n if (target.closest(\".pressy-settings-panel, .pressy-settings-toggle\"))\n return;\n if (target.closest('a, button, input, select, textarea, [role=\"button\"]'))\n return;\n\n // If settings panel is open, close it on any outside click\n if (settingsOpen) {\n setSettingsOpen(false);\n return;\n }\n\n const container = containerRef.current;\n if (!container) return;\n\n const rect = container.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const edgeZone = rect.width * 0.15;\n\n if (x < edgeZone) {\n goPrev();\n } else if (x > rect.width - edgeZone) {\n goNext();\n } else {\n // Middle third tap — single tap toggles footer, double tap toggles fullscreen\n const now = Date.now();\n const timeSinceLastTap = now - lastMiddleTapRef.current;\n lastMiddleTapRef.current = now;\n\n if (timeSinceLastTap < 300) {\n // Double tap — cancel pending single-tap action, toggle fullscreen\n if (middleTapTimerRef.current)\n clearTimeout(middleTapTimerRef.current);\n toggleFullscreen();\n } else {\n // Possible single tap — delay to check for double tap\n if (middleTapTimerRef.current)\n clearTimeout(middleTapTimerRef.current);\n middleTapTimerRef.current = setTimeout(() => {\n if (footerVisible) {\n setFooterVisible(false);\n if (footerTimerRef.current) clearTimeout(footerTimerRef.current);\n } else {\n showFooterTemporarily();\n }\n }, 300);\n }\n }\n },\n [\n goNext,\n goPrev,\n footerVisible,\n settingsOpen,\n showFooterTemporarily,\n toggleFullscreen,\n ]\n );\n\n // Hover zone tracking for desktop navigation hints\n const [hoverZone, setHoverZone] = useState<\"left\" | \"right\" | null>(null);\n\n const handleMouseMove = useCallback(\n (e: MouseEvent) => {\n const container = containerRef.current;\n if (!container) return;\n\n const rect = container.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n const third = rect.width / 3;\n\n if (x < third) {\n setHoverZone(\"left\");\n } else if (x > third * 2) {\n setHoverZone(\"right\");\n } else {\n setHoverZone(null);\n }\n\n // Show footer when mouse is in the bottom quarter\n if (y > rect.height * 0.75) {\n setFooterVisible(true);\n if (footerTimerRef.current) clearTimeout(footerTimerRef.current);\n } else if (!settingsOpen) {\n // Hide after a short delay when leaving the bottom area (not when settings is open)\n if (footerTimerRef.current) clearTimeout(footerTimerRef.current);\n footerTimerRef.current = setTimeout(() => setFooterVisible(false), 600);\n }\n },\n [settingsOpen]\n );\n\n const handleMouseLeave = useCallback(() => {\n setHoverZone(null);\n if (!settingsOpen) {\n if (footerTimerRef.current) clearTimeout(footerTimerRef.current);\n footerTimerRef.current = setTimeout(() => setFooterVisible(false), 600);\n }\n }, [settingsOpen]);\n\n // Keyboard navigation\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n // Don't intercept if user is in an input/textarea\n const tag = (e.target as HTMLElement).tagName;\n if (tag === \"INPUT\" || tag === \"TEXTAREA\" || tag === \"SELECT\") return;\n\n if (e.key === \"ArrowRight\" || e.key === \" \") {\n e.preventDefault();\n goNext();\n } else if (e.key === \"ArrowLeft\") {\n e.preventDefault();\n goPrev();\n } else if (e.key === \"Home\") {\n e.preventDefault();\n goToPage(0);\n } else if (e.key === \"End\") {\n e.preventDefault();\n goToPage(totalPages - 1);\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [goNext, goPrev, goToPage, totalPages]);\n\n // Touch swipe navigation with drag tracking, velocity detection, and rubber-band.\n // Listeners attach to the outer container (not the viewport) so they capture\n // touches that land on sibling elements like the tap-zone overlays.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const onTouchStart = (e: TouchEvent) => {\n const touch = e.touches[0];\n touchStartXRef.current = touch.clientX;\n touchStartYRef.current = touch.clientY;\n lastTouchXRef.current = touch.clientX;\n lastTouchTimeRef.current = performance.now();\n velocityRef.current = 0;\n isSwipingRef.current = false;\n isDraggingRef.current = false;\n };\n\n const onTouchMove = (e: TouchEvent) => {\n const touch = e.touches[0];\n const dx = touch.clientX - touchStartXRef.current;\n const dy = touch.clientY - touchStartYRef.current;\n\n // Lock direction after initial movement\n if (!isSwipingRef.current) {\n if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 10) {\n isSwipingRef.current = true;\n } else if (Math.abs(dy) > Math.abs(dx) && Math.abs(dy) > 10) {\n // Vertical scroll — not our concern\n return;\n } else {\n return; // Not enough movement yet\n }\n }\n\n e.preventDefault();\n\n // Track velocity (px per ms) using last touch position\n const now = performance.now();\n const timeDelta = now - lastTouchTimeRef.current;\n if (timeDelta > 0) {\n const instantVelocity =\n (touch.clientX - lastTouchXRef.current) / timeDelta;\n // Smooth velocity with exponential moving average\n velocityRef.current = 0.6 * instantVelocity + 0.4 * velocityRef.current;\n }\n lastTouchXRef.current = touch.clientX;\n lastTouchTimeRef.current = now;\n\n // Determine drag offset with rubber-band resistance at boundaries\n let offset = dx;\n const atStart = currentPage === 0;\n const atEnd = currentPage >= totalPages - 1;\n\n if ((atStart && dx > 0) || (atEnd && dx < 0)) {\n // Rubber-band: diminishing resistance using square root curve\n // This gives a natural iOS-like rubber-band feel\n const sign = dx > 0 ? 1 : -1;\n const absDx = Math.abs(dx);\n offset = sign * Math.sqrt(absDx) * 5;\n\n // Show chapter hint when overscrolling past boundary\n if (dx > 40 && atStart && effectivePrevChapter) {\n setChapterHint(\"prev\");\n } else if (dx < -40 && atEnd && effectiveNextChapter) {\n setChapterHint(\"next\");\n } else {\n setChapterHint(null);\n }\n } else {\n setChapterHint(null);\n }\n\n isDraggingRef.current = true;\n setIsDragging(true);\n setDragOffset(offset);\n };\n\n const onTouchEnd = (e: TouchEvent) => {\n if (!isSwipingRef.current || !isDraggingRef.current) {\n setIsDragging(false);\n setDragOffset(0);\n setChapterHint(null);\n return;\n }\n\n const dx = e.changedTouches[0].clientX - touchStartXRef.current;\n const velocity = velocityRef.current; // px/ms\n const distanceThreshold = 50;\n const velocityThreshold = 0.3; // px/ms — a fast flick\n const chapterThreshold = 80;\n\n const atStart = currentPage === 0;\n const atEnd = currentPage >= totalPages - 1;\n\n // Chapter navigation on overscroll\n if (atEnd && dx < -chapterThreshold && effectiveNextChapter) {\n setIsDragging(false);\n setDragOffset(0);\n setChapterHint(null);\n window.location.href = effectiveNextChapter.slug;\n return;\n }\n if (atStart && dx > chapterThreshold && effectivePrevChapter) {\n setIsDragging(false);\n setDragOffset(0);\n setChapterHint(null);\n window.location.href = effectivePrevChapter.slug;\n return;\n }\n\n // Determine page change: distance OR velocity triggers a turn\n if (dx < -distanceThreshold || velocity < -velocityThreshold) {\n goNext();\n } else if (dx > distanceThreshold || velocity > velocityThreshold) {\n goPrev();\n }\n\n // Reset drag state — the CSS transition handles the snap animation\n isDraggingRef.current = false;\n setIsDragging(false);\n setDragOffset(0);\n setChapterHint(null);\n };\n\n // Cancel drag if touch is interrupted\n const onTouchCancel = () => {\n isDraggingRef.current = false;\n setIsDragging(false);\n setDragOffset(0);\n setChapterHint(null);\n };\n\n container.addEventListener(\"touchstart\", onTouchStart, { passive: true });\n container.addEventListener(\"touchmove\", onTouchMove, { passive: false });\n container.addEventListener(\"touchend\", onTouchEnd, { passive: true });\n container.addEventListener(\"touchcancel\", onTouchCancel, { passive: true });\n\n return () => {\n container.removeEventListener(\"touchstart\", onTouchStart);\n container.removeEventListener(\"touchmove\", onTouchMove);\n container.removeEventListener(\"touchend\", onTouchEnd);\n container.removeEventListener(\"touchcancel\", onTouchCancel);\n };\n }, [\n currentPage,\n totalPages,\n goNext,\n goPrev,\n effectiveNextChapter,\n effectivePrevChapter,\n ]);\n\n // Compute per-chapter page indicator values\n const chapterPageInfo = (() => {\n if (!isMultiChapter || chapterRanges.length === 0) {\n return { chapterPage: currentPage, chapterTotalPages: totalPages };\n }\n const activeRange = chapterRanges.find((r) => r.slug === activeChapterSlug);\n if (!activeRange) {\n return { chapterPage: currentPage, chapterTotalPages: totalPages };\n }\n return {\n chapterPage: currentPage - activeRange.startPage,\n chapterTotalPages: activeRange.endPage - activeRange.startPage + 1,\n };\n })();\n\n // Book progress: position in the entire book based on word counts.\n // Maps currentPage/totalPages (across all loaded content) through\n // word counts to estimate absolute position in the full book.\n const progressPercent = (() => {\n if (!allChapters || allChapters.length === 0) {\n return totalPages > 1 ? (currentPage / (totalPages - 1)) * 100 : 100;\n }\n\n const totalWords = allChapters.reduce(\n (sum, ch) => sum + (ch.wordCount || 0),\n 0\n );\n if (totalWords === 0) return 0;\n\n const firstLoadedSlug = loadedChapters[0]?.slug || activeChapterSlug;\n let wordsBeforeLoaded = 0;\n let loadedWords = 0;\n let foundFirst = false;\n\n for (const ch of allChapters) {\n if (ch.slug === firstLoadedSlug) foundFirst = true;\n if (!foundFirst) {\n wordsBeforeLoaded += ch.wordCount || 0;\n } else if (loadedChapters.some((lc) => lc.slug === ch.slug)) {\n loadedWords += ch.wordCount || 0;\n } else {\n break;\n }\n }\n\n const pageFraction = totalPages > 1 ? currentPage / (totalPages - 1) : 0;\n const wordsInto = wordsBeforeLoaded + pageFraction * loadedWords;\n\n return Math.min(100, (wordsInto / totalWords) * 100);\n })();\n\n // Render content — either multi-chapter sections or single-chapter children\n const renderContent = () => {\n if (isMultiChapter && loadedChapters.length > 0) {\n return loadedChapters.map((ch) => (\n <section\n key={ch.slug}\n class=\"pressy-chapter-section\"\n data-chapter-slug={ch.slug}\n >\n <ChapterDivider title={ch.title} />\n <ch.Content components={mdxComponents || {}} />\n </section>\n ));\n }\n return children;\n };\n\n return (\n <div\n class=\"pressy-reader pressy-reader--paginated\"\n ref={containerRef}\n onClick={handleContainerClick}\n onMouseMove={handleMouseMove}\n onMouseLeave={handleMouseLeave}\n >\n {/* Paginated content viewport */}\n <div class=\"pressy-paginated-viewport\" ref={viewportRef}>\n <article\n ref={articleRef}\n class={`pressy-prose pressy-prose--paginated ${\n showDropCap ? \"\" : \"no-drop-cap\"\n }`}\n data-drop-cap={showDropCap}\n >\n {renderContent()}\n </article>\n </div>\n\n {/* Navigation arrows — appear on hover in left/right thirds */}\n <div\n class={`pressy-nav-arrow pressy-nav-arrow--prev ${\n hoverZone === \"left\" ? \"pressy-nav-arrow--visible\" : \"\"\n }`}\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </div>\n <div\n class={`pressy-nav-arrow pressy-nav-arrow--next ${\n hoverZone === \"right\" ? \"pressy-nav-arrow--visible\" : \"\"\n }`}\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"9 6 15 12 9 18\" />\n </svg>\n </div>\n\n {/* Chapter boundary hints */}\n {chapterHint === \"prev\" && effectivePrevChapter && (\n <div\n class=\"pressy-chapter-hint pressy-chapter-hint--prev\"\n aria-live=\"polite\"\n >\n <span class=\"pressy-chapter-hint-arrow\">{\"\\u2190\"}</span>\n <span class=\"pressy-chapter-hint-text\">\n {effectivePrevChapter.title}\n </span>\n </div>\n )}\n {chapterHint === \"next\" && effectiveNextChapter && (\n <div\n class=\"pressy-chapter-hint pressy-chapter-hint--next\"\n aria-live=\"polite\"\n >\n <span class=\"pressy-chapter-hint-text\">\n {effectiveNextChapter.title}\n </span>\n <span class=\"pressy-chapter-hint-arrow\">{\"\\u2192\"}</span>\n </div>\n )}\n\n {/* Page footer with progress — hidden by default */}\n <div\n class={`pressy-page-footer ${\n footerVisible || settingsOpen ? \"pressy-page-footer--visible\" : \"\"\n }`}\n >\n <div class=\"pressy-progress-bar\">\n <div\n class=\"pressy-progress-fill\"\n style={{ width: `${progressPercent}%` }}\n />\n </div>\n <div class=\"pressy-footer-row\">\n {bookTitle && <span class=\"pressy-footer-title\">{bookTitle}</span>}\n <button\n class=\"pressy-settings-toggle\"\n onClick={(e: MouseEvent) => {\n e.stopPropagation();\n setSettingsOpen(!settingsOpen);\n }}\n aria-label=\"Settings\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n width=\"18\"\n height=\"18\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\" />\n </svg>\n </button>\n </div>\n\n {/* Settings panel */}\n <div\n class={`pressy-settings-panel ${\n settingsOpen ? \"pressy-settings-panel--open\" : \"\"\n }`}\n >\n <div class=\"pressy-settings-section\">\n <div class=\"pressy-settings-label\">Theme</div>\n <div class=\"pressy-theme-options\">\n {(\n [\n {\n id: \"light\",\n label: \"Light\",\n icon: (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n width=\"16\"\n height=\"16\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"5\" />\n <line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\" />\n <line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\" />\n <line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\" />\n <line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\" />\n <line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\" />\n <line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\" />\n <line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\" />\n <line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\" />\n </svg>\n ),\n },\n {\n id: \"dark\",\n label: \"Dark\",\n icon: (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n width=\"16\"\n height=\"16\"\n >\n <path d=\"M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z\" />\n </svg>\n ),\n },\n {\n id: \"system\",\n label: \"System\",\n icon: (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n width=\"16\"\n height=\"16\"\n >\n <rect\n x=\"2\"\n y=\"3\"\n width=\"20\"\n height=\"14\"\n rx=\"2\"\n ry=\"2\"\n />\n <line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\" />\n <line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\" />\n </svg>\n ),\n },\n {\n id: \"sepia\",\n label: \"Sepia\",\n icon: (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n width=\"16\"\n height=\"16\"\n >\n <path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\" />\n <path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\" />\n </svg>\n ),\n },\n ] as const\n ).map((t) => (\n <button\n key={t.id}\n class={`pressy-theme-btn ${\n activeTheme === t.id ? \"pressy-theme-btn--active\" : \"\"\n }`}\n onClick={(e: MouseEvent) => {\n e.stopPropagation();\n handleThemeChange(t.id);\n }}\n >\n {t.icon}\n <span>{t.label}</span>\n </button>\n ))}\n </div>\n </div>\n <div class=\"pressy-settings-section\">\n <div class=\"pressy-settings-label\">Font Size</div>\n <div class=\"pressy-font-size-controls\">\n <button\n class=\"pressy-font-size-btn\"\n onClick={(e: MouseEvent) => {\n e.stopPropagation();\n handleFontSizeChange(-0.1);\n }}\n disabled={fontScale <= 0.8}\n aria-label=\"Decrease font size\"\n >\n A-\n </button>\n <span class=\"pressy-font-size-value\">\n {Math.round(fontScale * 100)}%\n </span>\n <button\n class=\"pressy-font-size-btn\"\n onClick={(e: MouseEvent) => {\n e.stopPropagation();\n handleFontSizeChange(0.1);\n }}\n disabled={fontScale >= 1.5}\n aria-label=\"Increase font size\"\n >\n A+\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <TextShare />\n <OfflineIndicator />\n\n <style>{PAGINATED_STYLES}</style>\n </div>\n );\n}\n\n// ── Styles ────────────────────────────────────────────────────\n\nconst SCROLL_STYLES = `\n .pressy-reader {\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n }\n\n .pressy-reader-main {\n flex: 1;\n padding: 2rem 0;\n }\n`;\n\nconst PAGINATED_STYLES = `\n html:has(.pressy-reader--paginated) body {\n margin: 0;\n }\n\n .pressy-reader--paginated {\n height: 100vh;\n height: 100dvh;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n position: relative;\n }\n\n /* Viewport clips overflow and shows one page at a time.\n Vertical padding gives consistent top/bottom margins on every page. */\n .pressy-paginated-viewport {\n flex: 1;\n overflow: hidden;\n position: relative;\n min-height: 0;\n padding-block: 2rem;\n box-sizing: border-box;\n }\n\n /* Article uses CSS multi-column layout for pagination.\n column-width is set dynamically via JS to match viewport width.\n Each column = one \"page\". Content overflows horizontally into new columns.\n translateX controlled by JS — transitions set dynamically during drag vs snap. */\n .pressy-prose--paginated {\n max-width: none;\n height: 100%;\n column-fill: auto;\n column-gap: 0;\n overflow: visible;\n box-sizing: border-box;\n padding: 0;\n will-change: transform;\n /* Transition is set dynamically: none during drag, ease-out on snap */\n }\n\n /* Center content elements within each column/page at a readable width */\n .pressy-prose--paginated > * {\n max-width: min(65ch, calc(100% - 3rem));\n margin-left: auto;\n margin-right: auto;\n }\n\n /* Preserve vertical margins from prose styles */\n .pressy-prose--paginated > h1,\n .pressy-prose--paginated > h2,\n .pressy-prose--paginated > h3,\n .pressy-prose--paginated > h4 {\n max-width: min(65ch, calc(100% - 3rem));\n margin-left: auto;\n margin-right: auto;\n }\n\n /* ── Navigation arrows ────────────────────────────────────── */\n /* Hover-triggered arrows on left/right edges for desktop navigation */\n .pressy-nav-arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n width: 2.5rem;\n height: 2.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--color-text-muted, #6c757d);\n opacity: 0;\n transition: opacity 0.2s ease;\n pointer-events: none;\n z-index: 5;\n }\n\n .pressy-nav-arrow svg {\n width: 1.5rem;\n height: 1.5rem;\n }\n\n .pressy-nav-arrow--prev {\n left: 0.75rem;\n }\n\n .pressy-nav-arrow--next {\n right: 0.75rem;\n }\n\n .pressy-nav-arrow--visible {\n opacity: 0.4;\n }\n\n /* Hide on touch devices — swipe handles navigation there */\n @media (hover: none) {\n .pressy-nav-arrow {\n display: none;\n }\n }\n\n /* ── Chapter boundary hints ─────────────────────────────── */\n /* Shown when overscrolling past first/last page of a chapter */\n .pressy-chapter-hint {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n background: var(--color-bg-subtle, #f5f5f5);\n border: 1px solid var(--color-border, #dee2e6);\n border-radius: 0.75rem;\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--color-text-muted, #6c757d);\n z-index: 20;\n pointer-events: none;\n animation: pressy-hint-fade-in 0.15s ease-out;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n max-width: 60%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .pressy-chapter-hint--prev {\n left: 1rem;\n }\n\n .pressy-chapter-hint--next {\n right: 1rem;\n }\n\n .pressy-chapter-hint-arrow {\n flex-shrink: 0;\n font-size: 1rem;\n opacity: 0.6;\n }\n\n .pressy-chapter-hint-text {\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n @keyframes pressy-hint-fade-in {\n from { opacity: 0; transform: translateY(-50%) scale(0.95); }\n to { opacity: 1; transform: translateY(-50%) scale(1); }\n }\n\n /* ── Page footer ───────────────────────────────────────────── */\n .pressy-page-footer {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n padding: 0.5rem 1.5rem 1rem;\n text-align: center;\n user-select: none;\n transform: translateY(100%);\n opacity: 0;\n transition: transform 0.25s ease, opacity 0.25s ease;\n z-index: 15;\n background: var(--color-bg, #ffffff);\n }\n\n .pressy-page-footer--visible {\n transform: translateY(0);\n opacity: 1;\n }\n\n /* Progress bar */\n .pressy-progress-bar {\n height: 3px;\n background: var(--color-border, #dee2e6);\n border-radius: 1.5px;\n overflow: hidden;\n }\n\n .pressy-progress-fill {\n height: 100%;\n background: var(--color-accent, #212529);\n border-radius: 1.5px;\n transition: width 0.3s ease;\n }\n\n /* ── Footer row (title + gear) ──────────────────────────── */\n .pressy-footer-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 0.5rem;\n gap: 0.5rem;\n }\n\n .pressy-footer-title {\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: 0.75rem;\n color: var(--color-text-muted, #6c757d);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n min-width: 0;\n }\n\n .pressy-settings-toggle {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border: none;\n background: transparent;\n color: var(--color-text-muted, #6c757d);\n cursor: pointer;\n border-radius: 0.375rem;\n transition: color 0.15s, background 0.15s;\n padding: 0;\n }\n\n .pressy-settings-toggle:hover {\n color: var(--color-text, #212529);\n background: var(--color-bg-subtle, #f8f9fa);\n }\n\n /* ── Settings panel ────────────────────────────────────── */\n .pressy-settings-panel {\n overflow: hidden;\n max-height: 0;\n opacity: 0;\n transition: max-height 0.25s ease, opacity 0.2s ease;\n border-top: 0 solid var(--color-border, #dee2e6);\n }\n\n .pressy-settings-panel--open {\n max-height: 300px;\n opacity: 1;\n border-top-width: 1px;\n margin-top: 0.5rem;\n padding-top: 0.75rem;\n }\n\n .pressy-settings-section {\n margin-bottom: 0.75rem;\n }\n\n .pressy-settings-section:last-child {\n margin-bottom: 0;\n }\n\n .pressy-settings-label {\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--color-text-muted, #6c757d);\n margin-bottom: 0.5rem;\n text-align: left;\n }\n\n .pressy-theme-options {\n display: flex;\n gap: 0.375rem;\n }\n\n .pressy-theme-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.25rem;\n padding: 0.375rem 0.5rem;\n border: 1.5px solid var(--color-border, #dee2e6);\n border-radius: 0.5rem;\n background: transparent;\n color: var(--color-text, #212529);\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: 0.6875rem;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n }\n\n .pressy-theme-btn:hover {\n background: var(--color-bg-subtle, #f8f9fa);\n }\n\n .pressy-theme-btn--active {\n border-color: var(--color-accent, #212529);\n background: var(--color-bg-subtle, #f8f9fa);\n font-weight: 600;\n }\n\n .pressy-font-size-controls {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 1rem;\n }\n\n .pressy-font-size-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border: 1.5px solid var(--color-border, #dee2e6);\n border-radius: 50%;\n background: transparent;\n color: var(--color-text, #212529);\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: 0.75rem;\n font-weight: 600;\n cursor: pointer;\n transition: border-color 0.15s, background 0.15s;\n }\n\n .pressy-font-size-btn:hover:not(:disabled) {\n background: var(--color-bg-subtle, #f8f9fa);\n border-color: var(--color-accent, #212529);\n }\n\n .pressy-font-size-btn:disabled {\n opacity: 0.3;\n cursor: default;\n }\n\n .pressy-font-size-value {\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: 0.8125rem;\n font-weight: 500;\n color: var(--color-text, #212529);\n min-width: 3ch;\n text-align: center;\n }\n\n /* ── Chapter sections ─────────────────────────────────── */\n .pressy-chapter-section + .pressy-chapter-section {\n break-before: column;\n }\n\n .pressy-chapter-divider {\n text-align: center;\n padding: 3rem 1.5rem;\n max-width: min(65ch, calc(100% - 3rem));\n margin: 0 auto;\n }\n\n .pressy-chapter-divider-title {\n font-size: 1.5rem;\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n margin: 0;\n }\n\n /* ── Reduced motion preference ────────────────────────────\n Disable page turn animations for users who prefer reduced motion. */\n @media (prefers-reduced-motion: reduce) {\n .pressy-prose--paginated {\n transition: none !important;\n }\n .pressy-progress-fill {\n transition: none !important;\n }\n }\n`;\n","export interface NavigationProps {\n prev?: { slug: string; title: string }\n next?: { slug: string; title: string }\n}\n\nexport function Navigation({ prev, next }: NavigationProps) {\n if (!prev && !next) return null\n\n return (\n <nav class=\"pressy-navigation\" aria-label=\"Chapter navigation\">\n <div class=\"pressy-nav-inner\">\n {prev ? (\n <a href={prev.slug} class=\"pressy-nav-link pressy-nav-prev\">\n <span class=\"pressy-nav-direction\">Previous</span>\n <span class=\"pressy-nav-title\">{prev.title}</span>\n </a>\n ) : (\n <div class=\"pressy-nav-placeholder\" />\n )}\n\n {next ? (\n <a href={next.slug} class=\"pressy-nav-link pressy-nav-next\">\n <span class=\"pressy-nav-direction\">Next</span>\n <span class=\"pressy-nav-title\">{next.title}</span>\n </a>\n ) : (\n <div class=\"pressy-nav-placeholder\" />\n )}\n </div>\n\n <style>{`\n .pressy-navigation {\n border-top: 1px solid var(--color-border);\n padding: 2rem 1.5rem;\n margin-top: 3rem;\n }\n\n .pressy-nav-inner {\n display: flex;\n justify-content: space-between;\n gap: 2rem;\n max-width: 65ch;\n margin: 0 auto;\n }\n\n .pressy-nav-link {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n text-decoration: none;\n padding: 1rem;\n border-radius: 0.5rem;\n transition: background 0.15s;\n max-width: 45%;\n }\n\n .pressy-nav-link:hover {\n background: var(--color-bg-subtle);\n }\n\n .pressy-nav-prev {\n align-items: flex-start;\n }\n\n .pressy-nav-next {\n align-items: flex-end;\n text-align: right;\n }\n\n .pressy-nav-direction {\n font-size: var(--font-size-sm);\n color: var(--color-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n }\n\n .pressy-nav-title {\n color: var(--color-text);\n font-weight: 500;\n }\n\n .pressy-nav-placeholder {\n flex: 1;\n }\n\n @media (max-width: 640px) {\n .pressy-nav-inner {\n flex-direction: column;\n gap: 1rem;\n }\n\n .pressy-nav-link {\n max-width: 100%;\n }\n\n .pressy-nav-next {\n align-items: flex-start;\n text-align: left;\n }\n }\n `}</style>\n </nav>\n )\n}\n","import { useSignal } from '@preact/signals'\nimport { useRef, useEffect } from 'preact/hooks'\n\nexport function TextShare() {\n const isVisible = useSignal(false)\n const position = useSignal({ x: 0, y: 0 })\n const selectedText = useSignal('')\n const buttonRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleSelectionChange = () => {\n const selection = window.getSelection()\n if (!selection || selection.isCollapsed) {\n isVisible.value = false\n return\n }\n\n const text = selection.toString().trim()\n if (text.length < 5) {\n isVisible.value = false\n return\n }\n\n selectedText.value = text\n\n // Position the share button above the selection\n const range = selection.getRangeAt(0)\n const rect = range.getBoundingClientRect()\n\n position.value = {\n x: rect.left + rect.width / 2,\n y: rect.top - 10,\n }\n isVisible.value = true\n }\n\n document.addEventListener('selectionchange', handleSelectionChange)\n document.addEventListener('mouseup', handleSelectionChange)\n\n return () => {\n document.removeEventListener('selectionchange', handleSelectionChange)\n document.removeEventListener('mouseup', handleSelectionChange)\n }\n }, [])\n\n const generateShareUrl = () => {\n // Use Text Fragments API for direct linking\n const encodedText = encodeURIComponent(selectedText.value)\n const url = new URL(window.location.href)\n url.hash = `:~:text=${encodedText}`\n return url.toString()\n }\n\n const handleShare = async () => {\n const url = generateShareUrl()\n const text = `\"${selectedText.value}\"`\n\n // Try Web Share API first\n if (navigator.share) {\n try {\n await navigator.share({\n text,\n url,\n })\n isVisible.value = false\n return\n } catch (err) {\n // User cancelled or share failed, fall through to clipboard\n }\n }\n\n // Fallback to clipboard\n try {\n await navigator.clipboard.writeText(`${text}\\n\\n${url}`)\n // Show copied feedback\n if (buttonRef.current) {\n buttonRef.current.classList.add('copied')\n setTimeout(() => {\n buttonRef.current?.classList.remove('copied')\n }, 2000)\n }\n } catch (err) {\n console.error('Failed to copy to clipboard:', err)\n }\n }\n\n const handleCopyLink = async () => {\n const url = generateShareUrl()\n try {\n await navigator.clipboard.writeText(url)\n if (buttonRef.current) {\n buttonRef.current.classList.add('copied')\n setTimeout(() => {\n buttonRef.current?.classList.remove('copied')\n }, 2000)\n }\n } catch (err) {\n console.error('Failed to copy link:', err)\n }\n }\n\n if (!isVisible.value) return null\n\n return (\n <div\n ref={buttonRef}\n class=\"pressy-text-share\"\n style={{\n left: `${position.value.x}px`,\n top: `${position.value.y}px`,\n }}\n >\n <button\n class=\"pressy-share-btn\"\n onClick={handleShare}\n aria-label=\"Share selected text\"\n title=\"Share quote\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92s2.92-1.31 2.92-2.92-1.31-2.92-2.92-2.92z\" />\n </svg>\n </button>\n\n <button\n class=\"pressy-copy-link-btn\"\n onClick={handleCopyLink}\n aria-label=\"Copy link to selected text\"\n title=\"Copy link\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z\" />\n </svg>\n </button>\n\n <style>{`\n .pressy-text-share {\n position: fixed;\n transform: translate(-50%, -100%);\n display: flex;\n gap: 0.25rem;\n background: var(--color-bg);\n border: 1px solid var(--color-border);\n border-radius: 0.5rem;\n padding: 0.25rem;\n box-shadow: var(--shadow-md);\n z-index: 1000;\n }\n\n .pressy-text-share::after {\n content: '';\n position: absolute;\n bottom: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 6px solid var(--color-bg);\n }\n\n .pressy-share-btn,\n .pressy-copy-link-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2rem;\n height: 2rem;\n border: none;\n background: transparent;\n color: var(--color-text-muted);\n cursor: pointer;\n border-radius: 0.25rem;\n transition: background 0.15s, color 0.15s;\n }\n\n .pressy-share-btn:hover,\n .pressy-copy-link-btn:hover {\n background: var(--color-bg-muted);\n color: var(--color-text);\n }\n\n .pressy-text-share.copied .pressy-copy-link-btn {\n color: var(--color-accent);\n }\n `}</style>\n </div>\n )\n}\n","import { useSignal } from '@preact/signals'\nimport { useEffect } from 'preact/hooks'\n\nexport function OfflineIndicator() {\n const isOffline = useSignal(!navigator.onLine)\n const isVisible = useSignal(false)\n\n useEffect(() => {\n const handleOnline = () => {\n isOffline.value = false\n // Show briefly when coming back online\n isVisible.value = true\n setTimeout(() => {\n isVisible.value = false\n }, 3000)\n }\n\n const handleOffline = () => {\n isOffline.value = true\n isVisible.value = true\n }\n\n window.addEventListener('online', handleOnline)\n window.addEventListener('offline', handleOffline)\n\n return () => {\n window.removeEventListener('online', handleOnline)\n window.removeEventListener('offline', handleOffline)\n }\n }, [])\n\n if (!isVisible.value) return null\n\n return (\n <div class={`pressy-offline-indicator ${isOffline.value ? 'offline' : 'online'}`}>\n {isOffline.value ? (\n <>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M23.64 7c-.45-.34-4.93-4-11.64-4-1.5 0-2.89.19-4.15.48L18.18 13.8 23.64 7zM3.41 1.31L2 2.72l2.05 2.05C1.91 5.76.59 6.82.36 7L12 21.5l3.91-4.87 3.32 3.32 1.41-1.41L3.41 1.31z\" />\n </svg>\n <span>You're offline</span>\n </>\n ) : (\n <>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M1 9l2 2c4.97-4.97 13.03-4.97 18 0l2-2C16.93 2.93 7.08 2.93 1 9zm8 8l3 3 3-3c-1.65-1.66-4.34-1.66-6 0zm-4-4l2 2c2.76-2.76 7.24-2.76 10 0l2-2C15.14 9.14 8.87 9.14 5 13z\" />\n </svg>\n <span>Back online</span>\n </>\n )}\n\n <style>{`\n .pressy-offline-indicator {\n position: fixed;\n bottom: 1.5rem;\n left: 50%;\n transform: translateX(-50%);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n border-radius: 2rem;\n font-size: var(--font-size-sm);\n font-weight: 500;\n z-index: 1000;\n animation: slideUp 0.3s ease;\n }\n\n .pressy-offline-indicator.offline {\n background: #fef2f2;\n color: #dc2626;\n border: 1px solid #fecaca;\n }\n\n .pressy-offline-indicator.online {\n background: #f0fdf4;\n color: #16a34a;\n border: 1px solid #bbf7d0;\n }\n\n @keyframes slideUp {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(1rem);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n }\n\n @media (prefers-color-scheme: dark) {\n .pressy-offline-indicator.offline {\n background: #450a0a;\n color: #fca5a5;\n border-color: #7f1d1d;\n }\n\n .pressy-offline-indicator.online {\n background: #052e16;\n color: #86efac;\n border-color: #166534;\n }\n }\n `}</style>\n </div>\n )\n}\n","export interface TOCItem {\n level: number\n text: string\n slug: string\n}\n\nexport interface TableOfContentsProps {\n items: TOCItem[]\n onNavigate?: () => void\n activeSlug?: string\n}\n\nexport function TableOfContents({ items, onNavigate, activeSlug }: TableOfContentsProps) {\n const handleClick = (slug: string) => {\n // Scroll to heading\n const element = document.getElementById(slug)\n if (element) {\n element.scrollIntoView({ behavior: 'smooth' })\n }\n onNavigate?.()\n }\n\n return (\n <nav class=\"pressy-toc\" aria-label=\"Table of contents\">\n <h2 class=\"pressy-toc-title\">Contents</h2>\n <ul class=\"pressy-toc-list\">\n {items.map((item) => (\n <li\n key={item.slug}\n class={`pressy-toc-item pressy-toc-level-${item.level}`}\n data-active={activeSlug === item.slug}\n >\n <a\n href={`#${item.slug}`}\n onClick={(e) => {\n e.preventDefault()\n handleClick(item.slug)\n }}\n class=\"pressy-toc-link\"\n >\n {item.text}\n </a>\n </li>\n ))}\n </ul>\n\n <style>{`\n .pressy-toc {\n font-size: var(--font-size-sm);\n }\n\n .pressy-toc-title {\n font-size: var(--font-size-base);\n font-weight: 600;\n margin-bottom: 1rem;\n color: var(--color-heading);\n }\n\n .pressy-toc-list {\n list-style: none;\n padding: 0;\n margin: 0;\n }\n\n .pressy-toc-item {\n margin-bottom: 0.5rem;\n }\n\n .pressy-toc-level-1 {\n padding-left: 0;\n }\n\n .pressy-toc-level-2 {\n padding-left: 1rem;\n }\n\n .pressy-toc-level-3 {\n padding-left: 2rem;\n }\n\n .pressy-toc-level-4 {\n padding-left: 3rem;\n }\n\n .pressy-toc-link {\n color: var(--color-text-muted);\n text-decoration: none;\n transition: color 0.15s;\n display: block;\n padding: 0.25rem 0;\n }\n\n .pressy-toc-link:hover {\n color: var(--color-text);\n }\n\n .pressy-toc-item[data-active=\"true\"] .pressy-toc-link {\n color: var(--color-accent);\n font-weight: 500;\n }\n `}</style>\n </nav>\n )\n}\n","import { useSignal } from '@preact/signals'\n\nexport interface PaywallProps {\n bookSlug: string\n bookTitle: string\n previewChapters: number\n currentChapter: number\n shopifyProductId?: string\n mode?: 'shopify' | 'email'\n onUnlock?: () => void\n}\n\nexport function Paywall({\n bookSlug,\n bookTitle,\n previewChapters,\n currentChapter,\n shopifyProductId,\n mode = 'email',\n onUnlock,\n}: PaywallProps) {\n const email = useSignal('')\n const isLoading = useSignal(false)\n const error = useSignal('')\n const isUnlocked = useSignal(false)\n\n // Check if already unlocked\n if (typeof window !== 'undefined') {\n const unlocked = localStorage.getItem(`pressy-unlocked-${bookSlug}`)\n if (unlocked) {\n isUnlocked.value = true\n }\n }\n\n if (isUnlocked.value) {\n return null\n }\n\n // Show paywall if past preview chapters\n if (currentChapter <= previewChapters) {\n return null\n }\n\n const handleEmailSubmit = async (e: Event) => {\n e.preventDefault()\n\n if (!email.value || !email.value.includes('@')) {\n error.value = 'Please enter a valid email address'\n return\n }\n\n isLoading.value = true\n error.value = ''\n\n try {\n // In a real implementation, this would send to a backend\n // For now, just unlock locally\n await new Promise((resolve) => setTimeout(resolve, 1000))\n\n localStorage.setItem(`pressy-unlocked-${bookSlug}`, 'email')\n localStorage.setItem(`pressy-email-${bookSlug}`, email.value)\n\n isUnlocked.value = true\n onUnlock?.()\n } catch (err) {\n error.value = 'Something went wrong. Please try again.'\n } finally {\n isLoading.value = false\n }\n }\n\n const handleShopifyPurchase = async () => {\n if (!shopifyProductId) {\n error.value = 'Purchase not available'\n return\n }\n\n isLoading.value = true\n\n try {\n // This would integrate with @pressy-pub/shopify\n // For now, just show that it would redirect\n const { createCheckout } = await import('@pressy-pub/shopify' as string)\n const checkoutUrl = await createCheckout(shopifyProductId)\n window.location.href = checkoutUrl\n } catch (err) {\n error.value = 'Failed to create checkout. Please try again.'\n isLoading.value = false\n }\n }\n\n return (\n <div class=\"pressy-paywall\">\n <div class=\"pressy-paywall-content\">\n <div class=\"pressy-paywall-icon\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z\" />\n </svg>\n </div>\n\n <h2 class=\"pressy-paywall-title\">Continue Reading</h2>\n <p class=\"pressy-paywall-description\">\n You've enjoyed the first {previewChapters} chapters of \"{bookTitle}\".\n {mode === 'shopify'\n ? ' Purchase the full book to continue reading.'\n : ' Enter your email to unlock the full book.'}\n </p>\n\n {mode === 'email' ? (\n <form class=\"pressy-paywall-form\" onSubmit={handleEmailSubmit}>\n <input\n type=\"email\"\n placeholder=\"Enter your email\"\n value={email.value}\n onInput={(e) => (email.value = (e.target as HTMLInputElement).value)}\n class=\"pressy-paywall-input\"\n disabled={isLoading.value}\n />\n <button type=\"submit\" class=\"pressy-paywall-button\" disabled={isLoading.value}>\n {isLoading.value ? 'Unlocking...' : 'Unlock Full Book'}\n </button>\n </form>\n ) : (\n <button\n class=\"pressy-paywall-button pressy-paywall-purchase\"\n onClick={handleShopifyPurchase}\n disabled={isLoading.value}\n >\n {isLoading.value ? 'Processing...' : 'Purchase Now'}\n </button>\n )}\n\n {error.value && <p class=\"pressy-paywall-error\">{error.value}</p>}\n\n <p class=\"pressy-paywall-note\">\n {mode === 'email'\n ? \"We'll never share your email with anyone.\"\n : 'Secure checkout powered by Shopify.'}\n </p>\n </div>\n\n <style>{`\n .pressy-paywall {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.8);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1.5rem;\n }\n\n .pressy-paywall-content {\n background: var(--color-bg);\n border-radius: 1rem;\n padding: 2.5rem;\n max-width: 400px;\n width: 100%;\n text-align: center;\n }\n\n .pressy-paywall-icon {\n color: var(--color-accent);\n margin-bottom: 1.5rem;\n }\n\n .pressy-paywall-title {\n font-size: var(--font-size-xl);\n font-weight: 600;\n margin-bottom: 0.75rem;\n color: var(--color-heading);\n }\n\n .pressy-paywall-description {\n color: var(--color-text-muted);\n margin-bottom: 1.5rem;\n line-height: 1.5;\n }\n\n .pressy-paywall-form {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n }\n\n .pressy-paywall-input {\n width: 100%;\n padding: 0.875rem 1rem;\n border: 1px solid var(--color-border);\n border-radius: 0.5rem;\n font-size: var(--font-size-base);\n background: var(--color-bg);\n color: var(--color-text);\n }\n\n .pressy-paywall-input:focus {\n outline: none;\n border-color: var(--color-accent);\n box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);\n }\n\n .pressy-paywall-button {\n width: 100%;\n padding: 0.875rem 1rem;\n border: none;\n border-radius: 0.5rem;\n font-size: var(--font-size-base);\n font-weight: 500;\n background: var(--color-accent);\n color: white;\n cursor: pointer;\n transition: opacity 0.15s;\n }\n\n .pressy-paywall-button:hover:not(:disabled) {\n opacity: 0.9;\n }\n\n .pressy-paywall-button:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .pressy-paywall-error {\n color: #dc2626;\n font-size: var(--font-size-sm);\n margin-top: 0.75rem;\n }\n\n .pressy-paywall-note {\n font-size: var(--font-size-sm);\n color: var(--color-text-muted);\n margin-top: 1.5rem;\n }\n `}</style>\n </div>\n )\n}\n","import { useSignal } from '@preact/signals'\n\nconst themes = ['light', 'dark', 'sepia'] as const\ntype Theme = typeof themes[number]\n\nexport function ThemeSwitcher() {\n const isOpen = useSignal(false)\n const currentTheme = useSignal<Theme>(\n (typeof localStorage !== 'undefined'\n ? (localStorage.getItem('pressy-theme') as Theme)\n : 'light') || 'light'\n )\n\n const setTheme = (theme: Theme) => {\n currentTheme.value = theme\n document.documentElement.setAttribute('data-theme', theme)\n localStorage.setItem('pressy-theme', theme)\n isOpen.value = false\n }\n\n const themeIcons: Record<Theme, string> = {\n light: '☀️',\n dark: '🌙',\n sepia: '📜',\n }\n\n const themeLabels: Record<Theme, string> = {\n light: 'Light',\n dark: 'Dark',\n sepia: 'Sepia',\n }\n\n return (\n <div class=\"pressy-theme-switcher\">\n <button\n class=\"pressy-theme-toggle\"\n onClick={() => (isOpen.value = !isOpen.value)}\n aria-label=\"Change theme\"\n aria-expanded={isOpen.value}\n >\n <span class=\"pressy-theme-icon\">{themeIcons[currentTheme.value]}</span>\n </button>\n\n {isOpen.value && (\n <div class=\"pressy-theme-menu\" role=\"menu\">\n {themes.map((theme) => (\n <button\n key={theme}\n class=\"pressy-theme-option\"\n onClick={() => setTheme(theme)}\n role=\"menuitem\"\n data-active={currentTheme.value === theme}\n >\n <span class=\"pressy-theme-icon\">{themeIcons[theme]}</span>\n <span class=\"pressy-theme-label\">{themeLabels[theme]}</span>\n </button>\n ))}\n </div>\n )}\n\n <style>{`\n .pressy-theme-switcher {\n position: relative;\n }\n\n .pressy-theme-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.5rem;\n height: 2.5rem;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: 0.5rem;\n transition: background 0.15s;\n font-size: 1.25rem;\n }\n\n .pressy-theme-toggle:hover {\n background: var(--color-bg-muted);\n }\n\n .pressy-theme-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 0.5rem;\n background: var(--color-bg);\n border: 1px solid var(--color-border);\n border-radius: 0.5rem;\n box-shadow: var(--shadow-md);\n overflow: hidden;\n z-index: 100;\n }\n\n .pressy-theme-option {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.75rem 1rem;\n border: none;\n background: transparent;\n cursor: pointer;\n text-align: left;\n color: var(--color-text);\n transition: background 0.15s;\n }\n\n .pressy-theme-option:hover {\n background: var(--color-bg-subtle);\n }\n\n .pressy-theme-option[data-active=\"true\"] {\n background: var(--color-bg-muted);\n font-weight: 500;\n }\n\n .pressy-theme-label {\n font-size: var(--font-size-sm);\n }\n `}</style>\n </div>\n )\n}\n","import { useSignal } from '@preact/signals'\nimport { useEffect } from 'preact/hooks'\n\nconst CACHED_BOOKS_KEY = 'pressy-cached-books'\n\nfunction readCachedBooks(): Set<string> {\n try {\n const stored = localStorage.getItem(CACHED_BOOKS_KEY)\n if (stored) return new Set(JSON.parse(stored))\n } catch {}\n return new Set()\n}\n\nexport interface DownloadBookProps {\n bookSlug: string\n chapterUrls: string[]\n /** Reactive signal: set of cached book slugs */\n cachedBooks: { value: Set<string> }\n /** Reactive signal: current download progress or null */\n cacheProgress: { value: { bookSlug: string; current: number; total: number } | null }\n /** Called to start downloading the book */\n onDownload: (bookSlug: string, chapterUrls: string[]) => void\n /** Called to remove the cached book */\n onRemove: (bookSlug: string) => void\n}\n\nexport function DownloadBook({\n bookSlug,\n chapterUrls,\n cachedBooks,\n cacheProgress,\n onDownload,\n onRemove,\n}: DownloadBookProps) {\n // Check localStorage directly for initial state, and also track the signal\n // for live updates (e.g. after downloading or removing).\n const isCached = useSignal(readCachedBooks().has(bookSlug) || cachedBooks.value.has(bookSlug))\n const isDownloading = useSignal(cacheProgress.value?.bookSlug === bookSlug)\n const progress = useSignal<number | null>(null)\n\n // Sync with external signals on each render\n useEffect(() => {\n const check = () => {\n isCached.value = readCachedBooks().has(bookSlug) || cachedBooks.value.has(bookSlug)\n isDownloading.value = cacheProgress.value?.bookSlug === bookSlug\n const p = cacheProgress.value\n progress.value = p && p.bookSlug === bookSlug\n ? Math.round((p.current / p.total) * 100)\n : null\n }\n\n // Poll briefly to catch signal updates (SW messages are async)\n const interval = setInterval(check, 500)\n check()\n return () => clearInterval(interval)\n }, [bookSlug])\n\n if (isCached.value) {\n return (\n <div class=\"pressy-download-book\">\n <div class=\"pressy-download-status\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z\" />\n </svg>\n <span>Available offline</span>\n </div>\n <button\n class=\"pressy-download-remove\"\n onClick={() => onRemove(bookSlug)}\n aria-label=\"Remove offline copy\"\n >\n Remove\n </button>\n\n <style>{STYLES}</style>\n </div>\n )\n }\n\n if (isDownloading.value) {\n return (\n <div class=\"pressy-download-book\">\n <div class=\"pressy-download-progress\">\n <div class=\"pressy-download-bar\">\n <div\n class=\"pressy-download-bar-fill\"\n style={{ width: `${progress.value || 0}%` }}\n />\n </div>\n <span class=\"pressy-download-percent\">{progress.value || 0}%</span>\n </div>\n\n <style>{STYLES}</style>\n </div>\n )\n }\n\n return (\n <div class=\"pressy-download-book\">\n <button\n class=\"pressy-download-btn\"\n onClick={() => onDownload(bookSlug, chapterUrls)}\n aria-label=\"Download for offline reading\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z\" />\n </svg>\n <span>Download for offline</span>\n </button>\n\n <style>{STYLES}</style>\n </div>\n )\n}\n\nconst STYLES = `\n .pressy-download-book {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 0;\n }\n\n .pressy-download-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n font-family: inherit;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--color-text, #1a1a1a);\n background: var(--color-bg-muted, #f5f5f5);\n border: 1px solid var(--color-border, #e5e5e5);\n border-radius: 0.5rem;\n cursor: pointer;\n transition: background 0.15s, border-color 0.15s;\n }\n\n .pressy-download-btn:hover {\n background: var(--color-bg-subtle, #eee);\n border-color: var(--color-text-muted, #999);\n }\n\n .pressy-download-status {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n font-size: var(--font-size-sm, 0.875rem);\n color: #16a34a;\n }\n\n .pressy-download-remove {\n font-family: inherit;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--color-text-muted, #666);\n background: none;\n border: none;\n cursor: pointer;\n text-decoration: underline;\n padding: 0;\n }\n\n .pressy-download-remove:hover {\n color: var(--color-text, #1a1a1a);\n }\n\n .pressy-download-progress {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n flex: 1;\n max-width: 300px;\n }\n\n .pressy-download-bar {\n flex: 1;\n height: 6px;\n background: var(--color-bg-muted, #f5f5f5);\n border-radius: 3px;\n overflow: hidden;\n }\n\n .pressy-download-bar-fill {\n height: 100%;\n background: var(--color-text, #1a1a1a);\n border-radius: 3px;\n transition: width 0.3s ease;\n }\n\n .pressy-download-percent {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--color-text-muted, #666);\n min-width: 3ch;\n text-align: right;\n }\n\n @media (prefers-color-scheme: dark) {\n .pressy-download-status {\n color: #86efac;\n }\n }\n`\n","import { useState, useEffect } from 'preact/hooks'\n\nexport interface ChapterProgressInfo {\n slug: string\n title: string\n order: number\n wordCount: number\n page: number\n totalPages: number\n}\n\nexport interface BookProgressProps {\n bookSlug: string\n chapters: Array<{\n slug: string\n title: string\n order: number\n wordCount?: number\n }>\n basePath: string\n loadAllProgress: () => Promise<\n Array<{ chapterSlug: string; page: number; totalPages: number }>\n >\n}\n\nexport function BookProgress({\n chapters,\n basePath,\n bookSlug,\n loadAllProgress,\n}: BookProgressProps) {\n const [progressMap, setProgressMap] = useState<\n Map<string, { page: number; totalPages: number }>\n >(new Map())\n\n useEffect(() => {\n loadAllProgress().then((allProgress) => {\n const chapterSlugs = new Set(chapters.map((ch) => ch.slug))\n const map = new Map<string, { page: number; totalPages: number }>()\n for (const p of allProgress) {\n if (chapterSlugs.has(p.chapterSlug)) {\n map.set(p.chapterSlug, { page: p.page, totalPages: p.totalPages })\n }\n }\n setProgressMap(map)\n })\n }, [chapters, loadAllProgress])\n\n // Calculate overall book progress based on word counts\n const totalWords = chapters.reduce((sum, ch) => sum + (ch.wordCount || 0), 0)\n let wordsRead = 0\n let chaptersCompleted = 0\n let chaptersStarted = 0\n\n for (const ch of chapters) {\n const progress = progressMap.get(ch.slug)\n if (!progress) continue\n\n const chapterWords = ch.wordCount || 0\n if (progress.totalPages > 0 && progress.page >= progress.totalPages - 1) {\n // Chapter completed\n wordsRead += chapterWords\n chaptersCompleted++\n chaptersStarted++\n } else if (progress.page > 0 && progress.totalPages > 0) {\n // Chapter in progress — estimate words read from page proportion\n wordsRead += (progress.page / progress.totalPages) * chapterWords\n chaptersStarted++\n }\n }\n\n const overallPercent = totalWords > 0 ? (wordsRead / totalWords) * 100 : 0\n const hasAnyProgress = chaptersStarted > 0\n\n return (\n <div class=\"pressy-book-progress-section\">\n {hasAnyProgress && (\n <div class=\"pressy-overall-progress\">\n <div class=\"pressy-overall-progress-bar\">\n <div\n class=\"pressy-overall-progress-fill\"\n style={{ width: `${overallPercent}%` }}\n />\n </div>\n <div class=\"pressy-overall-progress-text\">\n {Math.round(overallPercent)}% complete\n <span class=\"pressy-overall-progress-detail\">\n {chaptersCompleted} of {chapters.length} chapters\n </span>\n </div>\n </div>\n )}\n\n <nav class=\"pressy-chapter-list\">\n {chapters.map((ch) => {\n const progress = progressMap.get(ch.slug)\n const isCompleted =\n progress &&\n progress.totalPages > 0 &&\n progress.page >= progress.totalPages - 1\n const isStarted = progress && progress.page > 0 && !isCompleted\n\n return (\n <a\n href={`${basePath}/books/${bookSlug}/${ch.slug}`}\n class={`pressy-chapter-link ${isCompleted ? 'pressy-chapter--completed' : ''} ${isStarted ? 'pressy-chapter--started' : ''}`}\n >\n <span class=\"pressy-chapter-order\">{ch.order}.</span>\n <span class=\"pressy-chapter-title\">{ch.title}</span>\n {isCompleted && (\n <span class=\"pressy-chapter-badge pressy-chapter-badge--done\">\n Done\n </span>\n )}\n {isStarted && progress && (\n <span class=\"pressy-chapter-badge pressy-chapter-badge--reading\">\n p.{progress.page + 1}/{progress.totalPages}\n </span>\n )}\n </a>\n )\n })}\n </nav>\n\n <style>{BOOK_PROGRESS_STYLES}</style>\n </div>\n )\n}\n\nconst BOOK_PROGRESS_STYLES = `\n .pressy-overall-progress {\n margin-bottom: 1.5rem;\n padding: 1rem;\n background: var(--color-bg-subtle, #f5f5f5);\n border-radius: 0.5rem;\n }\n\n .pressy-overall-progress-bar {\n height: 4px;\n background: var(--color-border, #dee2e6);\n border-radius: 2px;\n overflow: hidden;\n margin-bottom: 0.5rem;\n }\n\n .pressy-overall-progress-fill {\n height: 100%;\n background: var(--color-accent, #212529);\n border-radius: 2px;\n transition: width 0.3s ease;\n }\n\n .pressy-overall-progress-text {\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--color-text-muted, #6c757d);\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .pressy-overall-progress-detail {\n opacity: 0.7;\n }\n\n .pressy-chapter-link {\n display: flex;\n gap: 0.75rem;\n align-items: center;\n padding: 0.75rem 1rem;\n text-decoration: none;\n color: var(--color-text, #1a1a1a);\n border-radius: 0.5rem;\n transition: background 0.15s;\n }\n\n .pressy-chapter-link:hover {\n background: var(--color-bg-subtle, #f5f5f5);\n }\n\n .pressy-chapter--completed {\n opacity: 0.7;\n }\n\n .pressy-chapter-title {\n flex: 1;\n }\n\n .pressy-chapter-badge {\n font-family: var(--font-heading, system-ui, -apple-system, sans-serif);\n font-size: 0.75rem;\n padding: 0.15rem 0.5rem;\n border-radius: 0.25rem;\n white-space: nowrap;\n }\n\n .pressy-chapter-badge--done {\n background: var(--color-accent, #212529);\n color: var(--color-bg, #fff);\n }\n\n .pressy-chapter-badge--reading {\n background: var(--color-bg-subtle, #f5f5f5);\n color: var(--color-text-muted, #6c757d);\n border: 1px solid var(--color-border, #dee2e6);\n }\n`\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["useEffect","useRef","jsx","jsxs","useSignal","useEffect","jsx","jsxs","jsx","jsxs","useRef","useEffect","jsx","jsxs","useSignal","jsx","jsxs","useSignal","jsx","jsxs","useSignal","useEffect","jsx","jsxs","useState","useEffect","jsx","jsxs"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pressy-pub/components",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Preact UI components for Pressy",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./content": {
|
|
15
|
+
"types": "./dist/content/index.d.ts",
|
|
16
|
+
"import": "./dist/content/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@preact/signals": "^1.2.0",
|
|
27
|
+
"preact": "^10.19.0",
|
|
28
|
+
"idb-keyval": "^6.2.1"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20.10.0",
|
|
32
|
+
"tsup": "^8.0.0",
|
|
33
|
+
"typescript": "^5.3.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@pressy-pub/typography": "0.1.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup",
|
|
40
|
+
"dev": "tsup --watch",
|
|
41
|
+
"typecheck": "tsc --noEmit"
|
|
42
|
+
}
|
|
43
|
+
}
|