mirror of
https://github.com/koel/koel
synced 2024-11-24 05:03:05 +00:00
feat: mark external songs with icon
This commit is contained in:
parent
ff033139a4
commit
f4a0e8d006
5 changed files with 39 additions and 6 deletions
|
@ -18,6 +18,7 @@ class SongResource extends JsonResource
|
|||
return [
|
||||
'type' => 'songs',
|
||||
'id' => $this->song->id,
|
||||
'owner_id' => $this->song->owner_id,
|
||||
'title' => $this->song->title,
|
||||
'lyrics' => $this->song->lyrics,
|
||||
'album_id' => $this->song->album->id,
|
||||
|
@ -35,7 +36,6 @@ class SongResource extends JsonResource
|
|||
'genre' => $this->song->genre,
|
||||
'year' => $this->song->year,
|
||||
'created_at' => $this->song->created_at,
|
||||
'owner_id' => $this->song->owner_id,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ const generate = (partOfCompilation = false): Song => {
|
|||
|
||||
return {
|
||||
type: 'songs',
|
||||
owner_id: faker.datatype.number({ min: 1, max: 999 }),
|
||||
artist_id: artistId,
|
||||
album_id: faker.datatype.number({ min: 2 }), // avoid Unknown Album by default
|
||||
artist_name: artistName,
|
||||
|
|
|
@ -10,7 +10,12 @@
|
|||
<SongThumbnail :song="song" />
|
||||
<main>
|
||||
<div class="details">
|
||||
<h3>{{ song.title }}</h3>
|
||||
<h3>
|
||||
<span class="external-mark" v-if="external">
|
||||
<Icon :icon="faSquareUpRight" />
|
||||
</span>
|
||||
{{ song.title }}
|
||||
</h3>
|
||||
<p class="by text-secondary">
|
||||
<a :href="`#/artist/${song.artist_id}`">{{ song.artist_name }}</a>
|
||||
- {{ pluralize(song.play_count, 'play') }}
|
||||
|
@ -22,11 +27,12 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { toRefs } from 'vue'
|
||||
import {faSquareUpRight} from '@fortawesome/free-solid-svg-icons'
|
||||
import { computed, toRefs } from 'vue'
|
||||
import { eventBus, pluralize } from '@/utils'
|
||||
import { queueStore } from '@/stores'
|
||||
import { playbackService } from '@/services'
|
||||
import { useDraggable } from '@/composables'
|
||||
import { useAuthorization, useDraggable } from '@/composables'
|
||||
|
||||
import SongThumbnail from '@/components/song/SongThumbnail.vue'
|
||||
import LikeButton from '@/components/song/SongLikeButton.vue'
|
||||
|
@ -34,8 +40,11 @@ import LikeButton from '@/components/song/SongLikeButton.vue'
|
|||
const props = defineProps<{ song: Song }>()
|
||||
const { song } = toRefs(props)
|
||||
|
||||
const { currentUser } = useAuthorization()
|
||||
const { startDragging } = useDraggable('songs')
|
||||
|
||||
const external = computed(() => song.value.owner_id !== currentUser.value?.id)
|
||||
|
||||
const requestContextMenu = (event: MouseEvent) => eventBus.emit('SONG_CONTEXT_MENU_REQUESTED', event, song.value)
|
||||
const onDragStart = (event: DragEvent) => startDragging(event, [song.value])
|
||||
|
||||
|
@ -136,6 +145,11 @@ article {
|
|||
flex-direction: column;
|
||||
gap: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
.external-mark {
|
||||
margin-right: .2rem;
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div
|
||||
:class="{ playing, selected: item.selected }"
|
||||
:class="{ playing, external, selected: item.selected }"
|
||||
class="song-item"
|
||||
data-testid="song-item"
|
||||
tabindex="0"
|
||||
|
@ -14,7 +14,12 @@
|
|||
<SongThumbnail :song="song" />
|
||||
</span>
|
||||
<span class="title-artist">
|
||||
<span class="title text-primary">{{ song.title }}</span>
|
||||
<span class="title text-primary">
|
||||
<span class="external-mark" v-if="external">
|
||||
<Icon :icon="faSquareUpRight" />
|
||||
</span>
|
||||
{{ song.title }}
|
||||
</span>
|
||||
<span class="artist">
|
||||
{{ song.artist_name }}
|
||||
</span>
|
||||
|
@ -28,20 +33,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { faSquareUpRight } from '@fortawesome/free-solid-svg-icons'
|
||||
import { computed, toRefs } from 'vue'
|
||||
import { playbackService } from '@/services'
|
||||
import { queueStore } from '@/stores'
|
||||
import { secondsToHis } from '@/utils'
|
||||
import { useAuthorization } from '@/composables'
|
||||
|
||||
import LikeButton from '@/components/song/SongLikeButton.vue'
|
||||
import SoundBars from '@/components/ui/SoundBars.vue'
|
||||
import SongThumbnail from '@/components/song/SongThumbnail.vue'
|
||||
|
||||
const { currentUser } = useAuthorization()
|
||||
|
||||
const props = defineProps<{ item: SongRow }>()
|
||||
const { item } = toRefs(props)
|
||||
|
||||
const song = computed(() => item.value.song)
|
||||
const playing = computed(() => ['Playing', 'Paused'].includes(song.value.playback_state!))
|
||||
const external = computed(() => song.value.owner_id !== currentUser.value?.id)
|
||||
const fmtLength = secondsToHis(song.value.length)
|
||||
|
||||
const play = () => {
|
||||
|
@ -64,6 +74,13 @@ const play = () => {
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.external-mark {
|
||||
display: inline-block !important;
|
||||
vertical-align: bottom;
|
||||
margin-right: .2rem;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
.cover {
|
||||
.control {
|
||||
|
|
1
resources/assets/js/types.d.ts
vendored
1
resources/assets/js/types.d.ts
vendored
|
@ -127,6 +127,7 @@ interface Album {
|
|||
interface Song {
|
||||
type: 'songs'
|
||||
readonly id: string
|
||||
readonly owner_id: User['id'],
|
||||
album_id: Album['id']
|
||||
album_name: Album['name']
|
||||
album_cover: Album['cover']
|
||||
|
|
Loading…
Reference in a new issue