update
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
export default {
|
||||
extends: [
|
||||
// add more generic rulesets here, such as:
|
||||
'eslint:recommended',
|
||||
'plugin:vue/vue3-recommended',
|
||||
],
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import {inject, type InjectionKey, ref, getCurrentInstance, watch} from "vue";
|
||||
import { inject, type InjectionKey, ref, getCurrentInstance, watch } from "vue";
|
||||
import { Bound } from "./utils";
|
||||
|
||||
export type UITool =
|
||||
|
||||
@@ -31,11 +31,13 @@ export class BeatStore extends Bound {
|
||||
activeBeatIndex = ref(0);
|
||||
activeBeat = computed<Beat | null>(() => this.beats.value[this.activeBeatIndex.value] ?? null);
|
||||
orientation = ref<"horizontal" | "vertical">("horizontal");
|
||||
trackSettingsOpen = ref<number | null>(null);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
watch([this.activeBeatIndex, this.orientation, this.beats], () => {
|
||||
this.saveDirtyGlobal.value = true;
|
||||
this.trackSettingsOpen.value = null;
|
||||
});
|
||||
|
||||
const saveInterval = setInterval(() => this.saveDirtyGlobal.value && this.save("localStorage"), 5 * 60 * 1000);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { isPosInt, EffectScoped } from "@/utils";
|
||||
import { ref, shallowRef, computed, watch, reactive, triggerRef, type Ref, type ShallowRef } from "vue";
|
||||
import type { BeatManager } from "./Beat";
|
||||
import { z } from "zod";
|
||||
import { useAppStateStore, type UITool } from "./AppState";
|
||||
import { useAppStateStore } from "./AppState";
|
||||
|
||||
export type TrackInitOptions = {
|
||||
visible?: boolean,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-if="beat" class="beat" :class="{ vertical: false }">
|
||||
<div v-if="beat" class="beat">
|
||||
<editable-text-field node-type="h3" class="beat-title" v-model="beat.name.value" />
|
||||
<div class="beat-main-container">
|
||||
<div class="beat-track-container" :class="{ dragging }">
|
||||
@@ -12,39 +12,49 @@
|
||||
:sticking-type="type + 1" />
|
||||
</div>
|
||||
</template>
|
||||
<VueDraggableNext v-else
|
||||
@start="dragging = true"
|
||||
@end="dragging = false"
|
||||
animation="150"
|
||||
ghost-class="ghost"
|
||||
handle=".handle"
|
||||
:list="tracks"
|
||||
@change="onMove"
|
||||
item-key="index">
|
||||
<transition-group name="fade">
|
||||
<template v-for="element in tracks">
|
||||
<div v-if="element.track.visible.value" class="beat-line" :key="element.index">
|
||||
<div class="track-actions">
|
||||
<span class="track-action">
|
||||
<icon color="var(--color-ui-neutral-dark)"
|
||||
@click="element.track.visible.value = !element.track.visible.value"
|
||||
:icon-name="element.track.visible.value ? 'eye' : 'eyeOff'" />
|
||||
</span>
|
||||
<span class="track-action"
|
||||
@click="applyToolToTrack(element.track)">
|
||||
<icon color="var(--color-ui-neutral-dark)" icon-name="paintBucket" />
|
||||
</span>
|
||||
<span class="handle track-action">
|
||||
<icon color="var(--color-ui-neutral-dark)" icon-name="list" />
|
||||
</span>
|
||||
<div v-else class="beat-wrap-row">
|
||||
<VueDraggableNext
|
||||
@start="dragging = true"
|
||||
@end="dragging = false"
|
||||
animation="150"
|
||||
ghost-class="ghost"
|
||||
handle=".handle"
|
||||
:list="tracks"
|
||||
@change="onMove"
|
||||
item-key="index">
|
||||
<transition-group name="fade">
|
||||
<template v-for="element in tracks">
|
||||
<div v-if="element.track.visible.value" :key="element.index">
|
||||
<div class="beat-line">
|
||||
<div class="track-actions">
|
||||
<span @click="toggleTrackSettings(element.index)" class="track-action">
|
||||
<icon color="var(--color-ui-neutral-dark)" :icon-name="trackSettingsOpen === element.index ? 'up' : 'down'" />
|
||||
</span>
|
||||
<span class="handle track-action">
|
||||
<icon color="var(--color-ui-neutral-dark)" icon-name="list" />
|
||||
</span>
|
||||
</div>
|
||||
<editable-text-field class="track-name" v-model="element.track.name.value" />
|
||||
<track-view :beat-index="beatIndex"
|
||||
:track-index="element.index" />
|
||||
</div>
|
||||
<track-settings-view v-show="trackSettingsOpen === element.index" :beat-index="beatIndex" :track-index="element.index" />
|
||||
</div>
|
||||
<editable-text-field class="track-name" v-model="element.track.name.value" />
|
||||
<track-view :beat-index="beatIndex"
|
||||
:track-index="element.index" />
|
||||
</div>
|
||||
</template>
|
||||
</transition-group>
|
||||
</VueDraggableNext>
|
||||
</template>
|
||||
</transition-group>
|
||||
</VueDraggableNext>
|
||||
</div>
|
||||
<!--
|
||||
<div v-for="i in beat.barCount.value - 1" class="beat-wrap-row">
|
||||
<template v-for="(element, j) in tracks" :key="j">
|
||||
<div v-if="element.track.visible.value" class="beat-line" :key="element.index">
|
||||
<track-view :beat-index="beatIndex"
|
||||
:bars="{ start: i, count: 1 }"
|
||||
:track-index="element.index" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,13 +70,14 @@
|
||||
import { TrackUnitStickingTypeList, type Track } from "@/Track";
|
||||
import Icon from "@/ui/Widgets/Icon/Icon.vue";
|
||||
import { StickingTypeIconMap } from "../TrackUnit/trackUnit";
|
||||
import TrackSettingsView from "@/ui/TrackSettings/TrackSettings.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
beatIndex: number,
|
||||
orientation?: "horizontal" | "vertical",
|
||||
}>();
|
||||
|
||||
const { beats } = useBeatStore();
|
||||
const { beats, trackSettingsOpen } = useBeatStore();
|
||||
const beat = computed(() => beats.value[props.beatIndex] ?? null);
|
||||
|
||||
const tracks = computed(() => {
|
||||
@@ -87,6 +98,14 @@
|
||||
|
||||
const dragging = ref(false);
|
||||
|
||||
function toggleTrackSettings(trackIndex: number) {
|
||||
if (trackSettingsOpen.value === trackIndex) {
|
||||
trackSettingsOpen.value = null;
|
||||
} else {
|
||||
trackSettingsOpen.value = trackIndex;
|
||||
}
|
||||
}
|
||||
|
||||
function onMove(evt: { moved: { oldIndex: number, newIndex: number }}) {
|
||||
if (props.orientation !== 'horizontal') {
|
||||
beat.value?.insertAt(tracks.value.length - 1 - evt.moved.oldIndex, tracks.value.length - 1 - evt.moved.newIndex);
|
||||
@@ -110,6 +129,11 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.beat-wrap-row {
|
||||
display: inline-block;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.beat-title {
|
||||
color: var(--color-title-light);
|
||||
text-align: center;
|
||||
@@ -124,7 +148,7 @@
|
||||
|
||||
.beat-main-container {
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
//white-space: nowrap;
|
||||
}
|
||||
|
||||
.track-name {
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
beatIndex: number,
|
||||
locked?: boolean,
|
||||
trackIndex: number,
|
||||
bars?: { start: number, count: number },
|
||||
}>();
|
||||
|
||||
const {
|
||||
@@ -52,8 +53,16 @@
|
||||
|
||||
const trackUnits = computed(() => {
|
||||
const units = [];
|
||||
if (track.value) {
|
||||
for (let i = 0; i < track.value.unitCount(); i++) {
|
||||
let start = 0;
|
||||
let end = 0;
|
||||
if (track.value && beat.value) {
|
||||
if (props.bars) {
|
||||
start = beat.value.timeSigUp.value * props.bars.start;
|
||||
end = start + beat.value.timeSigUp.value * props.bars.count;
|
||||
} else {
|
||||
end = track.value.unitCount();
|
||||
}
|
||||
for (let i = start; i < end; i++) {
|
||||
const unit = track.value.getUnitByIndex(i);
|
||||
if (unit) {
|
||||
units.push(unit);
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
<template>
|
||||
<div class="track-settings" v-if="track && beat">
|
||||
<div class="track-settings-title-container">
|
||||
<editable-text-field v-model="track.name.value" />
|
||||
<action-button icon-name="snowflake" type="secondary" alt="Bake Loops" :disabled="!track.looping.value" @click="track.bakeLoops()" />
|
||||
<action-button icon-name="trash" type="secondary" alt="Delete Track" @click="beat.removeTrack(trackIndex)" />
|
||||
<div class="loop-settings">
|
||||
<bool-box label="Loop:" v-model="track.looping.value" />
|
||||
</div>
|
||||
<div class="track-settings-lower">
|
||||
<action-button icon-name="snowflake" type="secondary" alt="Bake Loops" :disabled="!track.looping.value" @click="track.bakeLoops()" />
|
||||
<action-button icon-name="trash" type="secondary" alt="Delete Track" @click="beat.removeTrack(trackIndex)" />
|
||||
<div class="loop-settings">
|
||||
<bool-box label="Loop:" v-model="track.looping.value" />
|
||||
<div class="loop-settings-option" :class="{ hide: !track.looping.value }">
|
||||
<number-input v-model="track.loopLength.value" />
|
||||
</div>
|
||||
<div class="loop-settings-option" :class="{ hide: !track.looping.value }">
|
||||
<number-input v-model="track.loopLength.value" />
|
||||
</div>
|
||||
<div class="visibility">
|
||||
<icon color="var(--color-ui-neutral-dark)" :icon-name="track.visible.value ? 'eye' : 'eyeOff'" @click="track.visible.value = !track.visible.value"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import NumberInput from "@/ui/Widgets/NumberInput/NumberInput.vue";
|
||||
import Icon from "@/ui/Widgets/Icon/Icon.vue";
|
||||
import BoolBox from "@/ui/Widgets/BoolBox/BoolBox.vue";
|
||||
import ActionButton from "@/ui/Widgets/ActionButton/ActionButton.vue";
|
||||
import EditableTextField from "@/ui/Widgets/EditableTextField/EditableTextField.vue";
|
||||
import { useBeatStore } from "@/BeatStore";
|
||||
import { computed } from "vue";
|
||||
|
||||
@@ -39,54 +29,39 @@
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.track-settings-title-container input {
|
||||
min-width: 100%;
|
||||
height: 2em;
|
||||
}
|
||||
.track-settings {
|
||||
height: 3.5em;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.5em;
|
||||
background-color: var(--color-bg-medium);
|
||||
|
||||
.track-settings-title-container > div {
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
padding: 0.5em;
|
||||
transition: background-color 200ms;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.track-settings-title-container > div:hover {
|
||||
background-color: var(--color-ui-neutral-dark-hover);
|
||||
}
|
||||
|
||||
.track-settings-lower {
|
||||
height: 3.5em;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.track-settings-lower > * {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
.track-settings-lower:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.track-settings .loop-settings {
|
||||
.loop-settings {
|
||||
text-align: left;
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
.track-settings .loop-settings-option.hide {
|
||||
.loop-settings-option.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.track-settings .loop-settings-option {
|
||||
.loop-settings-option {
|
||||
flex: auto;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
> * {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.visibility {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -13,9 +13,13 @@ import Floppy from "@/assets/svgs/floppy2-fill.svg";
|
||||
import Delete from "@/assets/svgs/delete.svg";
|
||||
import Eye from "@/assets/svgs/eye.svg";
|
||||
import EyeOff from "@/assets/svgs/eye-off.svg";
|
||||
import PaintBucket from '@/assets/svgs/paint-bucket.svg';
|
||||
import Sun from '@/assets/svgs/sun.svg';
|
||||
import Moon from '@/assets/svgs/moon.svg';
|
||||
import PaintBucket from "@/assets/svgs/paint-bucket.svg";
|
||||
import Sun from "@/assets/svgs/sun.svg";
|
||||
import Moon from "@/assets/svgs/moon.svg";
|
||||
import Up from "@/assets/svgs/chevron-up.svg";
|
||||
import Down from "@/assets/svgs/chevron-down.svg";
|
||||
import Left from "@/assets/svgs/chevron-left.svg";
|
||||
import Right from "@/assets/svgs/chevron-right.svg";
|
||||
|
||||
export const IconUrlMap = {
|
||||
arrowClockwise: ArrowClockwise,
|
||||
@@ -36,6 +40,10 @@ export const IconUrlMap = {
|
||||
paintBucket: PaintBucket,
|
||||
sun: Sun,
|
||||
moon: Moon,
|
||||
up: Up,
|
||||
down: Down,
|
||||
left: Left,
|
||||
right: Right,
|
||||
} as const;
|
||||
|
||||
export type IconName = keyof typeof IconUrlMap;
|
||||
|
||||
@@ -13,7 +13,7 @@ html, body {
|
||||
--color-ui-neutral-dark-hover: #a1a1a1;
|
||||
--color-ui-neutral-dark-active: #c1c1c1;
|
||||
--color-bg-light: #e0e0e0;
|
||||
--color-bg-medium: #fff;
|
||||
--color-bg-medium: #eee;
|
||||
--color-bg-dark: #fff;
|
||||
--color-p-light: #282828;
|
||||
--color-p-light-hover: #fafafa;
|
||||
|
||||
Reference in New Issue
Block a user