Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions app/editor/note-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Effect } from "@tanstack/react-store";
import { useEffect } from "react";
import { ExternalNoteAction } from "~/editor/external-note-action";
import { setNotes } from "~/editor/indexed-db";
Expand Down Expand Up @@ -97,15 +96,10 @@ export const NoteEditor = () => {
* Listen to store changes. If the note changes we want to be able to
* debounce the save on Indexed DB.
*/
const effect = new Effect({
deps: [NoteStore],
eager: false,
fn: () => {
SystemStore.setState((c) => ({ ...c, save: "saving" }));
debouncedSave.debouncedFn();
},
const { unsubscribe } = NoteStore.subscribe(() => {
SystemStore.setState((c) => ({ ...c, save: "saving" }));
debouncedSave.debouncedFn();
});
const unmount = effect.mount();

/**
* Mount effect on load.
Expand All @@ -115,22 +109,22 @@ export const NoteEditor = () => {
* If the user switched tabs, minimized the browser, or closed the page,
* immediately save and unmount the effect.
*/
const handleVisibilityChange = () => {
const handleVisibilityChange = async () => {
if (document.visibilityState === "visible") {
return;
}

debouncedSave.flush();
unmount();
await debouncedSave.flush();
unsubscribe();
};

/**
* If the user is using an old browser, we handle the tab close with another function
* that does the same thing as the above.
*/
const handlePageHide = () => {
debouncedSave.flush();
unmount();
const handlePageHide = async () => {
await debouncedSave.flush();
unsubscribe();
};

/**
Expand All @@ -150,7 +144,7 @@ export const NoteEditor = () => {
document.removeEventListener("visibilitychange", handleVisibilityChange);
window.removeEventListener("pagehide", handlePageHide);
};
}, [unmount, debouncedSave.flush]);
}, [unsubscribe, debouncedSave.flush]);

const handleSave = async () => {
await debouncedSave.flush();
Expand Down
8 changes: 6 additions & 2 deletions app/editor/note-storage-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,16 @@ export const NoteStorageLoader = ({ children }: { children: ReactNode }) => {
getNotes()
.then((note) => {
batch(() => {
SystemStore.setState({ error: null, save: "idle", stage: "loaded" });
SystemStore.setState(() => ({
error: null,
save: "idle",
stage: "loaded",
}));
setInitialNoteStore(note);
});
})
.catch((error) => {
SystemStore.setState({ error, save: "idle", stage: "error" });
SystemStore.setState(() => ({ error, save: "idle", stage: "error" }));
});
}, []);

Expand Down
8 changes: 4 additions & 4 deletions app/editor/store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Store, useStore } from "@tanstack/react-store";
import { createStore, useStore } from "@tanstack/react-store";

/**
* Type definition for the `NoteStore` state.
Expand Down Expand Up @@ -34,7 +34,7 @@ type SystemStore = {
*
* @package
*/
export const SystemStore = new Store<SystemStore>({
export const SystemStore = createStore<SystemStore>({
error: null,
save: "idle",
stage: "initializing",
Expand All @@ -57,7 +57,7 @@ export const useSystemStore = <T>(selector: (state: SystemStore) => T): T => {
*
* @package
*/
export const NoteStore = new Store<NoteStore>({
export const NoteStore = createStore<NoteStore>({
content: "",
isFrozen: false,
lastUpdated: Date.now(),
Expand Down Expand Up @@ -111,7 +111,7 @@ export const resetContent = (lastUpdated: number) => {
* @package
*/
export const setInitialNoteStore = (note: NoteStore) => {
NoteStore.setState(note);
NoteStore.setState(() => note);
};

/**
Expand Down
6 changes: 3 additions & 3 deletions app/use-dark-mode.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Store, useStore } from "@tanstack/react-store";
import { createStore, useStore } from "@tanstack/react-store";
import { useEffect } from "react";

/**
* Color theme store. For now, the store is named dark theme store
* since it's the only thing being stored right now. This is not made
* as a state for synchronization if it gets called in other components.
*/
const DarkThemeStore = new Store(
const DarkThemeStore = createStore(
window.matchMedia("(prefers-color-scheme: dark)").matches,
);

Expand All @@ -31,7 +31,7 @@ DarkThemeStore.subscribe(() => {
* themes in the future.
*/
export const useDarkTheme = () => {
const isDark = useStore(DarkThemeStore);
const isDark = useStore(DarkThemeStore, (isDark) => isDark);

// Sync the theme with system preference.
useEffect(() => {
Expand Down
5 changes: 4 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.13/schema.json",
"$schema": "https://biomejs.dev/schemas/2.4.4/schema.json",
"assist": {
"actions": {
"source": {
Expand Down Expand Up @@ -41,6 +41,9 @@
},
"enabled": true,
"rules": {
"correctness": {
"noUnresolvedImports": "off"
},
"nursery": {
"useSortedClasses": {
"fix": "safe",
Expand Down
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,31 @@
"e2e-ci": "pnpm build && PRODUCTION_READY=1 pnpm e2e"
},
"dependencies": {
"@biomejs/biome": "2.3.13",
"@biomejs/biome": "2.4.4",
"@fontsource-variable/inter": "5.2.8",
"@playwright/test": "1.58.1",
"@tailwindcss/vite": "4.1.18",
"@tanstack/react-store": "0.8.0",
"@playwright/test": "1.58.2",
"@tailwindcss/vite": "4.2.1",
"@tanstack/react-store": "0.9.1",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/node": "25.1.0",
"@types/react": "19.2.10",
"@types/node": "25.3.3",
"@types/react": "19.2.14",
"@types/react-dom": "19.2.3",
"@vitejs/plugin-react": "5.1.2",
"@vitejs/plugin-react": "5.1.4",
"@vitest/coverage-v8": "4.0.18",
"clsx": "^2.1.1",
"dexie": "4.3.0",
"fake-indexeddb": "6.2.5",
"jsdom": "27.4.0",
"jsdom": "28.1.0",
"postcss": "^8.5.6",
"react": "19.2.4",
"react-dom": "19.2.4",
"react-textarea-autosize": "^8.5.9",
"sonner": "2.0.7",
"tailwind-merge": "3.4.0",
"tailwindcss": "4.1.18",
"tailwind-merge": "3.5.0",
"tailwindcss": "4.2.1",
"typescript": "5.9.3",
"valibot": "1.2.0",
"vite": "7.3.1",
Expand Down
Loading