mirror of
https://github.com/koel/koel
synced 2024-11-14 08:27:13 +00:00
feat: always show song list header action menu (#1869)
This commit is contained in:
parent
3848e8b52d
commit
5d9d75111a
5 changed files with 30 additions and 10 deletions
|
@ -70,7 +70,7 @@ new class extends UnitTestCase {
|
||||||
},
|
},
|
||||||
global: {
|
global: {
|
||||||
stubs: {
|
stubs: {
|
||||||
SongListSorter: this.stub('song-list-sorter'),
|
ActionMenu: this.stub('song-list-header-action-menu'),
|
||||||
},
|
},
|
||||||
provide: {
|
provide: {
|
||||||
[<symbol>SelectedPlayablesKey]: [ref(selectedPlayables), (value: Playable[]) => (selectedPlayables = value)],
|
[<symbol>SelectedPlayablesKey]: [ref(selectedPlayables), (value: Playable[]) => (selectedPlayables = value)],
|
||||||
|
|
|
@ -66,8 +66,8 @@
|
||||||
</template>
|
</template>
|
||||||
</span>
|
</span>
|
||||||
<span class="extra">
|
<span class="extra">
|
||||||
<SongListSorter
|
<ActionMenu
|
||||||
v-if="config.sortable"
|
:sortable="config.sortable"
|
||||||
:field="sortField"
|
:field="sortField"
|
||||||
:has-custom-order-sort="config.hasCustomOrderSort"
|
:has-custom-order-sort="config.hasCustomOrderSort"
|
||||||
:order="sortOrder"
|
:order="sortOrder"
|
||||||
|
@ -87,10 +87,10 @@ import { PlayableListConfigKey, PlayableListSortFieldKey, SongListSortOrderKey }
|
||||||
import type { getPlayableCollectionContentType } from '@/utils/typeGuards'
|
import type { getPlayableCollectionContentType } from '@/utils/typeGuards'
|
||||||
import { usePlayableListColumnVisibility } from '@/composables/usePlayableListColumnVisibility'
|
import { usePlayableListColumnVisibility } from '@/composables/usePlayableListColumnVisibility'
|
||||||
|
|
||||||
import SongListSorter from '@/components/song/song-list/SongListSorter.vue'
|
import ActionMenu from '@/components/song/song-list/SongListHeaderActionMenu.vue'
|
||||||
|
|
||||||
withDefaults(defineProps<{
|
withDefaults(defineProps<{
|
||||||
contentType?: ReturnType<getPlayableCollectionContentType>
|
contentType?: ReturnType<typeof getPlayableCollectionContentType>
|
||||||
}>(), {
|
}>(), {
|
||||||
contentType: 'songs',
|
contentType: 'songs',
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { screen } from '@testing-library/vue'
|
||||||
import { expect, it } from 'vitest'
|
import { expect, it } from 'vitest'
|
||||||
import UnitTestCase from '@/__tests__/UnitTestCase'
|
import UnitTestCase from '@/__tests__/UnitTestCase'
|
||||||
import { useLocalStorage } from '@/composables/useLocalStorage'
|
import { useLocalStorage } from '@/composables/useLocalStorage'
|
||||||
import Component from './SongListSorter.vue'
|
import Component from './SongListHeaderActionMenu.vue'
|
||||||
|
|
||||||
new class extends UnitTestCase {
|
new class extends UnitTestCase {
|
||||||
protected test () {
|
protected test () {
|
||||||
|
@ -15,6 +15,12 @@ new class extends UnitTestCase {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it ('emits the sort event when an item is clicked', async () => {
|
||||||
|
const { emitted } = this.render(Component)
|
||||||
|
await this.user.click(screen.getByText('Title'))
|
||||||
|
expect(emitted().sort[0]).toEqual(['title'])
|
||||||
|
})
|
||||||
|
|
||||||
it('contains proper items for episode-only lists', () => {
|
it('contains proper items for episode-only lists', () => {
|
||||||
this.render(Component, {
|
this.render(Component, {
|
||||||
props: {
|
props: {
|
||||||
|
@ -49,6 +55,17 @@ new class extends UnitTestCase {
|
||||||
screen.getByText('Custom Order')
|
screen.getByText('Custom Order')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('does not sort if the list is not sortable', async () => {
|
||||||
|
const { emitted } = this.render(Component, {
|
||||||
|
props: {
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.user.click(screen.getByText('Title'))
|
||||||
|
expect(emitted().sort).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
it('has a checkbox to toggle the column visibility', async () => {
|
it('has a checkbox to toggle the column visibility', async () => {
|
||||||
this.be().render(Component)
|
this.be().render(Component)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<article>
|
<article>
|
||||||
<button ref="button" class="w-full focus:text-k-highlight" title="Sort" @click.stop="trigger">
|
<button ref="button" class="w-full focus:text-k-highlight" title="Sort" @click.stop="trigger">
|
||||||
<Icon :icon="faSort" />
|
<Icon v-if="sortable" :icon="faSort" />
|
||||||
|
<Icon v-else :icon="faEllipsis" />
|
||||||
</button>
|
</button>
|
||||||
<OnClickOutside @trigger="hide">
|
<OnClickOutside @trigger="hide">
|
||||||
<menu ref="menu" class="context-menu normal-case tracking-normal">
|
<menu ref="menu" class="context-menu normal-case tracking-normal">
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
:key="item.label"
|
:key="item.label"
|
||||||
:class="currentlySortedBy(item.field) && 'active'"
|
:class="currentlySortedBy(item.field) && 'active'"
|
||||||
class="cursor-pointer flex justify-between !pl-3 hover:!bg-white/10"
|
class="cursor-pointer flex justify-between !pl-3 hover:!bg-white/10"
|
||||||
@click="sort(item.field)"
|
@click="sortable && sort(item.field)"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
v-if="shouldShowColumnVisibilityCheckboxes()"
|
v-if="shouldShowColumnVisibilityCheckboxes()"
|
||||||
|
@ -39,7 +40,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { isEqual } from 'lodash'
|
import { isEqual } from 'lodash'
|
||||||
import { faArrowDown, faArrowUp, faCheck, faSort } from '@fortawesome/free-solid-svg-icons'
|
import { faArrowDown, faArrowUp, faCheck, faEllipsis, faSort } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { OnClickOutside } from '@vueuse/components'
|
import { OnClickOutside } from '@vueuse/components'
|
||||||
import { computed, onBeforeUnmount, onMounted, ref, toRefs } from 'vue'
|
import { computed, onBeforeUnmount, onMounted, ref, toRefs } from 'vue'
|
||||||
import { useFloatingUi } from '@/composables/useFloatingUi'
|
import { useFloatingUi } from '@/composables/useFloatingUi'
|
||||||
|
@ -48,11 +49,13 @@ import type { getPlayableCollectionContentType } from '@/utils/typeGuards'
|
||||||
import { usePlayableListColumnVisibility } from '@/composables/usePlayableListColumnVisibility'
|
import { usePlayableListColumnVisibility } from '@/composables/usePlayableListColumnVisibility'
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
sortable?: boolean
|
||||||
field?: MaybeArray<PlayableListSortField> // the current field(s) being sorted by
|
field?: MaybeArray<PlayableListSortField> // the current field(s) being sorted by
|
||||||
order?: SortOrder
|
order?: SortOrder
|
||||||
hasCustomOrderSort?: boolean // whether to provide "custom order" sort (like for playlists)
|
hasCustomOrderSort?: boolean // whether to provide "custom order" sort (like for playlists)
|
||||||
contentType?: ReturnType<typeof getPlayableCollectionContentType>
|
contentType?: ReturnType<typeof getPlayableCollectionContentType>
|
||||||
}>(), {
|
}>(), {
|
||||||
|
sortable: true,
|
||||||
field: 'title',
|
field: 'title',
|
||||||
order: 'asc',
|
order: 'asc',
|
||||||
hasCustomOrderSort: false,
|
hasCustomOrderSort: false,
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
exports[`renders 1`] = `
|
exports[`renders 1`] = `
|
||||||
<div class="sortable song-list-header flex z-[2] bg-k-bg-secondary pl-5"><span class="track-number" data-testid="header-track-number" role="button" title="Sort by track number"> # <!--v-if--><!--v-if--></span><span class="title-artist" data-testid="header-title" role="button" title="Sort by title"> Title <br data-testid="Icon" icon="[object Object]" class="text-k-highlight"><!--v-if--></span><span title="Sort by album" class="album" data-testid="header-album" role="button">Album<span class="ml-2"><!--v-if--><!--v-if--></span></span>
|
<div class="sortable song-list-header flex z-[2] bg-k-bg-secondary pl-5"><span class="track-number" data-testid="header-track-number" role="button" title="Sort by track number"> # <!--v-if--><!--v-if--></span><span class="title-artist" data-testid="header-title" role="button" title="Sort by title"> Title <br data-testid="Icon" icon="[object Object]" class="text-k-highlight"><!--v-if--></span><span title="Sort by album" class="album" data-testid="header-album" role="button">Album<span class="ml-2"><!--v-if--><!--v-if--></span></span>
|
||||||
<!--v-if--><span class="time" data-testid="header-length" role="button" title="Sort by duration"> Time <!--v-if--><!--v-if--></span><span class="extra"><br data-testid="song-list-sorter" field="title" order="asc" content-type="songs"></span>
|
<!--v-if--><span class="time" data-testid="header-length" role="button" title="Sort by duration"> Time <!--v-if--><!--v-if--></span><span class="extra"><br data-testid="song-list-header-action-menu" sortable="true" field="title" order="asc" content-type="songs"></span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
Loading…
Reference in a new issue