update
This commit is contained in:
@@ -3,13 +3,12 @@ import { Bound } from "./utils";
|
||||
|
||||
export type UITool =
|
||||
| "track-unit-type"
|
||||
| "eraser"
|
||||
| "sticking";
|
||||
|
||||
export class AppStateStore extends Bound {
|
||||
class AppStateStore extends Bound {
|
||||
selectedTool = ref<UITool>("track-unit-type");
|
||||
activeTrackUnitType = ref(0);
|
||||
activeStickingType = ref(1);
|
||||
activeTrackUnitType = ref<number | null>(0);
|
||||
activeStickingType = ref<number | null>(1);
|
||||
unitMouseStart = ref<string | null>(null);
|
||||
selectingUnits = ref(false);
|
||||
deselectingUnits = ref(false);
|
||||
|
||||
@@ -23,7 +23,7 @@ const TrackSerialSchema = z.object({
|
||||
units: z.object({
|
||||
isOn: z.array(z.boolean()),
|
||||
type: z.array(z.number()),
|
||||
stickingType: z.array(z.number()),
|
||||
stickingType: z.array(z.number().nullable()),
|
||||
}),
|
||||
barCount: z.number(),
|
||||
loopLength: z.number(),
|
||||
@@ -72,7 +72,7 @@ export function deserialise(serial: unknown, manager: BeatManager) {
|
||||
export type TrackUnit = {
|
||||
on: boolean,
|
||||
type: number,
|
||||
stickingType: number,
|
||||
stickingType: number | null,
|
||||
};
|
||||
|
||||
export class Track extends EffectScoped {
|
||||
@@ -191,7 +191,7 @@ export class Track extends EffectScoped {
|
||||
};
|
||||
}
|
||||
|
||||
setStickingType(index: number, stickingType: number): void {
|
||||
setStickingType(index: number, stickingType: number | null): void {
|
||||
const unit = this.getUnitByIndex(index);
|
||||
if (!unit) {
|
||||
return;
|
||||
|
||||
1
src/assets/svgs/delete.svg
Normal file
1
src/assets/svgs/delete.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-delete"><path d="M21 4H8l-7 8 7 8h13a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z"></path><line x1="18" y1="9" x2="12" y2="15"></line><line x1="12" y1="9" x2="18" y2="15"></line></svg>
|
||||
|
After Width: | Height: | Size: 374 B |
@@ -5,18 +5,21 @@
|
||||
<div class="toolbox-button paint-button-cont"
|
||||
:class="{ active: selectedTool === 'track-unit-type' }"
|
||||
@click="selectedTool = 'track-unit-type'">
|
||||
<div
|
||||
<track-unit-box
|
||||
v-if="activeTrackUnitType !== null"
|
||||
class="paint-button"
|
||||
:class="getClasses({ on: true, type: TrackUnitTypeList[activeTrackUnitType]!, stickingType: null })" />
|
||||
:sticking-type="null" :on="true" :type="activeTrackUnitType" />
|
||||
<icon v-else class="paint-button" icon-name="eraser" />
|
||||
</div>
|
||||
<template #content>
|
||||
<div class="details">
|
||||
<div v-for="(type, i) in TrackUnitTypeList"
|
||||
:key="type"
|
||||
class="toolbox-button"
|
||||
:class="{ active: i === activeTrackUnitType }"
|
||||
@click="activeTrackUnitType = i; selectedTool = 'track-unit-type'">
|
||||
<div :class="getClasses({ on: true, type, stickingType: null })" />
|
||||
<div v-for="(type, i) in [...TrackUnitTypeList, null]"
|
||||
:key="type ?? 'eraser'"
|
||||
class="toolbox-button track-unit-type"
|
||||
:class="{ active: i === activeTrackUnitType || type === null && activeTrackUnitType === null }"
|
||||
@click="activeTrackUnitType = type === null ? null : i; selectedTool = 'track-unit-type'">
|
||||
<track-unit-box v-if="type !== null" :sticking-type="null" :on="true" :type="i" />
|
||||
<icon v-else icon-name="eraser" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -24,7 +27,7 @@
|
||||
<dropdown>
|
||||
<icon
|
||||
class="toolbox-button"
|
||||
:icon-name="PaintableTrackUnitStickingTypeList[activeStickingType]!"
|
||||
:icon-name="activeStickingType ? (PaintableTrackUnitStickingTypeList[activeStickingType] ?? 'eraser') : 'eraser'"
|
||||
:class="{ active: selectedTool === 'sticking' }"
|
||||
@click="selectedTool = 'sticking'" />
|
||||
<template #content>
|
||||
@@ -36,16 +39,15 @@
|
||||
@click="activeStickingType = i; selectedTool = 'sticking'">
|
||||
<icon :icon-name="StickingTypeIconMap[stickingType]" />
|
||||
</div>
|
||||
<div
|
||||
class="toolbox-button"
|
||||
:class="{ active: activeStickingType === null }"
|
||||
@click="activeStickingType = null; selectedTool = 'sticking'">
|
||||
<icon icon-name="eraser" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</dropdown>
|
||||
<dropdown>
|
||||
<icon
|
||||
class="toolbox-button"
|
||||
icon-name="eraser"
|
||||
:class="{ active: selectedTool === 'eraser' }"
|
||||
@click="selectedTool = 'eraser'" />
|
||||
</dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -56,7 +58,7 @@
|
||||
import { StickingTypeIconMap } from "@/ui/TrackUnit/trackUnit";
|
||||
import Icon from "@/ui/Widgets/Icon/Icon.vue";
|
||||
import Dropdown from '@/ui/Widgets/Dropdown/Dropdown.vue';
|
||||
import { getClasses } from "@/ui/TrackUnit/trackUnit";
|
||||
import TrackUnitBox from "@/ui/TrackUnitBox/TrackUnitBox.vue";
|
||||
|
||||
const {
|
||||
selectedTool,
|
||||
@@ -86,12 +88,19 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.track-unit-type {
|
||||
margin: 5em;
|
||||
}
|
||||
|
||||
.toolbox-button {
|
||||
cursor: pointer;
|
||||
color: black;
|
||||
|
||||
&.eraser {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
&.paint-button-cont {
|
||||
padding: 0.25em;
|
||||
background-color: var(--color-ui-bg-dark);
|
||||
|
||||
&:hover {
|
||||
@@ -111,10 +120,6 @@
|
||||
}
|
||||
|
||||
.paint-button {
|
||||
height: 1.5em;
|
||||
width: 1.5em;
|
||||
background-color: black;
|
||||
|
||||
&.active {
|
||||
background-color: var(--color-ui-neutral-dark);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,9 @@
|
||||
|
||||
function toggle(index: number) {
|
||||
if (!track.value) return;
|
||||
if (selectedTool.value === 'track-unit-type') {
|
||||
track.value.toggleUnit(index);
|
||||
}
|
||||
if (track.value.getUnitByIndex(index)?.on) {
|
||||
applyCurrentToolToTrackUnit(index);
|
||||
}
|
||||
@@ -75,10 +77,7 @@
|
||||
track.value?.setStickingType(index, activeStickingType.value);
|
||||
break;
|
||||
case "track-unit-type":
|
||||
track.value?.updateUnit(index, { on: true, type: activeTrackUnitType.value });
|
||||
break;
|
||||
case "eraser":
|
||||
track.value?.setUnitOn(index, false);
|
||||
track.value?.updateUnit(index, { on: activeTrackUnitType.value === null ? false : true, type: activeTrackUnitType.value === null ? undefined : activeTrackUnitType.value });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div :class="classes"
|
||||
<track-unit-box
|
||||
class="track-unit"
|
||||
:sticking-type="stickingType"
|
||||
:type="type"
|
||||
:on="on"
|
||||
@mousedown="handleMouseDown"
|
||||
@mouseup="handleMouseUp"
|
||||
@mouseover="handleMouseOver"
|
||||
@@ -7,21 +11,16 @@
|
||||
@mouseout="handleMouseOut"
|
||||
@touchstart="handleTouchStart"
|
||||
@touchend="handleTouchEnd"
|
||||
@contextmenu.prevent.stop="() => false">
|
||||
<icon v-if="iconName" :icon-name="iconName" />
|
||||
</div>
|
||||
@contextmenu.prevent.stop="() => false"/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TrackUnitStickingTypeList, TrackUnitTypeList } from "@/Track";
|
||||
import Icon from "@/ui/Widgets/Icon/Icon.vue";
|
||||
import { StickingTypeIconMap, getClasses } from "./trackUnit";
|
||||
import { computed } from "vue";
|
||||
import { useAppStateStore } from "@/AppState";
|
||||
import TrackUnitBox from "@/ui/TrackUnitBox/TrackUnitBox.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
id: string,
|
||||
stickingType: number,
|
||||
stickingType: number | null,
|
||||
type: number,
|
||||
on: boolean,
|
||||
}>();
|
||||
@@ -44,22 +43,6 @@
|
||||
let mouseHeld = false;
|
||||
let movement = 0;
|
||||
|
||||
const classes = computed(() => getClasses({
|
||||
on: props.on,
|
||||
stickingType: TrackUnitStickingTypeList[props.stickingType] ?? null,
|
||||
type: TrackUnitTypeList[props.type] ?? 'Normal',
|
||||
highlightable: true,
|
||||
}));
|
||||
|
||||
const iconName = computed(() => {
|
||||
const type = TrackUnitStickingTypeList[props.stickingType];
|
||||
if (type) {
|
||||
StickingTypeIconMap[type];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
function handleMouseDown(ev: MouseEvent): void {
|
||||
blockNextMouseUp = false;
|
||||
if (ev.button === 0) {
|
||||
@@ -125,53 +108,8 @@
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.track-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;
|
||||
}
|
||||
|
||||
.track-unit.highlightable:hover {
|
||||
border-color: #5f5f5f;
|
||||
background-color: #5f5f5f;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.vertical-mode .track-unit {
|
||||
margin-bottom: 4px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.track-unit.on {
|
||||
border-color: var(--color-ui-accent);
|
||||
background-color: var(--color-ui-accent);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.track-unit.on.Accent, .track-unit.on.Accent.highlightable:hover {
|
||||
border-color: var(--color-ui-neutral-light);
|
||||
}
|
||||
|
||||
.track-unit.on.highlightable:hover {
|
||||
border-color: var(--color-ui-accent-hover);
|
||||
background-color: var(--color-ui-accent-hover);
|
||||
}
|
||||
|
||||
.track-unit.on.Ghost {
|
||||
opacity: 60%;
|
||||
}
|
||||
|
||||
.track-unit .icon-view {
|
||||
display: none;
|
||||
}
|
||||
.track-unit.on.icon-visible .icon-view {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
87
src/ui/TrackUnitBox/TrackUnitBox.vue
Normal file
87
src/ui/TrackUnitBox/TrackUnitBox.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="track-unit-box" :class="classes">
|
||||
<icon v-if="iconName" :icon-name="iconName" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TrackUnitStickingTypeList, TrackUnitTypeList } from "@/Track";
|
||||
import Icon from "@/ui/Widgets/Icon/Icon.vue";
|
||||
import { StickingTypeIconMap, getClasses } from "@/ui/TrackUnit/trackUnit";
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
stickingType: number | null,
|
||||
type: number,
|
||||
on: boolean,
|
||||
}>();
|
||||
|
||||
const classes = computed(() => getClasses({
|
||||
on: props.on,
|
||||
stickingType: props.stickingType ? (TrackUnitStickingTypeList[props.stickingType] ?? null) : null,
|
||||
type: TrackUnitTypeList[props.type] ?? 'Normal',
|
||||
highlightable: true,
|
||||
}));
|
||||
|
||||
const iconName = computed(() => {
|
||||
if (props.stickingType) {
|
||||
const type = TrackUnitStickingTypeList[props.stickingType] ?? null;
|
||||
if (type) {
|
||||
return StickingTypeIconMap[type];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.track-unit-box {
|
||||
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;
|
||||
|
||||
&.highlightable {
|
||||
&:hover {
|
||||
border-color: #5f5f5f;
|
||||
background-color: #5f5f5f;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&.on {
|
||||
border-color: var(--color-ui-accent-hover);
|
||||
background-color: var(--color-ui-accent-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-view {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.on {
|
||||
border-color: var(--color-ui-accent);
|
||||
background-color: var(--color-ui-accent);
|
||||
transition: none;
|
||||
|
||||
&.Accent, &.Accent.highlightable:hover {
|
||||
border-color: var(--color-ui-neutral-light);
|
||||
}
|
||||
|
||||
&.Ghost {
|
||||
opacity: 60%;
|
||||
}
|
||||
|
||||
&.icon-visible .icon-view {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -10,6 +10,7 @@ import RightFoot from "@/assets/svgs/RF.png";
|
||||
import Eraser from "@/assets/svgs/eraser-fill.svg";
|
||||
import Upload from "@/assets/svgs/upload.svg";
|
||||
import Floppy from "@/assets/svgs/floppy2-fill.svg";
|
||||
import Delete from "@/assets/svgs/delete.svg";
|
||||
|
||||
export const IconUrlMap = {
|
||||
arrowClockwise: ArrowClockwise,
|
||||
@@ -24,6 +25,7 @@ export const IconUrlMap = {
|
||||
eraser: Eraser,
|
||||
upload: Upload,
|
||||
save: Floppy,
|
||||
delete: Delete,
|
||||
} as const;
|
||||
|
||||
export type IconName = keyof typeof IconUrlMap;
|
||||
|
||||
Reference in New Issue
Block a user