refactor: uiStore.ts
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
import type {
|
||||
ScriptItem,
|
||||
ScriptType,
|
||||
StableVersion,
|
||||
Visibility,
|
||||
} from "../../../services/api";
|
||||
|
||||
export type ToastTone = "success" | "error" | "info";
|
||||
export type ToastState = {
|
||||
tone: ToastTone;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type NewScriptForm = {
|
||||
name: string;
|
||||
scriptType: ScriptType;
|
||||
visibility: Visibility;
|
||||
parentPath: string;
|
||||
};
|
||||
|
||||
export type ContextMenuState = {
|
||||
x: number;
|
||||
y: number;
|
||||
kind: "root" | "directory" | "file";
|
||||
path: string;
|
||||
script?: ScriptItem;
|
||||
};
|
||||
|
||||
export type FolderDialogState = {
|
||||
open: boolean;
|
||||
parentPath: string;
|
||||
name: string;
|
||||
busy: boolean;
|
||||
};
|
||||
|
||||
export type PublishDialogState = {
|
||||
target: ScriptItem | null;
|
||||
releaseNote: string;
|
||||
visibility: Visibility;
|
||||
publishing: boolean;
|
||||
publishedVersion: StableVersion | null;
|
||||
};
|
||||
|
||||
export type UploadState = {
|
||||
parentPath: string;
|
||||
uploading: boolean;
|
||||
};
|
||||
|
||||
export const initialCreateForm: NewScriptForm = {
|
||||
name: "",
|
||||
scriptType: "notebook",
|
||||
visibility: "workspace",
|
||||
parentPath: "",
|
||||
};
|
||||
|
||||
type UiState = {
|
||||
toast: ToastState | null;
|
||||
createDialog: {
|
||||
open: boolean;
|
||||
creating: boolean;
|
||||
form: NewScriptForm;
|
||||
};
|
||||
folderDialog: FolderDialogState;
|
||||
contextMenu: ContextMenuState | null;
|
||||
workspaceMenuOpen: boolean;
|
||||
upload: UploadState;
|
||||
publish: PublishDialogState;
|
||||
|
||||
// toast
|
||||
pushToast: (toast: ToastState) => void;
|
||||
dismissToast: () => void;
|
||||
|
||||
// create dialog
|
||||
openCreateDialog: (parentPath?: string, scriptType?: ScriptType) => void;
|
||||
closeCreateDialog: () => void;
|
||||
setCreateForm: (form: NewScriptForm) => void;
|
||||
setCreating: (creating: boolean) => void;
|
||||
|
||||
// folder dialog
|
||||
openFolderDialog: (parentPath?: string) => void;
|
||||
closeFolderDialog: () => void;
|
||||
setFolderName: (name: string) => void;
|
||||
setFolderBusy: (busy: boolean) => void;
|
||||
|
||||
// context menu
|
||||
showContextMenu: (
|
||||
event: { clientX: number; clientY: number; preventDefault: () => void; stopPropagation: () => void },
|
||||
target: Omit<ContextMenuState, "x" | "y">,
|
||||
) => void;
|
||||
closeContextMenu: () => void;
|
||||
|
||||
// workspace menu (topbar)
|
||||
setWorkspaceMenuOpen: (open: boolean) => void;
|
||||
|
||||
// upload
|
||||
chooseUpload: (parentPath?: string) => void;
|
||||
setUploading: (uploading: boolean) => void;
|
||||
setUploadParentPath: (parentPath: string) => void;
|
||||
|
||||
// publish dialog
|
||||
openPublishDialog: (script: ScriptItem) => void;
|
||||
closePublishDialog: () => void;
|
||||
setReleaseNote: (note: string) => void;
|
||||
setPublishVisibility: (visibility: Visibility) => void;
|
||||
setPublishing: (publishing: boolean) => void;
|
||||
setPublishedVersion: (version: StableVersion) => void;
|
||||
clearPublishedVersion: () => void;
|
||||
};
|
||||
|
||||
export const useUiStore = create<UiState>((set) => ({
|
||||
toast: null,
|
||||
createDialog: {
|
||||
open: false,
|
||||
creating: false,
|
||||
form: initialCreateForm,
|
||||
},
|
||||
folderDialog: {
|
||||
open: false,
|
||||
parentPath: "",
|
||||
name: "",
|
||||
busy: false,
|
||||
},
|
||||
contextMenu: null,
|
||||
workspaceMenuOpen: false,
|
||||
upload: {
|
||||
parentPath: "",
|
||||
uploading: false,
|
||||
},
|
||||
publish: {
|
||||
target: null,
|
||||
releaseNote: "",
|
||||
visibility: "workspace",
|
||||
publishing: false,
|
||||
publishedVersion: null,
|
||||
},
|
||||
|
||||
pushToast: (toast) => set({ toast }),
|
||||
dismissToast: () => set({ toast: null }),
|
||||
|
||||
openCreateDialog: (parentPath = "", scriptType = "notebook") =>
|
||||
set((state) => ({
|
||||
contextMenu: null,
|
||||
createDialog: {
|
||||
open: true,
|
||||
creating: false,
|
||||
form: { ...initialCreateForm, parentPath, scriptType },
|
||||
},
|
||||
})),
|
||||
closeCreateDialog: () =>
|
||||
set((state) => ({
|
||||
createDialog: { ...state.createDialog, open: false },
|
||||
})),
|
||||
setCreateForm: (form) =>
|
||||
set((state) => ({ createDialog: { ...state.createDialog, form } })),
|
||||
setCreating: (creating) =>
|
||||
set((state) => ({ createDialog: { ...state.createDialog, creating } })),
|
||||
|
||||
openFolderDialog: (parentPath = "") =>
|
||||
set((state) => ({
|
||||
contextMenu: null,
|
||||
folderDialog: {
|
||||
open: true,
|
||||
parentPath,
|
||||
name: "",
|
||||
busy: false,
|
||||
},
|
||||
})),
|
||||
closeFolderDialog: () =>
|
||||
set((state) => ({
|
||||
folderDialog: { ...state.folderDialog, open: false },
|
||||
})),
|
||||
setFolderName: (name) =>
|
||||
set((state) => ({ folderDialog: { ...state.folderDialog, name } })),
|
||||
setFolderBusy: (busy) =>
|
||||
set((state) => ({ folderDialog: { ...state.folderDialog, busy } })),
|
||||
|
||||
showContextMenu: (event, target) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const width = 188;
|
||||
const height = target.kind === "file" ? 92 : 190;
|
||||
set({
|
||||
contextMenu: {
|
||||
...target,
|
||||
x: Math.min(event.clientX, window.innerWidth - width - 8),
|
||||
y: Math.min(event.clientY, window.innerHeight - height - 8),
|
||||
},
|
||||
});
|
||||
},
|
||||
closeContextMenu: () => set({ contextMenu: null }),
|
||||
|
||||
setWorkspaceMenuOpen: (open) => set({ workspaceMenuOpen: open }),
|
||||
|
||||
chooseUpload: (parentPath = "") =>
|
||||
set((state) => ({
|
||||
contextMenu: null,
|
||||
upload: { ...state.upload, parentPath },
|
||||
})),
|
||||
setUploading: (uploading) =>
|
||||
set((state) => ({ upload: { ...state.upload, uploading } })),
|
||||
setUploadParentPath: (parentPath) =>
|
||||
set((state) => ({ upload: { ...state.upload, parentPath } })),
|
||||
|
||||
openPublishDialog: (script) =>
|
||||
set((state) => ({
|
||||
publish: {
|
||||
...state.publish,
|
||||
target: script,
|
||||
releaseNote: "",
|
||||
visibility: script.visibility === "private" ? "private" : "workspace",
|
||||
},
|
||||
})),
|
||||
closePublishDialog: () =>
|
||||
set((state) => ({ publish: { ...state.publish, target: null } })),
|
||||
setReleaseNote: (note) =>
|
||||
set((state) => ({ publish: { ...state.publish, releaseNote: note } })),
|
||||
setPublishVisibility: (visibility) =>
|
||||
set((state) => ({ publish: { ...state.publish, visibility } })),
|
||||
setPublishing: (publishing) =>
|
||||
set((state) => ({ publish: { ...state.publish, publishing } })),
|
||||
setPublishedVersion: (version) =>
|
||||
set((state) => ({
|
||||
publish: {
|
||||
...state.publish,
|
||||
target: null,
|
||||
publishedVersion: version,
|
||||
},
|
||||
})),
|
||||
clearPublishedVersion: () =>
|
||||
set((state) => ({ publish: { ...state.publish, publishedVersion: null } })),
|
||||
}));
|
||||
Reference in New Issue
Block a user