diff --git a/index.html b/index.html index d5be1af..1f73080 100644 --- a/index.html +++ b/index.html @@ -6,8 +6,8 @@ Graph Notes - -
+ +

Loading Graph Notes...

diff --git a/src/App.tsx b/src/App.tsx index 9699175..7669375 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback, createContext, useContext } from "react"; +import { useState, useEffect, useCallback, createContext, useContext, lazy, Suspense } from "react"; import { Routes, Route, useNavigate, useParams } from "react-router-dom"; import { Sidebar } from "./components/Sidebar"; import { Editor } from "./components/Editor"; @@ -14,7 +14,7 @@ import { SearchReplace } from "./components/SearchReplace"; import { FlashcardView } from "./components/FlashcardView"; import { CSSEditor, useCustomCssInit } from "./components/CSSEditor"; import { TabBar } from "./components/TabBar"; -import { WhiteboardView } from "./components/WhiteboardView"; +const WhiteboardView = lazy(() => import("./components/WhiteboardView").then(m => ({ default: m.WhiteboardView }))); import { DatabaseView } from "./components/DatabaseView"; import { GitPanel } from "./components/GitPanel"; import { TimelineView } from "./components/TimelineView"; @@ -385,7 +385,7 @@ export default function App() { } /> } /> } /> - } /> +

Loading whiteboard...

}>} /> } /> } /> } /> @@ -411,6 +411,9 @@ function DailyView() { getOrCreateDaily(vaultPath).then((dailyPath) => { refreshNotes(); navigate(`/note/${encodeURIComponent(dailyPath)}`, { replace: true }); + }).catch((e) => { + console.error("[GraphNotes] Failed to create daily note:", e); + navigate("/", { replace: true }); }); }, [vaultPath, navigate, refreshNotes]); diff --git a/src/components/Editor.tsx b/src/components/Editor.tsx index 619f049..fe5b9ae 100644 --- a/src/components/Editor.tsx +++ b/src/components/Editor.tsx @@ -40,6 +40,7 @@ export function Editor() { const [writingGoal, setWritingGoal] = useState(0); const [goalEditing, setGoalEditing] = useState(false); const lastSnapshotRef = useRef(0); + const mermaidRef = useRef(null); const [noteEncrypted, setNoteEncrypted] = useState(false); const [lockScreenOpen, setLockScreenOpen] = useState(false); const [lockError, setLockError] = useState(null); @@ -105,9 +106,16 @@ export function Editor() { }, []); // ── Initialize / switch note ── + const contentRenderedRef = useRef(false); useEffect(() => { if (currentNote !== lastNoteRef.current) { lastNoteRef.current = currentNote; + contentRenderedRef.current = false; + renderToDOM(noteContent); + if (noteContent) contentRenderedRef.current = true; + } else if (!contentRenderedRef.current && noteContent) { + // Content arrived async after note switch — render it now + contentRenderedRef.current = true; renderToDOM(noteContent); } }, [currentNote, noteContent, renderToDOM]); @@ -417,15 +425,7 @@ export function Editor() { return () => document.removeEventListener("mousedown", handler); }, []); - if (!currentNote) { - return ( -
-

Select a note to begin editing

-
- ); - } - - const renderedMarkdown = (() => { + const renderedMarkdown = currentNote ? (() => { let html = marked(noteContent, { async: false }) as string; html = html.replace( /\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, @@ -436,10 +436,9 @@ export function Editor() { } ); return DOMPurify.sanitize(html, { ADD_ATTR: ['data-target'] }); - })(); + })() : ""; // Mermaid post-processing (render in a separate effect) - const mermaidRef = useRef(null); useEffect(() => { if (!isPreview || !mermaidRef.current) return; const mermaidBlocks = mermaidRef.current.querySelectorAll("code.language-mermaid"); @@ -641,6 +640,14 @@ export function Editor() { ? currentNote.replace(/\.md$/, "").split("/") : []; + if (!currentNote) { + return ( +
+

Select a note to begin editing

+
+ ); + } + return (
{/* ── Breadcrumbs ── */}