Add label list component

This commit is contained in:
MrKBear 2022-03-09 17:23:57 +08:00
parent c86a856a32
commit 54a03181f1
13 changed files with 182 additions and 34 deletions

View File

@ -37,6 +37,7 @@ div.color-input-root {
div.color-box {
width: 12px;
height: 12px;
border-radius: 3px;
}
}

View File

@ -58,7 +58,13 @@ class CommandBar extends Component<ICommandBarProps & IMixinSettingProps & IMixi
}
})}
{this.getRenderButton({ iconName: "StepSharedAdd", i18NKey: "Command.Bar.Add.Behavior.Info" })}
{this.getRenderButton({ iconName: "Tag", i18NKey: "Command.Bar.Add.Tag.Info" })}
{this.getRenderButton({
iconName: "Tag",
i18NKey: "Command.Bar.Add.Tag.Info",
click: () => {
this.props.status ? this.props.status.newLabel() : undefined;
}
})}
{this.getRenderButton({ iconName: "Camera", i18NKey: "Command.Bar.Camera.Info" })}
</div>
<div>

View File

@ -0,0 +1,64 @@
@import "../Theme/Theme.scss";
div.label {
width: auto;
height: auto;
display: inline-flex;
margin: 5px 5px;
justify-content: center;
vertical-align: middle;
align-items: stretch;
border-radius: 3px;
border: .5px solid transparent;
overflow: hidden;
user-select: none;
cursor: pointer;
div.label-color {
width: 3px;
margin-right: 2px;
border-radius: 3px;
flex-shrink: 0;
}
div.label-name {
padding: 2px 3px;
text-overflow: ellipsis;
overflow: hidden;
}
div.delete-button {
padding: 2px 3px;
border-radius: 3px;
display: flex;
align-items: center;
user-select: none;
cursor: pointer;
}
}
div.dark.label {
background-color: $lt-bg-color-lvl3-dark;
div.label-color {
color: $lt-bg-color-lvl3-dark;
}
div.delete-button:hover {
color: $lt-font-color-lvl2-dark;
background-color: $lt-bg-color-lvl2-dark;
}
}
div.light.label {
background-color: $lt-bg-color-lvl3-light;
div.label-color {
color: $lt-bg-color-lvl3-light;
}
div.delete-button:hover {
color: $lt-font-color-lvl2-light;
background-color: $lt-bg-color-lvl2-light;
}
}

View File

@ -0,0 +1,56 @@
import { Component } from "react";
import { Label } from "@Model/Label";
import { Icon } from "@fluentui/react";
import { useSetting, IMixinSettingProps, Themes } from "@Context/Setting";
import "./LabelList.scss";
interface ILabelListProps {
labels: Label[];
canDelete?: boolean;
}
interface ILabelListState {
focusLabel?: Label;
}
@useSetting
class LabelList extends Component<ILabelListProps & IMixinSettingProps, ILabelListState> {
public state: Readonly<ILabelListState> = {
focusLabel: undefined
};
private renderLabel(label: Label) {
const theme = this.props.setting?.themes ?? Themes.dark;
const themeClassName = theme === Themes.dark ? "dark" : "light";
const colorCss = `rgb(${label.color.join(",")})`;
return <div className={`label ${themeClassName}`} key={label.id}>
<div className="label-color" style={{
backgroundColor: colorCss
}}/>
<div className="label-name">
{label.name}
</div>
{
this.props.canDelete ?
<div className="delete-button">
<Icon iconName="delete"></Icon>
</div> : null
}
</div>
}
public render() {
return <>
{
this.props.labels.map((label) => {
return this.renderLabel(label);
})
}
</>
}
}
export { LabelList };

View File

@ -8,12 +8,18 @@ import { ClassicRenderer, MouseMod } from "@GLRender/ClassicRenderer";
import { Setting } from "./Setting";
import { I18N } from "@Component/Localization/Localization";
function randomColor() {
return [
function randomColor(unNormal: boolean = false) {
const color = [
Math.random() * .8 + .2,
Math.random() * .8 + .2,
Math.random() * .8 + .2, 1
]
if (unNormal) {
color[0] = Math.round(color[0] * 255),
color[1] = Math.round(color[1] * 255),
color[2] = Math.round(color[2] * 255)
}
return color;
}
interface IStatusEvent {
@ -34,6 +40,7 @@ class Status extends Emitter<IStatusEvent> {
*
*/
public objectNameIndex = 1;
public labelNameIndex = 1;
/**
*
@ -123,6 +130,17 @@ class Status extends Emitter<IStatusEvent> {
return range;
}
public newLabel() {
const label = this.model.addLabel(
I18N(this.setting.language, "Object.List.New.Label", {
id: this.labelNameIndex.toString()
})
);
label.color = randomColor(true);
this.labelNameIndex ++;
return label;
}
public setMouseMod(mod: MouseMod) {
this.mouseMod = mod;
if (this.renderer instanceof ClassicRenderer) {

View File

@ -25,6 +25,7 @@ const EN_US = {
"Input.Error.Length": "The length of the input content must be less than {num}",
"Object.List.New.Group": "Group object {id}",
"Object.List.New.Range": "Range object {id}",
"Object.List.New.Label": "Label {id}",
"Object.List.No.Data": "There are no objects in the model, click the button to create it",
"Panel.Title.Notfound": "{id}",
"Panel.Info.Notfound": "This panel with id {id} can not found!",

View File

@ -25,6 +25,7 @@ const ZH_CN = {
"Input.Error.Length": "输入内容长度须小于 {number}",
"Object.List.New.Group": "组对象 {id}",
"Object.List.New.Range": "范围对象 {id}",
"Object.List.New.Label": "标签 {id}",
"Object.List.No.Data": "模型中没有任何对象,点击按钮以创建",
"Panel.Title.Notfound": "{id}",
"Panel.Info.Notfound": "这个编号为 {id} 的面板无法找到!",

View File

@ -14,12 +14,12 @@ class Label {
/**
*
*/
public name?: string;
public name: string = "";
/**
* CSS
*/
public color?: string;
public color: number[] = [0, 0, 0];
/**
*
@ -31,10 +31,10 @@ class Label {
* @param id ID
* @param name
*/
public constructor(model:Model, id: ObjectID, name?: string) {
public constructor(model: Model, id: ObjectID, name?: string) {
this.model = model;
this.id = id;
this.name = name;
this.name = name ?? this.name;
}
/**

View File

@ -51,6 +51,8 @@ class SimulatorWeb extends Component {
individual.position[2] = (Math.random() - .5) * 2;
})
this.status.model.update(0);
this.status.newLabel().name = "New Label";
this.status.newLabel().name = "Test Label 01";
}
(window as any).s = this;

View File

@ -1,3 +1,4 @@
@import "../../Component/Theme/Theme.scss";
div.label-list-command-bar {
width: 100%;
@ -15,4 +16,18 @@ div.label-list-command-bar {
user-select: none;
cursor: pointer;
}
}
div.dark.label-list-command-bar {
div.command-item:hover {
background-color: $lt-bg-color-lvl3-dark;
}
}
div.light.label-list-command-bar {
div.command-item:hover {
background-color: $lt-bg-color-lvl3-light;
}
}

View File

@ -1,15 +1,23 @@
import { Theme } from "@Component/Theme/Theme";
import { LabelList as LabelListComponent } from "@Component/LabelList/LabelList";
import { Component } from "react";
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
import { Label } from "@Model/Label";
import "./LabelList.scss";
interface ILabelListProps {
}
class LabelList extends Component<ILabelListProps> {
@useStatusWithEvent("labelChange")
class LabelList extends Component<ILabelListProps & IMixinStatusProps> {
public render() {
return <Theme>LabelList</Theme>
let labels: Label[] = [];
if (this.props.status) {
labels = this.props.status.model.labelPool.concat([]);
}
return <LabelListComponent labels={labels} canDelete/>
}
}

View File

@ -1,23 +0,0 @@
import { BackgroundLevel, FontLevel, Theme } from "@Component/Theme/Theme";
import { Icon } from "@fluentui/react";
import { Component } from "react";
import "./LabelList.scss";
interface ILabelListCommandProps {}
class LabelListCommand extends Component<ILabelListCommandProps> {
public render() {
return <Theme
className="label-list-command-bar"
backgroundLevel={BackgroundLevel.Level4}
fontLevel={FontLevel.normal}
>
<div className="command-item">
<Icon iconName="Tag"></Icon>
</div>
</Theme>
}
}
export { LabelListCommand };

View File

@ -6,7 +6,6 @@ import { ObjectList } from "./ObjectList/ObjectList";
import { ObjectCommand } from "./ObjectList/ObjectCommand";
import { RangeDetails } from "./RangeDetails/RangeDetails";
import { LabelList } from "./LabelList/LabelList";
import { LabelListCommand } from "./LabelList/LabelListCommand";
interface IPanelInfo {
nameKey: string;
@ -41,7 +40,7 @@ PanelInfoMap.set("RangeDetails", {
})
PanelInfoMap.set("LabelList", {
nameKey: "Panel.Title.Label.List.View", introKay: "Panel.Info.Label.List.View",
class: LabelList, header: LabelListCommand, hidePadding: true
class: LabelList
})
function getPanelById(panelId: PanelId): ReactNode {