diff --git a/backend/app/routes/folders.py b/backend/app/routes/folders.py
index 9b4f976..02e1882 100644
--- a/backend/app/routes/folders.py
+++ b/backend/app/routes/folders.py
@@ -82,45 +82,18 @@ def update_folder(
folder_id: int, folder_update: FolderUpdate, session: Session = Depends(get_session)
):
"""Update a folder"""
- print(f"=== UPDATE FOLDER CALLED ===")
- print(f"Folder ID: {folder_id}")
- print(f"Update data received: {folder_update}")
-
folder = session.get(Folder, folder_id)
if not folder:
raise HTTPException(status_code=404, detail="Folder not found")
- print(
- f"Found folder: id={folder.id}, name={folder.name}, parent_id={folder.parent_id}"
- )
-
- # Update folder attributes from the request body
update_data = folder_update.model_dump(exclude_unset=True)
- print(f"Update data dict (exclude_unset): {update_data}")
- print(f"Update data keys: {list(update_data.keys())}")
for key, value in update_data.items():
- print(f"Setting {key} = {value}")
setattr(folder, key, value)
- print(
- f"After setattr: id={folder.id}, name={folder.name}, parent_id={folder.parent_id}"
- )
-
session.add(folder)
session.commit()
- print(f"Committed changes to database")
session.refresh(folder)
- print(
- f"After refresh: id={folder.id}, name={folder.name}, parent_id={folder.parent_id}"
- )
-
- # Verify the change persisted
- verification = session.get(Folder, folder_id)
- print(
- f"Verification query: id={verification.id}, name={verification.name}, parent_id={verification.parent_id}"
- )
- print(f"=== UPDATE COMPLETE ===")
return folder
diff --git a/backend/notes.db b/backend/notes.db
index fd73d29..19604f6 100644
Binary files a/backend/notes.db and b/backend/notes.db differ
diff --git a/frontend/src/components/editor/Editor.tsx b/frontend/src/components/editor/Editor.tsx
new file mode 100644
index 0000000..2edb707
--- /dev/null
+++ b/frontend/src/components/editor/Editor.tsx
@@ -0,0 +1,119 @@
+import {
+ BoldItalicUnderlineToggles,
+ codeBlockPlugin,
+ codeMirrorPlugin,
+ diffSourcePlugin,
+ headingsPlugin,
+ imagePlugin,
+ linkPlugin,
+ listsPlugin,
+ markdownShortcutPlugin,
+ MDXEditor,
+ quotePlugin,
+ SandpackConfig,
+ sandpackPlugin,
+ tablePlugin,
+ thematicBreakPlugin,
+ toolbarPlugin,
+ UndoRedo,
+} from "@mdxeditor/editor";
+import { useNoteStore } from "../../stores/notesStore";
+import { useEffect } from "react";
+import { useUIStore } from "../../stores/uiStore";
+
+const simpleSandpackConfig: SandpackConfig = {
+ defaultPreset: "react",
+ presets: [
+ {
+ label: "React",
+ name: "react",
+ meta: "live react",
+ sandpackTemplate: "react",
+ sandpackTheme: "dark",
+ snippetFileName: "/App.js",
+ snippetLanguage: "jsx",
+ },
+ ],
+};
+
+export const Editor = () => {
+ const { selectedNote, setContent, setTitle, updateNote } = useNoteStore();
+ const { updating, setUpdating } = useUIStore();
+
+ useEffect(() => {
+ if (!selectedNote) return;
+
+ const timer = setTimeout(async () => {
+ setUpdating(true);
+ handleUpdate();
+ }, 2000);
+
+ return () => clearTimeout(timer);
+ }, [selectedNote]);
+
+ const handleUpdate = async () => {
+ if (!selectedNote) return;
+ await updateNote(selectedNote.id);
+ console.log(selectedNote.id);
+
+ setTimeout(() => {
+ setUpdating(false);
+ }, 1000);
+ };
+
+ return (
+
+ {/* Title input */}
+
setTitle(e.target.value)}
+ className="w-full px-0 py-3 mb-4 text-3xl font-semibold bg-transparent border-b border-ctp-surface2 focus:outline-none focus:border-ctp-mauve transition-colors placeholder:text-ctp-overlay0 text-ctp-text"
+ />
+
+ (
+ <>
+
+
+ >
+ ),
+ }),
+
+ tablePlugin(),
+ listsPlugin(),
+ quotePlugin(),
+ thematicBreakPlugin(),
+ linkPlugin(),
+ codeBlockPlugin({ defaultCodeBlockLanguage: "js" }),
+ sandpackPlugin({ sandpackConfig: simpleSandpackConfig }),
+ codeMirrorPlugin({
+ codeBlockLanguages: {
+ js: "JavaScript",
+ css: "CSS",
+ python: "Python",
+ typescript: "TypeScript",
+ html: "HTML",
+ },
+ }),
+ imagePlugin(),
+ markdownShortcutPlugin(),
+ diffSourcePlugin({
+ viewMode: "rich-text",
+ diffMarkdown: "boo",
+ }),
+ ]}
+ />
+
+
+ );
+};
diff --git a/frontend/src/components/sidebar/DraggableNote.tsx b/frontend/src/components/sidebar/DraggableNote.tsx
index 0bf33d3..6516443 100644
--- a/frontend/src/components/sidebar/DraggableNote.tsx
+++ b/frontend/src/components/sidebar/DraggableNote.tsx
@@ -2,16 +2,11 @@ import React from "react";
import { useDraggable } from "@dnd-kit/core";
import { Note } from "../../api/notes";
import { NoteRead } from "../../api/folders";
+import { useNoteStore } from "../../stores/notesStore";
+
+export const DraggableNote = ({ note }: { note: NoteRead }) => {
+ const { selectedNote, setSelectedNote } = useNoteStore();
-export const DraggableNote = ({
- note,
- selectNote,
- selectedNote,
-}: {
- note: NoteRead;
- selectNote: (note: NoteRead) => void;
- selectedNote: NoteRead | null;
-}) => {
const { attributes, listeners, setNodeRef, transform } = useDraggable({
id: note.id,
data: { type: "note", note },
@@ -26,14 +21,16 @@ export const DraggableNote = ({
);
diff --git a/frontend/src/components/sidebar/DroppableFolder.tsx b/frontend/src/components/sidebar/DroppableFolder.tsx
index 35cfba2..4819271 100644
--- a/frontend/src/components/sidebar/DroppableFolder.tsx
+++ b/frontend/src/components/sidebar/DroppableFolder.tsx
@@ -1,22 +1,19 @@
import React from "react";
import { useDroppable, useDraggable } from "@dnd-kit/core";
import { Folder, NoteRead } from "../../api/folders";
+import { useNoteStore } from "../../stores/notesStore";
export const DroppableFolder = ({
folder,
- setSelectedFolder,
- selectedFolder,
- selectedNote,
setCollapse,
collapse,
}: {
folder: Partial;
- setSelectedFolder: (id: number | null) => void;
- selectedFolder: number | null;
- selectedNote: NoteRead | null;
setCollapse: React.Dispatch>;
collapse: boolean;
}) => {
+ const { setSelectedFolder, selectedFolder, selectedNote } = useNoteStore();
+
const { isOver, setNodeRef: setDroppableRef } = useDroppable({
id: folder.id!,
data: { type: "folder", folder },
diff --git a/frontend/src/components/sidebar/RecursiveFolder.tsx b/frontend/src/components/sidebar/RecursiveFolder.tsx
new file mode 100644
index 0000000..c70a1de
--- /dev/null
+++ b/frontend/src/components/sidebar/RecursiveFolder.tsx
@@ -0,0 +1,42 @@
+import { useState } from "react";
+import { FolderTreeNode } from "../../api/folders";
+import { DraggableNote } from "./DraggableNote";
+import { DroppableFolder } from "./DroppableFolder";
+
+interface RecursiveFolderProps {
+ folder: FolderTreeNode;
+ depth?: number;
+}
+
+export const RecursiveFolder = ({
+ folder,
+ depth = 0,
+}: RecursiveFolderProps) => {
+ const [collapse, setCollapse] = useState(false);
+
+ return (
+ 0 ? "1.5rem" : "0" }}
+ >
+
+ {collapse && (
+ <>
+
+ {folder.notes.map((note) => (
+
+ ))}
+
+ {folder.children.map((child) => (
+
+ ))}
+ >
+ )}
+
+ );
+};
diff --git a/frontend/src/components/sidebar/SideBar.tsx b/frontend/src/components/sidebar/SideBar.tsx
index c3165a0..7d0e150 100644
--- a/frontend/src/components/sidebar/SideBar.tsx
+++ b/frontend/src/components/sidebar/SideBar.tsx
@@ -17,6 +17,7 @@ import {
useSensors,
} from "@dnd-kit/core";
import { notesApi } from "../../api/notes";
+import { RecursiveFolder } from "./RecursiveFolder";
export const Sidebar = ({ clearSelection }: { clearSelection: () => void }) => {
// const [folderTree, setFolderTree] = useState(null);
@@ -143,15 +144,7 @@ export const Sidebar = ({ clearSelection }: { clearSelection: () => void }) => {
{/* Folder tree */}
{folderTree?.folders.map((folder) => (
-
+
))}
@@ -162,12 +155,7 @@ export const Sidebar = ({ clearSelection }: { clearSelection: () => void }) => {
Unsorted
*/}
{folderTree.orphaned_notes.map((note) => (
-
+
))}
)}
@@ -205,65 +193,3 @@ export const SidebarHeader = ({
);
};
-
-interface RenderFolderProps {
- folder: FolderTreeNode;
- depth?: number;
- setSelectedFolder: (id: number | null) => void;
- selectedFolder: number | null;
- selectedNote: NoteRead | null;
- selectNote: (note: NoteRead) => void;
-}
-
-const RenderFolder = ({
- folder,
- depth = 0,
- setSelectedFolder,
- selectedFolder,
- selectedNote,
- selectNote,
-}: RenderFolderProps) => {
- const [collapse, setCollapse] = useState(false);
-
- return (
- 0 ? "1.5rem" : "0" }}
- >
-
- {collapse && (
- <>
-
- {folder.notes.map((note) => (
-
- ))}
-
- {folder.children.map((child) => (
-
- ))}
- >
- )}
-
- );
-};
diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx
index 097423a..dd8b4d7 100644
--- a/frontend/src/pages/Home.tsx
+++ b/frontend/src/pages/Home.tsx
@@ -46,21 +46,8 @@ import SpinnerIcon from "../assets/fontawesome/svg/rotate.svg?react";
import { useNoteStore } from "../stores/notesStore";
import { create } from "zustand";
import { Sidebar } from "../components/sidebar/SideBar";
-
-const simpleSandpackConfig: SandpackConfig = {
- defaultPreset: "react",
- presets: [
- {
- label: "React",
- name: "react",
- meta: "live react",
- sandpackTemplate: "react",
- sandpackTheme: "dark",
- snippetFileName: "/App.js",
- snippetLanguage: "jsx",
- },
- ],
-};
+import { Editor } from "../components/editor/Editor";
+import { useUIStore } from "../stores/uiStore";
function Home() {
// const [folderTree, setFolderTree] = useState(null);
@@ -71,7 +58,7 @@ function Home() {
const [newFolderText, setNewFolderText] = useState("");
// const [selectedFolder, setSelectedFolder] = useState(null);
const [encrypted, setEncrypted] = useState(false);
- const [updating, setUpdating] = useState(false);
+ // const [updating, setUpdating] = useState(false);
const {
setSelectedFolder,
@@ -85,7 +72,7 @@ function Home() {
selectedNote,
} = useNoteStore();
-
+ const { updating } = useUIStore();
const newFolderRef = useRef(null);
@@ -99,31 +86,11 @@ function Home() {
}
}, [newFolder]);
- useEffect(() => {
- if (!selectedNote) return;
-
- const timer = setTimeout(async () => {
- setUpdating(true);
- handleUpdate();
- }, 2000);
-
- return () => clearTimeout(timer);
- }, [content, title]);
-
const handleCreate = async () => {
if (!title.trim()) return;
await createNote({ title, content, folder_id: null });
};
- const handleUpdate = async () => {
- if (!selectedNote) return;
- await updateNote(selectedNote.id, { title, content });
-
- setTimeout(() => {
- setUpdating(false);
- }, 1000);
- };
-
const handleDelete = async (id: number) => {
await notesApi.delete(id);
loadFolderTree();
@@ -136,193 +103,71 @@ function Home() {
setContent("");
};
-
-
return (
+
+ {/* Sidebar */}
-
- {/* Sidebar */}
+
-
+ {/* Main editor area */}
+
+ {/* Top accent bar */}
+
- {/* Main editor area */}
-
- {/* Top accent bar */}
-
+
- {/* Content area with padding */}
-
- {/* Title input */}
-
setTitle(e.target.value)}
- className="w-full px-0 py-3 mb-4 text-3xl font-semibold bg-transparent border-b border-ctp-surface2 focus:outline-none focus:border-ctp-mauve transition-colors placeholder:text-ctp-overlay0 text-ctp-text"
- />
-
- {/* Editor */}
-
- (
- <>
-
-
- >
- ),
- }),
-
- tablePlugin(),
- listsPlugin(),
- quotePlugin(),
- thematicBreakPlugin(),
- linkPlugin(),
- codeBlockPlugin({ defaultCodeBlockLanguage: "js" }),
- sandpackPlugin({ sandpackConfig: simpleSandpackConfig }),
- codeMirrorPlugin({
- codeBlockLanguages: {
- js: "JavaScript",
- css: "CSS",
- python: "Python",
- typescript: "TypeScript",
- html: "HTML",
- },
- }),
- imagePlugin(),
- markdownShortcutPlugin(),
- diffSourcePlugin({
- viewMode: "rich-text",
- diffMarkdown: "boo",
- }),
- ]}
- />
-
-
-
- {/* Action bar */}
-
- {selectedNote ? (
- <>
-
-
-
- >
- ) : (
-
- )}
-
-
-
- {/* Status indicator */}
-
- {updating ? (
+ {/* Action bar */}
+
+ {selectedNote ? (
<>
-
-
- Saving...
-
+ {/**/}
+
+
>
) : (
- <>
-
-
- Saved
-
- >
+
)}
+
+ {/* Status indicator */}
+
+ {updating ? (
+ <>
+
+
+ Saving...
+
+ >
+ ) : (
+ <>
+
+ Saved
+ >
+ )}
+
+
);
}
export default Home;
-
-interface RenderFolderProps {
- folder: FolderTreeNode;
- depth?: number;
- setSelectedFolder: (id: number | null) => void;
- selectedFolder: number | null;
- selectedNote: NoteRead | null;
- selectNote: (note: NoteRead) => void;
-}
-
-const RenderFolder = ({
- folder,
- depth = 0,
- setSelectedFolder,
- selectedFolder,
- selectedNote,
- selectNote,
-}: RenderFolderProps) => {
- const [collapse, setCollapse] = useState(false);
-
- return (
-
0 ? "1.5rem" : "0" }}
- >
-
- {collapse && (
- <>
-
- {folder.notes.map((note) => (
-
- ))}
-
- {folder.children.map((child) => (
-
- ))}
- >
- )}
-
- );
-};
diff --git a/frontend/src/stores/notesStore.ts b/frontend/src/stores/notesStore.ts
index 7f407fc..7e9135b 100644
--- a/frontend/src/stores/notesStore.ts
+++ b/frontend/src/stores/notesStore.ts
@@ -7,15 +7,18 @@ import {
NoteRead,
} from "../api/folders";
import { Note, NoteCreate, notesApi } from "../api/notes";
+import { getSelectedNode } from "@mdxeditor/editor";
interface NoteState {
folderTree: FolderTreeResponse | null;
selectedFolder: number | null;
selectedNote: NoteRead | null;
+ setContent: (content: string) => void;
+ setTitle: (title: string) => void;
loadFolderTree: () => Promise
;
createNote: (note: NoteCreate) => Promise;
- updateNote: (id: number, note: Partial) => Promise;
+ updateNote: (id: number) => Promise;
createFolder: (folder: FolderCreate) => Promise;
setSelectedFolder: (id: number | null) => void;
setSelectedNote: (id: NoteRead | null) => void;
@@ -26,6 +29,20 @@ export const useNoteStore = create()((set, get) => ({
selectedFolder: null,
selectedNote: null,
+ setContent: (content) => {
+ const currentNote = get().selectedNote;
+ if (currentNote) {
+ set({ selectedNote: { ...currentNote, content: content } });
+ }
+ },
+
+ setTitle: (title) => {
+ const currentNote = get().selectedNote;
+ if (currentNote) {
+ set({ selectedNote: { ...currentNote, title: title } });
+ }
+ },
+
loadFolderTree: async () => {
const data = await folderApi.tree();
set({ folderTree: data });
@@ -41,7 +58,8 @@ export const useNoteStore = create()((set, get) => ({
await get().loadFolderTree();
},
- updateNote: async (id: number, note: Partial) => {
+ updateNote: async (id: number) => {
+ const note = get().selectedNote as Partial;
await notesApi.update(id, note);
await get().loadFolderTree();
},
diff --git a/frontend/src/stores/uiStore.ts b/frontend/src/stores/uiStore.ts
new file mode 100644
index 0000000..6d9cca9
--- /dev/null
+++ b/frontend/src/stores/uiStore.ts
@@ -0,0 +1,13 @@
+import { create } from "zustand";
+
+interface UIState {
+ updating: boolean;
+ setUpdating: (update: boolean) => void;
+}
+
+export const useUIStore = create()((set, get) => ({
+ updating: false,
+ setUpdating: (update) => {
+ set({ updating: update });
+ },
+}));