diff --git a/backend/notes.db b/backend/notes.db index 04c85ac..77e2b53 100644 Binary files a/backend/notes.db and b/backend/notes.db differ diff --git a/frontend/src/pages/Home/Home.tsx b/frontend/src/pages/Home/Home.tsx index 4c884ee..d47cade 100644 --- a/frontend/src/pages/Home/Home.tsx +++ b/frontend/src/pages/Home/Home.tsx @@ -13,6 +13,8 @@ import { Note, NoteRead } from "@/api/notes"; import { DecryptedTagNode } from "@/api/encryption"; // @ts-ignore import XmarkIcon from "@/assets/fontawesome/svg/xmark.svg?react"; +// @ts-ignore +import PlusIcon from "@/assets/fontawesome/svg/plus.svg?react"; function Home() { const [newFolder] = useState(false); @@ -129,11 +131,14 @@ function Home() {
setTitle(e.target.value)} className="w-full p-4 pb-0 text-3xl font-semibold bg-transparent focus:outline-none border-transparent focus:border-ctp-mauve transition-colors placeholder:text-ctp-overlay0 text-ctp-text" /> + {/*
{editingNote?.tags && editingNote.tags.map((tag) => ( @@ -197,25 +202,99 @@ const Modal = () => { export const TagSelector = () => { const [value, setValue] = useState(""); + const containerRef = useRef(null); + const inputRef = useRef(null); const { data: tagTree, isLoading, error } = useTagTree(); const createTag = useCreateTag(); + const [expanded, setExpanded] = useState(false); + + // Close when clicking outside the entire component + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + containerRef.current && + !containerRef.current.contains(event.target as Node) + ) { + handleClose(); + } + }; + + if (expanded) { + document.addEventListener("mousedown", handleClickOutside); + return () => + document.removeEventListener("mousedown", handleClickOutside); + } + }, [expanded]); + + // Focus input when expanded + useEffect(() => { + if (expanded && inputRef.current) { + inputRef.current.focus(); + } + }, [expanded]); const handleEnter = async () => { createTag.mutate({ name: value }); }; + function handleClose() { + // If there’s a value, submit it; otherwise just collapse + if (value.trim()) { + // onsubmit?.(value.trim()); + } + setValue(""); + setExpanded(false); + } + + function handleKey(e: React.KeyboardEvent) { + if (e.key === "Enter") { + e.preventDefault(); + handleClose(); + } else if (e.key === "Escape") { + // Abort without submitting + setValue(""); + setExpanded(false); + } + } return ( -
- { - if (e.key === "Enter") handleEnter(); - }} - onChange={(e) => setValue(e.target.value)} - /> - {tagTree && tagTree.map((tag) => )} +
+
+ + + setValue(e.target.value)} + onKeyDown={handleKey} + placeholder={"Type here…"} + className={`text-xs z-30 + bg-transparent px-1.5 + focus:outline-none focus:ring-0 + transition-all duration-200 ease-out + ${expanded ? "w-32 opacity-100" : "w-0 opacity-0 pointer-events-none"} + `} + /> +
+ +
+ {tagTree && + tagTree + .filter((tag) => + value == "" ? false : (tag.name + tag.parentPath).includes(value), + ) + .map((tag) => )} +
); }; @@ -230,7 +309,10 @@ export const TagTree = ({ const [collapse, setCollapse] = useState(false); return ( -
+
setCollapse(!collapse)}>{tag.name}
{collapse && ( diff --git a/frontend/src/pages/Home/components/StatusIndicator.tsx b/frontend/src/pages/Home/components/StatusIndicator.tsx index ca7dd2b..47f22b9 100644 --- a/frontend/src/pages/Home/components/StatusIndicator.tsx +++ b/frontend/src/pages/Home/components/StatusIndicator.tsx @@ -24,14 +24,14 @@ export const StatusIndicator = () => { ) : updating ? ( <> - + {/* Saving... - + */} ) : ( <> - Saved + {/*Saved*/} )}
diff --git a/frontend/src/pages/TipTap.tsx b/frontend/src/pages/TipTap.tsx index 533d6fa..5125f7a 100644 --- a/frontend/src/pages/TipTap.tsx +++ b/frontend/src/pages/TipTap.tsx @@ -79,7 +79,7 @@ export const TiptapEditor = ({ } return ( -
+
{/* Toolbar */} {/*
@@ -191,7 +191,7 @@ export const TiptapEditor = ({ {/* Editor content */}
);