This commit is contained in:
Daniel Ledda
2024-12-01 17:42:58 +01:00
parent 91958489c0
commit a3b428a226
9 changed files with 112 additions and 101 deletions

View File

@@ -1,7 +0,0 @@
export default {
extends: [
// add more generic rulesets here, such as:
'eslint:recommended',
'plugin:vue/vue3-recommended',
],
};

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,7 +12,8 @@
:sticking-type="type + 1" />
</div>
</template>
<VueDraggableNext v-else
<div v-else class="beat-wrap-row">
<VueDraggableNext
@start="dragging = true"
@end="dragging = false"
animation="150"
@@ -23,16 +24,11 @@
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 v-if="element.track.visible.value" :key="element.index">
<div class="beat-line">
<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 @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" />
@@ -42,10 +38,24 @@
<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>
</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>
</template>
@@ -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 {

View File

@@ -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);

View File

@@ -1,9 +1,5 @@
<template>
<div class="track-settings" v-if="track && beat">
<div class="track-settings-title-container">
<editable-text-field v-model="track.name.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">
@@ -12,19 +8,13 @@
<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-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 {
.track-settings {
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;
}
background-color: var(--color-bg-medium);
.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>

View File

@@ -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;

View File

@@ -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;