improved settings layout and UX, added bake button, fixed icons, added icon colours, improved BoolBox appearance, added snowflake icon, removed unused BeatLikeLoopSettings, added disabled buttons
This commit is contained in:
@@ -1,98 +0,0 @@
|
|||||||
import "./BeatLikeLoopSettings.css";
|
|
||||||
import BeatLike from "@/BeatLike";
|
|
||||||
import NumberInputView from "@/ui/Widgets/NumberInput/NumberInputView";
|
|
||||||
import ISubscriber from "@/Subscriber";
|
|
||||||
import UINode, {UINodeOptions} from "@/ui/UINode";
|
|
||||||
import {BeatEvents} from "@/Beat";
|
|
||||||
import {IPublisher} from "@/Publisher";
|
|
||||||
import BoolBoxView from "@/ui/Widgets/BoolBox/BoolBoxView";
|
|
||||||
|
|
||||||
export type BeatLikeLoopSettingsViewUINodeOptions = UINodeOptions & {
|
|
||||||
beatLike: BeatLike,
|
|
||||||
title?: string,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class BeatLikeLoopSettingsView extends UINode implements ISubscriber {
|
|
||||||
private beatLike: BeatLike;
|
|
||||||
private loopLengthInput!: NumberInputView;
|
|
||||||
private loopCheckbox!: BoolBoxView;
|
|
||||||
private loopLengthSection!: HTMLDivElement;
|
|
||||||
private title: string;
|
|
||||||
|
|
||||||
constructor(options: BeatLikeLoopSettingsViewUINodeOptions) {
|
|
||||||
super(options);
|
|
||||||
this.beatLike = options.beatLike;
|
|
||||||
this.title = options.title ?? "Looping settings:";
|
|
||||||
this.setupBindings();
|
|
||||||
}
|
|
||||||
|
|
||||||
private setupBindings() {
|
|
||||||
this.beatLike.addSubscriber(this, [
|
|
||||||
BeatEvents.LoopLengthChanged,
|
|
||||||
BeatEvents.DisplayTypeChanged
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
notify<T extends string | number>(publisher: IPublisher<T> | null, event: "all" | T[] | T): void {
|
|
||||||
if (event === BeatEvents.LoopLengthChanged) {
|
|
||||||
this.loopLengthInput.setValue(this.beatLike.getLoopLength());
|
|
||||||
} else if (event === BeatEvents.DisplayTypeChanged) {
|
|
||||||
this.loopCheckbox.setValue(this.beatLike.isLooping());
|
|
||||||
if (this.beatLike.isLooping()) {
|
|
||||||
this.loopLengthSection.classList.remove("hide");
|
|
||||||
} else {
|
|
||||||
this.loopLengthSection.classList.add("hide");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setBeatLike(beatLike: BeatLike): void {
|
|
||||||
this.beatLike = beatLike;
|
|
||||||
this.notify(null, BeatEvents.LoopLengthChanged);
|
|
||||||
this.notify(null, BeatEvents.DisplayTypeChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
build(): HTMLElement {
|
|
||||||
this.loopLengthInput = new NumberInputView({
|
|
||||||
initialValue: this.beatLike.getLoopLength(),
|
|
||||||
label: "Length:",
|
|
||||||
onDecrement: () => this.beatLike.setLoopLength(this.beatLike.getLoopLength() - 1),
|
|
||||||
onIncrement: () => this.beatLike.setLoopLength(this.beatLike.getLoopLength() + 1),
|
|
||||||
onNewInput: (input: number) => this.beatLike.setLoopLength(input),
|
|
||||||
});
|
|
||||||
this.loopCheckbox = new BoolBoxView({
|
|
||||||
label: "On:",
|
|
||||||
value: this.beatLike.isLooping(),
|
|
||||||
onInput: (isChecked: boolean) => this.beatLike.setLooping(isChecked),
|
|
||||||
});
|
|
||||||
this.loopLengthSection = UINode.make("div", {
|
|
||||||
classes: ["loop-settings-option"],
|
|
||||||
subs: [
|
|
||||||
this.loopLengthInput.render(),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
if (this.beatLike.isLooping()) {
|
|
||||||
this.loopLengthSection.classList.remove("hide");
|
|
||||||
} else {
|
|
||||||
this.loopLengthSection.classList.add("hide");
|
|
||||||
}
|
|
||||||
return UINode.make("div", {
|
|
||||||
classes: ["loop-settings"],
|
|
||||||
subs: [
|
|
||||||
UINode.make("p", {innerText: this.title}),
|
|
||||||
UINode.make("div", {
|
|
||||||
classes: ["loop-settings-option-group"],
|
|
||||||
subs: [
|
|
||||||
UINode.make("div", {
|
|
||||||
classes: ["loop-settings-option"],
|
|
||||||
subs: [
|
|
||||||
this.loopCheckbox.render(),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
this.loopLengthSection,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +1,40 @@
|
|||||||
.beat-settings {
|
.beat-settings {
|
||||||
margin-bottom: 0.5em;
|
|
||||||
display: flex;
|
}
|
||||||
|
|
||||||
|
.beat-settings-title-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-settings-title {
|
||||||
|
width: 100%;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0.5em;
|
||||||
|
transition: background-color 200ms;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-settings-title:hover {
|
||||||
|
background-color: var(--color-ui-neutral-dark-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-settings-lower {
|
||||||
height: 3.5em;
|
height: 3.5em;
|
||||||
|
display: flex;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
.beat-settings-lower > * {
|
||||||
.beat-settings > * {
|
|
||||||
margin-right: 0.2em;
|
margin-right: 0.2em;
|
||||||
}
|
}
|
||||||
.beat-settings:last-child {
|
|
||||||
|
.beat-settings-lower:last-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.beat-settings-time-sig-up {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-settings-time-sig-down {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-settings-option {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-settings-option-group {
|
|
||||||
align-self: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-settings-time-sig input {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-settings-name-field {
|
|
||||||
width: 5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-settings .loop-settings {
|
.beat-settings .loop-settings {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
flex: auto;
|
flex: auto;
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ export type BeatSettingsViewUINodeOptions = UINodeOptions & {
|
|||||||
|
|
||||||
export default class BeatSettingsView extends UINode implements ISubscriber {
|
export default class BeatSettingsView extends UINode implements ISubscriber {
|
||||||
private beat: Beat;
|
private beat: Beat;
|
||||||
private nameInput!: HTMLInputElement;
|
|
||||||
private deleteButton!: ActionButtonView;
|
|
||||||
private loopLengthInput!: NumberInputView;
|
private loopLengthInput!: NumberInputView;
|
||||||
|
private bakeButton!: ActionButtonView;
|
||||||
private loopCheckbox!: BoolBoxView;
|
private loopCheckbox!: BoolBoxView;
|
||||||
private loopLengthSection!: HTMLDivElement;
|
private loopLengthSection!: HTMLDivElement;
|
||||||
private sub!: ISubscription;
|
private sub!: ISubscription;
|
||||||
|
private titleInput!: HTMLInputElement;
|
||||||
|
private titleDisplay!: HTMLSpanElement;
|
||||||
|
private editingTitle: boolean;
|
||||||
|
|
||||||
constructor(options: BeatSettingsViewUINodeOptions) {
|
constructor(options: BeatSettingsViewUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
|
this.editingTitle = false;
|
||||||
this.beat = options.beat;
|
this.beat = options.beat;
|
||||||
this.setupBindings();
|
this.setupBindings();
|
||||||
}
|
}
|
||||||
@@ -41,11 +44,13 @@ export default class BeatSettingsView extends UINode implements ISubscriber {
|
|||||||
|
|
||||||
notify<T extends string | number>(publisher: IPublisher<T> | null, event: "all" | T[] | T): void {
|
notify<T extends string | number>(publisher: IPublisher<T> | null, event: "all" | T[] | T): void {
|
||||||
if (event === BeatEvents.NewName) {
|
if (event === BeatEvents.NewName) {
|
||||||
this.nameInput.value = this.beat.getName();
|
this.titleInput.value = this.beat.getName();
|
||||||
|
this.titleDisplay.innerText = this.beat.getName();
|
||||||
} else if (event === BeatEvents.LoopLengthChanged) {
|
} else if (event === BeatEvents.LoopLengthChanged) {
|
||||||
this.loopLengthInput.setValue(this.beat.getLoopLength());
|
this.loopLengthInput.setValue(this.beat.getLoopLength());
|
||||||
} else if (event === BeatEvents.DisplayTypeChanged) {
|
} else if (event === BeatEvents.DisplayTypeChanged) {
|
||||||
this.loopCheckbox.setValue(this.beat.isLooping());
|
this.loopCheckbox.setValue(this.beat.isLooping());
|
||||||
|
this.bakeButton.setDisabled(!this.beat.isLooping());
|
||||||
if (this.beat.isLooping()) {
|
if (this.beat.isLooping()) {
|
||||||
this.loopLengthSection.classList.remove("hide");
|
this.loopLengthSection.classList.remove("hide");
|
||||||
} else {
|
} else {
|
||||||
@@ -55,16 +60,34 @@ export default class BeatSettingsView extends UINode implements ISubscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
build(): HTMLElement {
|
build(): HTMLElement {
|
||||||
this.nameInput = UINode.make("input", {
|
this.titleInput = UINode.make("input", {
|
||||||
value: this.beat.getName(),
|
value: this.beat.getName(),
|
||||||
classes: ["beat-settings-name-field"],
|
classes: ["beat-settings-title-input"],
|
||||||
type: "text",
|
type: "text",
|
||||||
oninput: (event: Event) => this.beat.setName((event.target as HTMLInputElement).value),
|
oninput: (event: Event) => {
|
||||||
|
this.beat.setName((event.target as HTMLInputElement).value);
|
||||||
|
},
|
||||||
|
onblur: () => this.titleInput.replaceWith(this.titleDisplay),
|
||||||
|
onkeyup: (event: KeyboardEvent) => {
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
(event.target as HTMLInputElement).blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.deleteButton = new ActionButtonView({
|
this.titleDisplay = UINode.make("div", {
|
||||||
icon: "trash",
|
innerText: this.beat.getName(),
|
||||||
|
classes: ["beat-settings-title"],
|
||||||
|
onclick: () => {
|
||||||
|
this.titleDisplay.replaceWith(this.titleInput);
|
||||||
|
this.titleInput.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.bakeButton = new ActionButtonView({
|
||||||
|
icon: "snowflake",
|
||||||
type: "secondary",
|
type: "secondary",
|
||||||
onClick: () => this.beat.delete(),
|
alt: "Bake Loops",
|
||||||
|
disabled: !this.beat.isLooping(),
|
||||||
|
onClick: () => this.beat.bakeLoops(),
|
||||||
});
|
});
|
||||||
this.loopLengthInput = new NumberInputView({
|
this.loopLengthInput = new NumberInputView({
|
||||||
initialValue: this.beat.getLoopLength(),
|
initialValue: this.beat.getLoopLength(),
|
||||||
@@ -91,7 +114,17 @@ export default class BeatSettingsView extends UINode implements ISubscriber {
|
|||||||
return UINode.make("div", {
|
return UINode.make("div", {
|
||||||
classes: ["beat-settings"],
|
classes: ["beat-settings"],
|
||||||
subs: [
|
subs: [
|
||||||
this.nameInput,
|
this.titleDisplay,
|
||||||
|
UINode.make("div", {
|
||||||
|
classes: ["beat-settings-lower"],
|
||||||
|
subs: [
|
||||||
|
this.bakeButton.render(),
|
||||||
|
new ActionButtonView({
|
||||||
|
icon: "trash",
|
||||||
|
type: "secondary",
|
||||||
|
alt: "Delete Track",
|
||||||
|
onClick: () => this.beat.delete(),
|
||||||
|
}).render(),
|
||||||
UINode.make("div", {
|
UINode.make("div", {
|
||||||
classes: ["loop-settings"],
|
classes: ["loop-settings"],
|
||||||
subs: [
|
subs: [
|
||||||
@@ -99,7 +132,8 @@ export default class BeatSettingsView extends UINode implements ISubscriber {
|
|||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
this.loopLengthSection,
|
this.loopLengthSection,
|
||||||
this.deleteButton.render(),
|
]
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ export default class RootView extends UINode {
|
|||||||
subs: [
|
subs: [
|
||||||
UINode.make("div", {
|
UINode.make("div", {
|
||||||
classes: ["root-hamburger"],
|
classes: ["root-hamburger"],
|
||||||
subs: [new IconView({iconName: "list"}).render()],
|
subs: [new IconView({iconName: "list", color: "var(--color-ui-neutral-dark)"}).render()],
|
||||||
onclick: () => this.toggleSidebar(),
|
onclick: () => this.toggleSidebar(),
|
||||||
}),
|
}),
|
||||||
UINode.make("div", {
|
UINode.make("div", {
|
||||||
classes: ["root-switch-mode"],
|
classes: ["root-switch-mode"],
|
||||||
subs: [new IconView({iconName: "arrowClockwise"}).render()],
|
subs: [new IconView({iconName: "arrowClockwise", color: "var(--color-ui-neutral-dark)"}).render()],
|
||||||
onclick: () => this.toggleOrientation(),
|
onclick: () => this.toggleOrientation(),
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,17 +5,20 @@
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-button.disabled {
|
||||||
|
cursor: default;
|
||||||
|
opacity: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.action-button.action-button-primary {
|
.action-button.action-button-primary {
|
||||||
background-color: var(--color-ui-accent);
|
background-color: var(--color-ui-accent);
|
||||||
color: var(--color-p-light);
|
color: var(--color-p-light);
|
||||||
}
|
}
|
||||||
|
.action-button.action-button-primary:hover:not.disabled {
|
||||||
.action-button.action-button-primary:hover {
|
|
||||||
background-color: var(--color-ui-accent-hover);
|
background-color: var(--color-ui-accent-hover);
|
||||||
color: var(--color-p-light-hover);
|
color: var(--color-p-light-hover);
|
||||||
}
|
}
|
||||||
|
.action-button.action-button-primary:active:not.disabled {
|
||||||
.action-button.action-button-primary:active {
|
|
||||||
background-color: var(--color-ui-accent-active);
|
background-color: var(--color-ui-accent-active);
|
||||||
color: var(--color-p-light-active);
|
color: var(--color-p-light-active);
|
||||||
}
|
}
|
||||||
@@ -24,13 +27,11 @@
|
|||||||
background-color: var(--color-ui-neutral-dark);
|
background-color: var(--color-ui-neutral-dark);
|
||||||
color: var(--color-p-light);
|
color: var(--color-p-light);
|
||||||
}
|
}
|
||||||
|
.action-button.action-button-secondary:hover:not.disabled {
|
||||||
.action-button.action-button-secondary:hover {
|
|
||||||
background-color: var(--color-ui-neutral-dark-hover);
|
background-color: var(--color-ui-neutral-dark-hover);
|
||||||
color: var(--color-p-light-hover);
|
color: var(--color-p-light-hover);
|
||||||
}
|
}
|
||||||
|
.action-button.action-button-secondary:active:not.disabled {
|
||||||
.action-button.action-button-secondary:active {
|
|
||||||
background-color: var(--color-ui-neutral-dark-active);
|
background-color: var(--color-ui-neutral-dark-active);
|
||||||
color: var(--color-p-light-active);
|
color: var(--color-p-light-active);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import IconView, {IconName} from "@/ui/Widgets/Icon/IconView";
|
|||||||
|
|
||||||
export type ActionButtonUINodeOptions = UINodeOptions & {
|
export type ActionButtonUINodeOptions = UINodeOptions & {
|
||||||
type?: "primary" | "secondary",
|
type?: "primary" | "secondary",
|
||||||
onClick?: (isChecked: boolean) => void,
|
onClick?: (event: MouseEvent) => void,
|
||||||
|
alt?: string,
|
||||||
|
disabled?: boolean,
|
||||||
} & ({
|
} & ({
|
||||||
icon: IconName,
|
icon: IconName,
|
||||||
label?: never,
|
label?: never,
|
||||||
@@ -17,8 +19,10 @@ export default class ActionButtonView extends UINode {
|
|||||||
private label: string | null = null;
|
private label: string | null = null;
|
||||||
private icon: IconName | null = null;
|
private icon: IconName | null = null;
|
||||||
private buttonElement!: HTMLButtonElement;
|
private buttonElement!: HTMLButtonElement;
|
||||||
private onClick: (isChecked: boolean) => void;
|
private onClick: (event: MouseEvent) => void;
|
||||||
private type: "primary" | "secondary";
|
private type: "primary" | "secondary";
|
||||||
|
private alt: string | null;
|
||||||
|
private disabled: boolean;
|
||||||
|
|
||||||
constructor(options: ActionButtonUINodeOptions) {
|
constructor(options: ActionButtonUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -27,22 +31,41 @@ export default class ActionButtonView extends UINode {
|
|||||||
} else if (typeof options.label !== "undefined") {
|
} else if (typeof options.label !== "undefined") {
|
||||||
this.label = options.label;
|
this.label = options.label;
|
||||||
}
|
}
|
||||||
|
this.disabled = options.disabled ?? false;
|
||||||
|
this.alt = options.alt ?? null;
|
||||||
this.type = options.type ?? "primary";
|
this.type = options.type ?? "primary";
|
||||||
this.onClick = options.onClick ?? (() => { /* dummy */ });
|
this.onClick = options.onClick ?? (() => { /* dummy */ });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDisabled(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
this.buttonElement.disabled = this.disabled;
|
||||||
|
if (isDisabled) {
|
||||||
|
this.buttonElement.classList.add("disabled");
|
||||||
|
} else {
|
||||||
|
this.buttonElement.classList.remove("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected build(): HTMLButtonElement {
|
protected build(): HTMLButtonElement {
|
||||||
this.buttonElement = UINode.make("button", {
|
this.buttonElement = UINode.make("button", {
|
||||||
classes: ["action-button", `action-button-${this.type}`],
|
classes: ["action-button", `action-button-${this.type}`],
|
||||||
onclick: this.onClick,
|
onclick: (event: MouseEvent) => this.disabled || this.onClick(event),
|
||||||
subs: [
|
subs: [
|
||||||
this.icon !== null ? new IconView({
|
this.icon !== null ? new IconView({
|
||||||
iconName: this.icon
|
iconName: this.icon,
|
||||||
|
color: "var(--color-p-light)",
|
||||||
}).render() : UINode.make("span", {
|
}).render() : UINode.make("span", {
|
||||||
innerText: this.label ?? ""
|
innerText: this.label ?? ""
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
if (this.alt) {
|
||||||
|
this.buttonElement.title = this.alt;
|
||||||
|
}
|
||||||
|
if (this.disabled) {
|
||||||
|
this.buttonElement.classList.add("disabled");
|
||||||
|
}
|
||||||
return this.buttonElement;
|
return this.buttonElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
.bool-box {
|
.bool-box {
|
||||||
height: 1.1em;
|
height: 1.5em;
|
||||||
|
position: relative;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin: 0.5em;
|
line-height: 1.5em;
|
||||||
line-height: 1em;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bool-box-label {
|
.bool-box-label {
|
||||||
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
top: -0.33em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.bool-box-checkbox[type="checkbox"] {
|
input.bool-box-checkbox[type="checkbox"] {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 2em;
|
width: 3em;
|
||||||
height: 1em;
|
height: 1.5em;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
top: 0.1em;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
@@ -27,9 +29,10 @@ input.bool-box-checkbox[type="checkbox"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input.bool-box-checkbox[type="checkbox"]::before {
|
input.bool-box-checkbox[type="checkbox"]::before {
|
||||||
width: 2em;
|
top: 0.3em;
|
||||||
height: 1em;
|
left: 0.3em;
|
||||||
margin: 0.1em;
|
width: 2.3em;
|
||||||
|
height: 0.9em;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
background-color: var(--color-ui-accent-active);
|
background-color: var(--color-ui-accent-active);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -46,21 +49,19 @@ input.bool-box-checkbox[type="checkbox"]:checked::before {
|
|||||||
input.bool-box-checkbox[type="checkbox"]::after {
|
input.bool-box-checkbox[type="checkbox"]::after {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 1.2em;
|
width: 1.35em;
|
||||||
height: 1.2em;
|
height: 1.35em;
|
||||||
border-radius: 1em;
|
border-radius: 100%;
|
||||||
border-color: var(--color-ui-neutral-dark);
|
|
||||||
border-width: 0.075em;
|
|
||||||
border-style: solid;
|
|
||||||
background-color: var(--color-ui-neutral-dark);
|
background-color: var(--color-ui-neutral-dark);
|
||||||
display: block;
|
display: block;
|
||||||
content: "";
|
content: "";
|
||||||
left: -0.05em;
|
top: 0.075em;
|
||||||
|
left: 0.025em;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
transition: left 200ms, background-color 200ms;
|
transition: left 200ms, background-color 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.bool-box-checkbox[type="checkbox"]:checked::after {
|
input.bool-box-checkbox[type="checkbox"]:checked::after {
|
||||||
left: 1.1em;
|
left: 1.575em;
|
||||||
background-color: var(--color-ui-neutral-light);
|
background-color: var(--color-ui-neutral-light);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
.icon-view {
|
.icon-view {
|
||||||
|
--icon-bg: black;
|
||||||
width: 2em;
|
width: 2em;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
-webkit-mask-size: 2em;
|
-webkit-mask-size: 2em;
|
||||||
mask-size: 2em;
|
mask-size: 2em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: black;
|
background-color: var(--icon-bg);
|
||||||
}
|
}
|
||||||
@@ -3,24 +3,29 @@ import "./Icon.css";
|
|||||||
import List from "./svgs/list.svg";
|
import List from "./svgs/list.svg";
|
||||||
import ArrowClockwise from "./svgs/arrow-clockwise.svg";
|
import ArrowClockwise from "./svgs/arrow-clockwise.svg";
|
||||||
import Trash from "./svgs/trash.svg";
|
import Trash from "./svgs/trash.svg";
|
||||||
|
import Snowflake from "./svgs/snowflake.svg";
|
||||||
|
|
||||||
const IconUrlMap = {
|
const IconUrlMap = {
|
||||||
arrowClockwise: ArrowClockwise,
|
arrowClockwise: ArrowClockwise,
|
||||||
list: List,
|
list: List,
|
||||||
trash: Trash,
|
trash: Trash,
|
||||||
|
snowflake: Snowflake,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type IconName = keyof typeof IconUrlMap;
|
export type IconName = keyof typeof IconUrlMap;
|
||||||
|
|
||||||
export type IconViewOptions = UINodeOptions & {
|
export type IconViewOptions = UINodeOptions & {
|
||||||
iconName: IconName,
|
iconName: IconName,
|
||||||
|
color?: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class IconView extends UINode {
|
export default class IconView extends UINode {
|
||||||
private iconUrl: string;
|
private iconUrl: string;
|
||||||
|
private color: string | null;
|
||||||
|
|
||||||
constructor(options: IconViewOptions) {
|
constructor(options: IconViewOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
|
this.color = options.color ?? null;
|
||||||
this.iconUrl = IconUrlMap[options.iconName];
|
this.iconUrl = IconUrlMap[options.iconName];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +33,8 @@ export default class IconView extends UINode {
|
|||||||
const icon = UINode.make("div", {
|
const icon = UINode.make("div", {
|
||||||
classes: ["icon-view"],
|
classes: ["icon-view"],
|
||||||
});
|
});
|
||||||
icon.style.cssText = `-webkit-mask-image: url(${this.iconUrl}); mask-image: url(${this.iconUrl});`;
|
const colorString = this.color ? `--icon-bg:${this.color}` : "";
|
||||||
|
icon.style.cssText = `-webkit-mask-image: url(${this.iconUrl}); mask-image: url(${this.iconUrl});${colorString}`;
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
3
src/ui/Widgets/Icon/svgs/snowflake.svg
Normal file
3
src/ui/Widgets/Icon/svgs/snowflake.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-snow2" viewBox="0 0 16 16">
|
||||||
|
<path d="M8 16a.5.5 0 0 1-.5-.5v-1.293l-.646.647a.5.5 0 0 1-.707-.708L7.5 12.793v-1.086l-.646.647a.5.5 0 0 1-.707-.708L7.5 10.293V8.866l-1.236.713-.495 1.85a.5.5 0 1 1-.966-.26l.237-.882-.94.542-.496 1.85a.5.5 0 1 1-.966-.26l.237-.882-1.12.646a.5.5 0 0 1-.5-.866l1.12-.646-.884-.237a.5.5 0 1 1 .26-.966l1.848.495.94-.542-.882-.237a.5.5 0 1 1 .258-.966l1.85.495L7 8l-1.236-.713-1.849.495a.5.5 0 1 1-.258-.966l.883-.237-.94-.542-1.85.495a.5.5 0 0 1-.258-.966l.883-.237-1.12-.646a.5.5 0 1 1 .5-.866l1.12.646-.237-.883a.5.5 0 0 1 .966-.258l.495 1.849.94.542-.236-.883a.5.5 0 0 1 .966-.258l.495 1.849 1.236.713V5.707L6.147 4.354a.5.5 0 1 1 .707-.708l.646.647V3.207L6.147 1.854a.5.5 0 1 1 .707-.708l.646.647V.5a.5.5 0 0 1 1 0v1.293l.647-.647a.5.5 0 1 1 .707.708L8.5 3.207v1.086l.647-.647a.5.5 0 1 1 .707.708L8.5 5.707v1.427l1.236-.713.495-1.85a.5.5 0 1 1 .966.26l-.236.882.94-.542.495-1.85a.5.5 0 1 1 .966.26l-.236.882 1.12-.646a.5.5 0 0 1 .5.866l-1.12.646.883.237a.5.5 0 1 1-.26.966l-1.848-.495-.94.542.883.237a.5.5 0 1 1-.26.966l-1.848-.495L9 8l1.236.713 1.849-.495a.5.5 0 0 1 .259.966l-.883.237.94.542 1.849-.495a.5.5 0 0 1 .259.966l-.883.237 1.12.646a.5.5 0 0 1-.5.866l-1.12-.646.236.883a.5.5 0 1 1-.966.258l-.495-1.849-.94-.542.236.883a.5.5 0 0 1-.966.258L9.736 9.58 8.5 8.866v1.427l1.354 1.353a.5.5 0 0 1-.707.708l-.647-.647v1.086l1.354 1.353a.5.5 0 0 1-.707.708l-.647-.647V15.5a.5.5 0 0 1-.5.5z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user