Add Blocknote editor, Add theme switching
This commit is contained in:
3185
package-lock.json
generated
3185
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -46,6 +46,9 @@
|
||||
"vite": "^5.4.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blocknote/core": "^0.46.1",
|
||||
"@blocknote/react": "^0.46.1",
|
||||
"@blocknote/shadcn": "^0.46.1",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-separator": "^1.1.8",
|
||||
|
||||
@@ -2,16 +2,19 @@ import { NoteProvider } from "../contexts/ActiveNoteContext";
|
||||
import { NotesStoreProvider } from "../contexts/NotesStore";
|
||||
import NoteEditor from "./NoteEditor"
|
||||
import AppLayout from "./AppLayout"
|
||||
import { ThemeProvider } from "../contexts/ThemeContext";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<NotesStoreProvider>
|
||||
<NoteProvider>
|
||||
<AppLayout>
|
||||
<NoteEditor />
|
||||
</AppLayout>
|
||||
</NoteProvider>
|
||||
</NotesStoreProvider>
|
||||
<ThemeProvider>
|
||||
<NotesStoreProvider>
|
||||
<NoteProvider>
|
||||
<AppLayout>
|
||||
<NoteEditor />
|
||||
</AppLayout>
|
||||
</NoteProvider>
|
||||
</NotesStoreProvider>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,30 +9,21 @@ import ListItem from "./ListItem"
|
||||
|
||||
import { useNote } from "../contexts/ActiveNoteContext"
|
||||
import { useNotesStore } from "../contexts/NotesStore"
|
||||
import { useState } from "react"
|
||||
import { useTheme } from "../contexts/ThemeContext"
|
||||
|
||||
function AppSidebar() {
|
||||
const { notes, createNote } = useNotesStore()
|
||||
const { setCurrentNote } = useNote()
|
||||
const [isDark, setIsDark] = useState(
|
||||
() => document.documentElement.classList.contains("dark")
|
||||
)
|
||||
|
||||
const toggleTheme = () => {
|
||||
const html = document.documentElement
|
||||
html.classList.toggle("dark")
|
||||
setIsDark(html.classList.contains("dark"))
|
||||
}
|
||||
const { theme, toggleTheme } = useTheme()
|
||||
|
||||
return (
|
||||
<Sidebar>
|
||||
|
||||
|
||||
<SidebarHeader className="justify-between px-4 py-3 border-b-1 gap-3.5">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="font-medium">Notes</span>
|
||||
<Button variant="ghost" size="sm" onClick={toggleTheme} className="text-muted-foreground">
|
||||
{isDark ? <Sun /> : <Moon />}
|
||||
{theme === "dark" ? <Sun /> : <Moon />}
|
||||
</Button>
|
||||
</div>
|
||||
<Input placeholder="Search Notes" className="shadow-none bg-background" />
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import "@blocknote/core/fonts/inter.css";
|
||||
import "@blocknote/shadcn/style.css";
|
||||
import { BlockNoteView } from "@blocknote/shadcn";
|
||||
import { useCreateBlockNote } from "@blocknote/react"
|
||||
import { useNote } from "../contexts/ActiveNoteContext"
|
||||
import { useTheme } from "../contexts/ThemeContext";
|
||||
|
||||
function NoteEditor() {
|
||||
const { currentNote, setCurrentNote } = useNote();
|
||||
const { currentNote } = useNote();
|
||||
const { theme } = useTheme();
|
||||
|
||||
const editor = useCreateBlockNote({
|
||||
initialContent: currentNote?.body
|
||||
});
|
||||
|
||||
if (!currentNote) return (
|
||||
<div className="p-6">
|
||||
@@ -12,7 +22,7 @@ function NoteEditor() {
|
||||
return (
|
||||
<div className="p-6">
|
||||
<h1>{ currentNote.title }</h1>
|
||||
<p>{ currentNote.body }</p>
|
||||
<BlockNoteView editor={editor as any} theme={theme} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
37
src/contexts/ThemeContext.tsx
Normal file
37
src/contexts/ThemeContext.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { createContext, useContext, useState } from "react";
|
||||
|
||||
type Theme = "light" | "dark";
|
||||
|
||||
const ThemeContext = createContext<{
|
||||
theme: Theme;
|
||||
toggleTheme: () => void;
|
||||
} | null>(null);
|
||||
|
||||
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
const [theme, setTheme] = useState<Theme>(() =>
|
||||
document.documentElement.classList.contains("dark")
|
||||
? "dark"
|
||||
: "light"
|
||||
);
|
||||
|
||||
const toggleTheme = () => {
|
||||
const html = document.documentElement;
|
||||
html.classList.toggle("dark");
|
||||
|
||||
setTheme(
|
||||
html.classList.contains("dark") ? "dark" : "light"
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ theme, toggleTheme }}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useTheme() {
|
||||
const ctx = useContext(ThemeContext);
|
||||
if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
|
||||
return ctx;
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
@source "../node_modules/@blocknote/shadcn";
|
||||
|
||||
body {
|
||||
font-family: "Fira Sans", sans-serif, monospace !important;
|
||||
}
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme inline {
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
@@ -115,6 +116,14 @@ body {
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
|
||||
/* Blocknote tweaks */
|
||||
--bn-colors-editor-background: #0a0a0a !important;
|
||||
--bn-colors-block-background: #0a0a0a !important;
|
||||
|
||||
.bn-add-file-button {
|
||||
background-color: var(--primary-foreground) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import { PartialBlock } from "@blocknote/core";
|
||||
|
||||
export class Note {
|
||||
id: string;
|
||||
title: string;
|
||||
body: string;
|
||||
body: PartialBlock<any, any, any>[];
|
||||
|
||||
constructor(data: Partial<Note> = {}) {
|
||||
this.id = data.id ?? this.randomNumber();
|
||||
this.title = data.title ?? "Untitled Note";
|
||||
this.body = data.body ?? "";
|
||||
this.body = data.body ?? this.defaultBody();
|
||||
}
|
||||
|
||||
private defaultBody(): any {
|
||||
return [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// TODO: replace with UUID
|
||||
|
||||
Reference in New Issue
Block a user