Add confirm popup component
This commit is contained in:
		
							parent
							
								
									89ae499d4b
								
							
						
					
					
						commit
						cc127696c5
					
				| @ -4,6 +4,7 @@ import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost | ||||
| import { useSetting, IMixinSettingProps } from "@Context/Setting"; | ||||
| import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status"; | ||||
| import { AllI18nKeys } from "../Localization/Localization"; | ||||
| import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup"; | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { MouseMod } from "@GLRender/ClassicRenderer"; | ||||
| import "./CommandBar.scss"; | ||||
| @ -72,7 +73,7 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi | ||||
|                     iconName: "Settings", | ||||
|                     i18NKey: "Command.Bar.Setting.Info", | ||||
|                     click: () => { | ||||
|                         this.props.status ? this.props.status.popup.showPopup() : undefined; | ||||
|                         this.props.status?.popup.showPopup(ConfirmPopup, {}); | ||||
|                     } | ||||
|                 })} | ||||
|             </div> | ||||
|  | ||||
| @ -0,0 +1,67 @@ | ||||
| @import "../Theme/Theme.scss"; | ||||
| 
 | ||||
| div.confirm-root { | ||||
| 	width: 100%; | ||||
| 	height: 100%; | ||||
| 
 | ||||
| 	div.content-views { | ||||
| 		width: 100%; | ||||
| 		height: calc( 100% - 36px ); | ||||
| 		box-sizing: border-box; | ||||
| 		padding: 10px; | ||||
| 	} | ||||
| 
 | ||||
| 	div.action-view { | ||||
| 		width: 100%; | ||||
| 		height: 36px; | ||||
| 		display: flex; | ||||
| 		box-sizing: border-box; | ||||
| 		padding-right: 5px; | ||||
| 		padding-bottom: 10px; | ||||
| 		justify-content: flex-end; | ||||
| 		align-items: center; | ||||
| 
 | ||||
| 		div.action-button { | ||||
| 			height: 26px; | ||||
| 			padding: 0 10px; | ||||
| 			border-radius: 3px; | ||||
| 			margin: 0 5px; | ||||
| 			display: flex; | ||||
| 			align-items: center; | ||||
| 			cursor: pointer; | ||||
| 			user-select: none; | ||||
| 		} | ||||
| 
 | ||||
| 		div.action-button.yes-button:hover { | ||||
| 			color: $lt-red; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| div.dark.confirm-root { | ||||
| 
 | ||||
| 	div.action-view { | ||||
| 
 | ||||
| 		div.action-button { | ||||
| 			background-color: $lt-bg-color-lvl3-dark; | ||||
| 		} | ||||
| 
 | ||||
| 		div.action-button:hover { | ||||
| 			background-color: $lt-bg-color-lvl2-dark; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| div.light.confirm-root { | ||||
| 
 | ||||
| 	div.action-view { | ||||
| 
 | ||||
| 		div.action-button { | ||||
| 			background-color: $lt-bg-color-lvl3-light; | ||||
| 		} | ||||
| 
 | ||||
| 		div.action-button:hover { | ||||
| 			background-color: $lt-bg-color-lvl2-light; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -1,8 +1,34 @@ | ||||
| import { Popup } from "@Context/Popups"; | ||||
| import { ReactNode } from "react"; | ||||
| import { Message } from "@Component/Message/Message"; | ||||
| import { Theme } from "@Component/Theme/Theme"; | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import "./ConfirmPopup.scss"; | ||||
| 
 | ||||
| class ConfirmPopup extends Popup { | ||||
| interface IConfirmPopupProps { | ||||
| 	 | ||||
| } | ||||
| class ConfirmPopup extends Popup<IConfirmPopupProps> { | ||||
| 
 | ||||
| 	public width: number = 300; | ||||
| 
 | ||||
| 	public height: number = 180; | ||||
| 
 | ||||
| 	public render(): ReactNode { | ||||
| 		return <Theme className="confirm-root"> | ||||
| 			<div className="content-views"> | ||||
| 				<Message i18nKey="ZH_CN"/> | ||||
| 			</div> | ||||
| 			<div className="action-view"> | ||||
| 				<div className="yes-button action-button"> | ||||
| 					<Localization i18nKey="Panel.Title.Group.Details.View"/> | ||||
| 				</div> | ||||
| 				<div className="no-button action-button"> | ||||
| 					<Localization i18nKey="Panel.Title.Group.Details.View"/> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</Theme>; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| export { ConfirmPopup } | ||||
| @ -66,7 +66,7 @@ div.popup-layer { | ||||
|             user-select: none; | ||||
|              | ||||
|             span { | ||||
|                 padding-left: 8px; | ||||
|                 padding-left: 10px; | ||||
|                 display: inline-block; | ||||
|                 vertical-align: middle; | ||||
|                 white-space: nowrap; | ||||
| @ -98,7 +98,6 @@ div.popup-layer.dark { | ||||
|     box-shadow: 0 0 15px rgba(0, 0, 0, 0.3); | ||||
| 
 | ||||
|     div.popup-layer-header { | ||||
|         background-color: $lt-bg-color-lvl3-dark; | ||||
| 
 | ||||
|         div.header-close-icon:hover { | ||||
|             background-color: $lt-bg-color-lvl2-dark; | ||||
| @ -111,7 +110,6 @@ div.popup-layer.light { | ||||
|     box-shadow: 0 0 15px rgba(0, 0, 0, 0.15); | ||||
| 
 | ||||
|     div.popup-layer-header { | ||||
|         background-color: $lt-bg-color-lvl3-light; | ||||
| 
 | ||||
|         div.header-close-icon:hover { | ||||
|             background-color: $lt-bg-color-lvl2-light; | ||||
|  | ||||
| @ -1,18 +1,22 @@ | ||||
| import { Component, ReactNode } from "react"; | ||||
| import { IMixinStatusProps, useStatusWithEvent } from "@Context/Status"; | ||||
| import { BackgroundLevel, Theme } from "@Component/Theme/Theme"; | ||||
| import { IMixinSettingProps, useSettingWithEvent } from "@Context/Setting"; | ||||
| import { BackgroundLevel, FontLevel, getClassList, Theme } from "@Component/Theme/Theme"; | ||||
| import { Popup as PopupModel } from "@Context/Popups"; | ||||
| import { Icon } from "@fluentui/react"; | ||||
| import "./Popup.scss"; | ||||
| 
 | ||||
| interface IPopupProps {} | ||||
| 
 | ||||
| @useSettingWithEvent("themes") | ||||
| @useStatusWithEvent("popupChange") | ||||
| class Popup extends Component<IPopupProps & IMixinStatusProps> { | ||||
| class Popup extends Component<IPopupProps & IMixinStatusProps & IMixinSettingProps> { | ||||
| 
 | ||||
|     private renderMask(index?: number, click?: () => void, key?: string): ReactNode { | ||||
|         const classList: string[] = ["popup-mask", "show-fade"]; | ||||
|         return <Theme | ||||
|         const classList: string[] = ["popup-mask", "show-fade",  | ||||
|             ...getClassList({}, this.props.setting) | ||||
|         ]; | ||||
|         return <div | ||||
|             key={key} | ||||
|             onClick={click} | ||||
|             className={classList.join(" ")} | ||||
| @ -61,7 +65,13 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> { | ||||
|     } | ||||
| 
 | ||||
|     private renderHeader(popup: PopupModel): ReactNode { | ||||
|         return <div className="popup-layer-header"> | ||||
|         return <div | ||||
|             className={getClassList({ | ||||
|                 className: "popup-layer-header", | ||||
|                 backgroundLevel: BackgroundLevel.Level3, | ||||
|                 fontLevel: FontLevel.Level3 | ||||
|             }, this.props.setting).join(" ")} | ||||
|         > | ||||
|             <div | ||||
|                 className="header-text" | ||||
|                 onMouseDown={(e) => { | ||||
| @ -87,7 +97,13 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> { | ||||
|     } | ||||
| 
 | ||||
|     private renderContent(popup: PopupModel) { | ||||
|         return <div className="popup-layer-content"> | ||||
|         return <div | ||||
|             className={getClassList({ | ||||
|                 className: "popup-layer-content", | ||||
|                 backgroundLevel: BackgroundLevel.Level4, | ||||
|                 fontLevel: FontLevel.normal | ||||
|             }, this.props.setting).join(" ")} | ||||
|         > | ||||
|             {popup.render()} | ||||
|         </div> | ||||
|     } | ||||
| @ -103,6 +119,7 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> { | ||||
|         } | ||||
| 
 | ||||
|         return <Theme | ||||
|             key={popup.id} | ||||
|             style={{ | ||||
|                 width: popup.width, | ||||
|                 height: popup.height, | ||||
| @ -110,9 +127,10 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> { | ||||
|                 top: popup.top, | ||||
|                 left: popup.left | ||||
|             }} | ||||
|             key={popup.id} | ||||
|             backgroundLevel={BackgroundLevel.Level4} | ||||
|             className="popup-layer show-scale" | ||||
|             className={getClassList({ | ||||
|                 className: "popup-layer show-scale", | ||||
|                 backgroundLevel: BackgroundLevel.Level4, | ||||
|             }, this.props.setting).join(" ")} | ||||
|         > | ||||
|             {this.renderHeader(popup)} | ||||
|             {this.renderContent(popup)} | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import { useSetting, Themes, IMixinSettingProps } from "@Context/Setting"; | ||||
| import { useSettingWithEvent, Themes, IMixinSettingProps, Setting } from "@Context/Setting"; | ||||
| import { Component, ReactNode, DetailedHTMLProps, HTMLAttributes } from "react"; | ||||
| import "./Theme.scss"; | ||||
| 
 | ||||
| @ -21,12 +21,33 @@ interface IThemeProps { | ||||
|     className?: string; | ||||
|     fontLevel?: FontLevel; | ||||
|     backgroundLevel?: BackgroundLevel; | ||||
| }  | ||||
| } | ||||
| 
 | ||||
| function getClassList(props: IThemeProps, setting?: Setting) { | ||||
|     const classNameList: string[] = []; | ||||
| 
 | ||||
|     if (props.className) { | ||||
|         classNameList.push(props.className); | ||||
|     } | ||||
| 
 | ||||
|     const theme = setting ? setting.themes : Themes.dark; | ||||
|     classNameList.push(theme === Themes.light ? "light" : "dark"); | ||||
| 
 | ||||
|     if (props.fontLevel) { | ||||
|         classNameList.push(`font-${props.fontLevel}`); | ||||
|     } | ||||
|      | ||||
|     if (props.backgroundLevel) { | ||||
|         classNameList.push(`background-${props.backgroundLevel}`); | ||||
|     } | ||||
| 
 | ||||
|     return classNameList; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 主题切换 | ||||
|  */ | ||||
| @useSetting | ||||
| @useSettingWithEvent("themes") | ||||
| class Theme extends Component< | ||||
|     IThemeProps & IMixinSettingProps & DetailedHTMLProps< | ||||
|         HTMLAttributes<HTMLDivElement>, HTMLDivElement | ||||
| @ -52,22 +73,7 @@ class Theme extends Component< | ||||
|     public render(): ReactNode { | ||||
| 
 | ||||
|         const setting = this.props.setting; | ||||
|         const classNameList: string[] = []; | ||||
| 
 | ||||
|         if (this.props.className) { | ||||
|             classNameList.push(this.props.className); | ||||
|         } | ||||
| 
 | ||||
|         const theme = setting ? setting.themes : Themes.dark; | ||||
|         classNameList.push(theme === Themes.light ? "light" : "dark"); | ||||
| 
 | ||||
|         if (this.props.fontLevel) { | ||||
|             classNameList.push(`font-${this.props.fontLevel}`); | ||||
|         } | ||||
|          | ||||
|         if (this.props.backgroundLevel) { | ||||
|             classNameList.push(`background-${this.props.backgroundLevel}`); | ||||
|         } | ||||
|         const classNameList = getClassList(this.props, setting); | ||||
| 
 | ||||
|         const propsObj = {...this.props}; | ||||
|         delete propsObj.className; | ||||
| @ -82,4 +88,4 @@ class Theme extends Component< | ||||
| } | ||||
| 
 | ||||
| export default Theme; | ||||
| export { Theme, FontLevel, BackgroundLevel }; | ||||
| export { Theme, FontLevel, BackgroundLevel, getClassList }; | ||||
| @ -1,11 +1,12 @@ | ||||
| import { ReactNode, createElement } from "react"; | ||||
| import { Emitter } from "@Model/Emitter"; | ||||
| import { Localization } from "@Component/Localization/Localization"; | ||||
| import { IAnyObject } from "@Model/Renderer"; | ||||
| 
 | ||||
| /** | ||||
|  * 弹窗类型 | ||||
|  */ | ||||
| class Popup<P extends any = any> { | ||||
| class Popup<P extends IAnyObject = IAnyObject> { | ||||
| 
 | ||||
|     public props: P; | ||||
| 
 | ||||
| @ -61,11 +62,6 @@ class Popup<P extends any = any> { | ||||
|      */ | ||||
|     public index: number = Infinity; | ||||
| 
 | ||||
|     /** | ||||
|      * react 节点 | ||||
|      */ | ||||
|     public reactNode: ReactNode; | ||||
| 
 | ||||
|     /** | ||||
|      * 渲染标题 | ||||
|      */ | ||||
| @ -73,13 +69,6 @@ class Popup<P extends any = any> { | ||||
|         return createElement(Localization, {i18nKey: "Popup.Title.Unnamed"}); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 渲染函数 | ||||
|      */ | ||||
|     public onRender(p: Popup): ReactNode { | ||||
|         return undefined; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 关闭回调 | ||||
|      */ | ||||
| @ -91,8 +80,7 @@ class Popup<P extends any = any> { | ||||
|      * 渲染节点 | ||||
|      */ | ||||
|     public render(): ReactNode { | ||||
|         this.reactNode = this.onRender(this) ?? this.reactNode; | ||||
|         return this.reactNode; | ||||
|         return null; | ||||
|     }; | ||||
| 
 | ||||
|     public close(): Popup | undefined { | ||||
| @ -144,10 +132,10 @@ class PopupController extends Emitter<IPopupControllerEvent> { | ||||
|     /** | ||||
|      * 实例化并开启一个弹窗 | ||||
|      */ | ||||
|     public showPopup<P extends any, T extends Popup<P>>( | ||||
|         popup?: (new () => T) | Popup<P>, props?: P | ||||
|     public showPopup<P extends IAnyObject, T extends Popup<P>>( | ||||
|         popup: (new (props: P) => T) | Popup<P>, props: P | ||||
|     ): Popup<P> { | ||||
|         let newPopup: Popup; | ||||
|         let newPopup: Popup<P>; | ||||
|         if (popup instanceof Popup) { | ||||
|             newPopup = popup; | ||||
|         } else { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user