diff --git a/source/Component/CommandBar/CommandBar.tsx b/source/Component/CommandBar/CommandBar.tsx index 1b25b6a..bd21180 100644 --- a/source/Component/CommandBar/CommandBar.tsx +++ b/source/Component/CommandBar/CommandBar.tsx @@ -68,7 +68,13 @@ class CommandBar extends Component
- {this.getRenderButton({ iconName: "Settings", i18NKey: "Command.Bar.Setting.Info" })} + {this.getRenderButton({ + iconName: "Settings", + i18NKey: "Command.Bar.Setting.Info", + click: () => { + this.props.status ? this.props.status.popup.showPopup() : undefined; + } + })}
} diff --git a/source/Component/Popup/Popup.scss b/source/Component/Popup/Popup.scss new file mode 100644 index 0000000..6c217fa --- /dev/null +++ b/source/Component/Popup/Popup.scss @@ -0,0 +1,71 @@ +@import "../Theme/Theme.scss"; + +@keyframes show-scale{ + from { + transform: scale3d(1.15, 1.15, 1); + } + to { + transform: scale3d(1, 1, 1); + } +} + +@keyframes show-fade{ + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +div.popup-mask.show-fade { + animation: show-fade .1s cubic-bezier(0, 0, 1, 1) both; + opacity: 1; +} + +div.popup-layer.show-scale { + animation: show-scale .3s cubic-bezier(.1, .9, .2, 1) both, + show-fade .1s cubic-bezier(0, 0, 1, 1) both; + transform: scale3d(1, 1, 1); + opacity: 1; +} + +div.popup-mask { + position: absolute; + cursor: pointer; + width: 100%; + height: 100%; +} + +div.popup-layer { + position: absolute; + border-radius: 3px; + overflow: hidden; + + div.popup-layer-header { + min-height: 32px; + max-height: 32px; + } +} + +div.popup-layer.dark { + + div.popup-layer-header { + background-color: $lt-bg-color-lvl3-dark; + } +} + +div.popup-layer.light { + + div.popup-layer-header { + background-color: $lt-bg-color-lvl3-light; + } +} + +div.dark.popup-mask { + background-color: rgba(0, 0, 0, 0.55); +} + +div.light.popup-mask { + background-color: rgba(0, 0, 0, 0.15); +} \ No newline at end of file diff --git a/source/Component/Popup/Popup.tsx b/source/Component/Popup/Popup.tsx new file mode 100644 index 0000000..4737249 --- /dev/null +++ b/source/Component/Popup/Popup.tsx @@ -0,0 +1,97 @@ +import { Component, ReactNode } from "react"; +import { IMixinStatusProps, useStatusWithEvent } from "@Context/Status"; +import { BackgroundLevel, Theme } from "@Component/Theme/Theme"; +import { Popup as PopupModel } from "@Context/Popups"; +import "./Popup.scss"; + +interface IPopupProps {} + +@useStatusWithEvent("popupChange") +class Popup extends Component { + + public renderMask(index?: number, click?: () => void, key?: string): ReactNode { + const classList: string[] = ["popup-mask", "show-fade"]; + return + } + + public renderRootMask(): ReactNode { + if (this.props.status) { + const needMask = this.props.status.popup.popups.some(popup => popup.needMask); + if (!needMask) return null; + return this.renderMask(this.props.status.popup.zIndex, + () => { + this.props.status?.popup.popups.forEach( + popup => popup.onClose() + ) + } + ); + } else { + return null; + } + } + + public renderMaskList(): ReactNode { + if (this.props.status) { + return this.props.status.popup.popups + .filter((popup) => { + return popup.needMask && popup.maskForSelf; + }) + .filter((_, index) => { + if (index === 0) return false; + return true; + }) + .map((popup) => { + return this.renderMask(popup.zIndex() - 1, + () => { + popup.onClose(); + }, popup.id + ); + }) + } else { + return null; + } + } + + public renderLayer(popup: PopupModel) { + const pageWidth = document.documentElement.clientWidth; + const pageHeight = document.documentElement.clientHeight; + const top = (pageHeight - popup.height) / 2; + const left = (pageWidth - popup.width) / 2; + + return +
+ +
+
+ } + + public render(): ReactNode { + return <> + {this.renderRootMask()} + {this.renderMaskList()} + {this.props.status?.popup.popups.map((popup) => { + return this.renderLayer(popup); + })} + ; + } +} + +export { Popup }; \ No newline at end of file diff --git a/source/Context/Popups.ts b/source/Context/Popups.ts index c3ae5d5..1d66303 100644 --- a/source/Context/Popups.ts +++ b/source/Context/Popups.ts @@ -8,11 +8,33 @@ type IPopupConstructor = new (controller: PopupController, id: string) => Popup; */ class Popup { + public zIndex() { + return this.index * 2 + this.controller.zIndex; + } + + public width: number = 300; + + public height: number = 200; + + public top: number = 0; + + public left: number = 0; + /** * 是否关闭 */ public isClose: boolean = false; + /** + * 需要蒙版 + */ + public needMask: boolean = true; + + /** + * 单独遮挡下层的蒙版 + */ + public maskForSelf: boolean = false; + /** * 唯一标识符 */ @@ -43,7 +65,9 @@ class Popup { /** * 关闭回调 */ - public onClose(): void {}; + public onClose(): void { + this.close(); + }; /** * 渲染节点 @@ -77,6 +101,11 @@ class PopupController extends Emitter { */ private idIndex = 0; + /** + * 最小弹窗 Index + */ + public zIndex = 100; + /** * 弹窗列表 */ @@ -121,7 +150,6 @@ class PopupController extends Emitter { if (isDelete) { closePopup = currentPopup; currentPopup.isClose = true; - currentPopup.onClose(); return false; } else { return true; diff --git a/source/Page/SimulatorWeb/SimulatorWeb.tsx b/source/Page/SimulatorWeb/SimulatorWeb.tsx index d4612bf..07587a5 100644 --- a/source/Page/SimulatorWeb/SimulatorWeb.tsx +++ b/source/Page/SimulatorWeb/SimulatorWeb.tsx @@ -9,6 +9,7 @@ import { initializeIcons } from '@fluentui/font-icons-mdl2'; import { RootContainer } from "@Component/Container/RootContainer"; import { LayoutDirection } from "@Context/Layout"; import { CommandBar } from "@Component/CommandBar/CommandBar"; +import { Popup } from "@Component/Popup/Popup"; import "./SimulatorWeb.scss"; initializeIcons("https://img.mrkbear.com/fabric-cdn-prod_20210407.001/"); @@ -101,6 +102,7 @@ class SimulatorWeb extends Component { backgroundLevel={BackgroundLevel.Level5} fontLevel={FontLevel.Level3} > +