fixed button styling, dev server, added switches for event handling, global baking, global reset, three BeatUnit states with styles, and mobile long touch to change beatunit type
This commit is contained in:
11
src/Beat.ts
11
src/Beat.ts
@@ -1,4 +1,4 @@
|
|||||||
import BeatUnit from "@/BeatUnit";
|
import BeatUnit, {BeatUnitType} from "@/BeatUnit";
|
||||||
import {IPublisher, Publisher} from "@/Publisher";
|
import {IPublisher, Publisher} from "@/Publisher";
|
||||||
import ISubscriber from "@/Subscriber";
|
import ISubscriber from "@/Subscriber";
|
||||||
import BeatLike from "@/BeatLike";
|
import BeatLike from "@/BeatLike";
|
||||||
@@ -22,6 +22,7 @@ export const enum BeatEvents {
|
|||||||
DisplayTypeChanged="BE3",
|
DisplayTypeChanged="BE3",
|
||||||
LoopLengthChanged="BE4",
|
LoopLengthChanged="BE4",
|
||||||
WantsRemoval="BE5",
|
WantsRemoval="BE5",
|
||||||
|
Baked="BE6",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
||||||
@@ -154,9 +155,15 @@ export default class Beat implements IPublisher<BeatEvents>, BeatLike {
|
|||||||
bakeLoops(): void {
|
bakeLoops(): void {
|
||||||
if (this.isLooping()) {
|
if (this.isLooping()) {
|
||||||
this.unitRecord.forEach((unit, i) => {
|
this.unitRecord.forEach((unit, i) => {
|
||||||
unit.setOn(this.getUnitByIndex(i)?.isOn() ?? false);
|
const reprUnitAtPos = this.getUnitByIndex(i);
|
||||||
|
if (reprUnitAtPos) {
|
||||||
|
unit.mimic(reprUnitAtPos);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
this.publisher.notifySubs(BeatEvents.Baked);
|
||||||
this.setLooping(false);
|
this.setLooping(false);
|
||||||
|
} else {
|
||||||
|
this.publisher.notifySubs(BeatEvents.Baked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,10 +46,17 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
||||||
if (event === BeatEvents.LoopLengthChanged || event === BeatEvents.DisplayTypeChanged) {
|
switch (event) {
|
||||||
|
case BeatEvents.LoopLengthChanged:
|
||||||
|
case BeatEvents.DisplayTypeChanged:
|
||||||
this.autoBeatLength();
|
this.autoBeatLength();
|
||||||
} else if (event === BeatEvents.WantsRemoval) {
|
break;
|
||||||
|
case BeatEvents.WantsRemoval:
|
||||||
this.removeBeat((publisher as Beat).getKey());
|
this.removeBeat((publisher as Beat).getKey());
|
||||||
|
break;
|
||||||
|
case BeatEvents.Baked:
|
||||||
|
this.setIsUsingAutoBeatLength(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +220,7 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
BeatEvents.LoopLengthChanged,
|
BeatEvents.LoopLengthChanged,
|
||||||
BeatEvents.WantsRemoval,
|
BeatEvents.WantsRemoval,
|
||||||
BeatEvents.DisplayTypeChanged,
|
BeatEvents.DisplayTypeChanged,
|
||||||
|
BeatEvents.Baked,
|
||||||
]);
|
]);
|
||||||
this.publisher.notifySubs(BeatGroupEvents.BeatListChanged);
|
this.publisher.notifySubs(BeatGroupEvents.BeatListChanged);
|
||||||
return newBeat;
|
return newBeat;
|
||||||
@@ -267,6 +275,5 @@ export default class BeatGroup implements IPublisher<BeatGroupEvents | BeatEvent
|
|||||||
|
|
||||||
bakeLoops(): void {
|
bakeLoops(): void {
|
||||||
this.beats.forEach(beat => beat.bakeLoops());
|
this.beats.forEach(beat => beat.bakeLoops());
|
||||||
this.setIsUsingAutoBeatLength(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import ISubscriber from "./Subscriber";
|
|||||||
export enum BeatUnitType {
|
export enum BeatUnitType {
|
||||||
Normal,
|
Normal,
|
||||||
GhostNote,
|
GhostNote,
|
||||||
|
Accent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -16,12 +17,18 @@ export const enum BeatUnitEvents {
|
|||||||
|
|
||||||
|
|
||||||
export default class BeatUnit implements IPublisher<BeatUnitEvents> {
|
export default class BeatUnit implements IPublisher<BeatUnitEvents> {
|
||||||
|
private static readonly TypeRotation = [
|
||||||
|
BeatUnitType.Normal,
|
||||||
|
BeatUnitType.GhostNote,
|
||||||
|
BeatUnitType.Accent,
|
||||||
|
] as const;
|
||||||
private publisher: Publisher<BeatUnitEvents, BeatUnit> = new Publisher<BeatUnitEvents, BeatUnit>(this);
|
private publisher: Publisher<BeatUnitEvents, BeatUnit> = new Publisher<BeatUnitEvents, BeatUnit>(this);
|
||||||
private on = false;
|
private on = false;
|
||||||
private type: BeatUnitType = BeatUnitType.Normal;
|
private typeIndex = 0;
|
||||||
|
|
||||||
constructor(on = false) {
|
constructor(on = false, type = BeatUnitType.Normal) {
|
||||||
this.on = on;
|
this.on = on;
|
||||||
|
this.setType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubscriber(subscriber: ISubscriber, eventType: "all" | BeatUnitEvents | BeatUnitEvents[]): ISubscription {
|
addSubscriber(subscriber: ISubscriber, eventType: "all" | BeatUnitEvents | BeatUnitEvents[]): ISubscription {
|
||||||
@@ -44,15 +51,29 @@ export default class BeatUnit implements IPublisher<BeatUnitEvents> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setType(type: BeatUnitType): void {
|
setType(type: BeatUnitType): void {
|
||||||
this.type = type;
|
this.typeIndex = BeatUnit.TypeRotation.indexOf(type);
|
||||||
this.publisher.notifySubs(BeatUnitEvents.TypeChange);
|
this.publisher.notifySubs(BeatUnitEvents.TypeChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
getType(): BeatUnitType {
|
getType(): BeatUnitType {
|
||||||
return this.type;
|
return BeatUnit.TypeRotation[this.typeIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
rotateType(): void {
|
||||||
|
if (this.typeIndex === BeatUnit.TypeRotation.length - 1) {
|
||||||
|
this.typeIndex = 0;
|
||||||
|
} else {
|
||||||
|
this.typeIndex += 1;
|
||||||
|
}
|
||||||
|
this.publisher.notifySubs(BeatUnitEvents.TypeChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
isOn(): boolean {
|
isOn(): boolean {
|
||||||
return this.on;
|
return this.on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mimic(beatUnit: BeatUnit): void {
|
||||||
|
this.setOn(beatUnit.isOn());
|
||||||
|
this.setType(beatUnit.getType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/main.ts
41
src/main.ts
@@ -1,38 +1,21 @@
|
|||||||
import BeatGroup from "@/BeatGroup";
|
|
||||||
import RootView from "@/ui/Root/RootView";
|
import RootView from "@/ui/Root/RootView";
|
||||||
import "@/ui/global.css";
|
import "@/ui/global.css";
|
||||||
|
|
||||||
const defaultSettings = {
|
|
||||||
barCount: 2,
|
|
||||||
isLooping: false,
|
|
||||||
timeSigUp: 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const mainBeatGroup = new BeatGroup(defaultSettings);
|
|
||||||
mainBeatGroup.addBeat({
|
|
||||||
name: "LF"
|
|
||||||
});
|
|
||||||
mainBeatGroup.addBeat({
|
|
||||||
name: "LH"
|
|
||||||
});
|
|
||||||
mainBeatGroup.addBeat({
|
|
||||||
name: "RH"
|
|
||||||
});
|
|
||||||
mainBeatGroup.addBeat({
|
|
||||||
name: "RF"
|
|
||||||
});
|
|
||||||
|
|
||||||
const appNode = document.querySelector("#app");
|
const appNode = document.querySelector("#app");
|
||||||
|
|
||||||
if (appNode) {
|
if (appNode) {
|
||||||
const appRoot = new RootView({
|
try {
|
||||||
title: "Drum Slayer",
|
const appRoot = new RootView({
|
||||||
mainBeatGroup: mainBeatGroup,
|
title: "Drum Slayer",
|
||||||
});
|
});
|
||||||
//@ts-ignore
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
window.appRoot = appRoot;
|
//@ts-ignore
|
||||||
appNode.appendChild(appRoot.render());
|
window.appRoot = appRoot;
|
||||||
console.log("OK!");
|
appNode.appendChild(appRoot.render());
|
||||||
|
console.log("OK!");
|
||||||
|
} catch (e) {
|
||||||
|
console.error("FUCK!", e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("FUCK!");
|
console.error("FUCK!");
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import UINode, {UINodeOptions} from "@/ui/UINode";
|
|||||||
import Beat, {BeatEvents} from "@/Beat";
|
import Beat, {BeatEvents} from "@/Beat";
|
||||||
import {IPublisher} from "@/Publisher";
|
import {IPublisher} from "@/Publisher";
|
||||||
import ISubscriber from "@/Subscriber";
|
import ISubscriber from "@/Subscriber";
|
||||||
import BeatUnitView from "./BeatUnit/BeatUnitView";
|
import BeatUnitView from "@/ui/BeatUnit/BeatUnitView";
|
||||||
import "./Beat.css";
|
import "./Beat.css";
|
||||||
|
|
||||||
export type BeatUINodeOptions = UINodeOptions & {
|
export type BeatUINodeOptions = UINodeOptions & {
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
.beat-unit {
|
|
||||||
width: 2em;
|
|
||||||
height: 2em;
|
|
||||||
margin-right: 4px;
|
|
||||||
background-color: var(--color-ui-neutral-dark);
|
|
||||||
border-width: 0.1em 0.1em 0.1em 0.1em;
|
|
||||||
border-color: var(--color-ui-neutral-dark);
|
|
||||||
border-style: solid;
|
|
||||||
display: inline-block;
|
|
||||||
transition: background-color 150ms;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vertical-mode .beat-unit {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-unit:hover {
|
|
||||||
border-color: var(--color-ui-neutral-dark-hover);
|
|
||||||
background-color: var(--color-ui-neutral-dark-hover);
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-unit.beat-unit-ghost:hover {
|
|
||||||
background-color: #c9e2c9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-unit.beat-unit-on {
|
|
||||||
background-color: var(--color-ui-accent);
|
|
||||||
border-color: var(--color-ui-accent);
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.beat-unit.beat-unit-on.beat-unit-ghost {
|
|
||||||
background-color: darkseagreen;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import UINode, {UINodeOptions} from "@/ui/UINode";
|
import UINode, {UINodeOptions} from "@/ui/UINode";
|
||||||
import BeatGroup, {BeatGroupEvents} from "@/BeatGroup";
|
import BeatGroup, {BeatGroupEvents} from "@/BeatGroup";
|
||||||
import BeatView from "./Beat/BeatView";
|
import BeatView from "@/ui/Beat/BeatView";
|
||||||
import "./BeatGroup.css";
|
import "./BeatGroup.css";
|
||||||
import ISubscriber from "@/Subscriber";
|
import ISubscriber from "@/Subscriber";
|
||||||
import {IPublisher} from "@/Publisher";
|
import {IPublisher} from "@/Publisher";
|
||||||
@@ -28,6 +28,12 @@ export default class BeatGroupView extends UINode implements ISubscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBeatGroup(newBeatGroup: BeatGroup): void {
|
||||||
|
this.beatGroup = newBeatGroup;
|
||||||
|
this.beatGroup.addSubscriber(this, BeatGroupEvents.BeatListChanged);
|
||||||
|
this.redraw();
|
||||||
|
}
|
||||||
|
|
||||||
build(): HTMLDivElement {
|
build(): HTMLDivElement {
|
||||||
this.beatViews = [];
|
this.beatViews = [];
|
||||||
for (let i = 0; i < this.beatGroup.getBeatCount(); i++) {
|
for (let i = 0; i < this.beatGroup.getBeatCount(); i++) {
|
||||||
|
|||||||
@@ -20,35 +20,52 @@ export default class BeatGroupSettingsView extends UINode implements ISubscriber
|
|||||||
private autoBeatLengthCheckbox!: BoolBoxView;
|
private autoBeatLengthCheckbox!: BoolBoxView;
|
||||||
private beatSettingsViews: BeatSettingsView[] = [];
|
private beatSettingsViews: BeatSettingsView[] = [];
|
||||||
private beatSettingsContainer!: HTMLDivElement;
|
private beatSettingsContainer!: HTMLDivElement;
|
||||||
|
private static readonly EventTypeSubscriptions = [
|
||||||
|
BeatGroupEvents.BarCountChanged,
|
||||||
|
BeatGroupEvents.TimeSigUpChanged,
|
||||||
|
BeatEvents.DisplayTypeChanged,
|
||||||
|
BeatGroupEvents.BeatListChanged,
|
||||||
|
BeatGroupEvents.LockingChanged,
|
||||||
|
BeatGroupEvents.AutoBeatSettingsChanged,
|
||||||
|
];
|
||||||
|
|
||||||
constructor(options: BeatGroupSettingsUINodeOptions) {
|
constructor(options: BeatGroupSettingsUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
this.beatGroup = options.beatGroup;
|
this.beatGroup = options.beatGroup;
|
||||||
this.beatGroup.addSubscriber(this, [
|
this.setupBindings();
|
||||||
BeatGroupEvents.BarCountChanged,
|
|
||||||
BeatGroupEvents.TimeSigUpChanged,
|
|
||||||
BeatEvents.DisplayTypeChanged,
|
|
||||||
BeatGroupEvents.BeatListChanged,
|
|
||||||
BeatGroupEvents.LockingChanged,
|
|
||||||
BeatGroupEvents.AutoBeatSettingsChanged,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
notify<T extends string | number>(publisher: IPublisher<T>, event: "all" | T[] | T): void {
|
setBeatGroup(newBeatGroup: BeatGroup): void {
|
||||||
if (event === BeatGroupEvents.BarCountChanged) {
|
this.beatGroup = newBeatGroup;
|
||||||
|
this.setupBindings();
|
||||||
|
BeatGroupSettingsView.EventTypeSubscriptions.forEach(eventType => this.notify(null, eventType));
|
||||||
|
}
|
||||||
|
|
||||||
|
setupBindings(): void {
|
||||||
|
this.beatGroup.addSubscriber(this, BeatGroupSettingsView.EventTypeSubscriptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
notify<T extends string | number>(publisher: IPublisher<T> | null, event: "all" | T[] | T): void {
|
||||||
|
switch(event) {
|
||||||
|
case BeatGroupEvents.BarCountChanged:
|
||||||
this.barCountInput.setValue(this.beatGroup.getBarCount());
|
this.barCountInput.setValue(this.beatGroup.getBarCount());
|
||||||
} else if (event === BeatGroupEvents.TimeSigUpChanged) {
|
break;
|
||||||
|
case BeatGroupEvents.TimeSigUpChanged:
|
||||||
this.timeSigUpInput.setValue(this.beatGroup.getTimeSigUp());
|
this.timeSigUpInput.setValue(this.beatGroup.getTimeSigUp());
|
||||||
} else if (event === BeatGroupEvents.BeatListChanged) {
|
break;
|
||||||
|
case BeatGroupEvents.BeatListChanged:
|
||||||
this.remakeBeatSettingsViews();
|
this.remakeBeatSettingsViews();
|
||||||
} else if (event === BeatGroupEvents.LockingChanged) {
|
break;
|
||||||
|
case BeatGroupEvents.LockingChanged:
|
||||||
if (this.beatGroup.barsLocked()) {
|
if (this.beatGroup.barsLocked()) {
|
||||||
this.barCountInput.disable();
|
this.barCountInput.disable();
|
||||||
} else {
|
} else {
|
||||||
this.barCountInput.enable();
|
this.barCountInput.enable();
|
||||||
}
|
}
|
||||||
} else if (event === BeatGroupEvents.AutoBeatSettingsChanged) {
|
break;
|
||||||
|
case BeatGroupEvents.AutoBeatSettingsChanged:
|
||||||
this.autoBeatLengthCheckbox.setValue(this.beatGroup.autoBeatLengthOn());
|
this.autoBeatLengthCheckbox.setValue(this.beatGroup.autoBeatLengthOn());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
55
src/ui/BeatUnit/BeatUnit.css
Normal file
55
src/ui/BeatUnit/BeatUnit.css
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
.beat-unit {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
margin-right: 4px;
|
||||||
|
background-color: #464646;
|
||||||
|
border-color: #464646;
|
||||||
|
border-width: 0.1em 0.1em 0.1em 0.1em;
|
||||||
|
border-style: solid;
|
||||||
|
display: inline-block;
|
||||||
|
transition: background-color 100ms, border-color 100ms;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-unit:hover {
|
||||||
|
border-color: #5f5f5f;
|
||||||
|
background-color: #5f5f5f;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-mode .beat-unit {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-unit.beat-unit-on {
|
||||||
|
border-color: var(--color-ui-accent);
|
||||||
|
background-color: var(--color-ui-accent);
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-unit.beat-unit-on:hover {
|
||||||
|
border-color: var(--color-ui-accent-hover);
|
||||||
|
background-color: var(--color-ui-accent-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-unit.beat-unit-on.beat-unit-ghost {
|
||||||
|
border-color: var(--color-ui-neutral-light);
|
||||||
|
background-color: var(--color-ui-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-unit.beat-unit-on.beat-unit-ghost:hover {
|
||||||
|
border-color: var(--color-ui-neutral-light);
|
||||||
|
background-color: var(--color-ui-accent-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-unit.beat-unit-on.beat-unit-accent {
|
||||||
|
border-color: var(--color-ui-accent);
|
||||||
|
background-color: var(--color-ui-accent);
|
||||||
|
opacity: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.beat-unit.beat-unit-on.beat-unit-accent:hover {
|
||||||
|
border-color: var(--color-ui-accent-hover);
|
||||||
|
background-color: var(--color-ui-accent-hover);
|
||||||
|
}
|
||||||
@@ -12,6 +12,8 @@ export default class BeatUnitView extends UINode implements ISubscriber {
|
|||||||
private beatUnit: BeatUnit;
|
private beatUnit: BeatUnit;
|
||||||
private subscription: ISubscription | null = null;
|
private subscription: ISubscription | null = null;
|
||||||
private publisher: IPublisher<BeatUnitEvents> = new Publisher<BeatUnitEvents, BeatUnitView>(this);
|
private publisher: IPublisher<BeatUnitEvents> = new Publisher<BeatUnitEvents, BeatUnitView>(this);
|
||||||
|
private touchTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
|
|
||||||
constructor(options: BeatUnitUINodeOptions) {
|
constructor(options: BeatUnitUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -29,10 +31,21 @@ export default class BeatUnitView extends UINode implements ISubscriber {
|
|||||||
private setupBindings() {
|
private setupBindings() {
|
||||||
this.subscription?.unbind();
|
this.subscription?.unbind();
|
||||||
this.subscription = this.beatUnit.addSubscriber(this, "all");
|
this.subscription = this.beatUnit.addSubscriber(this, "all");
|
||||||
this.onMouseUp((ev: MouseEvent) => {
|
this.onMouseDown((ev: MouseEvent) => {
|
||||||
if (ev.button === 1) {
|
if (ev.button === 1) {
|
||||||
const currentType = this.beatUnit.getType();
|
this.beatUnit.rotateType();
|
||||||
this.beatUnit.setType(currentType === BeatUnitType.GhostNote ? BeatUnitType.Normal : BeatUnitType.GhostNote);
|
}
|
||||||
|
});
|
||||||
|
this.getNode().addEventListener("touchstart", () => {
|
||||||
|
this.touchTimeout = setTimeout(() => {
|
||||||
|
this.beatUnit.rotateType();
|
||||||
|
this.touchTimeout = null;
|
||||||
|
}, 600);
|
||||||
|
});
|
||||||
|
this.getNode().addEventListener("touchend", () => {
|
||||||
|
if (this.touchTimeout) {
|
||||||
|
clearTimeout(this.touchTimeout);
|
||||||
|
this.touchTimeout = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -55,12 +68,19 @@ export default class BeatUnitView extends UINode implements ISubscriber {
|
|||||||
} else if (event === BeatUnitEvents.Off) {
|
} else if (event === BeatUnitEvents.Off) {
|
||||||
this.getNode().classList.remove("beat-unit-on");
|
this.getNode().classList.remove("beat-unit-on");
|
||||||
} else if (event === BeatUnitEvents.TypeChange) {
|
} else if (event === BeatUnitEvents.TypeChange) {
|
||||||
const showingAsGhost = this.getNode().classList.contains("beat-unit-ghost");
|
switch (this.beatUnit.getType()) {
|
||||||
const isGhost = this.beatUnit.getType() === BeatUnitType.GhostNote;
|
case BeatUnitType.Normal:
|
||||||
if (isGhost && !showingAsGhost) {
|
|
||||||
this.getNode().classList.add("beat-unit-ghost");
|
|
||||||
} else if (!isGhost && showingAsGhost) {
|
|
||||||
this.getNode().classList.remove("beat-unit-ghost");
|
this.getNode().classList.remove("beat-unit-ghost");
|
||||||
|
this.getNode().classList.remove("beat-unit-accent");
|
||||||
|
break;
|
||||||
|
case BeatUnitType.GhostNote:
|
||||||
|
this.getNode().classList.remove("beat-unit-accent");
|
||||||
|
this.getNode().classList.add("beat-unit-ghost");
|
||||||
|
break;
|
||||||
|
case BeatUnitType.Accent:
|
||||||
|
this.getNode().classList.remove("beat-unit-ghost");
|
||||||
|
this.getNode().classList.add("beat-unit-accent");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,14 +97,14 @@ export default class BeatUnitView extends UINode implements ISubscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onHover(cb: () => void): void {
|
onHover(cb: () => void): void {
|
||||||
this.getNode().onmouseover = cb;
|
this.getNode().addEventListener("mouseover", cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseDown(cb: (ev: MouseEvent) => void): void {
|
onMouseDown(cb: (ev: MouseEvent) => void): void {
|
||||||
this.getNode().onmousedown = cb;
|
this.getNode().addEventListener("mousedown", cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseUp(cb: (ev: MouseEvent) => void): void {
|
onMouseUp(cb: (ev: MouseEvent) => void): void {
|
||||||
this.getNode().onmouseup = cb;
|
this.getNode().addEventListener("mouseup", cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,11 +64,12 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-hamburger, .root-switch-mode {
|
.root-quick-access-button {
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 2em;
|
width: 2em;
|
||||||
height: 2em;
|
height: 2em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.root-beat-stage-container {
|
.root-beat-stage-container {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import IconView from "@/ui/Widgets/Icon/IconView";
|
|||||||
|
|
||||||
export type RootUINodeOptions = UINodeOptions & {
|
export type RootUINodeOptions = UINodeOptions & {
|
||||||
title: string,
|
title: string,
|
||||||
mainBeatGroup: BeatGroup,
|
mainBeatGroup?: BeatGroup,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class RootView extends UINode {
|
export default class RootView extends UINode {
|
||||||
@@ -20,11 +20,25 @@ export default class RootView extends UINode {
|
|||||||
|
|
||||||
constructor(options: RootUINodeOptions) {
|
constructor(options: RootUINodeOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
this.mainBeatGroup = options.mainBeatGroup;
|
this.mainBeatGroup = options.mainBeatGroup ?? RootView.defaultMainBeatGroup();
|
||||||
this.beatGroupView = new BeatGroupView({title: options.title, beatGroup: this.mainBeatGroup});
|
this.beatGroupView = new BeatGroupView({title: options.title, beatGroup: this.mainBeatGroup});
|
||||||
this.title = options.title;
|
this.title = options.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static defaultMainBeatGroup(): BeatGroup {
|
||||||
|
const defaultSettings = {
|
||||||
|
barCount: 2,
|
||||||
|
isLooping: false,
|
||||||
|
timeSigUp: 8,
|
||||||
|
};
|
||||||
|
const mainBeatGroup = new BeatGroup(defaultSettings);
|
||||||
|
mainBeatGroup.addBeat({name: "LF"});
|
||||||
|
mainBeatGroup.addBeat({name: "LH"});
|
||||||
|
mainBeatGroup.addBeat({name: "RH"});
|
||||||
|
mainBeatGroup.addBeat({name: "RF"});
|
||||||
|
return mainBeatGroup;
|
||||||
|
}
|
||||||
|
|
||||||
toggleSidebar(): void {
|
toggleSidebar(): void {
|
||||||
this.getNode().classList.toggle("sidebar-visible");
|
this.getNode().classList.toggle("sidebar-visible");
|
||||||
}
|
}
|
||||||
@@ -46,15 +60,30 @@ export default class RootView extends UINode {
|
|||||||
classes: ["root-sidebar-toggle"],
|
classes: ["root-sidebar-toggle"],
|
||||||
subs: [
|
subs: [
|
||||||
UINode.make("div", {
|
UINode.make("div", {
|
||||||
classes: ["root-hamburger"],
|
classes: ["root-quick-access-button"],
|
||||||
subs: [new IconView({iconName: "list", color: "var(--color-ui-neutral-dark)"}).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-quick-access-button"],
|
||||||
subs: [new IconView({iconName: "arrowClockwise", color: "var(--color-ui-neutral-dark)"}).render()],
|
subs: [new IconView({iconName: "arrowClockwise", color: "var(--color-ui-neutral-dark)"}).render()],
|
||||||
onclick: () => this.toggleOrientation(),
|
onclick: () => this.toggleOrientation(),
|
||||||
})
|
}),
|
||||||
|
UINode.make("div", {
|
||||||
|
classes: ["root-quick-access-button"],
|
||||||
|
subs: [new IconView({iconName: "snowflake", color: "var(--color-ui-neutral-dark)"}).render()],
|
||||||
|
onclick: () => this.mainBeatGroup.bakeLoops(),
|
||||||
|
}),
|
||||||
|
UINode.make("div", {
|
||||||
|
classes: ["root-quick-access-button"],
|
||||||
|
title: "Reset all",
|
||||||
|
subs: [new IconView({iconName: "trash", color: "var(--color-ui-neutral-dark)"}).render()],
|
||||||
|
onclick: () => {
|
||||||
|
this.mainBeatGroup = RootView.defaultMainBeatGroup();
|
||||||
|
this.beatGroupSettingsView.setBeatGroup(this.mainBeatGroup);
|
||||||
|
this.beatGroupView.setBeatGroup(this.mainBeatGroup);
|
||||||
|
},
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
this.sidebar = UINode.make("div", {
|
this.sidebar = UINode.make("div", {
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
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);
|
||||||
}
|
}
|
||||||
@@ -27,11 +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:not(.disabled) {
|
||||||
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:not(.disabled) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ const webpackConfig = {
|
|||||||
|
|
||||||
output: {
|
output: {
|
||||||
filename: "bundle.js",
|
filename: "bundle.js",
|
||||||
publicPath: "static/",
|
publicPath: "/static/",
|
||||||
path: path.resolve(__dirname, "./public/static"),
|
path: path.resolve(__dirname, "./public/static"),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user