feat: more/improved styles, moved settings

This commit is contained in:
Daniel Ledda
2021-09-05 21:06:15 +02:00
parent 9967de43dd
commit 27cf8cdac8
13 changed files with 174 additions and 155 deletions

View File

@@ -36,7 +36,7 @@ export default class Beat implements IPublisher<BeatEvents>, BeatLike {
private looping: boolean;
constructor(options?: BeatInitOptions) {
this.key = `Beat-${Beat.count}`;
this.key = `B-${Beat.count}`;
this.name = options?.name ?? this.key;
this.setTimeSignature({up: options?.timeSig?.up ?? 4, down: options?.timeSig?.down ?? 4});
this.setBarCount(options?.bars ?? 4);

View File

@@ -3,26 +3,6 @@
padding-left: 1em;
}
.beat-settings-btn {
cursor: pointer;
line-height: 2em;
display: inline-block;
height: 2em;
border: 1px solid grey;
border-radius: 1em;
user-select: none;
transition: background-color 150ms;
}
.beat-settings-btn:hover {
background-color: #eaeaea;
}
.beat-settings-btn.active {
background-color: lightgrey;
transition: none;
}
.beat-unit-block {
height: 2em;
}

View File

@@ -4,7 +4,6 @@ import {IPublisher} from "../../../Publisher";
import ISubscriber from "../../../Subscriber";
import BeatUnitView from "./BeatUnit/BeatUnitView";
import "./Beat.css";
import BeatSettingsView from "../../BeatSettings/BeatSettingsView";
export type BeatUINodeOptions = UINodeOptions & {
beat: Beat,
@@ -13,8 +12,6 @@ export type BeatUINodeOptions = UINodeOptions & {
export default class BeatView extends UINode implements ISubscriber {
private beat: Beat;
private title!: HTMLHeadingElement;
private settingsView!: BeatSettingsView;
private settingsToggleButton!: HTMLDivElement;
private beatUnitViews: BeatUnitView[] = [];
private beatUnitViewBlock: HTMLElement | null = null;
private lastHoveredBeatUnitView: BeatUnitView | null = null;
@@ -45,15 +42,6 @@ export default class BeatView extends UINode implements ISubscriber {
}
}
private toggleSettings() {
this.settingsView.toggleVisible();
if (this.settingsView.isOpen()) {
this.settingsToggleButton.classList.add("active");
} else {
this.settingsToggleButton.classList.remove("active");
}
}
private rebuildBeatUnitViews() {
const beatUnitCount = this.beat.getBarCount() * this.beat.getTimeSigUp();
this.beatUnitViews.splice(beatUnitCount, this.beatUnitViews.length - beatUnitCount);
@@ -148,12 +136,6 @@ export default class BeatView extends UINode implements ISubscriber {
if (!this.beatUnitViewBlock) {
throw new Error("Beat unit block setup failed!");
}
this.settingsView = new BeatSettingsView({beat: this.beat});
this.settingsToggleButton = UINode.make("div", {
classes: ["beat-settings-btn"],
innerText: "Settings",
onclick: () => this.toggleSettings()
});
this.node = UINode.make("div", {
classes: ["beat"],
subs: [
@@ -164,11 +146,6 @@ export default class BeatView extends UINode implements ISubscriber {
this.beatUnitViewBlock,
]
}),
this.settingsToggleButton,
UINode.make("div", {
classes: ["beat-settings-container"],
subs: [this.settingsView.render()],
}),
],
});
return this.node;

View File

@@ -6,6 +6,8 @@ import ISubscriber from "../../Subscriber";
import BeatGroup, {BeatGroupEvents} from "../../BeatGroup";
import {IPublisher} from "../../Publisher";
import {BeatEvents} from "../../Beat";
import BoolBoxView from "../Widgets/BoolBox/BoolBoxView";
import BeatSettingsView from "../BeatSettings/BeatSettingsView";
export type BeatGroupSettingsUINodeOptions = UINodeOptions & {
beatGroup: BeatGroup,
@@ -16,8 +18,8 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
private barCountInput!: NumberInputView;
private timeSigUpInput!: NumberInputView;
private loopSettingsView!: BeatLikeLoopSettingsView;
private autoBeatLengthCheckbox!: HTMLInputElement;
private forceFullBarsCheckbox!: HTMLInputElement;
private autoBeatLengthCheckbox!: BoolBoxView;
private forceFullBarsCheckbox!: BoolBoxView;
private autoBeatOptions!: HTMLElement;
constructor(options: BeatGroupSettingsUINodeOptions) {
@@ -58,19 +60,10 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
setter: (input: number) => this.beatGroup.setTimeSigUp(input),
getter: () => this.beatGroup.getTimeSigUp(),
});
this.autoBeatLengthCheckbox = UINode.make("input", {
type: "checkbox",
checked: this.beatGroup.autoBeatLengthOn(),
oninput: () => {
this.beatGroup.setIsUsingAutoBeatLength(this.autoBeatLengthCheckbox.checked);
},
});
this.forceFullBarsCheckbox = UINode.make("input", {
type: "checkbox",
checked: this.beatGroup.forcesFullBars(),
oninput: () => {
this.beatGroup.setForcesFullBars(this.forceFullBarsCheckbox.checked);
},
this.autoBeatLengthCheckbox = new BoolBoxView({
label: "Auto beat length:",
value: this.beatGroup.autoBeatLengthOn(),
onInput: (isChecked: boolean) => this.beatGroup.setIsUsingAutoBeatLength(isChecked),
});
this.autoBeatOptions = UINode.make("div", {
classes: ["beat-group-settings-option-group"],
@@ -78,19 +71,15 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
UINode.make("div", {
classes: ["beat-group-settings-autobeat-option", "beat-group-settings-option"],
subs: [
UINode.make("label", { innerText: "Auto beat length:"}),
this.autoBeatLengthCheckbox,
],
}),
UINode.make("div", {
classes: ["beat-group-settings-autobeat-option", "beat-group-settings-option"],
subs: [
UINode.make("label", { innerText: "Force full bars:"}),
this.forceFullBarsCheckbox,
this.autoBeatLengthCheckbox.render(),
],
}),
]
});
const beatSettingsViews = [];
for (let i = 0; i < this.beatGroup.getBeatCount(); i++) {
beatSettingsViews.push(new BeatSettingsView({ beat: this.beatGroup.getBeatByIndex(i) }));
}
this.node = UINode.make("div", {
classes: ["beat-group-settings"],
subs: [
@@ -114,7 +103,8 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
UINode.make("button", {
innerText: "New Track",
onclick: () => this.beatGroup.addBeat(),
})
}),
...beatSettingsViews.map(view => view.render()),
],
}),
],

View File

@@ -19,4 +19,8 @@
.loop-settings-option {
display: flex;
justify-content: center;
}
.loop-settings-option.hide {
display: none;
}

View File

@@ -5,6 +5,7 @@ import ISubscriber from "../../Subscriber";
import UINode, {UINodeOptions} from "../UINode";
import {BeatEvents} from "../../Beat";
import {IPublisher} from "../../Publisher";
import BoolBoxView from "../Widgets/BoolBox/BoolBoxView";
export type BeatLikeLoopSettingsViewUINodeOptions = UINodeOptions & {
beatLike: BeatLike,
@@ -13,7 +14,8 @@ export type BeatLikeLoopSettingsViewUINodeOptions = UINodeOptions & {
export default class BeatLikeLoopSettingsView extends UINode implements ISubscriber {
private beatLike: BeatLike;
private loopLengthInput!: NumberInputView;
private loopCheckbox!: HTMLInputElement;
private loopCheckbox!: BoolBoxView;
private loopLengthSection!: HTMLDivElement;
constructor(options: BeatLikeLoopSettingsViewUINodeOptions) {
super(options);
@@ -32,7 +34,12 @@ export default class BeatLikeLoopSettingsView extends UINode implements ISubscri
if (event === BeatEvents.LoopLengthChanged) {
this.loopLengthInput.setValue(this.beatLike.getLoopLength());
} else if (event === BeatEvents.DisplayTypeChanged) {
this.loopCheckbox.checked = this.beatLike.isLooping();
this.loopCheckbox.setValue(this.beatLike.isLooping());
if (this.beatLike.isLooping()) {
this.loopLengthSection.classList.remove("hide");
} else {
this.loopLengthSection.classList.add("hide");
}
}
}
@@ -44,34 +51,36 @@ export default class BeatLikeLoopSettingsView extends UINode implements ISubscri
onIncrement: () => this.beatLike.setLoopLength(this.beatLike.getLoopLength() + 1),
onNewInput: (input: number) => this.beatLike.setLoopLength(input),
});
this.loopCheckbox = UINode.make("input", {
classes: ["loop-settings-loop-toggle"],
type: "checkbox",
checked: this.beatLike.isLooping(),
oninput: (event: Event) => {
this.beatLike.setLooping((event.target as HTMLInputElement).checked);
},
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");
}
this.node = UINode.make("div", {
classes: ["loop-settings"],
subs: [
UINode.make("p", {innerText: "Looping:"}),
UINode.make("p", {innerText: "Global looping settings:"}),
UINode.make("div", {
classes: ["loop-settings-option-group"],
subs: [
UINode.make("div", {
classes: ["loop-settings-option"],
subs: [
this.loopLengthInput.render(),
],
}),
UINode.make("div", {
classes: ["loop-settings-option"],
subs: [
UINode.make("label", {innerText: "On:"}),
this.loopCheckbox,
this.loopCheckbox.render(),
],
}),
this.loopLengthSection,
],
}),
]

View File

@@ -1,13 +1,8 @@
.beat-settings {
padding: 1em;
display: none;
text-align: center;
width: 40em;
justify-content: space-evenly;
}
.beat-settings.visible {
display: inline-flex;
text-align: center;
justify-content: space-evenly;
}
.beat-settings-time-sig-up {

View File

@@ -2,7 +2,6 @@ import "./BeatSettings.css";
import Beat, {BeatEvents} from "../../Beat";
import UINode, {UINodeOptions} from "../UINode";
import ISubscriber from "../../Subscriber";
import NumberInputView from "../Widgets/NumberInput/NumberInputView";
import BeatLikeLoopSettingsView from "../BeatLikeLoopSettings/BeatLikeLoopSettingsView";
import {IPublisher} from "../../Publisher";
@@ -32,19 +31,6 @@ export default class BeatSettingsView extends UINode implements ISubscriber {
}
}
toggleVisible(): void {
this.visible = !this.visible;
if (this.visible) {
this.node?.classList.add("visible");
} else {
this.node?.classList.remove("visible");
}
}
isOpen(): boolean {
return this.visible;
}
rebuild(): HTMLElement {
this.loopSettingsView = new BeatLikeLoopSettingsView({beatLike: this.beat});
this.nameInput = UINode.make("input", {

View File

@@ -49,52 +49,6 @@
margin: auto;
}
input[type="checkbox"] {
position: relative;
width: 2em;
height: 1em;
padding: 0;
margin: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
input[type="checkbox"]::before {
width: 2em;
height: 1em;
border-radius: 1em;
background-color: var(--color-ui-accent-dark);
display: block;
content: "";
z-index: 0;
position: absolute;
transition: background-color 200ms;
}
input[type="checkbox"]:checked::before {
background-color: var(--color-ui-accent-light);
}
input[type="checkbox"]::after {
position: absolute;
width: 1em;
height: 1em;
border-radius: 1em;
border-color: var(--color-ui-neutral-dark);
border-width: 1px;
background-color: var(--color-ui-neutral-light);
display: block;
content: "";
z-index: 1;
right: 1em;
transition: right 200ms;
}
input[type="checkbox"]:checked::after {
right: 0;
}
* {
user-drag: none;
user-select: none;

View File

@@ -0,0 +1,61 @@
.bool-box {
height: 1.1em;
margin: 0.5em;
line-height: 1em;
}
.bool-box-label {
display: inline-block;
margin-right: 0.5em;
}
input.bool-box-checkbox[type="checkbox"] {
position: relative;
display: inline-block;
width: 2em;
height: 1em;
padding: 0;
top: 0.1em;
margin: 0;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
input.bool-box-checkbox[type="checkbox"]::before {
width: 2em;
height: 1em;
border-radius: 1em;
background-color: var(--color-ui-accent-dark);
display: inline-block;
content: "";
z-index: 0;
position: absolute;
transition: background-color 200ms;
}
input.bool-box-checkbox[type="checkbox"]:checked::before {
background-color: var(--color-ui-accent-light);
}
input.bool-box-checkbox[type="checkbox"]::after {
position: absolute;
width: 1.05em;
height: 1.05em;
border-radius: 1em;
border-color: var(--color-ui-neutral-dark);
border-width: 0.05em;
border-style: solid;
background-color: var(--color-ui-neutral-dark);
display: block;
content: "";
top: -0.075em;
z-index: 1;
left: -0.075em;
transition: left 200ms, background-color 200ms;
}
input.bool-box-checkbox[type="checkbox"]:checked::after {
left: 0.925em;
background-color: var(--color-ui-neutral-light);
}

View File

@@ -0,0 +1,59 @@
import "./BoolBox.css";
import UINode, {UINodeOptions} from "../../UINode";
export type BoolBoxUINodeOptions = UINodeOptions & {
label?: string,
value?: boolean,
onInput?: (isChecked: boolean) => void,
};
export default class BoolBoxView extends UINode {
private label: string | null;
private labelElement!: HTMLLabelElement;
private checkboxElement!: HTMLInputElement;
private onInput: (isChecked: boolean) => void;
constructor(options: BoolBoxUINodeOptions) {
super(options);
this.label = options.label ?? "";
this.onInput = options.onInput ?? (() => { /* dummy */ });
}
setLabel(newLabel: string | null): void {
if (newLabel !== null) {
this.label = newLabel;
this.labelElement.innerText = newLabel;
this.labelElement.classList.add("visible");
} else {
this.label = newLabel;
this.labelElement.innerText = "";
this.labelElement.classList.remove("visible");
}
}
setValue(isChecked: boolean): void {
this.checkboxElement.checked = isChecked;
}
rebuild(): HTMLDivElement {
this.labelElement = UINode.make("label", {
classes: ["bool-box-label"],
innerText: this.label ?? "",
});
if (this.label !== null) {
this.labelElement.classList.add("visible");
}
this.checkboxElement = UINode.make("input", {
type: "checkbox",
classes: ["bool-box-checkbox"],
oninput: (event: Event) => this.onInput((event.target as HTMLInputElement).checked),
});
return UINode.make("div", {
classes: ["bool-box"],
subs: [
this.labelElement,
this.checkboxElement,
],
});
}
}

View File

@@ -2,6 +2,10 @@
text-align: center;
}
.number-input-label {
margin-bottom: 0.5em;
}
input[type="number"].number-input-input {
-webkit-appearance: textfield;
-moz-appearance: textfield;

View File

@@ -76,7 +76,7 @@ export default class NumberInputView extends UINode {
type: "number",
classes: ["number-input-input"],
valueAsNumber: this.value,
oninput: (event: Event) => {
onblur: (event: Event) => {
const input = (event.target as HTMLInputElement).valueAsNumber;
if (!isNaN(input)) {
if (this.onNewInput) {