mirror of
https://github.com/usememos/memos.git
synced 2025-02-22 06:07:51 +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(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "about-site-dialog",
|
className: "about-site-dialog",
|
||||||
|
dialogName: "about-site-dialog",
|
||||||
},
|
},
|
||||||
AboutSiteDialog
|
AboutSiteDialog
|
||||||
);
|
);
|
||||||
|
@ -69,6 +69,7 @@ export default function showArchivedMemoDialog(): void {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "archived-memo-dialog",
|
className: "archived-memo-dialog",
|
||||||
|
dialogName: "archived-memo-dialog",
|
||||||
},
|
},
|
||||||
ArchivedMemoDialog,
|
ArchivedMemoDialog,
|
||||||
{}
|
{}
|
||||||
|
@ -117,6 +117,7 @@ function showChangeMemberPasswordDialog(user: User) {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "change-member-password-dialog",
|
className: "change-member-password-dialog",
|
||||||
|
dialogName: "change-member-password-dialog",
|
||||||
},
|
},
|
||||||
ChangeMemberPasswordDialog,
|
ChangeMemberPasswordDialog,
|
||||||
{ user }
|
{ user }
|
||||||
|
@ -97,6 +97,7 @@ function showChangeMemoCreatedTsDialog(memoId: MemoId) {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "change-memo-created-ts-dialog",
|
className: "change-memo-created-ts-dialog",
|
||||||
|
dialogName: "change-memo-created-ts-dialog",
|
||||||
},
|
},
|
||||||
ChangeMemoCreatedTsDialog,
|
ChangeMemoCreatedTsDialog,
|
||||||
{
|
{
|
||||||
|
@ -115,6 +115,7 @@ function showChangePasswordDialog() {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "change-password-dialog",
|
className: "change-password-dialog",
|
||||||
|
dialogName: "change-password-dialog",
|
||||||
},
|
},
|
||||||
ChangePasswordDialog
|
ChangePasswordDialog
|
||||||
);
|
);
|
||||||
|
@ -87,6 +87,7 @@ function showChangeResourceFilenameDialog(resourceId: ResourceId, resourceFilena
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "change-resource-filename-dialog",
|
className: "change-resource-filename-dialog",
|
||||||
|
dialogName: "change-resource-filename-dialog",
|
||||||
},
|
},
|
||||||
ChangeResourceFilenameDialog,
|
ChangeResourceFilenameDialog,
|
||||||
{
|
{
|
||||||
|
@ -291,6 +291,7 @@ export default function showCreateShortcutDialog(shortcutId?: ShortcutId): void
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "create-shortcut-dialog",
|
className: "create-shortcut-dialog",
|
||||||
|
dialogName: "create-shortcut-dialog",
|
||||||
},
|
},
|
||||||
CreateShortcutDialog,
|
CreateShortcutDialog,
|
||||||
{ shortcutId }
|
{ shortcutId }
|
||||||
|
@ -115,6 +115,7 @@ export default function showDailyReviewDialog(datestamp: DateStamp = Date.now())
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "daily-review-dialog",
|
className: "daily-review-dialog",
|
||||||
|
dialogName: "daily-review-dialog",
|
||||||
},
|
},
|
||||||
DailyReviewDialog,
|
DailyReviewDialog,
|
||||||
{ currentDateStamp: datestamp }
|
{ currentDateStamp: datestamp }
|
||||||
|
@ -3,13 +3,15 @@ import { createRoot } from "react-dom/client";
|
|||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { ANIMATION_DURATION } from "../../helpers/consts";
|
import { ANIMATION_DURATION } from "../../helpers/consts";
|
||||||
import store from "../../store";
|
import store from "../../store";
|
||||||
import "../../less/base-dialog.less";
|
import { useDialogStore } from "../../store/module";
|
||||||
import { CssVarsProvider } from "@mui/joy";
|
import { CssVarsProvider } from "@mui/joy";
|
||||||
import theme from "../../theme";
|
import theme from "../../theme";
|
||||||
|
import "../../less/base-dialog.less";
|
||||||
|
|
||||||
interface DialogConfig {
|
interface DialogConfig {
|
||||||
className: string;
|
className: string;
|
||||||
clickSpaceDestroy?: boolean;
|
clickSpaceDestroy?: boolean;
|
||||||
|
dialogName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends DialogConfig, DialogProps {
|
interface Props extends DialogConfig, DialogProps {
|
||||||
@ -17,12 +19,17 @@ interface Props extends DialogConfig, DialogProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const BaseDialog: React.FC<Props> = (props: Props) => {
|
const BaseDialog: React.FC<Props> = (props: Props) => {
|
||||||
const { children, className, clickSpaceDestroy, destroy } = props;
|
const { children, className, clickSpaceDestroy, dialogName, destroy } = props;
|
||||||
|
const dialogStore = useDialogStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
dialogStore.pushDialogStack(dialogName);
|
||||||
const handleKeyDown = (event: KeyboardEvent) => {
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
if (event.code === "Escape") {
|
if (event.code === "Escape") {
|
||||||
destroy();
|
if (dialogName === dialogStore.topDialogStack()) {
|
||||||
|
dialogStore.popDialogStack();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ interface CommonDialogProps {
|
|||||||
content: string;
|
content: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: DialogStyle;
|
style?: DialogStyle;
|
||||||
|
dialogName: string;
|
||||||
closeBtnText?: string;
|
closeBtnText?: string;
|
||||||
confirmBtnText?: string;
|
confirmBtnText?: string;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
@ -82,6 +83,7 @@ export const showCommonDialog = (props: CommonDialogProps) => {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: `common-dialog ${props?.className ?? ""}`,
|
className: `common-dialog ${props?.className ?? ""}`,
|
||||||
|
dialogName: `common-dialog ${props?.className ?? ""}`,
|
||||||
},
|
},
|
||||||
CommonDialog,
|
CommonDialog,
|
||||||
props
|
props
|
||||||
|
@ -124,6 +124,7 @@ export default function showPreviewImageDialog(imgUrls: string[] | string, initi
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "preview-image-dialog",
|
className: "preview-image-dialog",
|
||||||
|
dialogName: "preview-image-dialog",
|
||||||
},
|
},
|
||||||
PreviewImageDialog,
|
PreviewImageDialog,
|
||||||
{
|
{
|
||||||
|
@ -125,6 +125,7 @@ const ResourcesDialog: React.FC<Props> = (props: Props) => {
|
|||||||
title: t("resources.delete-resource"),
|
title: t("resources.delete-resource"),
|
||||||
content: warningText,
|
content: warningText,
|
||||||
style: "warning",
|
style: "warning",
|
||||||
|
dialogName: "delete-unused-resources",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
for (const resource of unusedResources) {
|
for (const resource of unusedResources) {
|
||||||
await resourceStore.deleteResourceById(resource.id);
|
await resourceStore.deleteResourceById(resource.id);
|
||||||
@ -143,6 +144,7 @@ const ResourcesDialog: React.FC<Props> = (props: Props) => {
|
|||||||
title: t("resources.delete-resource"),
|
title: t("resources.delete-resource"),
|
||||||
content: warningText,
|
content: warningText,
|
||||||
style: "warning",
|
style: "warning",
|
||||||
|
dialogName: "delete-resource-dialog",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await resourceStore.deleteResourceById(resource.id);
|
await resourceStore.deleteResourceById(resource.id);
|
||||||
},
|
},
|
||||||
@ -242,6 +244,7 @@ export default function showResourcesDialog() {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "resources-dialog",
|
className: "resources-dialog",
|
||||||
|
dialogName: "resources-dialog",
|
||||||
},
|
},
|
||||||
ResourcesDialog,
|
ResourcesDialog,
|
||||||
{}
|
{}
|
||||||
|
@ -148,6 +148,7 @@ export default function showResourcesSelectorDialog() {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "resources-selector-dialog",
|
className: "resources-selector-dialog",
|
||||||
|
dialogName: "resources-selector-dialog",
|
||||||
},
|
},
|
||||||
ResourcesSelectorDialog,
|
ResourcesSelectorDialog,
|
||||||
{}
|
{}
|
||||||
|
@ -92,6 +92,7 @@ export default function showSettingDialog(): void {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "setting-dialog",
|
className: "setting-dialog",
|
||||||
|
dialogName: "setting-dialog",
|
||||||
},
|
},
|
||||||
SettingDialog,
|
SettingDialog,
|
||||||
{}
|
{}
|
||||||
|
@ -79,6 +79,7 @@ const PreferencesSection = () => {
|
|||||||
title: `Archive Member`,
|
title: `Archive Member`,
|
||||||
content: `❗️Are you sure to archive ${user.username}?`,
|
content: `❗️Are you sure to archive ${user.username}?`,
|
||||||
style: "warning",
|
style: "warning",
|
||||||
|
dialogName: "archive-user-dialog",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await userStore.patchUser({
|
await userStore.patchUser({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
@ -102,6 +103,7 @@ const PreferencesSection = () => {
|
|||||||
title: `Delete Member`,
|
title: `Delete Member`,
|
||||||
content: `Are you sure to delete ${user.username}? THIS ACTION IS IRREVERSIABLE.❗️`,
|
content: `Are you sure to delete ${user.username}? THIS ACTION IS IRREVERSIABLE.❗️`,
|
||||||
style: "warning",
|
style: "warning",
|
||||||
|
dialogName: "delete-user-dialog",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await userStore.deleteUser({
|
await userStore.deleteUser({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
|
@ -16,6 +16,7 @@ const MyAccountSection = () => {
|
|||||||
title: "Reset Open API",
|
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?",
|
content: "❗️The existing API will be invalidated and a new one will be generated, are you sure you want to reset?",
|
||||||
style: "warning",
|
style: "warning",
|
||||||
|
dialogName: "reset-openid-dialog",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await userStore.patchUser({
|
await userStore.patchUser({
|
||||||
id: user.id,
|
id: user.id,
|
||||||
|
@ -190,6 +190,7 @@ export default function showShareMemoDialog(memo: Memo): void {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "share-memo-dialog",
|
className: "share-memo-dialog",
|
||||||
|
dialogName: "share-memo-dialog",
|
||||||
},
|
},
|
||||||
ShareMemoDialog,
|
ShareMemoDialog,
|
||||||
{ memo }
|
{ memo }
|
||||||
|
@ -139,6 +139,7 @@ function showUpdateAccountDialog() {
|
|||||||
generateDialog(
|
generateDialog(
|
||||||
{
|
{
|
||||||
className: "update-account-dialog",
|
className: "update-account-dialog",
|
||||||
|
dialogName: "update-account-dialog",
|
||||||
},
|
},
|
||||||
UpdateAccountDialog
|
UpdateAccountDialog
|
||||||
);
|
);
|
||||||
|
@ -7,6 +7,7 @@ import editorReducer from "./reducer/editor";
|
|||||||
import shortcutReducer from "./reducer/shortcut";
|
import shortcutReducer from "./reducer/shortcut";
|
||||||
import locationReducer from "./reducer/location";
|
import locationReducer from "./reducer/location";
|
||||||
import resourceReducer from "./reducer/resource";
|
import resourceReducer from "./reducer/resource";
|
||||||
|
import dialogReducer from "./reducer/dialog";
|
||||||
|
|
||||||
const store = configureStore({
|
const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
@ -17,6 +18,7 @@ const store = configureStore({
|
|||||||
shortcut: shortcutReducer,
|
shortcut: shortcutReducer,
|
||||||
location: locationReducer,
|
location: locationReducer,
|
||||||
resource: resourceReducer,
|
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 "./resource";
|
||||||
export * from "./shortcut";
|
export * from "./shortcut";
|
||||||
export * from "./user";
|
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