diff --git a/index.html b/index.html
index d5be1af..1f73080 100644
--- a/index.html
+++ b/index.html
@@ -6,8 +6,8 @@
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 ── */}