/* This file is part of the Notesnook project (https://notesnook.com/) Copyright (C) 2023 Streetwriters (Private) Limited This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import "@notesnook/editor/styles/styles.css"; import { Monograph } from "./types"; import { Box, Button, Flex, Image, Input, Link, Text } from "@theme-ui/components"; import { ClientOnly } from "remix-utils/client-only"; import { Editor } from "./editor.client"; import { formatDate } from "@notesnook/core"; import { slugify } from "../../utils/slugify"; import { useCallback, useEffect, useRef, useState } from "react"; import { NNCrypto } from "../../utils/nncrypto.client"; import { hashNavigate } from "../../utils/use-hash-location"; import { Icon } from "@notesnook/ui"; import { mdiAlertCircleOutline, mdiArrowUp, mdiClose, mdiListBoxOutline, mdiLockOutline } from "@mdi/js"; import { Footer } from "../footer"; import ReportDialog from "./report-modal"; type TableOfContent = { title: string; id: string; level: number; node: HTMLElement; }; const headings = ["h1", "h2", "h3", "h4", "h5", "h6"]; const levelsMap: Record = { H1: 0, H2: 1, H3: 2, H4: 3, H5: 4, H6: 5 }; const selector = headings.map((h) => `.ProseMirror ${h}`).join(","); function generateTableOfContents() { const toc: TableOfContent[] = []; const headings = document.querySelectorAll(selector); let level = -1; let currentHeading = 0; for (const heading of headings) { const isCalloutHeading = heading.closest(".callout"); if (isCalloutHeading) { continue; } const text = heading.textContent || ""; const nodeName = heading.nodeName; const headingLevel = levelsMap[nodeName]; let id = "heading-" + slugify(text); const count = toc.filter((n) => n.id === id).length; if (count > 0) id = `${id}-${count}`; heading.setAttribute("id", id); level = currentHeading < headingLevel ? level + 1 : currentHeading > headingLevel ? headingLevel : level; currentHeading = headingLevel; toc.push({ title: text, id, level, node: heading }); } return toc; } export const MonographPage = ({ monograph, encodedKey, apiHost }: { monograph: Monograph; encodedKey?: string; apiHost: string; }) => { const [reportDialogVisible, setReportDialogVisible] = useState(false); const [tableOfContents, setTableOfContents] = useState([]); const [content, setContent] = useState(monograph.content); const [showTableOfContents, setShowTableOfContents] = useState(false); const editorContainer = useRef(null); if (!content && monograph.encryptedContent) return ( }> {() => ( setContent(content)} encodedKey={encodedKey} /> )} ); return ( {monograph.title} {formatDate(monograph.datePublished, { type: "date-time", dateFormat: "YYYY-MM-DD", timeFormat: "24-hour" })} {monograph.encryptedContent ? ( End-to-end encrypted ) : ( )}

" }} sx={{ color: "paragraph", cursor: "text" }} /> } > {() => (

"} onLoad={() => { const toc = generateTableOfContents(); setTableOfContents(toc); }} /> )}
{showTableOfContents ? ( <> CONTENTS ) : null} {showTableOfContents ? ( { setShowTableOfContents(false); }} > CONTENTS setShowTableOfContents(false)} /> ) : null}