mirror of
https://github.com/usememos/memos.git
synced 2025-02-21 05:40:57 +01:00
feat: esc
key to exit multiple dialogs (#692)
* fix: `esc` key to exit multiple dialogs * update * update * update * Update web/src/components/Dialog/BaseDialog.tsx Co-authored-by: boojack <stevenlgtm@gmail.com>
This commit is contained in:
parent
e79d67d127
commit
55695f2189
@ -59,6 +59,7 @@ export default function showAboutSiteDialog(): void {
|
||||
generateDialog(
|
||||
{
|
||||
className: "about-site-dialog",
|
||||
dialogName: "about-site-dialog",
|
||||
},
|
||||
AboutSiteDialog
|
||||
);
|
||||
|
@ -69,6 +69,7 @@ export default function showArchivedMemoDialog(): void {
|
||||
generateDialog(
|
||||
{
|
||||
className: "archived-memo-dialog",
|
||||
dialogName: "archived-memo-dialog",
|
||||
},
|
||||
ArchivedMemoDialog,
|
||||
{}
|
||||
|
@ -117,6 +117,7 @@ function showChangeMemberPasswordDialog(user: User) {
|
||||
generateDialog(
|
||||
{
|
||||
className: "change-member-password-dialog",
|
||||
dialogName: "change-member-password-dialog",
|
||||
},
|
||||
ChangeMemberPasswordDialog,
|
||||
{ user }
|
||||
|
@ -97,6 +97,7 @@ function showChangeMemoCreatedTsDialog(memoId: MemoId) {
|
||||
generateDialog(
|
||||
{
|
||||
className: "change-memo-created-ts-dialog",
|
||||
dialogName: "change-memo-created-ts-dialog",
|
||||
},
|
||||
ChangeMemoCreatedTsDialog,
|
||||
{
|
||||
|
@ -115,6 +115,7 @@ function showChangePasswordDialog() {
|
||||
generateDialog(
|
||||
{
|
||||
className: "change-password-dialog",
|
||||
dialogName: "change-password-dialog",
|
||||
},
|
||||
ChangePasswordDialog
|
||||
);
|
||||
|
@ -87,6 +87,7 @@ function showChangeResourceFilenameDialog(resourceId: ResourceId, resourceFilena
|
||||
generateDialog(
|
||||
{
|
||||
className: "change-resource-filename-dialog",
|
||||
dialogName: "change-resource-filename-dialog",
|
||||
},
|
||||
ChangeResourceFilenameDialog,
|
||||
{
|
||||
|
@ -291,6 +291,7 @@ export default function showCreateShortcutDialog(shortcutId?: ShortcutId): void
|
||||
generateDialog(
|
||||
{
|
||||
className: "create-shortcut-dialog",
|
||||
dialogName: "create-shortcut-dialog",
|
||||
},
|
||||
CreateShortcutDialog,
|
||||
{ shortcutId }
|
||||
|
@ -115,6 +115,7 @@ export default function showDailyReviewDialog(datestamp: DateStamp = Date.now())
|
||||
generateDialog(
|
||||
{
|
||||
className: "daily-review-dialog",
|
||||
dialogName: "daily-review-dialog",
|
||||
},
|
||||
DailyReviewDialog,
|
||||
{ currentDateStamp: datestamp }
|
||||
|
@ -3,13 +3,15 @@ import { createRoot } from "react-dom/client";
|
||||
import { Provider } from "react-redux";
|
||||
import { ANIMATION_DURATION } from "../../helpers/consts";
|
||||
import store from "../../store";
|
||||
import "../../less/base-dialog.less";
|
||||
import { useDialogStore } from "../../store/module";
|
||||
import { CssVarsProvider } from "@mui/joy";
|
||||
import theme from "../../theme";
|
||||
import "../../less/base-dialog.less";
|
||||
|
||||
interface DialogConfig {
|
||||
className: string;
|
||||
clickSpaceDestroy?: boolean;
|
||||
dialogName: string;
|
||||
}
|
||||
|
||||
interface Props extends DialogConfig, DialogProps {
|
||||
@ -17,12 +19,17 @@ interface Props extends DialogConfig, DialogProps {
|
||||
}
|
||||
|
||||
const BaseDialog: React.FC<Props> = (props: Props) => {
|
||||
const { children, className, clickSpaceDestroy, destroy } = props;
|
||||
const { children, className, clickSpaceDestroy, dialogName, destroy } = props;
|
||||
const dialogStore = useDialogStore();
|
||||
|
||||
useEffect(() => {
|
||||
dialogStore.pushDialogStack(dialogName);
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.code === "Escape") {
|
||||
destroy();
|
||||
if (dialogName === dialogStore.topDialogStack()) {
|
||||
dialogStore.popDialogStack();
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -72,6 +72,7 @@ interface CommonDialogProps {
|
||||
content: string;
|
||||
className?: string;
|
||||
style?: DialogStyle;
|
||||
dialogName: string;
|
||||
closeBtnText?: string;
|
||||
confirmBtnText?: string;
|
||||
onClose?: () => void;
|
||||
@ -82,6 +83,7 @@ export const showCommonDialog = (props: CommonDialogProps) => {
|
||||
generateDialog(
|
||||
{
|
||||
className: `common-dialog ${props?.className ?? ""}`,
|
||||
dialogName: `common-dialog ${props?.className ?? ""}`,
|
||||
},
|
||||
CommonDialog,
|
||||
props
|
||||
|
@ -124,6 +124,7 @@ export default function showPreviewImageDialog(imgUrls: string[] | string, initi
|
||||
generateDialog(
|
||||
{
|
||||
className: "preview-image-dialog",
|
||||
dialogName: "preview-image-dialog",
|
||||
},
|
||||
PreviewImageDialog,
|
||||
{
|
||||
|
@ -125,6 +125,7 @@ const ResourcesDialog: React.FC<Props> = (props: Props) => {
|
||||
title: t("resources.delete-resource"),
|
||||
content: warningText,
|
||||
style: "warning",
|
||||
dialogName: "delete-unused-resources",
|
||||
onConfirm: async () => {
|
||||
for (const resource of unusedResources) {
|
||||
await resourceStore.deleteResourceById(resource.id);
|
||||
@ -143,6 +144,7 @@ const ResourcesDialog: React.FC<Props> = (props: Props) => {
|
||||
title: t("resources.delete-resource"),
|
||||
content: warningText,
|
||||
style: "warning",
|
||||
dialogName: "delete-resource-dialog",
|
||||
onConfirm: async () => {
|
||||
await resourceStore.deleteResourceById(resource.id);
|
||||
},
|
||||
@ -242,6 +244,7 @@ export default function showResourcesDialog() {
|
||||
generateDialog(
|
||||
{
|
||||
className: "resources-dialog",
|
||||
dialogName: "resources-dialog",
|
||||
},
|
||||
ResourcesDialog,
|
||||
{}
|
||||
|
@ -148,6 +148,7 @@ export default function showResourcesSelectorDialog() {
|
||||
generateDialog(
|
||||
{
|
||||
className: "resources-selector-dialog",
|
||||
dialogName: "resources-selector-dialog",
|
||||
},
|
||||
ResourcesSelectorDialog,
|
||||
{}
|
||||
|
@ -92,6 +92,7 @@ export default function showSettingDialog(): void {
|
||||
generateDialog(
|
||||
{
|
||||
className: "setting-dialog",
|
||||
dialogName: "setting-dialog",
|
||||
},
|
||||
SettingDialog,
|
||||
{}
|
||||
|
@ -79,6 +79,7 @@ const PreferencesSection = () => {
|
||||
title: `Archive Member`,
|
||||
content: `❗️Are you sure to archive ${user.username}?`,
|
||||
style: "warning",
|
||||
dialogName: "archive-user-dialog",
|
||||
onConfirm: async () => {
|
||||
await userStore.patchUser({
|
||||
id: user.id,
|
||||
@ -102,6 +103,7 @@ const PreferencesSection = () => {
|
||||
title: `Delete Member`,
|
||||
content: `Are you sure to delete ${user.username}? THIS ACTION IS IRREVERSIABLE.❗️`,
|
||||
style: "warning",
|
||||
dialogName: "delete-user-dialog",
|
||||
onConfirm: async () => {
|
||||
await userStore.deleteUser({
|
||||
id: user.id,
|
||||
|
@ -16,6 +16,7 @@ const MyAccountSection = () => {
|
||||
title: "Reset Open API",
|
||||
content: "❗️The existing API will be invalidated and a new one will be generated, are you sure you want to reset?",
|
||||
style: "warning",
|
||||
dialogName: "reset-openid-dialog",
|
||||
onConfirm: async () => {
|
||||
await userStore.patchUser({
|
||||
id: user.id,
|
||||
|
@ -190,6 +190,7 @@ export default function showShareMemoDialog(memo: Memo): void {
|
||||
generateDialog(
|
||||
{
|
||||
className: "share-memo-dialog",
|
||||
dialogName: "share-memo-dialog",
|
||||
},
|
||||
ShareMemoDialog,
|
||||
{ memo }
|
||||
|
@ -139,6 +139,7 @@ function showUpdateAccountDialog() {
|
||||
generateDialog(
|
||||
{
|
||||
className: "update-account-dialog",
|
||||
dialogName: "update-account-dialog",
|
||||
},
|
||||
UpdateAccountDialog
|
||||
);
|
||||
|
@ -7,6 +7,7 @@ import editorReducer from "./reducer/editor";
|
||||
import shortcutReducer from "./reducer/shortcut";
|
||||
import locationReducer from "./reducer/location";
|
||||
import resourceReducer from "./reducer/resource";
|
||||
import dialogReducer from "./reducer/dialog";
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
@ -17,6 +18,7 @@ const store = configureStore({
|
||||
shortcut: shortcutReducer,
|
||||
location: locationReducer,
|
||||
resource: resourceReducer,
|
||||
dialog: dialogReducer,
|
||||
},
|
||||
});
|
||||
|
||||
|
23
web/src/store/module/dialog.ts
Normal file
23
web/src/store/module/dialog.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import store, { useAppSelector } from "..";
|
||||
import { pushDialogStack, popDialogStack } from "../reducer/dialog";
|
||||
import { last } from "lodash";
|
||||
|
||||
export const useDialogStore = () => {
|
||||
const state = useAppSelector((state) => state.editor);
|
||||
|
||||
return {
|
||||
state,
|
||||
getState: () => {
|
||||
return store.getState().dialog;
|
||||
},
|
||||
pushDialogStack: (dialogName: string) => {
|
||||
store.dispatch(pushDialogStack(dialogName));
|
||||
},
|
||||
popDialogStack: () => {
|
||||
store.dispatch(popDialogStack());
|
||||
},
|
||||
topDialogStack: () => {
|
||||
return last(store.getState().dialog.dialogStack);
|
||||
},
|
||||
};
|
||||
};
|
@ -5,3 +5,4 @@ export * from "./memo";
|
||||
export * from "./resource";
|
||||
export * from "./shortcut";
|
||||
export * from "./user";
|
||||
export * from "./dialog";
|
||||
|
30
web/src/store/reducer/dialog.ts
Normal file
30
web/src/store/reducer/dialog.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
interface State {
|
||||
dialogStack: string[];
|
||||
}
|
||||
|
||||
const dialogSlice = createSlice({
|
||||
name: "dialog",
|
||||
initialState: {
|
||||
dialogStack: [],
|
||||
} as State,
|
||||
reducers: {
|
||||
pushDialogStack: (state, action: PayloadAction<string>) => {
|
||||
return {
|
||||
...state,
|
||||
dialogStack: [...state.dialogStack, action.payload],
|
||||
};
|
||||
},
|
||||
popDialogStack: (state) => {
|
||||
return {
|
||||
...state,
|
||||
dialogStack: state.dialogStack.slice(0, state.dialogStack.length - 1),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { pushDialogStack, popDialogStack } = dialogSlice.actions;
|
||||
|
||||
export default dialogSlice.reducer;
|
Loading…
x
Reference in New Issue
Block a user