- {/*
*/}
-
- 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 ? (
+ <>
+
setTitle(e.target.value)}
+ className="w-full self-center p-4 pb-2 pt-2 text-3xl font-semibold focus:outline-none border-transparent focus:border-accent transition-colors placeholder:text-overlay0 text-text bg-surface1"
+ />
+
+ {" "}
+ {editorView == "parsed" ? (
+
+ ) : (
+
+ )}
+
+ >
+ ) : (
+
+
+
+
Select a note or create a new one
+
+
+ )}
@@ -152,14 +185,16 @@ function Home() {
export default Home;
const Modal = () => {
- const { setShowModal } = useUIStore();
+ const { setShowModal, modalContent, showModal } = useUIStore();
+ const ModalContent = modalContent;
+ if (!showModal || !ModalContent) return null;
return (
setShowModal(false)}
- className="fixed inset-0 h-screen w-screen flex items-center justify-center bg-ctp-crust/70 backdrop-blur-sm z-50"
+ className="fixed inset-0 h-screen w-screen flex items-center justify-center bg-crust/70 backdrop-blur-sm z-50"
>
{
exit={{ opacity: 0, scale: 0.95, y: 20 }}
transition={{ type: "spring", duration: 0.3 }}
onClick={(e) => e.stopPropagation()}
- className="relative w-full max-w-md mx-4 bg-ctp-base rounded-xl border-ctp-surface2 border p-8 shadow-2xl"
+ className="relative w-full max-w-md mx-4 bg-base rounded-xl border-surface1 border p-8 shadow-2xl"
>
-
+
+ {/**/}
);
diff --git a/frontend/src/pages/Home/components/StatusIndicator.tsx b/frontend/src/pages/Home/components/StatusIndicator.tsx
index 47f22b9..164422b 100644
--- a/frontend/src/pages/Home/components/StatusIndicator.tsx
+++ b/frontend/src/pages/Home/components/StatusIndicator.tsx
@@ -6,32 +6,43 @@ import CheckIcon from "../../../assets/fontawesome/svg/circle-check.svg?react";
import SpinnerIcon from "../../../assets/fontawesome/svg/rotate.svg?react";
// @ts-ignore
import WarningIcon from "../../../assets/fontawesome/svg/circle-exclamation.svg?react";
+import { Login } from "@/pages/Login";
export const StatusIndicator = () => {
const { encryptionKey } = useAuthStore();
- const { updating, setShowModal } = useUIStore();
+ const { updating, setShowModal, editorView, setEditorView, setModalContent } =
+ useUIStore();
return (
{
if (!encryptionKey) {
+ setModalContent(Login);
setShowModal(true);
}
}}
>
+
+ setEditorView(editorView == "parsed" ? "unparsed" : "parsed")
+ }
+ >
+ {editorView}
+
{!encryptionKey ? (
-
+
) : updating ? (
<>
-
- {/*
+
+ {/*
Saving...
*/}
>
) : (
<>
-
- {/*Saved*/}
+
+ {/*Saved*/}
>
)}
diff --git a/frontend/src/pages/Home/components/sidebar/SideBar.tsx b/frontend/src/pages/Home/components/sidebar/SideBar.tsx
index 19d06ea..82a40db 100644
--- a/frontend/src/pages/Home/components/sidebar/SideBar.tsx
+++ b/frontend/src/pages/Home/components/sidebar/SideBar.tsx
@@ -41,7 +41,7 @@ export const Sidebar = () => {
const { encryptionKey } = useAuthStore();
- const { setSideBarResize, sideBarResize } = useUIStore();
+ const { setSideBarResize, sideBarResize, setColourScheme } = useUIStore();
useEffect(() => {
if (newFolder && newFolderRef.current) {
newFolderRef.current.focus();
@@ -163,7 +163,7 @@ export const Sidebar = () => {
>
{
style={{ width: `${sideBarResize}px` }}
>
-
+
<>
{
{/* Loading state */}
{isLoading && (
-
+
)}
{/* Error state */}
{error && (
-
+
)}
@@ -236,16 +236,19 @@ export const Sidebar = () => {
>
)}
+ {/*
+
+
*/}
{activeItem?.type === "note" && (
-
+
{activeItem.data.title}
)}
{activeItem?.type === "folder" && (
-
-
+
+
{activeItem.data.name}
)}
diff --git a/frontend/src/pages/Home/components/sidebar/subcomponents/DraggableNote.tsx b/frontend/src/pages/Home/components/sidebar/subcomponents/DraggableNote.tsx
index 7a727ab..75a8a1c 100644
--- a/frontend/src/pages/Home/components/sidebar/subcomponents/DraggableNote.tsx
+++ b/frontend/src/pages/Home/components/sidebar/subcomponents/DraggableNote.tsx
@@ -39,8 +39,8 @@ export const DraggableNote = ({ note }: { note: NoteRead }) => {
}}
className={` rounded-sm px-2 mb-0.5 select-none cursor-pointer font-light transition-all duration-150 flex items-center gap-1 ${
selectedNote?.id === note.id
- ? "bg-ctp-mauve text-ctp-base"
- : "hover:bg-ctp-surface1"
+ ? "bg-accent text-base"
+ : "hover:bg-surface1"
}`}
>
diff --git a/frontend/src/pages/Home/components/sidebar/subcomponents/DroppableFolder.tsx b/frontend/src/pages/Home/components/sidebar/subcomponents/DroppableFolder.tsx
index d0e0d90..3c35f5a 100644
--- a/frontend/src/pages/Home/components/sidebar/subcomponents/DroppableFolder.tsx
+++ b/frontend/src/pages/Home/components/sidebar/subcomponents/DroppableFolder.tsx
@@ -65,10 +65,10 @@ export const DroppableFolder = ({
>
{(folder.notes?.length ?? 0) > 0 && (
)}
-
+
{folder.name}
diff --git a/frontend/src/pages/Home/components/sidebar/subcomponents/FolderTree.tsx b/frontend/src/pages/Home/components/sidebar/subcomponents/FolderTree.tsx
index ed04fba..d3594ef 100644
--- a/frontend/src/pages/Home/components/sidebar/subcomponents/FolderTree.tsx
+++ b/frontend/src/pages/Home/components/sidebar/subcomponents/FolderTree.tsx
@@ -29,7 +29,7 @@ export const FolderTree = ({ folder, depth = 0 }: FolderTreeProps) => {
className="overflow-hidden flex flex-col"
>
{/* The line container */}
-
+
{/* Notes */}
{folder.notes.map((note) => (
diff --git a/frontend/src/pages/Home/components/sidebar/subcomponents/SideBarHeader.tsx b/frontend/src/pages/Home/components/sidebar/subcomponents/SideBarHeader.tsx
index e93aead..39768f1 100644
--- a/frontend/src/pages/Home/components/sidebar/subcomponents/SideBarHeader.tsx
+++ b/frontend/src/pages/Home/components/sidebar/subcomponents/SideBarHeader.tsx
@@ -5,16 +5,46 @@ import FolderPlusIcon from "@assets/fontawesome/svg/folder-plus.svg?react";
import TagsIcon from "@assets/fontawesome/svg/tags.svg?react";
// @ts-ignore
import FileCirclePlusIcon from "@assets/fontawesome/svg/file-circle-plus.svg?react";
+// @ts-ignore
+import GearIcon from "@assets/fontawesome/svg/gear.svg?react";
import { useUIStore } from "@/stores/uiStore";
import { useCreateNote } from "@/hooks/useFolders";
import { NoteCreate } from "@/api/notes";
+import { Login } from "@/pages/Login";
+import { ColourState } from "@/stores/uiStore";
+
+const Test = () => {
+ const { colourScheme, setColourScheme } = useUIStore();
+
+ const handleColor = (key: string, value: string) => {
+ setColourScheme({
+ ...colourScheme,
+ [key]: value,
+ });
+ };
+
+ return (
+ <>
+ {Object.entries(colourScheme).map(([key, value]) => (
+
+
+ handleColor(key, e.target.value)}
+ />
+
+ ))}
+ >
+ );
+};
export const SidebarHeader = ({
setNewFolder,
}: {
setNewFolder: React.Dispatch
>;
}) => {
- const { selectedFolder } = useUIStore();
+ const { selectedFolder, setShowModal, setModalContent } = useUIStore();
const createNote = useCreateNote();
const handleCreate = async () => {
createNote.mutate({
@@ -23,22 +53,34 @@ export const SidebarHeader = ({
folder_id: selectedFolder,
} as NoteCreate);
};
+
+ const handleSettings = () => {
+ setModalContent(Test);
+ setShowModal(true);
+ };
return (
-
-
+
+
+
diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx
index 5756a4a..1b61959 100644
--- a/frontend/src/pages/Login.tsx
+++ b/frontend/src/pages/Login.tsx
@@ -30,14 +30,10 @@ export const Login = () => {
onSubmit={handleSubmit}
className="gap-4 flex flex-col max-w-md mx-auto"
>
-
- Welcome Back
-
+
Welcome Back
-
+
{
-
+
{
{error && (
-
+
{error}
)}
@@ -72,11 +66,11 @@ export const Login = () => {
id="remember"
checked={remember}
onChange={(e) => setRemember(e.target.checked)}
- className="accent-ctp-mauve cursor-pointer"
+ className="accent-accent cursor-pointer"
/>
@@ -84,7 +78,7 @@ export const Login = () => {
diff --git a/frontend/src/pages/Register.tsx b/frontend/src/pages/Register.tsx
index 3708c2f..c364d4e 100644
--- a/frontend/src/pages/Register.tsx
+++ b/frontend/src/pages/Register.tsx
@@ -27,14 +27,10 @@ export const Register = () => {
onSubmit={handleSubmit}
className="gap-4 flex flex-col max-w-md mx-auto"
>
-
- Create Account
-
+
Create Account
-
+
{
-
+
{
-
+
{
{error && (
-
+
{error}
)}
diff --git a/frontend/src/pages/Test.tsx b/frontend/src/pages/Test.tsx
index 914758d..eb6c764 100644
--- a/frontend/src/pages/Test.tsx
+++ b/frontend/src/pages/Test.tsx
@@ -1,6 +1,6 @@
export const Test = () => {
return (
-
+
+
{/* Toolbar */}
{/*
@@ -88,28 +93,28 @@ export const TiptapEditor = ({
className={editor.isActive("bold") ? "active" : ""}
title="Bold (Ctrl+B)"
>
-
+
@@ -153,35 +158,35 @@ export const TiptapEditor = ({
className={editor.isActive("bulletList") ? "active" : ""}
title="Bullet list"
>
-
+
diff --git a/frontend/src/pages/tiptap.css b/frontend/src/pages/tiptap.css
index d5acfd5..adcb78a 100644
--- a/frontend/src/pages/tiptap.css
+++ b/frontend/src/pages/tiptap.css
@@ -7,33 +7,37 @@
}
*::-webkit-scrollbar-track {
- @apply bg-ctp-mantle rounded-full;
+ @apply bg-surface0 rounded-full;
}
*::-webkit-scrollbar-thumb {
- @apply bg-ctp-surface2 rounded-full;
+ @apply bg-surface1 rounded-full;
}
*::-webkit-scrollbar-thumb:hover {
- @apply bg-ctp-overlay0;
+ @apply bg-overlay0;
}
/* Firefox scrollbar */
* {
scrollbar-width: thin;
- scrollbar-color: var(--color-ctp-surface2) var(--color-ctp-mantle);
+ scrollbar-color: var(--color-surface1) var(--color-surface0);
}
.tiptap-editor {
- @apply flex flex-col h-full bg-ctp-base;
+ @apply flex flex-col h-full bg-base;
}
.ProseMirror {
- @apply text-ctp-text;
+ @apply text-text;
}
.editor-toolbar {
- @apply flex gap-2 px-4 bg-ctp-mantle border-b border-ctp-surface2 flex-wrap items-center;
+ @apply flex gap-2 px-4 bg-surface0 border-b border-surface1 flex-wrap items-center;
+}
+
+.editor-content {
+ @apply h-full;
}
.toolbar-group {
@@ -41,19 +45,19 @@
}
.toolbar-divider {
- @apply w-px h-6 bg-ctp-surface2;
+ @apply w-px h-6 bg-surface1;
}
.editor-toolbar button {
- @apply p-2 bg-transparent border-none rounded-sm text-ctp-text cursor-pointer transition-all duration-150 text-sm font-semibold min-w-8 flex items-center justify-center;
+ @apply p-2 bg-transparent border-none rounded-sm text-text cursor-pointer transition-all duration-150 text-sm font-semibold min-w-8 flex items-center justify-center;
}
.editor-toolbar button:hover:not(:disabled) {
- @apply bg-ctp-surface0;
+ @apply bg-surface0;
}
.editor-toolbar button.active {
- @apply bg-ctp-mauve text-ctp-base;
+ @apply bg-accent text-base;
}
.editor-toolbar button:disabled {
@@ -66,59 +70,59 @@
.ProseMirror p.is-editor-empty:first-child::before {
content: attr(data-placeholder);
- @apply float-left text-ctp-overlay0 pointer-events-none h-0;
+ @apply float-left text-overlay0 pointer-events-none h-0;
}
.ProseMirror ul {
@apply mb-0!;
}
.ProseMirror h1 {
- @apply text-3xl font-bold text-ctp-mauve mt-8 mb-4;
+ @apply text-3xl font-bold mt-6 mb-4 text-accent;
}
.ProseMirror h2 {
- @apply text-2xl font-semibold text-ctp-blue mt-6 mb-3;
+ @apply text-2xl font-semibold text-accent mt-4 mb-3;
}
.ProseMirror h3 {
- @apply text-xl font-semibold text-ctp-mauve mt-5 mb-2;
+ @apply text-xl font-semibold text-accent mt-5 mb-2;
}
.ProseMirror code {
- @apply bg-ctp-surface0 text-ctp-peach px-1.5 py-0.5 rounded text-sm;
+ @apply bg-surface0 text-accent px-1.5 py-0.5 rounded text-sm;
font-family: "JetBrains Mono", "Fira Code", monospace;
}
.ProseMirror .code-block {
- @apply bg-ctp-surface0 border border-ctp-surface2 rounded-sm p-4 my-4 overflow-x-auto;
+ @apply bg-surface0 border border-surface1 rounded-sm p-4 my-4 overflow-x-auto;
font-family: "JetBrains Mono", "Fira Code", monospace;
}
.ProseMirror .code-block code {
- @apply bg-transparent p-0 text-ctp-text;
+ @apply bg-transparent p-0 text-text;
}
.ProseMirror blockquote {
- @apply border-l-4 border-ctp-mauve pl-4 ml-0 text-ctp-subtext0 italic;
+ @apply border-l-4 border-accent pl-4 ml-0 text-subtext italic;
}
.ProseMirror hr {
- @apply border-none border-t-2 border-ctp-surface2 my-8;
+ @apply border-none border-t-2 border-surface1 my-8;
}
.ProseMirror a {
- @apply text-ctp-blue underline;
+ @apply text-accent underline;
}
.ProseMirror a:hover {
- @apply text-ctp-sapphire;
+ @apply text-accent;
}
.ProseMirror strong {
- @apply text-ctp-peach font-semibold;
+ @apply text-accent font-semibold;
}
.ProseMirror em {
- @apply text-ctp-yellow;
+ @apply text-accent;
}
/* Task List (Checkboxes) */
@@ -135,7 +139,7 @@
}
.ProseMirror ul[data-type="taskList"] > li > label input[type="checkbox"] {
- @apply cursor-pointer m-0 accent-ctp-mauve;
+ @apply cursor-pointer m-0 accent-accent;
}
.ProseMirror ul[data-type="taskList"] > li > div {
@@ -147,18 +151,18 @@
}
.ProseMirror li[data-checked="true"] > div > p {
- @apply line-through text-ctp-overlay0;
+ @apply line-through text-text/40;
text-decoration-style: wavy;
text-decoration-thickness: 1px;
}
.ProseMirror u {
- @apply decoration-ctp-mauve;
+ @apply decoration-accent;
/*text-decoration-style: wavy;*/
}
.ProseMirror li::marker {
- @apply text-ctp-mauve;
+ @apply text-accent;
}
/* tiptap.css */
@@ -172,3 +176,19 @@
margin-top: 0 !important;
margin-bottom: 0 !important;
}
+
+hr {
+ border: none;
+ height: 3px;
+ background: repeating-linear-gradient(
+ 90deg,
+ var(--color-accent) 0px,
+ var(--color-accent) 8px,
+ var(--color-accent) 16px
+ );
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 6'%3E%3Cpath d='M0 3 Q 3 0, 6 3 T 12 3 T 18 3 T 24 3' stroke='black' stroke-width='2' fill='none'/%3E%3C/svg%3E")
+ repeat-x;
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 6'%3E%3Cpath d='M0 3 Q 3 0, 6 3 T 12 3 T 18 3 T 24 3' stroke='black' stroke-width='2' fill='none'/%3E%3C/svg%3E")
+ repeat-x;
+ margin: 2em 0;
+}
diff --git a/frontend/src/stores/uiStore.ts b/frontend/src/stores/uiStore.ts
index fa54506..724aa8a 100644
--- a/frontend/src/stores/uiStore.ts
+++ b/frontend/src/stores/uiStore.ts
@@ -1,6 +1,27 @@
import { Note, NoteRead } from "@/api/notes";
import { create } from "zustand";
import { persist } from "zustand/middleware";
+import { Login } from "@/pages/Login";
+
+interface HSL {
+ H: Number;
+ S: Number;
+ L: Number;
+}
+
+export interface ColourState {
+ base: string;
+ surface0: string;
+ surface1: string;
+ overlay0: string;
+ overlay1: string;
+ text: string;
+ subtext: string;
+ accent: string;
+ warn: string;
+ success: string;
+ danger: string;
+}
interface UIState {
updating: boolean;
@@ -9,17 +30,26 @@ interface UIState {
showModal: boolean;
setShowModal: (show: boolean) => void;
+ modalContent: React.ComponentType | null;
+ setModalContent: (content: React.ComponentType) => void;
+
sideBarResize: number;
setSideBarResize: (size: number) => void;
sideBarView: string;
setSideBarView: (view: string) => void;
+ editorView: string;
+ setEditorView: (view: string) => void;
+
selectedNote: NoteRead | null;
setSelectedNote: (note: NoteRead | null) => void;
selectedFolder: number | null;
setSelectedFolder: (id: number | null) => void;
+
+ colourScheme: ColourState;
+ setColourScheme: (colors: ColourState) => void;
}
export const useUIStore = create
()(
@@ -33,6 +63,10 @@ export const useUIStore = create()(
setShowModal: (show) => {
set({ showModal: show });
},
+ modalContent: null,
+ setModalContent: (content) => {
+ set({ modalContent: content });
+ },
sideBarResize: 300,
setSideBarResize: (size) => {
set({ sideBarResize: size });
@@ -41,6 +75,10 @@ export const useUIStore = create()(
setSideBarView: (view) => {
set({ sideBarView: view });
},
+ editorView: "parsed",
+ setEditorView: (view) => {
+ set({ editorView: view });
+ },
selectedNote: null,
setSelectedNote: (id: NoteRead | null) => {
@@ -51,6 +89,28 @@ export const useUIStore = create()(
setSelectedFolder: (id: number | null) => {
set({ selectedFolder: id });
},
+
+ colourScheme: {
+ base: "#24273a",
+ surface0: "#1e2030",
+ surface1: "#181926",
+ overlay0: "#363a4f",
+ overlay1: "#494d64",
+ text: "#cad3f5",
+ subtext: "#b8c0e0",
+ accent: "#e2a16f",
+ danger: "#e26f6f",
+ success: "#6fe29b",
+ warn: "#e2c56f",
+ },
+
+ setColourScheme: (colors: ColourState) => {
+ set({ colourScheme: colors });
+
+ Object.entries(colors).forEach(([key, value]) => {
+ document.documentElement.style.setProperty(`--color-${key}`, value);
+ });
+ },
}),
{