Skip to content

Commit 82bda06

Browse files
committed
refactor: #86evubq13 Update UI components and logic for improved functionality and user experience
- Remove unused CSS styles from default.vue to streamline the layout. - Enhance Card.vue by adding a header action slot for better interaction with section titles. - Update IconButton.vue to include a tooltip for better accessibility and user guidance. - Implement reset functionality in SongFloatingToolbox.vue for transpose, scroll, font size, and layout adjustments. - Add reset labels in multiple language files to support new reset functionality. - Refactor useTranspose.ts to improve chord transposition logic and maintain consistency with previous versions.
1 parent 8428db3 commit 82bda06

15 files changed

Lines changed: 485 additions & 398 deletions

File tree

admin_panel/layouts/default.vue

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -130,58 +130,4 @@ export default {
130130
.page-content {
131131
@apply px-4 pt-16;
132132
}
133-
134-
// html {
135-
// font-family:
136-
// 'Source Sans Pro',
137-
// -apple-system,
138-
// BlinkMacSystemFont,
139-
// 'Segoe UI',
140-
// Roboto,
141-
// 'Helvetica Neue',
142-
// Arial,
143-
// sans-serif;
144-
// font-size: 16px;
145-
// word-spacing: 1px;
146-
// -ms-text-size-adjust: 100%;
147-
// -webkit-text-size-adjust: 100%;
148-
// -moz-osx-font-smoothing: grayscale;
149-
// -webkit-font-smoothing: antialiased;
150-
// box-sizing: border-box;
151-
// }
152-
153-
// *,
154-
// *::before,
155-
// *::after {
156-
// box-sizing: border-box;
157-
// margin: 0;
158-
// }
159-
160-
// .button--green {
161-
// display: inline-block;
162-
// border-radius: 4px;
163-
// border: 1px solid #3b8070;
164-
// color: #3b8070;
165-
// text-decoration: none;
166-
// padding: 10px 30px;
167-
// }
168-
169-
// .button--green:hover {
170-
// color: #fff;
171-
// background-color: #3b8070;
172-
// }
173-
174-
// .button--grey {
175-
// display: inline-block;
176-
// border-radius: 4px;
177-
// border: 1px solid #35495e;
178-
// color: #35495e;
179-
// text-decoration: none;
180-
// padding: 10px 30px;
181-
// margin-left: 15px;
182-
// }
183-
184-
// .button--grey:hover {
185-
// color: #fff;
186-
// background-color: #35495e;
187-
// }</style>
133+
</style>

end_user/components/base/Card.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ const classes = computed(() => {
2525

2626
<template>
2727
<div :class="classes">
28-
<div v-if="title && variant === 'section'" class="text-xs font-bold text-text-muted uppercase mb-3">
29-
{{ title }}
28+
<div v-if="title && variant === 'section'" class="flex items-center justify-between mb-3">
29+
<div class="text-xs font-bold text-text-muted uppercase">
30+
{{ title }}
31+
</div>
32+
<slot name="header-action" />
3033
</div>
3134
<slot />
3235
</div>

end_user/components/base/IconButton.vue

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<script setup lang="ts">
22
import { computed } from 'vue'
3+
import Tooltip from '~/components/base/Tooltip.vue'
34
45
const props = defineProps<{
5-
variant?: 'primary' | 'secondary'
6-
size?: 'sm' | 'md' | 'lg'
6+
variant?: 'primary' | 'secondary' | 'ghost'
7+
size?: 'xs' | 'sm' | 'md' | 'lg'
78
icon: any
89
ariaLabel: string
10+
title?: string
911
}>()
1012
1113
const emit = defineEmits<{
@@ -19,15 +21,18 @@ const classes = computed(() => {
1921
primary: 'bg-grad-primary text-white shadow-md hover:scale-105',
2022
secondary:
2123
'bg-surface-card border border-border-subtle text-text-secondary hover:text-text-accent',
24+
ghost: 'bg-transparent text-text-muted hover:text-text-primary hover:bg-surface-muted',
2225
}
2326
2427
const sizes = {
28+
xs: 'w-7 h-7',
2529
sm: 'w-10 h-10',
2630
md: 'w-12 h-12',
2731
lg: 'w-14 h-14',
2832
}
2933
3034
const iconSizes = {
35+
xs: 'w-3.5 h-3.5',
3136
sm: 'w-4 h-4',
3237
md: 'w-5 h-5',
3338
lg: 'w-6 h-6',
@@ -41,7 +46,9 @@ const classes = computed(() => {
4146
</script>
4247

4348
<template>
44-
<button :class="classes.button" :aria-label="ariaLabel" @click="emit('click')">
45-
<component :is="icon" :class="[classes.icon, variant === 'primary' ? 'fill-current' : '']" />
46-
</button>
49+
<Tooltip :text="title || ''" position="top">
50+
<button :class="classes.button" :aria-label="ariaLabel" @click="emit('click')">
51+
<component :is="icon" :class="[classes.icon, variant === 'primary' ? 'fill-current' : '']" />
52+
</button>
53+
</Tooltip>
4754
</template>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue'
3+
4+
const props = defineProps<{
5+
text: string
6+
position?: 'top' | 'bottom' | 'left' | 'right'
7+
}>()
8+
9+
const isVisible = ref(false)
10+
11+
const show = () => isVisible.value = true
12+
const hide = () => isVisible.value = false
13+
14+
const positionClasses = {
15+
top: 'bottom-full left-1/2 -translate-x-1/2 mb-2',
16+
bottom: 'top-full left-1/2 -translate-x-1/2 mt-2',
17+
left: 'right-full top-1/2 -translate-y-1/2 mr-2',
18+
right: 'left-full top-1/2 -translate-y-1/2 ml-2'
19+
}
20+
</script>
21+
22+
<template>
23+
<div class="relative inline-flex" @mouseenter="show" @mouseleave="hide" @focusin="show" @focusout="hide">
24+
<slot />
25+
26+
<Transition enter-active-class="transition duration-200 ease-out" enter-from-class="opacity-0 scale-95"
27+
enter-to-class="opacity-100 scale-100" leave-active-class="transition duration-150 ease-in"
28+
leave-from-class="opacity-100 scale-100" leave-to-class="opacity-0 scale-95">
29+
<div v-if="isVisible && text"
30+
class="absolute z-50 px-2 py-1 text-xs font-medium text-white bg-gray-900 rounded shadow-sm whitespace-nowrap pointer-events-none"
31+
:class="positionClasses[position || 'top']" role="tooltip">
32+
{{ text }}
33+
<!-- Arrow -->
34+
<div class="absolute w-2 h-2 bg-gray-900 transform rotate-45" :class="{
35+
'bottom-[-4px] left-1/2 -translate-x-1/2': position === 'top' || !position,
36+
'top-[-4px] left-1/2 -translate-x-1/2': position === 'bottom',
37+
'right-[-4px] top-1/2 -translate-y-1/2': position === 'left',
38+
'left-[-4px] top-1/2 -translate-y-1/2': position === 'right'
39+
}"></div>
40+
</div>
41+
</Transition>
42+
</div>
43+
</template>

end_user/components/widget/song/SongFloatingToolbox.vue

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script setup lang="ts">
22
import { ref, computed, nextTick, watch, onMounted } from 'vue'
33
import { useI18n } from 'vue-i18n'
4-
import { Music, Play, Pause, Zap, Minus, Plus, ChevronLeft, ChevronRight, LayoutGrid, AlignJustify } from 'lucide-vue-next'
4+
import { Music, Play, Pause, Zap, Minus, Plus, ChevronLeft, ChevronRight, LayoutGrid, AlignJustify, RotateCcw } from 'lucide-vue-next'
55
import { useTranspose } from '~/composables/useTranspose'
66
import IconButton from '~/components/base/IconButton.vue'
77
import Stepper from '~/components/base/Stepper.vue'
@@ -34,6 +34,10 @@ const emit = defineEmits<{
3434
(e: 'update:fontSize', value: number): void
3535
(e: 'update:gridMode', value: boolean): void
3636
(e: 'update:gridColumns', value: GridColumns): void
37+
(e: 'reset:transpose'): void
38+
(e: 'reset:scroll'): void
39+
(e: 'reset:fontSize'): void
40+
(e: 'reset:layout'): void
3741
}>()
3842
3943
// Column options for grid
@@ -178,8 +182,13 @@ const closeDrawer = () => {
178182
<div class="hidden lg:flex flex-col gap-6 sticky top-24">
179183
<!-- Transpose Card -->
180184
<Card variant="section" :title="t('toolbox.transpose')">
185+
<template #header-action>
186+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
187+
:title="t('toolbox.reset')" @click="emit('reset:transpose')" />
188+
</template>
181189
<!-- +/- Controls -->
182-
<div class="mb-3">
190+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of +/- controls regardless of app direction -->
191+
<div class="mb-3" dir="ltr">
183192
<Stepper :model-value="currentTableIndex" :min="0" :max="11" :step="1" :format-value="formatKeyName"
184193
:decrease-aria-label="t('toolbox.ariaLabels.decreaseTranspose')"
185194
:increase-aria-label="t('toolbox.ariaLabels.increaseTranspose')" size="md" variant="compact"
@@ -192,7 +201,8 @@ const closeDrawer = () => {
192201
@click="scrollCarousel(carouselRef, -1)" />
193202

194203
<!-- Carousel Container -->
195-
<div ref="carouselRef" class="flex gap-1 overflow-x-auto scrollbar-hide scroll-smooth px-7 py-1"
204+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of keys regardless of app direction -->
205+
<div ref="carouselRef" dir="ltr" class="flex gap-1 overflow-x-auto scrollbar-hide scroll-smooth px-7 py-1"
196206
style="scrollbar-width: none; -ms-overflow-style: none;">
197207
<button v-for="key in keySignatures" :key="key.index" :data-key-index="key.index"
198208
class="flex-shrink-0 w-9 h-9 rounded-lg font-mono text-sm font-bold transition-all cursor-pointer" :class="[
@@ -218,6 +228,10 @@ const closeDrawer = () => {
218228

219229
<!-- Auto Scroll Card -->
220230
<Card variant="section" :title="t('toolbox.autoScroll')">
231+
<template #header-action>
232+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
233+
:title="t('toolbox.reset')" @click="emit('reset:scroll')" />
234+
</template>
221235
<div class="relative group">
222236
<button
223237
class="w-full px-4 py-2 rounded-lg font-bold transition-colors flex items-center justify-center mb-3 cursor-pointer"
@@ -233,22 +247,36 @@ const closeDrawer = () => {
233247
</div>
234248

235249
<div class="text-xs text-text-muted mb-2">{{ t('toolbox.speed') }}</div>
236-
<Stepper :model-value="scrollSpeed" :min="MIN_SPEED" :max="MAX_SPEED" :step="SPEED_STEP"
237-
:format-value="formatSpeed" :decrease-aria-label="t('toolbox.ariaLabels.decreaseSpeed')"
238-
:increase-aria-label="t('toolbox.ariaLabels.increaseSpeed')" size="md" variant="compact"
239-
@update:model-value="(val) => emit('update:speed', val)" />
250+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of +/- controls regardless of app direction -->
251+
<div dir="ltr">
252+
<Stepper :model-value="scrollSpeed" :min="MIN_SPEED" :max="MAX_SPEED" :step="SPEED_STEP"
253+
:format-value="formatSpeed" :decrease-aria-label="t('toolbox.ariaLabels.decreaseSpeed')"
254+
:increase-aria-label="t('toolbox.ariaLabels.increaseSpeed')" size="md" variant="compact"
255+
@update:model-value="(val) => emit('update:speed', val)" />
256+
</div>
240257
</Card>
241258

242259
<!-- Font Size Card -->
243260
<Card variant="section" :title="t('toolbox.fontSize')">
244-
<Stepper :model-value="fontSize" :min="0.8" :max="2.0" :step="0.1" :format-value="formatFontSize"
245-
:decrease-aria-label="t('toolbox.ariaLabels.decreaseFontSize')"
246-
:increase-aria-label="t('toolbox.ariaLabels.increaseFontSize')" size="md" variant="compact"
247-
@update:model-value="(val) => emit('update:fontSize', val)" />
261+
<template #header-action>
262+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
263+
:title="t('toolbox.reset')" @click="emit('reset:fontSize')" />
264+
</template>
265+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of +/- controls regardless of app direction -->
266+
<div dir="ltr">
267+
<Stepper :model-value="fontSize" :min="0.8" :max="2.0" :step="0.1" :format-value="formatFontSize"
268+
:decrease-aria-label="t('toolbox.ariaLabels.decreaseFontSize')"
269+
:increase-aria-label="t('toolbox.ariaLabels.increaseFontSize')" size="md" variant="compact"
270+
@update:model-value="(val) => emit('update:fontSize', val)" />
271+
</div>
248272
</Card>
249273

250274
<!-- Layout Card (Grid Toggle) -->
251275
<Card variant="section" :title="t('toolbox.layout')">
276+
<template #header-action>
277+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
278+
:title="t('toolbox.reset')" @click="emit('reset:layout')" />
279+
</template>
252280
<div class="mb-3">
253281
<SegmentedControl :model-value="gridMode" :options="gridModeOptions" size="md" variant="default"
254282
@update:model-value="(val) => emit('update:gridMode', val)" />
@@ -303,10 +331,17 @@ const closeDrawer = () => {
303331

304332
<!-- Transpose Tab -->
305333
<div v-if="activeTab === 'transpose'" class="space-y-6">
306-
<h3 class="text-lg font-bold text-center">{{ t('toolbox.transposeKey') }}</h3>
334+
<div class="flex items-center justify-center relative">
335+
<h3 class="text-lg font-bold text-center">{{ t('toolbox.transposeKey') }}</h3>
336+
<div class="absolute right-0">
337+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
338+
:title="t('toolbox.reset')" @click="emit('reset:transpose')" />
339+
</div>
340+
</div>
307341

308342
<!-- +/- Controls with Current Key -->
309-
<div class="flex items-center justify-center gap-6">
343+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of +/- controls regardless of app direction -->
344+
<div class="flex items-center justify-center gap-6" dir="ltr">
310345
<IconButton :icon="Minus" variant="secondary" size="sm" :ariaLabel="t('toolbox.ariaLabels.decreaseTranspose')"
311346
@click="stepKey(-1)" />
312347

@@ -325,7 +360,9 @@ const closeDrawer = () => {
325360
@click="scrollCarousel(mobileCarouselRef, -1)" />
326361

327362
<!-- Carousel Container -->
328-
<div ref="mobileCarouselRef" class="flex gap-2 overflow-x-auto scrollbar-hide scroll-smooth px-10 py-2"
363+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of keys regardless of app direction -->
364+
<div ref="mobileCarouselRef" dir="ltr"
365+
class="flex gap-2 overflow-x-auto scrollbar-hide scroll-smooth px-10 py-2"
329366
style="scrollbar-width: none; -ms-overflow-style: none;">
330367
<button v-for="key in keySignatures" :key="key.index" :data-key-index="key.index"
331368
class="flex-shrink-0 w-12 h-12 rounded-xl font-mono text-base font-bold transition-all cursor-pointer"
@@ -353,9 +390,16 @@ const closeDrawer = () => {
353390

354391
<!-- Scroll/Speed Tab -->
355392
<div v-else-if="activeTab === 'scroll'" class="space-y-6">
356-
<h3 class="text-lg font-bold text-center">{{ t('toolbox.autoScrollSpeed') }}</h3>
393+
<div class="flex items-center justify-center relative">
394+
<h3 class="text-lg font-bold text-center">{{ t('toolbox.autoScrollSpeed') }}</h3>
395+
<div class="absolute right-0">
396+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
397+
:title="t('toolbox.reset')" @click="emit('reset:scroll')" />
398+
</div>
399+
</div>
357400

358-
<div class="flex items-center justify-center gap-6">
401+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of +/- controls regardless of app direction -->
402+
<div class="flex items-center justify-center gap-6" dir="ltr">
359403
<IconButton :icon="Minus" variant="secondary" size="sm" :disabled="scrollSpeed <= MIN_SPEED"
360404
:ariaLabel="t('toolbox.ariaLabels.decreaseSpeed')" @click="stepSpeed(-1)" />
361405

@@ -368,18 +412,29 @@ const closeDrawer = () => {
368412
</div>
369413

370414
<div class="flex items-center justify-between bg-surface-muted rounded-xl p-4">
371-
<span class="text-sm font-bold">{{ t('toolbox.fontSize') }}</span>
372-
<Stepper :model-value="fontSize" :min="0.8" :max="2.0" :step="0.1" :format-value="formatFontSize"
373-
:decrease-aria-label="t('toolbox.ariaLabels.decreaseFontSize')"
374-
:increase-aria-label="t('toolbox.ariaLabels.increaseFontSize')" size="sm" variant="compact"
375-
@update:model-value="(val) => emit('update:fontSize', val)" />
415+
<div class="flex items-center gap-2">
416+
<span class="text-sm font-bold">{{ t('toolbox.fontSize') }}</span>
417+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
418+
:title="t('toolbox.reset')" @click="emit('reset:fontSize')" />
419+
</div>
420+
<!-- Note: dir="ltr" is mandatory here to ensure correct order of +/- controls regardless of app direction -->
421+
<div dir="ltr">
422+
<Stepper :model-value="fontSize" :min="0.8" :max="2.0" :step="0.1" :format-value="formatFontSize"
423+
:decrease-aria-label="t('toolbox.ariaLabels.decreaseFontSize')"
424+
:increase-aria-label="t('toolbox.ariaLabels.increaseFontSize')" size="sm" variant="compact"
425+
@update:model-value="(val) => emit('update:fontSize', val)" />
426+
</div>
376427
</div>
377428

378429
<!-- Grid Layout & Columns Combined (Mobile) -->
379430
<div class="bg-surface-muted rounded-xl p-4 space-y-3">
380431
<!-- Layout Toggle Row -->
381432
<div class="flex items-center justify-between">
382-
<span class="text-sm font-bold">{{ t('toolbox.layout') }}</span>
433+
<div class="flex items-center gap-2">
434+
<span class="text-sm font-bold">{{ t('toolbox.layout') }}</span>
435+
<IconButton :icon="RotateCcw" variant="ghost" size="xs" :ariaLabel="t('toolbox.reset')"
436+
:title="t('toolbox.reset')" @click="emit('reset:layout')" />
437+
</div>
383438
<SegmentedControl :model-value="gridMode" :options="gridModeOptions" size="lg" variant="compact"
384439
@update:model-value="(val) => emit('update:gridMode', val)" />
385440
</div>

0 commit comments

Comments
 (0)