refactor: Moving to svelteless, added Jenkinsfile
Some checks failed
Gitea djledda.de/arne-drums/pipeline/head There was a failure building this commit
Some checks failed
Gitea djledda.de/arne-drums/pipeline/head There was a failure building this commit
This commit is contained in:
32
.eslintrc.json
Normal file
32
.eslintrc.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
4
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"double"
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
]
|
||||
}
|
||||
}
|
||||
19
Jenkinsfile
vendored
Normal file
19
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
pipeline {
|
||||
agent any
|
||||
tools {
|
||||
nodejs "node"
|
||||
}
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'npm install'
|
||||
sh 'npm run build'
|
||||
}
|
||||
}
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
sh 'rsync ./public /var/www/public/html/drums'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6770
package-lock.json
generated
6770
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -20,17 +20,29 @@
|
||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
||||
"@rollup/plugin-typescript": "^8.0.0",
|
||||
"@tsconfig/svelte": "^1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.2",
|
||||
"@typescript-eslint/parser": "^4.29.2",
|
||||
"@webpack-cli/generators": "^2.3.0",
|
||||
"css-loader": "^6.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"mini-css-extract-plugin": "^2.2.0",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-css-only": "^3.1.0",
|
||||
"rollup-plugin-livereload": "^2.0.0",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"svelte": "^3.0.0",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"source-map-support": "^0.5.19",
|
||||
"style-loader": "^3.2.1",
|
||||
"svelte-check": "^1.0.0",
|
||||
"svelte-preprocess": "^4.0.0",
|
||||
"ts-loader": "^9.2.5",
|
||||
"tslib": "^2.0.0",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"typescript": "^4.4.0-dev.20210525",
|
||||
"source-map-support": "^0.5.19"
|
||||
}
|
||||
"typescript": "^4.4.0-insiders.20210805",
|
||||
"webpack": "^5.51.1",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.0.0"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
h1.svelte-pvij5y{text-align:center;color:red}.main-contianer.svelte-pvij5y{width:100%}h1.svelte-1f51h8v.svelte-1f51h8v{color:red;text-align:center}.unit.svelte-1f51h8v.svelte-1f51h8v{display:block}.lines.landscape.svelte-1f51h8v .unit.svelte-1f51h8v{display:inline-block}.bar.svelte-1f51h8v.svelte-1f51h8v{display:block;margin-bottom:1em}.lines.landscape.svelte-1f51h8v .bar.svelte-1f51h8v{display:inline-block;margin-bottom:0;margin-right:1em}.drum-line.svelte-1f51h8v.svelte-1f51h8v{display:block;overflow-x:scroll}.drum-line.svelte-1f51h8v h3.svelte-1f51h8v{display:inline-block;width:3em}.lines.landscape.svelte-1f51h8v .drum-line.svelte-1f51h8v{display:inline-block}.lines.svelte-1f51h8v.svelte-1f51h8v{width:100%;justify-content:center;display:flex;flex-direction:row;margin:auto}.lines.landscape.svelte-1f51h8v.svelte-1f51h8v{flex-direction:column}.unit.svelte-1lue60t{height:2em;width:2em;background-color:white;border:solid black 1px}.active.svelte-1lue60t{background-color:#d97474}.ghost.svelte-1lue60t{background-color:#bc8787}
|
||||
h1.svelte-pvij5y{text-align:center;color:red}.main-contianer.svelte-pvij5y{width:100%}.options.svelte-ijae3p.svelte-ijae3p{border:#333333 1px solid}.unit.svelte-ijae3p.svelte-ijae3p{display:block}.lines.landscape.svelte-ijae3p .unit.svelte-ijae3p{display:inline-block}.bar.svelte-ijae3p.svelte-ijae3p{display:block;margin-bottom:1em}.lines.landscape.svelte-ijae3p .bar.svelte-ijae3p{display:inline-block;margin-bottom:0;margin-right:1em}.drum-line.svelte-ijae3p.svelte-ijae3p{display:block;overflow-x:scroll}.drum-line.svelte-ijae3p h3.svelte-ijae3p{display:inline-block;width:3em}.drum-line.svelte-ijae3p .options-button.svelte-ijae3p{display:inline-block}.lines.landscape.svelte-ijae3p .drum-line.svelte-ijae3p{display:inline-block}.lines.svelte-ijae3p.svelte-ijae3p{width:100%;justify-content:center;display:flex;flex-direction:row;margin:auto}.lines.landscape.svelte-ijae3p.svelte-ijae3p{flex-direction:column}.unit.svelte-1lue60t{height:2em;width:2em;background-color:white;border:solid black 1px}.active.svelte-1lue60t{background-color:#d97474}.ghost.svelte-1lue60t{background-color:#bc8787}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
323
src/Beat.ts
323
src/Beat.ts
@@ -1,163 +1,162 @@
|
||||
import BeatUnit, {BeatUnitType} from "./BeatUnit";
|
||||
|
||||
export type BeatInitOptions = {
|
||||
timeSig: {
|
||||
up: number,
|
||||
down: number,
|
||||
},
|
||||
bars: number,
|
||||
drumSchema: string[],
|
||||
};
|
||||
|
||||
export default class Beat {
|
||||
private timeSigUp: number = 4;
|
||||
private timeSigDown: number = 4;
|
||||
private readonly unitRecords: Record<string, BeatUnit[]>;
|
||||
private readonly drumSchema: string[];
|
||||
private notify: () => void = () => {};
|
||||
private barCount: number = 1;
|
||||
|
||||
constructor(options?: BeatInitOptions) {
|
||||
this.unitRecords = {};
|
||||
if (options) {
|
||||
this.drumSchema = [...options.drumSchema];
|
||||
this.initUnitRecords();
|
||||
this.setTimeSignature(options.timeSig.up, options.timeSig.down);
|
||||
this.setBars(options.bars);
|
||||
} else {
|
||||
this.drumSchema = ['LF', 'LH', 'RH', 'RF'];
|
||||
this.initUnitRecords();
|
||||
this.setTimeSignature(4, 4);
|
||||
this.setBars(48);
|
||||
}
|
||||
}
|
||||
|
||||
private initUnitRecords(): void {
|
||||
for (const drumSchemaTag of this.drumSchema) {
|
||||
this.unitRecords[drumSchemaTag] = [];
|
||||
}
|
||||
}
|
||||
|
||||
setTimeSignature(up: number, down: number): void {
|
||||
if (Beat.isValidTimeSigRange(up)) {
|
||||
if (Beat.isValidTimeSigRange(down)) {
|
||||
this.timeSigUp = up | 0;
|
||||
this.timeSigDown = down | 0;
|
||||
this.updateBeatUnitLength();
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setBars(barCount: number): void {
|
||||
const isPosInt = (barCount > 0 && (barCount | 0) === barCount);
|
||||
if (!isPosInt || barCount == this.barCount) {
|
||||
return;
|
||||
}
|
||||
this.barCount = barCount;
|
||||
this.updateBeatUnitLength();
|
||||
this.notify();
|
||||
}
|
||||
|
||||
private updateBeatUnitLength() {
|
||||
const newBarCount = this.barCount * this.timeSigUp;
|
||||
for (const drumSchemaTag of this.drumSchema) {
|
||||
const unitRecord = this.unitRecords[drumSchemaTag];
|
||||
if (newBarCount < unitRecord.length) {
|
||||
unitRecord.splice(this.barCount, unitRecord.length - newBarCount);
|
||||
} else if (newBarCount > unitRecord.length) {
|
||||
const barsToAdd = newBarCount - unitRecord.length;
|
||||
for (let i = 0; i < barsToAdd; i++) {
|
||||
unitRecord.push(new BeatUnit());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getTimeSigUp(): number {
|
||||
return this.timeSigUp;
|
||||
}
|
||||
|
||||
getTimeSigDown(): number {
|
||||
return this.timeSigDown;
|
||||
}
|
||||
|
||||
stringify(): string {
|
||||
let stringified = this.drumSchema.join(" ");
|
||||
stringified += "\n";
|
||||
for (let i = 0; i < this.unitRecords[this.drumSchema[0]].length; i++) {
|
||||
for (const drumSchemaTag of this.drumSchema) {
|
||||
stringified += this.unitRecords[drumSchemaTag][i].stringify() + " ";
|
||||
}
|
||||
if (i % this.timeSigUp === 2) {
|
||||
stringified += "\n";
|
||||
}
|
||||
stringified += "\n";
|
||||
}
|
||||
return stringified;
|
||||
}
|
||||
|
||||
swapSchemaOrder(index1: number, index2: number): void {
|
||||
if (this.drumSchema[index1] && this.drumSchema[index2]) {
|
||||
const temp = this.drumSchema[index1];
|
||||
this.drumSchema[index1] = this.drumSchema[index2];
|
||||
this.drumSchema[index2] = temp;
|
||||
}
|
||||
this.notify();
|
||||
}
|
||||
|
||||
turnUnitOn(schemaKey: string, index: number): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
if (this.unitRecords[schemaKey] && this.unitRecords[schemaKey][index]) {
|
||||
this.unitRecords[schemaKey][index].setOn(true);
|
||||
}
|
||||
}
|
||||
|
||||
turnUnitOff(schemaKey: string, index: number): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
if (this.unitRecords[schemaKey] && this.unitRecords[schemaKey][index]) {
|
||||
this.unitRecords[schemaKey][index].setOn(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
toggleUnit(schemaKey: string, index: number): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
if (this.unitRecords[schemaKey] && this.unitRecords[schemaKey][index]) {
|
||||
this.unitRecords[schemaKey][index].toggle();
|
||||
}
|
||||
}
|
||||
|
||||
setUnitType(schemaKey: string, index: number, type: BeatUnitType): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
this.unitRecords[schemaKey]?.[index]?.setType(type);
|
||||
}
|
||||
|
||||
onUpdate(updateCallback: () => void) {
|
||||
this.notify = updateCallback;
|
||||
}
|
||||
|
||||
getUnit(schemaKey: string, index: number): BeatUnit | null {
|
||||
return this.unitRecords[schemaKey]?.[index] ?? null;
|
||||
}
|
||||
|
||||
getDrumSchema(): string[] {
|
||||
return this.drumSchema.slice();
|
||||
}
|
||||
|
||||
getBarCount(): number {
|
||||
return this.barCount;
|
||||
}
|
||||
|
||||
private static isValidTimeSigRange(sig: number): boolean {
|
||||
return sig >= 2 && sig <= 64;
|
||||
}
|
||||
import BeatUnit, {BeatUnitType} from "./BeatUnit";
|
||||
|
||||
export type BeatInitOptions = {
|
||||
timeSig: {
|
||||
up: number,
|
||||
down: number,
|
||||
},
|
||||
name: string,
|
||||
bars: number,
|
||||
};
|
||||
|
||||
export default class Beat {
|
||||
private static count = 0;
|
||||
private readonly key: string;
|
||||
private name: string;
|
||||
private timeSigUp = 4;
|
||||
private timeSigDown = 4;
|
||||
private readonly unitRecord: BeatUnit[] = [];
|
||||
private observers: (() => void)[] = [];
|
||||
private barCount = 1;
|
||||
|
||||
constructor(options: BeatInitOptions) {
|
||||
this.key = `Beat-${Beat.count}`;
|
||||
if (options.timeSig) {
|
||||
this.name = options.name;
|
||||
this.setTimeSignature(options.timeSig.up, options.timeSig.down);
|
||||
this.setBars(options.bars);
|
||||
} else {
|
||||
this.name = this.key;
|
||||
this.setTimeSignature(4, 4);
|
||||
this.setBars(48);
|
||||
}
|
||||
Beat.count++;
|
||||
}
|
||||
|
||||
setTimeSignature(up: number, down: number): void {
|
||||
if (Beat.isValidTimeSigRange(up)) {
|
||||
if (Beat.isValidTimeSigRange(down)) {
|
||||
this.timeSigUp = up | 0;
|
||||
this.timeSigDown = down | 0;
|
||||
this.updateBeatUnitLength();
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setBars(barCount: number): void {
|
||||
const isPosInt = (barCount > 0 && (barCount | 0) === barCount);
|
||||
if (!isPosInt || barCount == this.barCount) {
|
||||
return;
|
||||
}
|
||||
this.barCount = barCount;
|
||||
this.updateBeatUnitLength();
|
||||
this.notify();
|
||||
}
|
||||
|
||||
private updateBeatUnitLength() {
|
||||
const newBarCount = this.barCount * this.timeSigUp;
|
||||
if (newBarCount < this.unitRecord.length) {
|
||||
this.unitRecord.splice(this.barCount * this.timeSigUp, this.unitRecord.length - newBarCount);
|
||||
} else if (newBarCount > this.unitRecord.length) {
|
||||
const barsToAdd = newBarCount - this.unitRecord.length;
|
||||
for (let i = 0; i < barsToAdd; i++) {
|
||||
this.unitRecord.push(new BeatUnit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getTimeSigUp(): number {
|
||||
return this.timeSigUp;
|
||||
}
|
||||
|
||||
getTimeSigDown(): number {
|
||||
return this.timeSigDown;
|
||||
}
|
||||
|
||||
turnUnitOn(index: number): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
const unit = this.getUnit(index);
|
||||
if (unit) {
|
||||
unit.setOn(true);
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
turnUnitOff(index: number): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
const unit = this.getUnit(index);
|
||||
if (unit) {
|
||||
unit.setOn(false);
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
toggleUnit(index: number): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
const unit = this.getUnit(index);
|
||||
if (unit) {
|
||||
unit.toggle();
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
setUnitType(index: number, type: BeatUnitType): void {
|
||||
if (Math.abs(index | 0) !== index) {
|
||||
return;
|
||||
}
|
||||
this.getUnit(index).setType(type);
|
||||
this.notify();
|
||||
}
|
||||
|
||||
unitIsOn(index: number): boolean {
|
||||
return this.getUnit(index)?.isOn();
|
||||
}
|
||||
|
||||
unitType(index: number): BeatUnitType {
|
||||
return this.getUnit(index)?.getType();
|
||||
}
|
||||
|
||||
onUpdate(updateCallback: () => void): void {
|
||||
this.observers.push(updateCallback);
|
||||
}
|
||||
|
||||
private getUnit(index: number): BeatUnit {
|
||||
if (!this.unitRecord[index]) {
|
||||
throw new Error(`Invalid beat unit index! - ${index}`);
|
||||
}
|
||||
return this.unitRecord[index];
|
||||
}
|
||||
|
||||
getBarCount(): number {
|
||||
return this.barCount;
|
||||
}
|
||||
|
||||
getKey(): string {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
private static isValidTimeSigRange(sig: number): boolean {
|
||||
return sig >= 2 && sig <= 64;
|
||||
}
|
||||
|
||||
private notify(): void {
|
||||
this.observers.forEach(observer => observer());
|
||||
}
|
||||
|
||||
setName(newName: string): void {
|
||||
this.name = newName;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
102
src/BeatGroup.ts
Normal file
102
src/BeatGroup.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import Beat, {BeatInitOptions} from "./Beat";
|
||||
|
||||
type BeatGroupInitOptions = {
|
||||
beats: BeatInitOptions[],
|
||||
}
|
||||
|
||||
export default class BeatGroup {
|
||||
private beats: Beat[] = [];
|
||||
private beatKeyMap: Record<string, number> = {};
|
||||
private subscribers: (() => void)[] = [];
|
||||
|
||||
constructor(options: BeatGroupInitOptions) {
|
||||
for (const beatOptions of options.beats) {
|
||||
const newBeat = new Beat(beatOptions);
|
||||
this.beats.push(newBeat);
|
||||
this.beatKeyMap[newBeat.getKey()] = this.beats.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
getBeatByKey(beatKey: string): Beat {
|
||||
if (typeof this.beatKeyMap[beatKey] === "undefined") {
|
||||
throw new Error(`Could not find the beat with key: ${beatKey}`);
|
||||
}
|
||||
return this.getBeatByIndex(this.beatKeyMap[beatKey]);
|
||||
}
|
||||
|
||||
getBeatByIndex(beatIndex: number): Beat {
|
||||
if (!this.beats[beatIndex]) {
|
||||
throw new Error(`Could not find the beat with index: ${beatIndex}`);
|
||||
}
|
||||
return this.beats[beatIndex];
|
||||
}
|
||||
|
||||
getBeatCount(): number {
|
||||
return this.beats.length;
|
||||
}
|
||||
|
||||
getBeatKeys(): string[] {
|
||||
return this.beats.map(beat => beat.getKey());
|
||||
}
|
||||
|
||||
swapBeatsByIndices(beatIndex1: number, beatIndex2: number): void {
|
||||
const beat1 = this.getBeatByIndex(beatIndex1);
|
||||
const beat2 = this.getBeatByIndex(beatIndex2);
|
||||
this.beats[beatIndex1] = beat2;
|
||||
this.beats[beatIndex2] = beat1;
|
||||
this.beatKeyMap[beat1.getKey()] = beatIndex2;
|
||||
this.beatKeyMap[beat2.getKey()] = beatIndex1;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
swapBeatsByKeys(beatKey1: string, beatKey2: string): void {
|
||||
const index1 = this.beatKeyMap[this.getBeatByKey(beatKey1).getKey()];
|
||||
const index2 = this.beatKeyMap[this.getBeatByKey(beatKey2).getKey()];
|
||||
this.swapBeatsByIndices(index1, index2);
|
||||
}
|
||||
|
||||
private notify(): void {
|
||||
this.subscribers.forEach(subscriber => subscriber());
|
||||
}
|
||||
|
||||
onBeatChangeByKey(beatKey: string, subscriber: (beatKey: string) => void): void {
|
||||
this.getBeatByKey(beatKey).onUpdate(() => subscriber(beatKey));
|
||||
}
|
||||
|
||||
onBeatChangeByIndex(beatIndex: number, subscriber: (beatIndex: number) => void): void {
|
||||
this.getBeatByIndex(beatIndex).onUpdate(() => subscriber(beatIndex));
|
||||
}
|
||||
|
||||
onBeatsChange(subscriber: () => void): void {
|
||||
this.subscribers.push(subscriber);
|
||||
}
|
||||
|
||||
moveBeatBack(beatKey: string): void {
|
||||
const index = this.beatKeyMap[beatKey];
|
||||
if (typeof index !== "undefined" && index > 0) {
|
||||
this.swapBeatsByIndices(index, index - 1);
|
||||
}
|
||||
this.notify();
|
||||
}
|
||||
|
||||
moveBeatForward(beatKey: string): void {
|
||||
const index = this.beatKeyMap[beatKey];
|
||||
if (typeof index !== "undefined" && index < this.getBeatCount()) {
|
||||
this.swapBeatsByIndices(index, index + 1);
|
||||
}
|
||||
this.notify();
|
||||
}
|
||||
|
||||
canMoveBeatBack(beatKey: string): boolean {
|
||||
return this.beatKeyMap[beatKey] > 0;
|
||||
}
|
||||
|
||||
canMoveBeatForward(beatKey: string): boolean {
|
||||
return this.beatKeyMap[beatKey] < this.beats.length - 1;
|
||||
}
|
||||
|
||||
setBeatName(beatKey: string, newName: string): void {
|
||||
this.getBeatByKey(beatKey).setName(newName);
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
107
src/BeatUnit.ts
107
src/BeatUnit.ts
@@ -1,59 +1,48 @@
|
||||
export enum BeatUnitType {
|
||||
Normal,
|
||||
GhostNote,
|
||||
}
|
||||
|
||||
|
||||
export default class BeatUnit {
|
||||
private on: boolean = false;
|
||||
private type: BeatUnitType = BeatUnitType.Normal;
|
||||
private onUpdateCallbacks: ((on: boolean, type: BeatUnitType) => void)[] = [];
|
||||
|
||||
constructor(on: boolean = false) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
stringify(): string {
|
||||
if (!this.on) {
|
||||
return "O";
|
||||
}
|
||||
if (this.type === BeatUnitType.GhostNote) {
|
||||
return "G";
|
||||
} else {
|
||||
return "#";
|
||||
}
|
||||
}
|
||||
|
||||
toggle(): void {
|
||||
this.on = !this.on;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
setOn(on: boolean): void {
|
||||
this.on = on;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
setType(type: BeatUnitType) {
|
||||
this.type = type;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
getType(): BeatUnitType {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
isOn(): boolean {
|
||||
return this.on;
|
||||
}
|
||||
|
||||
onUpdate(callback: (on: boolean, type: BeatUnitType) => void) {
|
||||
this.onUpdateCallbacks.push(callback);
|
||||
}
|
||||
|
||||
notify(): void {
|
||||
for (const cb of this.onUpdateCallbacks) {
|
||||
cb(this.on, this.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
export enum BeatUnitType {
|
||||
Normal,
|
||||
GhostNote,
|
||||
}
|
||||
|
||||
|
||||
export default class BeatUnit {
|
||||
private on = false;
|
||||
private type: BeatUnitType = BeatUnitType.Normal;
|
||||
private onUpdateCallbacks: ((on: boolean, type: BeatUnitType) => void)[] = [];
|
||||
|
||||
constructor(on = false) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
toggle(): void {
|
||||
this.on = !this.on;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
setOn(on: boolean): void {
|
||||
this.on = on;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
setType(type: BeatUnitType): void {
|
||||
this.type = type;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
getType(): BeatUnitType {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
isOn(): boolean {
|
||||
return this.on;
|
||||
}
|
||||
|
||||
onUpdate(callback: (on: boolean, type: BeatUnitType) => void): void {
|
||||
this.onUpdateCallbacks.push(callback);
|
||||
}
|
||||
|
||||
notify(): void {
|
||||
for (const cb of this.onUpdateCallbacks) {
|
||||
cb(this.on, this.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
src/Store.ts
20
src/Store.ts
@@ -1,20 +0,0 @@
|
||||
import type BeatUnit from "./BeatUnit";
|
||||
import Beat, {BeatInitOptions} from "./Beat";
|
||||
|
||||
export default class Store {
|
||||
private beat: Beat;
|
||||
constructor(options: BeatInitOptions) {
|
||||
this.beat = new Beat(options);
|
||||
}
|
||||
|
||||
getBeat() {
|
||||
return this.beat;
|
||||
}
|
||||
|
||||
subscribeBeatUnit(schemaKey: string, index: number, callback: (unit: BeatUnit) => void): BeatUnit {
|
||||
this.beat.onUnitUpdate(() => {
|
||||
callback(this.beat.getUnit(schemaKey, index));
|
||||
});
|
||||
return this.beat.getUnit(schemaKey, index);
|
||||
}
|
||||
}
|
||||
3
src/config.json
Normal file
3
src/config.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"development": true
|
||||
}
|
||||
1
src/index.ts
Normal file
1
src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
console.log("Hello World!");
|
||||
54
src/main.ts
54
src/main.ts
@@ -1,18 +1,38 @@
|
||||
import App from './ui/App.svelte';
|
||||
import Store from "./Store";
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
props: {
|
||||
store: new Store({
|
||||
bars: 10,
|
||||
timeSig: {
|
||||
down: 4,
|
||||
up: 4,
|
||||
},
|
||||
drumSchema: ['LF', 'LH', 'RH', 'RF'],
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
import App from "./ui/App.svelte";
|
||||
import Store from "./Store";
|
||||
|
||||
const defaultSettings = {
|
||||
bars: 10,
|
||||
timeSig: {
|
||||
down: 4,
|
||||
up: 4,
|
||||
},
|
||||
};
|
||||
|
||||
const store = new Store({
|
||||
beats: [
|
||||
{
|
||||
name: "LF",
|
||||
...defaultSettings,
|
||||
},
|
||||
{
|
||||
name: "LH",
|
||||
...defaultSettings,
|
||||
},
|
||||
{
|
||||
name: "RH",
|
||||
...defaultSettings,
|
||||
},
|
||||
{
|
||||
name: "RF",
|
||||
...defaultSettings,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
props: {store},
|
||||
});
|
||||
|
||||
export default app;
|
||||
@@ -1,13 +1,4 @@
|
||||
import {BeatUnitType} from "./BeatUnit";
|
||||
import Beat from "./Beat";
|
||||
|
||||
const beat = new Beat({
|
||||
drumSchema: ["LH", "RH", "LF", "LR"],
|
||||
timeSig: {
|
||||
up: 3,
|
||||
down: 4,
|
||||
},
|
||||
bars: 10,
|
||||
});
|
||||
|
||||
console.log(beat.stringify());
|
||||
@@ -1,23 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Store from "../Store";
|
||||
import Beat from "./Beat.svelte";
|
||||
|
||||
export let store: Store;
|
||||
</script>
|
||||
|
||||
<h1>
|
||||
ArneDrums
|
||||
</h1>
|
||||
<div class="main-contianer">
|
||||
<Beat beat="{store.getBeat()}"/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
.main-contianer {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -1,104 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type Beat from "../Beat";
|
||||
import BeatUnit from "./BeatUnit.svelte";
|
||||
|
||||
export let beat: Beat;
|
||||
export let landscape: boolean = true;
|
||||
|
||||
beat.onUpdate(() => {
|
||||
beat = beat;
|
||||
});
|
||||
|
||||
$: timeSigUp = beat.getTimeSigUp();
|
||||
$: barCount = beat.getBarCount();
|
||||
$: drumSchema = beat.getDrumSchema();
|
||||
|
||||
function addBar() {
|
||||
beat.setBars(beat.getBarCount() + 1);
|
||||
}
|
||||
|
||||
function removeBar() {
|
||||
beat.setBars(beat.getBarCount() - 1);
|
||||
}
|
||||
|
||||
function handleInputTimeSigUp(e: InputEvent) {
|
||||
const sigUp = Number((e.target as HTMLInputElement).value);
|
||||
beat.setTimeSignature(sigUp, beat.getTimeSigDown());
|
||||
}
|
||||
|
||||
function handleInputTimeSigDown(e: InputEvent) {
|
||||
const sigDown = Number((e.target as HTMLInputElement).value);
|
||||
beat.setTimeSignature(beat.getTimeSigUp(), sigDown);
|
||||
}
|
||||
</script>
|
||||
|
||||
<h1>Beat</h1>
|
||||
|
||||
<button on:click={addBar}>Add Bar</button>
|
||||
<button on:click={removeBar}>Remove Bar</button>
|
||||
<button on:click={() => landscape = !landscape}>Toggle View</button>
|
||||
<h3>Time Sig</h3>
|
||||
<input type="text" value="{beat.getTimeSigUp()}" on:input={handleInputTimeSigUp}/>
|
||||
<p>---</p>
|
||||
<input type="text" value="{beat.getTimeSigDown()}" on:input={handleInputTimeSigDown}/>
|
||||
|
||||
<div class="lines" class:landscape={landscape}>
|
||||
{#each drumSchema as drumSchemaKey}
|
||||
<div class="drum-line">
|
||||
<h3>{drumSchemaKey}</h3>
|
||||
{#each {length: barCount} as _, barIndex}
|
||||
<div class="bar">
|
||||
{#each {length: timeSigUp} as _, noteIndex}
|
||||
<div class="unit">
|
||||
<BeatUnit unit="{beat.getUnit(drumSchemaKey, timeSigUp*barIndex + noteIndex)}"/>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
color: red;
|
||||
text-align: center;
|
||||
}
|
||||
.unit {
|
||||
display: block;
|
||||
}
|
||||
.lines.landscape .unit {
|
||||
display: inline-block;
|
||||
}
|
||||
.bar {
|
||||
display: block;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.lines.landscape .bar {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
margin-right: 1em;
|
||||
}
|
||||
.drum-line {
|
||||
display: block;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.drum-line h3 {
|
||||
display: inline-block;
|
||||
width: 3em;
|
||||
}
|
||||
.lines.landscape .drum-line {
|
||||
display: inline-block;
|
||||
}
|
||||
.lines {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: auto;
|
||||
}
|
||||
.lines.landscape {
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
@@ -1,35 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type BeatUnit from "../BeatUnit";
|
||||
import {BeatUnitType} from "../BeatUnit";
|
||||
|
||||
export let unit: BeatUnit;
|
||||
|
||||
unit.onUpdate(() => {
|
||||
unit = unit;
|
||||
});
|
||||
|
||||
$: ghost = unit.getType() === BeatUnitType.GhostNote;
|
||||
$: active = unit.isOn();
|
||||
|
||||
function onClick() {
|
||||
unit.toggle();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="unit" class:ghost={ghost} class:active={active} on:click={onClick}>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.unit {
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
background-color: white;
|
||||
border: solid black 1px;
|
||||
}
|
||||
.active {
|
||||
background-color: #d97474;
|
||||
}
|
||||
.ghost {
|
||||
background-color: #bc8787;
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "ESNext"],
|
||||
"target": "ESNext"
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noImplicitAny": true,
|
||||
"module": "es6",
|
||||
"target": "es5",
|
||||
"allowJs": true
|
||||
},
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["./node_modules/*", "./__sapper__/*"]
|
||||
}
|
||||
"files": ["src/index.ts"]
|
||||
}
|
||||
|
||||
67
webpack.config.js
Normal file
67
webpack.config.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// Generated using webpack-cli https://github.com/webpack/webpack-cli
|
||||
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
|
||||
const isProduction = process.env.NODE_ENV == 'production';
|
||||
|
||||
|
||||
const stylesHandler = MiniCssExtractPlugin.loader;
|
||||
|
||||
|
||||
|
||||
const config = {
|
||||
entry: './src/index.ts',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
},
|
||||
devServer: {
|
||||
open: true,
|
||||
host: 'localhost',
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'index.html',
|
||||
}),
|
||||
|
||||
new MiniCssExtractPlugin(),
|
||||
|
||||
// Add your plugins here
|
||||
// Learn more about plugins from https://webpack.js.org/configuration/plugins/
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(ts|tsx)$/i,
|
||||
loader: 'ts-loader',
|
||||
exclude: ['/node_modules/'],
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: [stylesHandler,'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
|
||||
type: 'asset',
|
||||
},
|
||||
|
||||
// Add your rules for custom modules here
|
||||
// Learn more about loaders from https://webpack.js.org/loaders/
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = () => {
|
||||
if (isProduction) {
|
||||
config.mode = 'production';
|
||||
|
||||
|
||||
} else {
|
||||
config.mode = 'development';
|
||||
}
|
||||
return config;
|
||||
};
|
||||
Reference in New Issue
Block a user