Add zustand dev tools
This commit is contained in:
@@ -50,6 +50,7 @@
|
|||||||
"@mui/system": "7.3.1",
|
"@mui/system": "7.3.1",
|
||||||
"@mui/utils": "7.3.1",
|
"@mui/utils": "7.3.1",
|
||||||
"@mui/x-date-pickers": "8.10.0",
|
"@mui/x-date-pickers": "8.10.0",
|
||||||
|
"@redux-devtools/extension": "3.3.0",
|
||||||
"@vibrant/color": "4.0.0",
|
"@vibrant/color": "4.0.0",
|
||||||
"apollo-upload-client": "18.0.1",
|
"apollo-upload-client": "18.0.1",
|
||||||
"csstype": "3.1.3",
|
"csstype": "3.1.3",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { createRef, MutableRefObject } from 'react';
|
import { createRef, MutableRefObject } from 'react';
|
||||||
import { ImmerStateCreator } from '@/lib/zustand/Zustand.types.ts';
|
import { SliceCreator } from '@/lib/zustand/Zustand.types.ts';
|
||||||
import { ScrollOffset } from '@/base/Base.types.ts';
|
import { ScrollOffset } from '@/base/Base.types.ts';
|
||||||
import { useAutomaticScrolling } from '@/base/hooks/useAutomaticScrolling.ts';
|
import { useAutomaticScrolling } from '@/base/hooks/useAutomaticScrolling.ts';
|
||||||
import { noOp } from '@/lib/HelperFunctions.ts';
|
import { noOp } from '@/lib/HelperFunctions.ts';
|
||||||
@@ -58,50 +58,86 @@ const DEFAULT_STATE = {
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export const createReaderAutoScrollStoreSlice = <T extends ReaderAutoScrollStoreSlice>(
|
export const createReaderAutoScrollStoreSlice = <T extends ReaderAutoScrollStoreSlice>(
|
||||||
...[set, get]: Parameters<ImmerStateCreator<T>>
|
...[createActionName, set, get]: Parameters<SliceCreator<T>>
|
||||||
): ReaderAutoScrollStoreSlice =>
|
): ReaderAutoScrollStoreSlice => ({
|
||||||
({
|
|
||||||
autoScroll: {
|
autoScroll: {
|
||||||
...DEFAULT_STATE,
|
...DEFAULT_STATE,
|
||||||
reset: () => ({ autoScroll: { ...get().autoScroll, ...DEFAULT_STATE } }),
|
reset: () => ({ autoScroll: { ...get().autoScroll, ...DEFAULT_STATE } }),
|
||||||
setIsActive: (active) =>
|
setIsActive: (active) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.isActive = active;
|
draft.autoScroll.isActive = active;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setIsActive'),
|
||||||
|
),
|
||||||
setIsPaused: (paused) =>
|
setIsPaused: (paused) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.isPaused = paused;
|
draft.autoScroll.isPaused = paused;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setIsPaused'),
|
||||||
|
),
|
||||||
setStart: (start) =>
|
setStart: (start) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.start = start;
|
draft.autoScroll.start = start;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setStart'),
|
||||||
|
),
|
||||||
setCancel: (cancel) =>
|
setCancel: (cancel) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.cancel = cancel;
|
draft.autoScroll.cancel = cancel;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setCancel'),
|
||||||
|
),
|
||||||
setToggleActive: (toggleActive) =>
|
setToggleActive: (toggleActive) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.toggleActive = toggleActive;
|
draft.autoScroll.toggleActive = toggleActive;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setToggleActive'),
|
||||||
|
),
|
||||||
setPause: (pause) =>
|
setPause: (pause) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.pause = pause;
|
draft.autoScroll.pause = pause;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setPause'),
|
||||||
|
),
|
||||||
setResume: (resume) =>
|
setResume: (resume) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.resume = resume;
|
draft.autoScroll.resume = resume;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setResume'),
|
||||||
|
),
|
||||||
setInvert: (invert) =>
|
setInvert: (invert) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.invert = invert;
|
draft.autoScroll.invert = invert;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setInvert'),
|
||||||
|
),
|
||||||
setDirection: (direction) =>
|
setDirection: (direction) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.autoScroll.direction = direction;
|
draft.autoScroll.direction = direction;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setDirection'),
|
||||||
|
),
|
||||||
setScrollRef: (scrollElement) =>
|
setScrollRef: (scrollElement) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
if (!scrollElement) {
|
if (!scrollElement) {
|
||||||
draft.autoScroll.scrollRef = undefined;
|
draft.autoScroll.scrollRef = undefined;
|
||||||
return;
|
return;
|
||||||
@@ -111,6 +147,9 @@ export const createReaderAutoScrollStoreSlice = <T extends ReaderAutoScrollStore
|
|||||||
ref.current = scrollElement;
|
ref.current = scrollElement;
|
||||||
// @ts-expect-error - TS2322: Type MutableRefObject<HTMLElement | null> is not assignable to type WritableDraft<MutableRefObject<HTMLElement | null>>
|
// @ts-expect-error - TS2322: Type MutableRefObject<HTMLElement | null> is not assignable to type WritableDraft<MutableRefObject<HTMLElement | null>>
|
||||||
draft.autoScroll.scrollRef = ref;
|
draft.autoScroll.scrollRef = ref;
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
}) satisfies ReaderAutoScrollStoreSlice;
|
undefined,
|
||||||
|
createActionName('setScrollRef'),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ImmerStateCreator } from '@/lib/zustand/Zustand.types.ts';
|
import { SliceCreator } from '@/lib/zustand/Zustand.types.ts';
|
||||||
|
|
||||||
export interface ReaderOverlayStoreSlice {
|
export interface ReaderOverlayStoreSlice {
|
||||||
overlay: {
|
overlay: {
|
||||||
@@ -21,14 +21,18 @@ const DEFAULT_STATE = {
|
|||||||
} satisfies Pick<ReaderOverlayStoreSlice['overlay'], 'isVisible'>;
|
} satisfies Pick<ReaderOverlayStoreSlice['overlay'], 'isVisible'>;
|
||||||
|
|
||||||
export const createReaderOverlayStoreSlice = <T extends ReaderOverlayStoreSlice>(
|
export const createReaderOverlayStoreSlice = <T extends ReaderOverlayStoreSlice>(
|
||||||
...[set, get]: Parameters<ImmerStateCreator<T>>
|
...[createActionName, set, get]: Parameters<SliceCreator<T>>
|
||||||
): ReaderOverlayStoreSlice => ({
|
): ReaderOverlayStoreSlice => ({
|
||||||
overlay: {
|
overlay: {
|
||||||
isVisible: DEFAULT_STATE.isVisible,
|
isVisible: DEFAULT_STATE.isVisible,
|
||||||
setIsVisible: (visible) =>
|
setIsVisible: (visible) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.overlay.isVisible = visible;
|
draft.overlay.isVisible = visible;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setIsVisible'),
|
||||||
|
),
|
||||||
reset: () => ({ overlay: { ...get().overlay, ...DEFAULT_STATE } }),
|
reset: () => ({ overlay: { ...get().overlay, ...DEFAULT_STATE } }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ImmerStateCreator } from '@/lib/zustand/Zustand.types.ts';
|
import { SliceCreator } from '@/lib/zustand/Zustand.types.ts';
|
||||||
import { TReaderProgressBarContext } from '@/features/reader/overlay/progress-bar/ReaderProgressBar.types.ts';
|
import { TReaderProgressBarContext } from '@/features/reader/overlay/progress-bar/ReaderProgressBar.types.ts';
|
||||||
|
|
||||||
export interface ReaderProgressBarStoreSlice {
|
export interface ReaderProgressBarStoreSlice {
|
||||||
@@ -21,18 +21,26 @@ const DEFAULT_STATE = {
|
|||||||
} satisfies Pick<ReaderProgressBarStoreSlice['progressBar'], 'isDragging' | 'isMaximized'>;
|
} satisfies Pick<ReaderProgressBarStoreSlice['progressBar'], 'isDragging' | 'isMaximized'>;
|
||||||
|
|
||||||
export const createReaderProgressBarStoreSlice = <T extends ReaderProgressBarStoreSlice>(
|
export const createReaderProgressBarStoreSlice = <T extends ReaderProgressBarStoreSlice>(
|
||||||
...[set, get]: Parameters<ImmerStateCreator<T>>
|
...[createActionName, set, get]: Parameters<SliceCreator<T>>
|
||||||
): ReaderProgressBarStoreSlice => ({
|
): ReaderProgressBarStoreSlice => ({
|
||||||
progressBar: {
|
progressBar: {
|
||||||
...DEFAULT_STATE,
|
...DEFAULT_STATE,
|
||||||
setIsMaximized: (maximized) =>
|
setIsMaximized: (maximized) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.progressBar.isMaximized = maximized;
|
draft.progressBar.isMaximized = maximized;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setIsMaximized'),
|
||||||
|
),
|
||||||
setIsDragging: (dragging) =>
|
setIsDragging: (dragging) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.progressBar.isDragging = dragging;
|
draft.progressBar.isDragging = dragging;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setIsDragging'),
|
||||||
|
),
|
||||||
reset: () => ({ progressBar: { ...get().progressBar, ...DEFAULT_STATE } }),
|
reset: () => ({ progressBar: { ...get().progressBar, ...DEFAULT_STATE } }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ImmerStateCreator } from '@/lib/zustand/Zustand.types.ts';
|
import { SliceCreator } from '@/lib/zustand/Zustand.types.ts';
|
||||||
import { ReaderStateChapters } from '@/features/reader/Reader.types.ts';
|
import { ReaderStateChapters } from '@/features/reader/Reader.types.ts';
|
||||||
|
|
||||||
export interface ReaderChaptersStoreSlice {
|
export interface ReaderChaptersStoreSlice {
|
||||||
@@ -44,13 +44,14 @@ export const READER_DEFAULT_CHAPTERS_STATE = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const createReaderChaptersStoreSlice = <T extends ReaderChaptersStoreSlice>(
|
export const createReaderChaptersStoreSlice = <T extends ReaderChaptersStoreSlice>(
|
||||||
...[set, get]: Parameters<ImmerStateCreator<T>>
|
...[createActionName, set, get]: Parameters<SliceCreator<T>>
|
||||||
): ReaderChaptersStoreSlice => ({
|
): ReaderChaptersStoreSlice => ({
|
||||||
chapters: {
|
chapters: {
|
||||||
...READER_DEFAULT_CHAPTERS_STATE.chapters,
|
...READER_DEFAULT_CHAPTERS_STATE.chapters,
|
||||||
reset: () => ({ chapters: { ...get().chapters, ...READER_DEFAULT_CHAPTERS_STATE.chapters } }),
|
reset: () => ({ chapters: { ...get().chapters, ...READER_DEFAULT_CHAPTERS_STATE.chapters } }),
|
||||||
setReaderStateChapters: (state) =>
|
setReaderStateChapters: (state) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
if (typeof state === 'function') {
|
if (typeof state === 'function') {
|
||||||
draft.chapters = {
|
draft.chapters = {
|
||||||
...get().chapters,
|
...get().chapters,
|
||||||
@@ -63,6 +64,9 @@ export const createReaderChaptersStoreSlice = <T extends ReaderChaptersStoreSlic
|
|||||||
...get().chapters,
|
...get().chapters,
|
||||||
...state,
|
...state,
|
||||||
};
|
};
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setReaderStateChapters'),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ReaderStatePages, ReaderTransitionPageMode } from '@/features/reader/Reader.types.ts';
|
import { ReaderStatePages, ReaderTransitionPageMode } from '@/features/reader/Reader.types.ts';
|
||||||
import { ImmerStateCreator } from '@/lib/zustand/Zustand.types.ts';
|
import { SliceCreator } from '@/lib/zustand/Zustand.types.ts';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
|
|
||||||
export interface ReaderPagesStoreSlice {
|
export interface ReaderPagesStoreSlice {
|
||||||
@@ -48,47 +48,79 @@ export const READER_DEFAULT_PAGES_STATE: Omit<
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const createReaderPagesStoreSlice = <T extends ReaderPagesStoreSlice>(
|
export const createReaderPagesStoreSlice = <T extends ReaderPagesStoreSlice>(
|
||||||
...[set, get]: Parameters<ImmerStateCreator<T>>
|
...[createActionName, set, get]: Parameters<SliceCreator<T>>
|
||||||
): ReaderPagesStoreSlice => ({
|
): ReaderPagesStoreSlice => ({
|
||||||
pages: {
|
pages: {
|
||||||
...READER_DEFAULT_PAGES_STATE,
|
...READER_DEFAULT_PAGES_STATE,
|
||||||
reset: () => ({ pages: { ...get().pages, ...READER_DEFAULT_PAGES_STATE } }),
|
reset: () => ({ pages: { ...get().pages, ...READER_DEFAULT_PAGES_STATE } }),
|
||||||
setCurrentPageIndex: (index) =>
|
setCurrentPageIndex: (index) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.pages.currentPageIndex = index;
|
draft.pages.currentPageIndex = index;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setCurrentPageIndex'),
|
||||||
|
),
|
||||||
setPageToScrollToIndex: (index) =>
|
setPageToScrollToIndex: (index) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.pages.pageToScrollToIndex = index;
|
draft.pages.pageToScrollToIndex = index;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setPageToScrollToIndex'),
|
||||||
|
),
|
||||||
setTotalPages: (total) =>
|
setTotalPages: (total) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.pages.totalPages = total;
|
draft.pages.totalPages = total;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setTotalPages'),
|
||||||
|
),
|
||||||
setPageUrls: (urls) =>
|
setPageUrls: (urls) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.pages.pageUrls = urls;
|
draft.pages.pageUrls = urls;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setPageUrls'),
|
||||||
|
),
|
||||||
setPageLoadStates: (loadStates) =>
|
setPageLoadStates: (loadStates) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
if (typeof loadStates === 'function') {
|
if (typeof loadStates === 'function') {
|
||||||
draft.pages.pageLoadStates = loadStates(get().pages.pageLoadStates);
|
draft.pages.pageLoadStates = loadStates(get().pages.pageLoadStates);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
draft.pages.pageLoadStates = loadStates;
|
draft.pages.pageLoadStates = loadStates;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setPageLoadStates'),
|
||||||
|
),
|
||||||
setPages: (pages) =>
|
setPages: (pages) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.pages.pages = pages;
|
draft.pages.pages = pages;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setPages'),
|
||||||
|
),
|
||||||
setTransitionPageMode: (mode) =>
|
setTransitionPageMode: (mode) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.pages.transitionPageMode = mode;
|
draft.pages.transitionPageMode = mode;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setTransitionPageMode'),
|
||||||
|
),
|
||||||
setRetryFailedPagesKeyPrefix: (prefix) =>
|
setRetryFailedPagesKeyPrefix: (prefix) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.pages.retryFailedPagesKeyPrefix = prefix;
|
draft.pages.retryFailedPagesKeyPrefix = prefix;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setRetryFailedPagesKeyPrefix'),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
import { devtools } from 'zustand/middleware';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
import { useShallow } from 'zustand/react/shallow';
|
import { useShallow } from 'zustand/react/shallow';
|
||||||
import { TMangaReader } from '@/features/manga/Manga.types.ts';
|
import { TMangaReader } from '@/features/manga/Manga.types.ts';
|
||||||
@@ -33,6 +34,9 @@ import {
|
|||||||
createReaderChaptersStoreSlice,
|
createReaderChaptersStoreSlice,
|
||||||
ReaderChaptersStoreSlice,
|
ReaderChaptersStoreSlice,
|
||||||
} from '@/features/reader/stores/ReaderChaptersStore.ts';
|
} from '@/features/reader/stores/ReaderChaptersStore.ts';
|
||||||
|
import { ZustandUtil } from '@/lib/zustand/ZustandUtil.ts';
|
||||||
|
|
||||||
|
const UNSERIALIZABLE_KEYS = ['scrollRef'];
|
||||||
|
|
||||||
interface ReaderStore
|
interface ReaderStore
|
||||||
extends ReaderOverlayStoreSlice,
|
extends ReaderOverlayStoreSlice,
|
||||||
@@ -64,10 +68,17 @@ const DEFAULT_STATE = {
|
|||||||
} satisfies Pick<ReaderStore, 'manga'> & { scrollbar: Pick<ReaderStore['scrollbar'], 'xSize' | 'ySize'> };
|
} satisfies Pick<ReaderStore, 'manga'> & { scrollbar: Pick<ReaderStore['scrollbar'], 'xSize' | 'ySize'> };
|
||||||
|
|
||||||
const readerStore = create<ReaderStore>()(
|
const readerStore = create<ReaderStore>()(
|
||||||
immer((set, get, store) => ({
|
devtools(
|
||||||
|
immer((set, get, store) => {
|
||||||
|
const createActionName = ZustandUtil.createActionNameCreator('reader');
|
||||||
|
const createActionNameCreator = (name: string) =>
|
||||||
|
ZustandUtil.createActionNameCreator(name, createActionName);
|
||||||
|
|
||||||
|
return {
|
||||||
...DEFAULT_STATE,
|
...DEFAULT_STATE,
|
||||||
reset: () =>
|
reset: () =>
|
||||||
set(() => ({
|
set(
|
||||||
|
() => ({
|
||||||
...get(),
|
...get(),
|
||||||
...DEFAULT_STATE,
|
...DEFAULT_STATE,
|
||||||
scrollbar: {
|
scrollbar: {
|
||||||
@@ -84,39 +95,73 @@ const readerStore = create<ReaderStore>()(
|
|||||||
...get().chapters.reset(),
|
...get().chapters.reset(),
|
||||||
...get().progressBar.reset(),
|
...get().progressBar.reset(),
|
||||||
...get().tapZone.reset(),
|
...get().tapZone.reset(),
|
||||||
})),
|
|
||||||
setManga: (manga) =>
|
|
||||||
set((draft) => {
|
|
||||||
draft.manga = manga;
|
|
||||||
}),
|
}),
|
||||||
|
undefined,
|
||||||
|
createActionName('reset'),
|
||||||
|
),
|
||||||
|
setManga: (manga) =>
|
||||||
|
set(
|
||||||
|
(draft) => {
|
||||||
|
draft.manga = manga;
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setManga'),
|
||||||
|
),
|
||||||
scrollbar: {
|
scrollbar: {
|
||||||
...DEFAULT_STATE.scrollbar,
|
...DEFAULT_STATE.scrollbar,
|
||||||
setXSize: (size) =>
|
setXSize: (size) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.scrollbar.xSize = size;
|
draft.scrollbar.xSize = size;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('scrollbar', 'setXSize'),
|
||||||
|
),
|
||||||
setYSize: (size) =>
|
setYSize: (size) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.scrollbar.ySize = size;
|
draft.scrollbar.ySize = size;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('scrollbar', 'setYSize'),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
...DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG,
|
...DEFAULT_READER_SETTINGS_WITH_DEFAULT_FLAG,
|
||||||
setSettings: (settings) =>
|
setSettings: (settings) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.settings = {
|
draft.settings = {
|
||||||
...get().settings,
|
...get().settings,
|
||||||
...settings,
|
...settings,
|
||||||
};
|
};
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
...createReaderOverlayStoreSlice(set, get, store),
|
undefined,
|
||||||
...createReaderAutoScrollStoreSlice(set, get, store),
|
createActionName('settings', 'setSettings'),
|
||||||
...createReaderPagesStoreSlice(set, get, store),
|
),
|
||||||
...createReaderChaptersStoreSlice(set, get, store),
|
},
|
||||||
...createReaderProgressBarStoreSlice(set, get, store),
|
...createReaderOverlayStoreSlice(createActionNameCreator('overlay'), set, get, store),
|
||||||
...createReaderTapZoneStoreSlice(set, get, store),
|
...createReaderAutoScrollStoreSlice(createActionNameCreator('autoScroll'), set, get, store),
|
||||||
})),
|
...createReaderPagesStoreSlice(createActionNameCreator('pages'), set, get, store),
|
||||||
|
...createReaderChaptersStoreSlice(createActionNameCreator('chapters'), set, get, store),
|
||||||
|
...createReaderProgressBarStoreSlice(createActionNameCreator('progressBar'), set, get, store),
|
||||||
|
...createReaderTapZoneStoreSlice(createActionNameCreator('tapZone'), set, get, store),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: 'ReaderStore',
|
||||||
|
anonymousActionType: 'reader/action',
|
||||||
|
serialize: {
|
||||||
|
replacer: (key: string, value: any) => {
|
||||||
|
if (UNSERIALIZABLE_KEYS.includes(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
export const useReaderStore = <T>(selector: (state: ReaderStore) => T): T => readerStore(useShallow(selector));
|
export const useReaderStore = <T>(selector: (state: ReaderStore) => T): T => readerStore(useShallow(selector));
|
||||||
export const getReaderStore = () => readerStore.getState();
|
export const getReaderStore = () => readerStore.getState();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ImmerStateCreator } from '@/lib/zustand/Zustand.types.ts';
|
import { SliceCreator } from '@/lib/zustand/Zustand.types.ts';
|
||||||
import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts';
|
import { TReaderTapZoneContext } from '@/features/reader/tap-zones/TapZoneLayout.types.ts';
|
||||||
|
|
||||||
export interface ReaderTapZoneStoreSlice {
|
export interface ReaderTapZoneStoreSlice {
|
||||||
@@ -20,14 +20,18 @@ const DEFAULT_STATE = {
|
|||||||
} satisfies Pick<ReaderTapZoneStoreSlice['tapZone'], 'showPreview'>;
|
} satisfies Pick<ReaderTapZoneStoreSlice['tapZone'], 'showPreview'>;
|
||||||
|
|
||||||
export const createReaderTapZoneStoreSlice = <T extends ReaderTapZoneStoreSlice>(
|
export const createReaderTapZoneStoreSlice = <T extends ReaderTapZoneStoreSlice>(
|
||||||
...[set, get]: Parameters<ImmerStateCreator<T>>
|
...[createActionName, set, get]: Parameters<SliceCreator<T>>
|
||||||
): ReaderTapZoneStoreSlice => ({
|
): ReaderTapZoneStoreSlice => ({
|
||||||
tapZone: {
|
tapZone: {
|
||||||
...DEFAULT_STATE,
|
...DEFAULT_STATE,
|
||||||
setShowPreview: (showPreview) =>
|
setShowPreview: (showPreview) =>
|
||||||
set((draft) => {
|
set(
|
||||||
|
(draft) => {
|
||||||
draft.tapZone.showPreview = showPreview;
|
draft.tapZone.showPreview = showPreview;
|
||||||
}),
|
},
|
||||||
|
undefined,
|
||||||
|
createActionName('setShowPreview'),
|
||||||
|
),
|
||||||
reset: () => ({ tapZone: { ...get().tapZone, ...DEFAULT_STATE } }),
|
reset: () => ({ tapZone: { ...get().tapZone, ...DEFAULT_STATE } }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,11 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { StateCreator } from 'zustand';
|
import { StateCreator as ZustandStateCreator } from 'zustand';
|
||||||
|
|
||||||
export type ImmerStateCreator<T> = StateCreator<T, [['zustand/immer', never], never], [], T>;
|
export type StateCreator<T> = ZustandStateCreator<T, [['zustand/devtools', never], ['zustand/immer', never]], [], T>;
|
||||||
|
|
||||||
|
export type SliceCreator<T> = (
|
||||||
|
actionNameCreator: (...names: string[]) => string,
|
||||||
|
...args: Parameters<StateCreator<T>>
|
||||||
|
) => T;
|
||||||
|
|||||||
23
src/lib/zustand/ZustandUtil.ts
Normal file
23
src/lib/zustand/ZustandUtil.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) Contributors to the Suwayomi project
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ZustandUtil {
|
||||||
|
static createActionName(...names: string[]) {
|
||||||
|
const storeAndSlices = names.slice(0, -1);
|
||||||
|
const action = names.slice(-1)[0];
|
||||||
|
|
||||||
|
return `${storeAndSlices.join(':')}/${action}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createActionNameCreator(
|
||||||
|
name: string,
|
||||||
|
parentCreator: typeof ZustandUtil.createActionName = ZustandUtil.createActionName,
|
||||||
|
): typeof ZustandUtil.createActionName {
|
||||||
|
return (...names: string[]) => parentCreator(name, ...names);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
yarn.lock
13
yarn.lock
@@ -2634,6 +2634,14 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f"
|
||||||
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==
|
||||||
|
|
||||||
|
"@redux-devtools/extension@3.3.0":
|
||||||
|
version "3.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@redux-devtools/extension/-/extension-3.3.0.tgz#bc775d289f15604c472112920beac2cf4dbb7907"
|
||||||
|
integrity sha512-X34S/rC8S/M1BIrkYD1mJ5f8vlH0BDqxXrs96cvxSBo4FhMdbhU+GUGsmNYov1xjSyLMHgo8NYrUG8bNX7525g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.23.2"
|
||||||
|
immutable "^4.3.4"
|
||||||
|
|
||||||
"@remix-run/router@1.19.1":
|
"@remix-run/router@1.19.1":
|
||||||
version "1.19.1"
|
version "1.19.1"
|
||||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.19.1.tgz#984771bfd1de2715f42394c87fb716c1349e014f"
|
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.19.1.tgz#984771bfd1de2715f42394c87fb716c1349e014f"
|
||||||
@@ -5981,6 +5989,11 @@ immer@10.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc"
|
resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc"
|
||||||
integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
|
integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
|
||||||
|
|
||||||
|
immutable@^4.3.4:
|
||||||
|
version "4.3.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381"
|
||||||
|
integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==
|
||||||
|
|
||||||
immutable@~3.7.6:
|
immutable@~3.7.6:
|
||||||
version "3.7.6"
|
version "3.7.6"
|
||||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"
|
resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b"
|
||||||
|
|||||||
Reference in New Issue
Block a user