Merge pull request 'Add pop-up system & delete confirmation pops up' (#25) from dev-mrkbear into master
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: http://git.mrkbear.com/MrKBear/living-together/pulls/25
This commit is contained in:
commit
bb762c8273
@ -4,6 +4,7 @@ import { LocalizationTooltipHost } from "../Localization/LocalizationTooltipHost
|
|||||||
import { useSetting, IMixinSettingProps } from "@Context/Setting";
|
import { useSetting, IMixinSettingProps } from "@Context/Setting";
|
||||||
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
||||||
import { AllI18nKeys } from "../Localization/Localization";
|
import { AllI18nKeys } from "../Localization/Localization";
|
||||||
|
import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup";
|
||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { MouseMod } from "@GLRender/ClassicRenderer";
|
import { MouseMod } from "@GLRender/ClassicRenderer";
|
||||||
import "./CommandBar.scss";
|
import "./CommandBar.scss";
|
||||||
@ -72,7 +73,7 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi
|
|||||||
iconName: "Settings",
|
iconName: "Settings",
|
||||||
i18NKey: "Command.Bar.Setting.Info",
|
i18NKey: "Command.Bar.Setting.Info",
|
||||||
click: () => {
|
click: () => {
|
||||||
this.props.status ? this.props.status.popup.showPopup() : undefined;
|
// this.props.status?.popup.showPopup(ConfirmPopup, {});
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
67
source/Component/ConfirmPopup/ConfirmPopup.scss
Normal file
67
source/Component/ConfirmPopup/ConfirmPopup.scss
Normal file
@ -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.red {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
source/Component/ConfirmPopup/ConfirmPopup.tsx
Normal file
60
source/Component/ConfirmPopup/ConfirmPopup.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { Popup } from "@Context/Popups";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
import { Message } from "@Component/Message/Message";
|
||||||
|
import { Theme } from "@Component/Theme/Theme";
|
||||||
|
import { AllI18nKeys, Localization } from "@Component/Localization/Localization";
|
||||||
|
import "./ConfirmPopup.scss";
|
||||||
|
|
||||||
|
interface IConfirmPopupProps {
|
||||||
|
titleI18N?: AllI18nKeys;
|
||||||
|
infoI18n: AllI18nKeys;
|
||||||
|
yesI18n?: AllI18nKeys;
|
||||||
|
noI18n?: AllI18nKeys;
|
||||||
|
yes?: () => any;
|
||||||
|
no?: () => any;
|
||||||
|
red?: "yes" | "no";
|
||||||
|
}
|
||||||
|
class ConfirmPopup extends Popup<IConfirmPopupProps> {
|
||||||
|
|
||||||
|
public width: number = 300;
|
||||||
|
|
||||||
|
public height: number = 180;
|
||||||
|
|
||||||
|
public onRenderHeader(): ReactNode {
|
||||||
|
return <Localization i18nKey={this.props.titleI18N ?? "Popup.Title.Confirm"}/>
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): ReactNode {
|
||||||
|
|
||||||
|
const yesClassList: string[] = ["action-button", "yes-button"];
|
||||||
|
const noClassList: string[] = ["action-button", "no-button"];
|
||||||
|
if (this.props.red === "no") {
|
||||||
|
noClassList.push("red");
|
||||||
|
}
|
||||||
|
if (this.props.red === "yes") {
|
||||||
|
yesClassList.push("red");
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Theme className="confirm-root">
|
||||||
|
<div className="content-views">
|
||||||
|
<Message i18nKey={this.props.infoI18n}/>
|
||||||
|
</div>
|
||||||
|
<div className="action-view">
|
||||||
|
<div className={yesClassList.join(" ")} onClick={() => {
|
||||||
|
this.props.yes ? this.props.yes() : null;
|
||||||
|
this.close();
|
||||||
|
}}>
|
||||||
|
<Localization i18nKey={this.props.yesI18n ?? "Popup.Action.Yes"}/>
|
||||||
|
</div>
|
||||||
|
<div className={noClassList.join(" ")} onClick={() => {
|
||||||
|
this.props.no ? this.props.no() : null;
|
||||||
|
this.close();
|
||||||
|
}}>
|
||||||
|
<Localization i18nKey={this.props.noI18n ?? "Popup.Action.No"}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Theme>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ConfirmPopup }
|
@ -34,15 +34,31 @@ div.popup-layer.show-scale {
|
|||||||
|
|
||||||
div.popup-mask {
|
div.popup-mask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: pointer;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.focus.popup-layer {
|
||||||
|
border: 0.8px solid #514feb;
|
||||||
|
}
|
||||||
|
|
||||||
div.popup-layer {
|
div.popup-layer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
overflow: hidden;
|
transition: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 0.8px solid transparent;
|
||||||
|
|
||||||
|
div.popup-layer-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.popup-layer-root-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
div.popup-layer-header {
|
div.popup-layer-header {
|
||||||
min-height: $header-height;
|
min-height: $header-height;
|
||||||
@ -59,9 +75,9 @@ div.popup-layer {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
padding-left: 8px;
|
padding-left: 10px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: bottom;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -79,12 +95,56 @@ div.popup-layer {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.popup-layer-content {
|
||||||
|
height: calc( 100% - 32px );
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.drag-line-root.drag-line-y {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.drag-line-root {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
div.drag-line {
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.render-drag-block-root {
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
div.render-drag-block {
|
||||||
|
min-width: 5px;
|
||||||
|
min-height: 5px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.drag-line:hover {
|
||||||
|
background-color: $lt-blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.drag-line.hover {
|
||||||
|
background-color: $lt-blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.popup-layer.dark {
|
div.popup-layer.dark {
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
div.popup-layer-header {
|
div.popup-layer-header {
|
||||||
background-color: $lt-bg-color-lvl3-dark;
|
|
||||||
|
|
||||||
div.header-close-icon:hover {
|
div.header-close-icon:hover {
|
||||||
background-color: $lt-bg-color-lvl2-dark;
|
background-color: $lt-bg-color-lvl2-dark;
|
||||||
@ -94,9 +154,9 @@ div.popup-layer.dark {
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.popup-layer.light {
|
div.popup-layer.light {
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.15);
|
||||||
|
|
||||||
div.popup-layer-header {
|
div.popup-layer-header {
|
||||||
background-color: $lt-bg-color-lvl3-light;
|
|
||||||
|
|
||||||
div.header-close-icon:hover {
|
div.header-close-icon:hover {
|
||||||
background-color: $lt-bg-color-lvl2-light;
|
background-color: $lt-bg-color-lvl2-light;
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { IMixinStatusProps, useStatusWithEvent } from "@Context/Status";
|
import { IMixinStatusProps, useStatusWithEvent } from "@Context/Status";
|
||||||
import { BackgroundLevel, Theme } from "@Component/Theme/Theme";
|
import { IMixinSettingProps, useSettingWithEvent } from "@Context/Setting";
|
||||||
import { Popup as PopupModel } from "@Context/Popups";
|
import { BackgroundLevel, FontLevel, getClassList, Theme } from "@Component/Theme/Theme";
|
||||||
|
import { Popup as PopupModel, ResizeDragDirection } from "@Context/Popups";
|
||||||
import { Icon } from "@fluentui/react";
|
import { Icon } from "@fluentui/react";
|
||||||
import "./Popup.scss";
|
import "./Popup.scss";
|
||||||
|
|
||||||
interface IPopupProps {}
|
interface IPopupProps {}
|
||||||
|
|
||||||
|
@useSettingWithEvent("themes")
|
||||||
@useStatusWithEvent("popupChange")
|
@useStatusWithEvent("popupChange")
|
||||||
class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
class Popup extends Component<IPopupProps & IMixinStatusProps & IMixinSettingProps> {
|
||||||
|
|
||||||
public renderMask(index?: number, click?: () => void, key?: string): ReactNode {
|
private renderMask(index?: number, click?: () => void, key?: string): ReactNode {
|
||||||
const classList: string[] = ["popup-mask", "show-fade"];
|
const classList: string[] = ["popup-mask", "show-fade",
|
||||||
return <Theme
|
...getClassList({}, this.props.setting)
|
||||||
|
];
|
||||||
|
return <div
|
||||||
key={key}
|
key={key}
|
||||||
onClick={click}
|
onClick={click}
|
||||||
className={classList.join(" ")}
|
className={classList.join(" ")}
|
||||||
@ -22,7 +26,7 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderRootMask(): ReactNode {
|
private renderRootMask(): ReactNode {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
const needMask = this.props.status.popup.popups.some(popup => popup.needMask);
|
const needMask = this.props.status.popup.popups.some(popup => popup.needMask);
|
||||||
if (!needMask) return null;
|
if (!needMask) return null;
|
||||||
@ -38,7 +42,7 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderMaskList(): ReactNode {
|
private renderMaskList(): ReactNode {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
return this.props.status.popup.popups
|
return this.props.status.popup.popups
|
||||||
.filter((popup) => {
|
.filter((popup) => {
|
||||||
@ -60,9 +64,22 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderHeader(popup: PopupModel): ReactNode {
|
private renderHeader(popup: PopupModel): ReactNode {
|
||||||
return <div className="popup-layer-header">
|
return <div
|
||||||
<div className="header-text">
|
className={getClassList({
|
||||||
|
className: "popup-layer-header",
|
||||||
|
backgroundLevel: BackgroundLevel.Level3,
|
||||||
|
fontLevel: FontLevel.Level3
|
||||||
|
}, this.props.setting).join(" ")}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="header-text"
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
popup.isOnMouseDown = true;
|
||||||
|
popup.lastMouseLeft = e.clientX;
|
||||||
|
popup.lastMouseTop = e.clientY;
|
||||||
|
}}
|
||||||
|
>
|
||||||
{popup.onRenderHeader()}
|
{popup.onRenderHeader()}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -76,28 +93,322 @@ class Popup extends Component<IPopupProps & IMixinStatusProps> {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderLayer(popup: PopupModel) {
|
private renderContent(popup: PopupModel) {
|
||||||
|
return <div
|
||||||
|
className={getClassList({
|
||||||
|
className: "popup-layer-content",
|
||||||
|
backgroundLevel: BackgroundLevel.Level4,
|
||||||
|
fontLevel: FontLevel.normal
|
||||||
|
}, this.props.setting).join(" ")}
|
||||||
|
>
|
||||||
|
{popup.render()}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderDragBlock(dir: ResizeDragDirection, popup: PopupModel) {
|
||||||
|
return <div className="render-drag-block-root">
|
||||||
|
<div
|
||||||
|
draggable={false}
|
||||||
|
style={{
|
||||||
|
cursor: this.mapDirToCursor.get(dir),
|
||||||
|
zIndex: popup.zIndex() + 2
|
||||||
|
}}
|
||||||
|
className="render-drag-block"
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
popup.lastMouseLeft = e.clientX;
|
||||||
|
popup.lastMouseTop = e.clientY;
|
||||||
|
popup.resizeDragDirection = dir;
|
||||||
|
popup.isResizeMouseDown = true;
|
||||||
|
}}
|
||||||
|
onMouseEnter={() => {
|
||||||
|
popup.resizeHoverDirection = dir;
|
||||||
|
this.forceUpdate();
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
popup.resizeHoverDirection = undefined;
|
||||||
|
this.forceUpdate();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapDirToCursor = new Map<ResizeDragDirection, string>([
|
||||||
|
[ResizeDragDirection.rightTop, "sw-resize"],
|
||||||
|
[ResizeDragDirection.rightBottom, "nw-resize"],
|
||||||
|
[ResizeDragDirection.leftBottom, "sw-resize"],
|
||||||
|
[ResizeDragDirection.LeftTop, "nw-resize"]
|
||||||
|
]);
|
||||||
|
|
||||||
|
private renderDragLine(dir: ResizeDragDirection, popup: PopupModel) {
|
||||||
|
let xy: boolean = false;
|
||||||
|
const dragLineCList: string[] = ["drag-line"];
|
||||||
|
|
||||||
|
if (dir === ResizeDragDirection.top || dir === ResizeDragDirection.bottom) {
|
||||||
|
xy = false;
|
||||||
|
}
|
||||||
|
if (dir === ResizeDragDirection.left || dir === ResizeDragDirection.right) {
|
||||||
|
xy = true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
dir === ResizeDragDirection.top &&
|
||||||
|
(
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.LeftTop ||
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.rightTop
|
||||||
|
)
|
||||||
|
) ||
|
||||||
|
(
|
||||||
|
dir === ResizeDragDirection.bottom &&
|
||||||
|
(
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.leftBottom ||
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.rightBottom
|
||||||
|
)
|
||||||
|
) ||
|
||||||
|
(
|
||||||
|
dir === ResizeDragDirection.right &&
|
||||||
|
(
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.rightTop ||
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.rightBottom
|
||||||
|
)
|
||||||
|
) ||
|
||||||
|
(
|
||||||
|
dir === ResizeDragDirection.left &&
|
||||||
|
(
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.leftBottom ||
|
||||||
|
popup.resizeHoverDirection === ResizeDragDirection.LeftTop
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
dragLineCList.push("hover")
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div
|
||||||
|
className={"drag-line-root" + (xy ? " drag-line-y" : "")}
|
||||||
|
style={{
|
||||||
|
width: xy ? "0" : "100%",
|
||||||
|
height: xy ? "100%" : "0",
|
||||||
|
zIndex: popup.zIndex() + 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
xy && dir === ResizeDragDirection.left ? this.renderDragBlock(
|
||||||
|
ResizeDragDirection.LeftTop, popup
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
xy && dir === ResizeDragDirection.right ? this.renderDragBlock(
|
||||||
|
ResizeDragDirection.rightTop, popup
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{
|
||||||
|
!xy && dir === ResizeDragDirection.bottom ? this.renderDragBlock(
|
||||||
|
ResizeDragDirection.leftBottom, popup
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
<div
|
||||||
|
draggable={false}
|
||||||
|
className={dragLineCList.join(" ")}
|
||||||
|
style={{
|
||||||
|
cursor: xy ? "e-resize" : "n-resize",
|
||||||
|
minWidth: xy ? "4px" : "calc( 100% + 2px )",
|
||||||
|
minHeight: xy ? "calc( 100% + 2px )" : "4px"
|
||||||
|
}}
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
popup.lastMouseLeft = e.clientX;
|
||||||
|
popup.lastMouseTop = e.clientY;
|
||||||
|
popup.resizeDragDirection = dir;
|
||||||
|
popup.isResizeMouseDown = true;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
!xy && dir === ResizeDragDirection.bottom ? this.renderDragBlock(
|
||||||
|
ResizeDragDirection.rightBottom, popup
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderLayer(popup: PopupModel) {
|
||||||
const pageWidth = document.documentElement.clientWidth;
|
const pageWidth = document.documentElement.clientWidth;
|
||||||
const pageHeight = document.documentElement.clientHeight;
|
const pageHeight = document.documentElement.clientHeight;
|
||||||
const top = (pageHeight - popup.height) / 2;
|
if (isNaN(popup.top)) {
|
||||||
const left = (pageWidth - popup.width) / 2;
|
popup.top = (pageHeight - popup.height) / 2;
|
||||||
|
}
|
||||||
|
if (isNaN(popup.left)) {
|
||||||
|
popup.left = (pageWidth - popup.width) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
return <Theme
|
return <Theme
|
||||||
|
key={popup.id}
|
||||||
style={{
|
style={{
|
||||||
width: popup.width,
|
width: popup.width,
|
||||||
height: popup.height,
|
height: popup.height,
|
||||||
zIndex: popup.zIndex(),
|
zIndex: popup.zIndex(),
|
||||||
top: top,
|
top: popup.top,
|
||||||
left: left
|
left: popup.left
|
||||||
}}
|
}}
|
||||||
key={popup.id}
|
className={getClassList({
|
||||||
backgroundLevel={BackgroundLevel.Level4}
|
className: "popup-layer show-scale",
|
||||||
className="popup-layer show-scale"
|
backgroundLevel: BackgroundLevel.Level4,
|
||||||
|
}, this.props.setting).join(" ")}
|
||||||
>
|
>
|
||||||
|
{this.renderDragLine(ResizeDragDirection.top, popup)}
|
||||||
|
<div className="popup-layer-container">
|
||||||
|
{this.renderDragLine(ResizeDragDirection.left, popup)}
|
||||||
|
<div className="popup-layer-root-content">
|
||||||
{this.renderHeader(popup)}
|
{this.renderHeader(popup)}
|
||||||
|
{this.renderContent(popup)}
|
||||||
|
</div>
|
||||||
|
{this.renderDragLine(ResizeDragDirection.right, popup)}
|
||||||
|
</div>
|
||||||
|
{this.renderDragLine(ResizeDragDirection.bottom, popup)}
|
||||||
</Theme>
|
</Theme>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isMouseDown: boolean = false;
|
||||||
|
|
||||||
|
private handelMouseDown = () => {
|
||||||
|
this.isMouseDown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handelMouseUp = () => {
|
||||||
|
this.isMouseDown = false;
|
||||||
|
if (this.props.status) {
|
||||||
|
this.props.status.popup.popups.forEach((popup) => {
|
||||||
|
popup.isOnMouseDown = false;
|
||||||
|
popup.resizeDragDirection = undefined;
|
||||||
|
popup.isResizeMouseDown = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private resize(popup: PopupModel, dis: number, dir: boolean, lsk: boolean) {
|
||||||
|
|
||||||
|
if (dir) {
|
||||||
|
// Y
|
||||||
|
popup.isResizeOverFlowY = false;
|
||||||
|
const heightBackup = popup.height
|
||||||
|
const topBackup = popup.top;
|
||||||
|
if (lsk) {
|
||||||
|
popup.height += dis;
|
||||||
|
} else {
|
||||||
|
popup.top += dis;
|
||||||
|
popup.height -= dis;
|
||||||
|
}
|
||||||
|
if (popup.height < popup.minHeight) {
|
||||||
|
popup.height = heightBackup;
|
||||||
|
popup.top = topBackup;
|
||||||
|
popup.isResizeOverFlowY = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// X
|
||||||
|
popup.isResizeOverFlowX = false;
|
||||||
|
const leftBackup = popup.left
|
||||||
|
const widthBackup = popup.width;
|
||||||
|
if (lsk) {
|
||||||
|
popup.width += dis;
|
||||||
|
} else {
|
||||||
|
popup.left += dis;
|
||||||
|
popup.width -= dis;
|
||||||
|
}
|
||||||
|
if (popup.width < popup.minWidth) {
|
||||||
|
popup.width = widthBackup;
|
||||||
|
popup.left = leftBackup;
|
||||||
|
popup.isResizeOverFlowX = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handelMouseMove = (e: MouseEvent) => {
|
||||||
|
let isActionSuccess: boolean = false;
|
||||||
|
if (
|
||||||
|
this.isMouseDown &&
|
||||||
|
this.props.status &&
|
||||||
|
this.props.status.popup.popups.some(popup => popup.isOnMouseDown)
|
||||||
|
) {
|
||||||
|
this.props.status.popup.popups.forEach((popup) => {
|
||||||
|
if (popup.isOnMouseDown) {
|
||||||
|
popup.top += e.clientY - popup.lastMouseTop;
|
||||||
|
popup.left += e.clientX - popup.lastMouseLeft;
|
||||||
|
popup.lastMouseLeft = e.clientX;
|
||||||
|
popup.lastMouseTop = e.clientY;
|
||||||
|
isActionSuccess = true;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.props.status) {
|
||||||
|
this.props.status.popup.popups.forEach((popup) => {
|
||||||
|
if (popup.resizeDragDirection) {
|
||||||
|
|
||||||
|
let moveX = e.clientX - popup.lastMouseLeft;
|
||||||
|
let moveY = e.clientY - popup.lastMouseTop;
|
||||||
|
switch (popup.resizeDragDirection) {
|
||||||
|
|
||||||
|
case ResizeDragDirection.LeftTop:
|
||||||
|
this.resize(popup, moveX, false, false);
|
||||||
|
this.resize(popup, moveY, true, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResizeDragDirection.leftBottom:
|
||||||
|
this.resize(popup, moveX, false, false);
|
||||||
|
this.resize(popup, moveY, true, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResizeDragDirection.rightTop:
|
||||||
|
this.resize(popup, moveX, false, true);
|
||||||
|
this.resize(popup, moveY, true, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResizeDragDirection.rightBottom:
|
||||||
|
this.resize(popup, moveX, false, true);
|
||||||
|
this.resize(popup, moveY, true, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResizeDragDirection.top:
|
||||||
|
this.resize(popup, moveY, true, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResizeDragDirection.left:
|
||||||
|
this.resize(popup, moveX, false, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResizeDragDirection.bottom:
|
||||||
|
this.resize(popup, moveY, true, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ResizeDragDirection.right:
|
||||||
|
this.resize(popup, moveX, false, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!popup.isResizeOverFlowX) {
|
||||||
|
popup.lastMouseLeft = e.clientX;
|
||||||
|
}
|
||||||
|
if (!popup.isResizeOverFlowY) {
|
||||||
|
popup.lastMouseTop = e.clientY;
|
||||||
|
}
|
||||||
|
isActionSuccess = true;
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isActionSuccess) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
window.addEventListener("mousemove", this.handelMouseMove);
|
||||||
|
window.addEventListener("mousedown", this.handelMouseDown);
|
||||||
|
window.addEventListener("mouseup", this.handelMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
window.removeEventListener("mousemove", this.handelMouseMove);
|
||||||
|
window.removeEventListener("mousedown", this.handelMouseDown);
|
||||||
|
window.removeEventListener("mouseup", this.handelMouseUp);
|
||||||
|
}
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
return <>
|
return <>
|
||||||
{this.renderRootMask()}
|
{this.renderRootMask()}
|
||||||
|
@ -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 { Component, ReactNode, DetailedHTMLProps, HTMLAttributes } from "react";
|
||||||
import "./Theme.scss";
|
import "./Theme.scss";
|
||||||
|
|
||||||
@ -23,10 +23,31 @@ interface IThemeProps {
|
|||||||
backgroundLevel?: BackgroundLevel;
|
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<
|
class Theme extends Component<
|
||||||
IThemeProps & IMixinSettingProps & DetailedHTMLProps<
|
IThemeProps & IMixinSettingProps & DetailedHTMLProps<
|
||||||
HTMLAttributes<HTMLDivElement>, HTMLDivElement
|
HTMLAttributes<HTMLDivElement>, HTMLDivElement
|
||||||
@ -52,22 +73,7 @@ class Theme extends Component<
|
|||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
|
|
||||||
const setting = this.props.setting;
|
const setting = this.props.setting;
|
||||||
const classNameList: string[] = [];
|
const classNameList = getClassList(this.props, setting);
|
||||||
|
|
||||||
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 propsObj = {...this.props};
|
const propsObj = {...this.props};
|
||||||
delete propsObj.className;
|
delete propsObj.className;
|
||||||
@ -82,4 +88,4 @@ class Theme extends Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default Theme;
|
export default Theme;
|
||||||
export { Theme, FontLevel, BackgroundLevel };
|
export { Theme, FontLevel, BackgroundLevel, getClassList };
|
@ -15,6 +15,10 @@ div.toggles-input {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.checkbox.red:hover {
|
||||||
|
color: $lt-red !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.dark.text-field-root {
|
div.dark.text-field-root {
|
||||||
|
@ -8,6 +8,7 @@ interface ITogglesInputProps extends ITextFieldProps {
|
|||||||
onIconName?: string;
|
onIconName?: string;
|
||||||
offIconName?: string;
|
offIconName?: string;
|
||||||
valueChange?: (value: boolean) => any;
|
valueChange?: (value: boolean) => any;
|
||||||
|
red?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class TogglesInput extends Component<ITogglesInputProps> {
|
class TogglesInput extends Component<ITogglesInputProps> {
|
||||||
@ -20,7 +21,7 @@ class TogglesInput extends Component<ITogglesInputProps> {
|
|||||||
customStyle
|
customStyle
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="checkbox"
|
className={"checkbox" + (this.props.red ? " red" : "")}
|
||||||
style={{
|
style={{
|
||||||
cursor: this.props.disableI18n ? "not-allowed" : "pointer"
|
cursor: this.props.disableI18n ? "not-allowed" : "pointer"
|
||||||
}}
|
}}
|
||||||
|
@ -1,25 +1,48 @@
|
|||||||
import { ReactNode, createElement } from "react";
|
import { ReactNode, createElement } from "react";
|
||||||
import { Emitter } from "@Model/Emitter";
|
import { Emitter } from "@Model/Emitter";
|
||||||
import { Localization } from "@Component/Localization/Localization";
|
import { Localization } from "@Component/Localization/Localization";
|
||||||
|
import { IAnyObject } from "@Model/Renderer";
|
||||||
|
|
||||||
type IPopupConstructor = new (controller: PopupController, id: string) => Popup;
|
enum ResizeDragDirection {
|
||||||
|
top = 1,
|
||||||
|
rightTop = 2,
|
||||||
|
right = 3,
|
||||||
|
rightBottom = 4,
|
||||||
|
bottom = 5,
|
||||||
|
leftBottom = 6,
|
||||||
|
left = 7,
|
||||||
|
LeftTop = 8
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 弹窗类型
|
* 弹窗类型
|
||||||
*/
|
*/
|
||||||
class Popup {
|
class Popup<P extends IAnyObject = IAnyObject> {
|
||||||
|
|
||||||
|
public props: P;
|
||||||
|
|
||||||
|
public constructor(props: P) {
|
||||||
|
this.props = props;
|
||||||
|
}
|
||||||
|
|
||||||
public zIndex() {
|
public zIndex() {
|
||||||
return this.index * 2 + this.controller.zIndex;
|
return this.index * 5 + this.controller.zIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public width: number = 300;
|
public width: number = 300;
|
||||||
|
|
||||||
public height: number = 200;
|
public height: number = 200;
|
||||||
|
public minWidth: number = 300;
|
||||||
public top: number = 0;
|
public minHeight: number = 200;
|
||||||
|
public top: number = NaN;
|
||||||
public left: number = 0;
|
public left: number = NaN;
|
||||||
|
public lastMouseTop: number = 0;
|
||||||
|
public lastMouseLeft: number = 0;
|
||||||
|
public isOnMouseDown: boolean = false;
|
||||||
|
public resizeHoverDirection?: ResizeDragDirection;
|
||||||
|
public resizeDragDirection?: ResizeDragDirection;
|
||||||
|
public isResizeMouseDown: boolean = false;
|
||||||
|
public isResizeOverFlowX: boolean = false;
|
||||||
|
public isResizeOverFlowY: boolean = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否关闭
|
* 是否关闭
|
||||||
@ -39,23 +62,18 @@ class Popup {
|
|||||||
/**
|
/**
|
||||||
* 唯一标识符
|
* 唯一标识符
|
||||||
*/
|
*/
|
||||||
public id: string;
|
public id: string = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 控制器
|
* 控制器
|
||||||
*/
|
*/
|
||||||
public controller: PopupController;
|
public controller: PopupController = undefined as any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染层级
|
* 渲染层级
|
||||||
*/
|
*/
|
||||||
public index: number = Infinity;
|
public index: number = Infinity;
|
||||||
|
|
||||||
/**
|
|
||||||
* react 节点
|
|
||||||
*/
|
|
||||||
public reactNode: ReactNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染标题
|
* 渲染标题
|
||||||
*/
|
*/
|
||||||
@ -63,13 +81,6 @@ class Popup {
|
|||||||
return createElement(Localization, {i18nKey: "Popup.Title.Unnamed"});
|
return createElement(Localization, {i18nKey: "Popup.Title.Unnamed"});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 渲染函数
|
|
||||||
*/
|
|
||||||
public onRender(p: Popup): ReactNode {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关闭回调
|
* 关闭回调
|
||||||
*/
|
*/
|
||||||
@ -81,15 +92,14 @@ class Popup {
|
|||||||
* 渲染节点
|
* 渲染节点
|
||||||
*/
|
*/
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
this.reactNode = this.onRender(this);
|
return null;
|
||||||
return this.reactNode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public close() {
|
public close(): Popup | undefined {
|
||||||
return this.controller.closePopup(this);
|
return this.controller.closePopup(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(controller: PopupController, id: string) {
|
public init(controller: PopupController, id: string) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
@ -134,8 +144,16 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
|||||||
/**
|
/**
|
||||||
* 实例化并开启一个弹窗
|
* 实例化并开启一个弹窗
|
||||||
*/
|
*/
|
||||||
public showPopup<P extends IPopupConstructor>(popup?: P): Popup {
|
public showPopup<P extends IAnyObject, T extends Popup<P>>(
|
||||||
let newPopup = new (popup ?? Popup)(this, `P-${this.idIndex ++}`);
|
popup: (new (props: P) => T) | Popup<P>, props: P
|
||||||
|
): Popup<P> {
|
||||||
|
let newPopup: Popup<P>;
|
||||||
|
if (popup instanceof Popup) {
|
||||||
|
newPopup = popup;
|
||||||
|
} else {
|
||||||
|
newPopup = new (popup ?? Popup)(props);
|
||||||
|
}
|
||||||
|
newPopup.init(this, `P-${this.idIndex ++}`);
|
||||||
this.popups.push(newPopup);
|
this.popups.push(newPopup);
|
||||||
this.sortPopup();
|
this.sortPopup();
|
||||||
return newPopup;
|
return newPopup;
|
||||||
@ -172,4 +190,4 @@ class PopupController extends Emitter<IPopupControllerEvent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Popup, PopupController }
|
export { Popup, PopupController, ResizeDragDirection }
|
@ -45,6 +45,12 @@ const EN_US = {
|
|||||||
"Panel.Title.Group.Details.View": "Group",
|
"Panel.Title.Group.Details.View": "Group",
|
||||||
"Panel.Info.Group.Details.View": "Edit view group attributes",
|
"Panel.Info.Group.Details.View": "Edit view group attributes",
|
||||||
"Popup.Title.Unnamed": "Popup message",
|
"Popup.Title.Unnamed": "Popup message",
|
||||||
|
"Popup.Title.Confirm": "Confirm message",
|
||||||
|
"Popup.Action.Yes": "Confirm",
|
||||||
|
"Popup.Action.No": "Cancel",
|
||||||
|
"Popup.Action.Objects.Confirm.Title": "Confirm Delete",
|
||||||
|
"Popup.Action.Objects.Confirm.Delete": "Delete",
|
||||||
|
"Popup.Delete.Objects.Confirm": "Are you sure you want to delete this object(s)? The object is deleted and cannot be recalled.",
|
||||||
"Build.In.Label.Name.All.Group": "All group",
|
"Build.In.Label.Name.All.Group": "All group",
|
||||||
"Build.In.Label.Name.All.Range": "All range",
|
"Build.In.Label.Name.All.Range": "All range",
|
||||||
"Common.No.Data": "No Data",
|
"Common.No.Data": "No Data",
|
||||||
|
@ -45,6 +45,12 @@ const ZH_CN = {
|
|||||||
"Panel.Title.Group.Details.View": "群",
|
"Panel.Title.Group.Details.View": "群",
|
||||||
"Panel.Info.Group.Details.View": "编辑查看群属性",
|
"Panel.Info.Group.Details.View": "编辑查看群属性",
|
||||||
"Popup.Title.Unnamed": "弹窗消息",
|
"Popup.Title.Unnamed": "弹窗消息",
|
||||||
|
"Popup.Title.Confirm": "确认消息",
|
||||||
|
"Popup.Action.Yes": "确定",
|
||||||
|
"Popup.Action.No": "取消",
|
||||||
|
"Popup.Action.Objects.Confirm.Title": "删除确认",
|
||||||
|
"Popup.Action.Objects.Confirm.Delete": "删除",
|
||||||
|
"Popup.Delete.Objects.Confirm": "你确定要删除这个(些)对象吗?对象被删除将无法撤回。",
|
||||||
"Build.In.Label.Name.All.Group": "全部群",
|
"Build.In.Label.Name.All.Group": "全部群",
|
||||||
"Build.In.Label.Name.All.Range": "全部范围",
|
"Build.In.Label.Name.All.Range": "全部范围",
|
||||||
"Common.No.Data": "暂无数据",
|
"Common.No.Data": "暂无数据",
|
||||||
|
@ -10,6 +10,7 @@ import { Group, GenMod } from "@Model/Group";
|
|||||||
import { AllI18nKeys } from "@Component/Localization/Localization";
|
import { AllI18nKeys } from "@Component/Localization/Localization";
|
||||||
import { ComboInput, IDisplayItem } from "@Component/ComboInput/ComboInput";
|
import { ComboInput, IDisplayItem } from "@Component/ComboInput/ComboInput";
|
||||||
import { ObjectPicker } from "@Component/ObjectPicker/ObjectPicker";
|
import { ObjectPicker } from "@Component/ObjectPicker/ObjectPicker";
|
||||||
|
import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup";
|
||||||
import "./GroupDetails.scss";
|
import "./GroupDetails.scss";
|
||||||
|
|
||||||
interface IGroupDetailsProps {}
|
interface IGroupDetailsProps {}
|
||||||
@ -88,12 +89,21 @@ class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TogglesInput
|
<TogglesInput
|
||||||
keyI18n="Common.Attr.Key.Delete"
|
keyI18n="Common.Attr.Key.Delete" red
|
||||||
onIconName="delete" offIconName="delete"
|
onIconName="delete" offIconName="delete"
|
||||||
valueChange={() => {
|
valueChange={() => {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
this.props.status.model.deleteObject([group]);
|
const status = this.props.status;
|
||||||
this.props.status.setFocusObject(new Set());
|
status.popup.showPopup(ConfirmPopup, {
|
||||||
|
infoI18n: "Popup.Delete.Objects.Confirm",
|
||||||
|
titleI18N: "Popup.Action.Objects.Confirm.Title",
|
||||||
|
yesI18n: "Popup.Action.Objects.Confirm.Delete",
|
||||||
|
red: "yes",
|
||||||
|
yes: () => {
|
||||||
|
status.model.deleteObject([group]);
|
||||||
|
status.setFocusObject(new Set());
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -147,7 +157,7 @@ class GroupDetails extends Component<IGroupDetailsProps & IMixinStatusProps> {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TogglesInput
|
<TogglesInput
|
||||||
keyI18n="Common.Attr.Key.Generation"
|
keyI18n="Common.Attr.Key.Kill.Random"
|
||||||
onIconName="RemoveFilter" offIconName="RemoveFilter"
|
onIconName="RemoveFilter" offIconName="RemoveFilter"
|
||||||
valueChange={() => {
|
valueChange={() => {
|
||||||
group.killIndividuals()
|
group.killIndividuals()
|
||||||
|
@ -5,6 +5,7 @@ import { Message } from "@Component/Message/Message";
|
|||||||
import { ColorInput } from "@Component/ColorInput/ColorInput";
|
import { ColorInput } from "@Component/ColorInput/ColorInput";
|
||||||
import { Label } from "@Model/Label";
|
import { Label } from "@Model/Label";
|
||||||
import { TogglesInput } from "@Component/TogglesInput/TogglesInput";
|
import { TogglesInput } from "@Component/TogglesInput/TogglesInput";
|
||||||
|
import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup";
|
||||||
import "./LabelDetails.scss";
|
import "./LabelDetails.scss";
|
||||||
|
|
||||||
@useStatusWithEvent("focusLabelChange", "labelAttrChange", "labelChange")
|
@useStatusWithEvent("focusLabelChange", "labelAttrChange", "labelChange")
|
||||||
@ -27,10 +28,21 @@ class LabelDetails extends Component<IMixinStatusProps> {
|
|||||||
}
|
}
|
||||||
}}/>
|
}}/>
|
||||||
|
|
||||||
<TogglesInput keyI18n="Common.Attr.Key.Delete" onIconName="delete" offIconName="delete" valueChange={() => {
|
<TogglesInput
|
||||||
|
keyI18n="Common.Attr.Key.Delete" onIconName="delete" red
|
||||||
|
offIconName="delete" valueChange={() => {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
this.props.status.model.deleteLabel(label);
|
const status = this.props.status;
|
||||||
this.props.status.setLabelObject();
|
status.popup.showPopup(ConfirmPopup, {
|
||||||
|
infoI18n: "Popup.Delete.Objects.Confirm",
|
||||||
|
titleI18N: "Popup.Action.Objects.Confirm.Title",
|
||||||
|
yesI18n: "Popup.Action.Objects.Confirm.Delete",
|
||||||
|
red: "yes",
|
||||||
|
yes: () => {
|
||||||
|
status.model.deleteLabel(label);
|
||||||
|
status.setLabelObject();
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}}/>
|
}}/>
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
|||||||
import { useSetting, IMixinSettingProps } from "@Context/Setting";
|
import { useSetting, IMixinSettingProps } from "@Context/Setting";
|
||||||
import { Label } from "@Model/Label";
|
import { Label } from "@Model/Label";
|
||||||
import { Message } from "@Component/Message/Message";
|
import { Message } from "@Component/Message/Message";
|
||||||
|
import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup";
|
||||||
import "./LabelList.scss";
|
import "./LabelList.scss";
|
||||||
|
|
||||||
interface ILabelListProps {
|
interface ILabelListProps {
|
||||||
@ -47,8 +48,17 @@ class LabelList extends Component<ILabelListProps & IMixinStatusProps & IMixinSe
|
|||||||
}}
|
}}
|
||||||
deleteLabel={(label) => {
|
deleteLabel={(label) => {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
this.props.status.model.deleteLabel(label);
|
const status = this.props.status;
|
||||||
this.props.status.setLabelObject();
|
status.popup.showPopup(ConfirmPopup, {
|
||||||
|
infoI18n: "Popup.Delete.Objects.Confirm",
|
||||||
|
titleI18N: "Popup.Action.Objects.Confirm.Title",
|
||||||
|
yesI18n: "Popup.Action.Objects.Confirm.Delete",
|
||||||
|
red: "yes",
|
||||||
|
yes: () => {
|
||||||
|
status.model.deleteLabel(label);
|
||||||
|
status.setLabelObject();
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
this.labelInnerClick = true;
|
this.labelInnerClick = true;
|
||||||
}}
|
}}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { BackgroundLevel, FontLevel, Theme } from "@Component/Theme/Theme";
|
import { BackgroundLevel, FontLevel, Theme } from "@Component/Theme/Theme";
|
||||||
import { useStatus, IMixinStatusProps } from "../../Context/Status";
|
import { useStatus, IMixinStatusProps } from "../../Context/Status";
|
||||||
|
import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup";
|
||||||
import { Icon } from "@fluentui/react";
|
import { Icon } from "@fluentui/react";
|
||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { ObjectID } from "@Model/Renderer";
|
import { ObjectID } from "@Model/Renderer";
|
||||||
@ -54,15 +55,24 @@ class ObjectCommand extends Component<IMixinStatusProps> {
|
|||||||
<Icon iconName="CubeShape"></Icon>
|
<Icon iconName="CubeShape"></Icon>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="command-item"
|
className="command-item red"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (this.props.status) {
|
if (this.props.status && this.props.status.focusObject.size > 0) {
|
||||||
|
const status = this.props.status;
|
||||||
|
status.popup.showPopup(ConfirmPopup, {
|
||||||
|
infoI18n: "Popup.Delete.Objects.Confirm",
|
||||||
|
titleI18N: "Popup.Action.Objects.Confirm.Title",
|
||||||
|
yesI18n: "Popup.Action.Objects.Confirm.Delete",
|
||||||
|
red: "yes",
|
||||||
|
yes: () => {
|
||||||
let deleteId: ObjectID[] = [];
|
let deleteId: ObjectID[] = [];
|
||||||
this.props.status.focusObject.forEach((obj) => {
|
status.focusObject.forEach((obj) => {
|
||||||
deleteId.push(obj);
|
deleteId.push(obj);
|
||||||
})
|
})
|
||||||
this.props.status.model.deleteObject(deleteId);
|
status.model.deleteObject(deleteId);
|
||||||
this.props.status.setFocusObject(new Set<ObjectID>());
|
status.setFocusObject(new Set<ObjectID>());
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -59,6 +59,10 @@ div.object-list-command-bar {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.command-item.red:hover {
|
||||||
|
color: $lt-red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.dark.object-list-command-bar {
|
div.dark.object-list-command-bar {
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { AttrInput } from "@Component/AttrInput/AttrInput";
|
import { AttrInput } from "@Component/AttrInput/AttrInput";
|
||||||
import { useStatusWithEvent, IMixinStatusProps, Status } from "@Context/Status";
|
import { useStatusWithEvent, IMixinStatusProps, Status } from "@Context/Status";
|
||||||
import { AllI18nKeys } from "@Component/Localization/Localization";
|
|
||||||
import { Message } from "@Component/Message/Message";
|
import { Message } from "@Component/Message/Message";
|
||||||
import { Range } from "@Model/Range";
|
import { Range } from "@Model/Range";
|
||||||
import { ObjectID } from "@Model/Renderer";
|
import { ObjectID } from "@Model/Renderer";
|
||||||
import { ColorInput } from "@Component/ColorInput/ColorInput";
|
import { ColorInput } from "@Component/ColorInput/ColorInput";
|
||||||
import { TogglesInput } from "@Component/TogglesInput/TogglesInput";
|
import { TogglesInput } from "@Component/TogglesInput/TogglesInput";
|
||||||
import { LabelPicker } from "@Component/LabelPicker/LabelPicker";
|
import { LabelPicker } from "@Component/LabelPicker/LabelPicker";
|
||||||
|
import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup";
|
||||||
import "./RangeDetails.scss";
|
import "./RangeDetails.scss";
|
||||||
|
|
||||||
@useStatusWithEvent("rangeAttrChange", "focusObjectChange", "rangeLabelChange")
|
@useStatusWithEvent("rangeAttrChange", "focusObjectChange", "rangeLabelChange")
|
||||||
@ -53,12 +53,21 @@ class RangeDetails extends Component<IMixinStatusProps> {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TogglesInput
|
<TogglesInput
|
||||||
keyI18n="Common.Attr.Key.Delete"
|
keyI18n="Common.Attr.Key.Delete" red
|
||||||
onIconName="delete" offIconName="delete"
|
onIconName="delete" offIconName="delete"
|
||||||
valueChange={() => {
|
valueChange={() => {
|
||||||
if (this.props.status) {
|
if (this.props.status) {
|
||||||
this.props.status.model.deleteObject([range]);
|
const status = this.props.status;
|
||||||
this.props.status.setFocusObject(new Set());
|
status.popup.showPopup(ConfirmPopup, {
|
||||||
|
infoI18n: "Popup.Delete.Objects.Confirm",
|
||||||
|
titleI18N: "Popup.Action.Objects.Confirm.Title",
|
||||||
|
yesI18n: "Popup.Action.Objects.Confirm.Delete",
|
||||||
|
red: "yes",
|
||||||
|
yes: () => {
|
||||||
|
status.model.deleteObject([range]);
|
||||||
|
status.setFocusObject(new Set());
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user