Skip to content

Commit 0c9c956

Browse files
committed
persist local fs to indexdb rather than local storage
1 parent 111bfcd commit 0c9c956

File tree

7 files changed

+117
-74
lines changed

7 files changed

+117
-74
lines changed

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"@types/pako": "^2.0.1",
1616
"@types/uuid": "^9.0.4",
1717
"base64-js": "^1.5.1",
18+
"idb-keyval": "^6.2.2",
1819
"pako": "^2.1.0",
1920
"polished": "^4.3.1",
2021
"react": "^18.2.0",

src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import Desktop from "./components/Desktop";
44
import useSystemSettings from "./stores/systemSettingsStore";
55

66
function App() {
7-
const settings = useSystemSettings();
7+
const fontColor = useSystemSettings((s) => s.fontColor);
88
return (
99
<div className="App">
1010
<Global
1111
styles={css`
1212
body {
13-
color: ${settings.fontColor};
13+
color: ${fontColor};
1414
}
1515
`}
1616
/>

src/components/AppSideBar/AppSideBar.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ function AppSideBar({
2626
s.secondaryColor,
2727
]);
2828
return (
29-
<StyledSideBar>
30-
<StyledItemContainer>
29+
<StyledSideBar className="app-side-bar">
30+
<StyledItemContainer className="app-side-bar__item-container">
3131
{items.map((item) => (
3232
<Button
3333
padding={"6px 10px"}
@@ -42,6 +42,7 @@ function AppSideBar({
4242
key={item.title}
4343
separators={itemSeparators}
4444
separatorColor={itemSeparatorColor}
45+
className="app-side-bar__item"
4546
>
4647
{item.title}
4748
</Button>

src/stores/calendarStore.ts

Lines changed: 79 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
getSpannedDays,
44
toLocalISODateString,
55
} from "../common/utils/dateUtils";
6+
import { persist } from "zustand/middleware";
67

78
interface CalendarEvent {
89
id: string;
@@ -30,79 +31,92 @@ interface CalendarStoreState {
3031
updateEvent(event: CalendarEvent): void;
3132
}
3233

33-
export const useCalendarStore = create<CalendarStoreState>()((set, get) => ({
34-
events: {},
35-
_eventIdsByDay: {},
36-
addEvent(event) {
37-
set((state) => {
38-
const events = { ...state.events };
39-
const eventIdsByDay = { ...state._eventIdsByDay };
40-
events[event.id] = event;
34+
export const useCalendarStore = create<CalendarStoreState>()(
35+
persist(
36+
(set, get) => ({
37+
events: {},
38+
_eventIdsByDay: {},
39+
addEvent(event) {
40+
set((state) => {
41+
const events = { ...state.events };
42+
const eventIdsByDay = { ...state._eventIdsByDay };
43+
events[event.id] = event;
4144

42-
for (const day of getSpannedDays(event.start, event.end)) {
43-
const key = toLocalISODateString(day);
44-
eventIdsByDay[key] = [...(eventIdsByDay[key] ?? []), event.id];
45-
}
45+
for (const day of getSpannedDays(event.start, event.end)) {
46+
const key = toLocalISODateString(day);
47+
eventIdsByDay[key] = [...(eventIdsByDay[key] ?? []), event.id];
48+
}
4649

47-
return { events, _eventIdsByDay: eventIdsByDay };
48-
});
49-
},
50-
removeEvent(id) {
51-
set((state) => {
52-
if (!state.events[id]) return {};
53-
const events = { ...state.events };
54-
const event = state.events[id];
55-
delete events[id];
50+
return { events, _eventIdsByDay: eventIdsByDay };
51+
});
52+
},
53+
removeEvent(id) {
54+
set((state) => {
55+
if (!state.events[id]) return {};
56+
const events = { ...state.events };
57+
const event = state.events[id];
58+
delete events[id];
5659

57-
const eventIdsByDay = { ...state._eventIdsByDay };
60+
const eventIdsByDay = { ...state._eventIdsByDay };
5861

59-
for (const day of getSpannedDays(event.start, event.end)) {
60-
const key = toLocalISODateString(day);
61-
if (!eventIdsByDay[key] || !eventIdsByDay[key].includes(id)) continue;
62-
const eventIds = eventIdsByDay[key].filter((eventId) => eventId !== id);
63-
eventIdsByDay[key] = eventIds;
62+
for (const day of getSpannedDays(event.start, event.end)) {
63+
const key = toLocalISODateString(day);
64+
if (!eventIdsByDay[key] || !eventIdsByDay[key].includes(id))
65+
continue;
66+
const eventIds = eventIdsByDay[key].filter(
67+
(eventId) => eventId !== id,
68+
);
69+
eventIdsByDay[key] = eventIds;
6470

65-
if (!eventIdsByDay[key].length) {
66-
delete eventIdsByDay[key];
67-
}
68-
}
71+
if (!eventIdsByDay[key].length) {
72+
delete eventIdsByDay[key];
73+
}
74+
}
6975

70-
return { events, _eventIdsByDay: eventIdsByDay };
71-
});
72-
},
73-
updateEvent(event) {
74-
if (!get().events[event.id]) {
75-
get().addEvent(event);
76-
return;
77-
}
78-
set((state) => {
79-
// the updated event may span different days.
80-
// we could be smarter/more performant about this, but
81-
// lets just be lazy and clear the _eventIdsByDay for
82-
// the current range and add them for the new range.
76+
return { events, _eventIdsByDay: eventIdsByDay };
77+
});
78+
},
79+
updateEvent(event) {
80+
if (!get().events[event.id]) {
81+
get().addEvent(event);
82+
return;
83+
}
84+
set((state) => {
85+
// the updated event may span different days.
86+
// we could be smarter/more performant about this, but
87+
// lets just be lazy and clear the _eventIdsByDay for
88+
// the current range and add them for the new range.
8389

84-
const id = event.id;
85-
const events = { ...state.events };
86-
const eventIdsByDay = { ...state._eventIdsByDay };
87-
events[id] = event;
90+
const id = event.id;
91+
const events = { ...state.events };
92+
const eventIdsByDay = { ...state._eventIdsByDay };
93+
events[id] = event;
8894

89-
for (const day of getSpannedDays(event.start, event.end)) {
90-
const key = toLocalISODateString(day);
91-
if (!eventIdsByDay[key] || !eventIdsByDay[key].includes(id)) continue;
92-
const eventIds = eventIdsByDay[key].filter((eventId) => eventId !== id);
93-
eventIdsByDay[key] = eventIds;
95+
for (const day of getSpannedDays(event.start, event.end)) {
96+
const key = toLocalISODateString(day);
97+
if (!eventIdsByDay[key] || !eventIdsByDay[key].includes(id))
98+
continue;
99+
const eventIds = eventIdsByDay[key].filter(
100+
(eventId) => eventId !== id,
101+
);
102+
eventIdsByDay[key] = eventIds;
94103

95-
if (!eventIdsByDay[key].length) {
96-
delete eventIdsByDay[key];
97-
}
98-
}
104+
if (!eventIdsByDay[key].length) {
105+
delete eventIdsByDay[key];
106+
}
107+
}
99108

100-
for (const day of getSpannedDays(event.start, event.end)) {
101-
const key = toLocalISODateString(day);
102-
eventIdsByDay[key] = [...(eventIdsByDay[key] ?? []), event.id];
103-
}
109+
for (const day of getSpannedDays(event.start, event.end)) {
110+
const key = toLocalISODateString(day);
111+
eventIdsByDay[key] = [...(eventIdsByDay[key] ?? []), event.id];
112+
}
104113

105-
return { _eventIdsByDay: eventIdsByDay, events };
106-
});
107-
},
108-
}));
114+
return { _eventIdsByDay: eventIdsByDay, events };
115+
});
116+
},
117+
}),
118+
{
119+
name: "calendar",
120+
},
121+
),
122+
);

src/stores/idbStorageAdaptor.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { del, get, set } from "idb-keyval";
2+
import { StateStorage } from "zustand/middleware";
3+
4+
export const idbStorageAdaptor: StateStorage = {
5+
getItem: async (name) => {
6+
return (await get<string>(name)) ?? null;
7+
},
8+
setItem: async (name, value) => {
9+
await set(name, value);
10+
},
11+
removeItem: async (name) => {
12+
await del(name);
13+
},
14+
};
15+
16+
export default idbStorageAdaptor;

src/stores/localFS.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { create } from "zustand";
2-
import { persist } from "zustand/middleware";
2+
import { createJSONStorage, persist } from "zustand/middleware";
3+
import { idbStorageAdaptor } from "./idbStorageAdaptor";
34

45
export type FSDirectory = {
56
name: string;
@@ -128,6 +129,8 @@ export interface LocalFSState {
128129
removeFromFavorites: (path: string) => void;
129130
}
130131

132+
type PersistedLocalFSState = Omit<LocalFSState, "separator">;
133+
131134
export const useLocalFS = create<LocalFSState>()(
132135
persist(
133136
(set, get) => {
@@ -364,10 +367,11 @@ export const useLocalFS = create<LocalFSState>()(
364367
},
365368
{
366369
name: "local-fs",
367-
partialize: (state) => {
368-
const updated = { ...state } as Partial<LocalFSState>;
369-
delete updated.separator;
370-
return updated;
370+
storage: createJSONStorage(() => idbStorageAdaptor),
371+
partialize: (state): PersistedLocalFSState => {
372+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
373+
const { separator: _sep, ...rest } = state;
374+
return rest;
371375
},
372376
},
373377
),

0 commit comments

Comments
 (0)