style(front): Section component on explore, small playbutton dropdown-only's

This commit is contained in:
ArneBo 2025-02-05 12:26:23 +01:00
parent ca1ccf5a49
commit bbc239b96c
5 changed files with 123 additions and 118 deletions

View File

@ -106,6 +106,7 @@ const isOpen = ref(false)
> >
<OptionsButton <OptionsButton
v-if="dropdownOnly" v-if="dropdownOnly"
v-bind="$attrs"
@click="isOpen = !isOpen" @click="isOpen = !isOpen"
:isGhost="discrete" :isGhost="discrete"
/> />

View File

@ -17,6 +17,7 @@ import Section from '~/components/ui/Section.vue'
import Alert from '~/components/ui/Alert.vue' import Alert from '~/components/ui/Alert.vue'
import Spacer from '~/components/ui/Spacer.vue' import Spacer from '~/components/ui/Spacer.vue'
import Loader from '~/components/ui/Loader.vue' import Loader from '~/components/ui/Loader.vue'
import Heading from '~/components/ui/Heading.vue'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
@ -108,127 +109,126 @@ watch(() => props.websocketHandlers.includes('Listen'), (to) => {
<template> <template>
<!-- TODO: Use activity.vue --> <!-- TODO: Use activity.vue -->
<div class="component-track-widget"> <h2 v-if="!!$slots.title">
<h2 v-if="!!$slots.title"> <slot name="title" />
<slot name="title" /> <span
<span v-if="showCount"
v-if="showCount" class="ui tiny circular label"
class="ui tiny circular label" >{{ count }}</span>
>{{ count }}</span> </h2>
</h2> <Alert
<Alert v-if="count === 0"
v-if="count === 0" blue
blue style="text-align: center;"
style="text-align: center;" >
> <i class="bi bi-music-note-list" />
<i class="bi bi-music-note-list" /> {{ t('components.audio.track.Widget.empty.noResults') }}
{{ t('components.audio.track.Widget.empty.noResults') }}
<Loader v-if="isLoading" />
</Alert>
<Section
v-if="count > 0"
medium-items
>
<div class="funkwhale activity"
v-for="object in objects"
:key="object.id"
:class="['item', itemClasses]"
>
<div class="activity-image">
<img
v-if="object.track.album && object.track.album.cover"
v-lazy="store.getters['instance/absoluteUrl'](object.track.album.cover.urls.medium_square_crop)"
alt=""
>
<img
v-else-if="object.track.cover"
v-lazy="store.getters['instance/absoluteUrl'](object.track.cover.urls.medium_square_crop)"
alt=""
>
<img
v-else-if="object.track.artist_credit && object.track.artist_credit.length > 1"
v-lazy="getArtistCoverUrl(object.track.artist_credit)"
alt=""
>
<i
v-else
class="bi bi-vinyl-fill"
/>
<!-- TODO: Add Playbutton overlay -->
</div>
<div class="activity-content">
<div class="track-title">
<router-link
class="funkwhale link artist"
:to="{name: 'library.tracks.detail', params: {id: object.track.id}}"
>
{{ object.track.title }}
</router-link>
</div>
<div
v-if="object.track.artist_credit"
class="funkwhale link artist"
>
<span
v-for="ac in object.track.artist_credit"
:key="ac.artist.id"
>
<router-link
class="discrete link"
:to="{ name: 'library.artists.detail', params: { id: ac.artist.id } }"
>
{{ ac.credit }}
</router-link>
<span v-if="ac.joinphrase">{{ ac.joinphrase }}</span>
</span>
</div>
<TagsList
label-classes="tiny"
:truncate-size="20"
:limit="2"
:show-more="false"
:tags="object.track.tags"
/>
<div
v-if="isActivity"
class="extra"
>
<router-link
class="funkwhale link user"
:to="{name: 'profile.overview', params: {username: object.actor.name}}"
>
<span class="at symbol" />{{ object.actor.name }}
</router-link>
<span class="right floated"><human-date :date="object.creation_date" /></span>
</div>
</div>
<play-button
:account="object.actor"
:dropdown-only="true"
:track="object.track"
/>
</div>
</Section>
<Loader v-if="isLoading" /> <Loader v-if="isLoading" />
<template v-if="nextPage"> </Alert>
<Spacer :size="16"/> <template
<Button v-if="count > 0"
primary medium-items
@click="fetchData(nextPage as string)" >
> <div class="funkwhale activity"
{{ t('components.audio.track.Widget.button.more') }} v-for="object in objects"
</Button> :key="object.id"
</template> :class="['item', itemClasses]"
</div> >
<div class="activity-image">
<img
v-if="object.track.album && object.track.album.cover"
v-lazy="store.getters['instance/absoluteUrl'](object.track.album.cover.urls.medium_square_crop)"
alt=""
>
<img
v-else-if="object.track.cover"
v-lazy="store.getters['instance/absoluteUrl'](object.track.cover.urls.medium_square_crop)"
alt=""
>
<img
v-else-if="object.track.artist_credit && object.track.artist_credit.length > 1"
v-lazy="getArtistCoverUrl(object.track.artist_credit)"
alt=""
>
<i
v-else
class="bi bi-vinyl-fill"
/>
<!-- TODO: Add Playbutton overlay -->
</div>
<div class="activity-content">
<router-link
class="funkwhale link artist"
:to="{name: 'library.tracks.detail', params: {id: object.track.id}}"
>
<Heading :h3="object.track.title" title />
</router-link>
<Spacer :size="2"/>
<div
v-if="object.track.artist_credit"
class="funkwhale link artist"
>
<span
v-for="ac in object.track.artist_credit"
:key="ac.artist.id"
>
<router-link
class="discrete link"
:to="{ name: 'library.artists.detail', params: { id: ac.artist.id } }"
>
{{ ac.credit }}
</router-link>
<span v-if="ac.joinphrase">{{ ac.joinphrase }}</span>
</span>
</div>
<TagsList
label-classes="tiny"
:truncate-size="20"
:limit="2"
:show-more="false"
:tags="object.track.tags"
/>
<Spacer :size="4"/>
<div
v-if="isActivity"
class="extra"
>
<router-link
class="funkwhale link user"
:to="{name: 'profile.overview', params: {username: object.actor.name}}"
>
<span class="at symbol" />{{ object.actor.name }}
</router-link>
<span class="right floated"><human-date :date="object.creation_date" /></span>
</div>
</div>
<play-button
:account="object.actor"
:dropdown-only="true"
:track="object.track"
square-small
/>
</div>
</template>
<Loader v-if="isLoading" />
<template v-if="nextPage">
<Spacer :size="16"/>
<Button
primary
@click="fetchData(nextPage as string)"
>
{{ t('components.audio.track.Widget.button.more') }}
</Button>
</template>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.funkwhale { .funkwhale {
&.activity { &.activity {
padding: 12px 0; padding-top: 14px;
border-top: 1px solid; border-top: 1px solid;
margin: -11px 0;
@include light-theme { @include light-theme {
border-color: var(--fw-gray-300); border-color: var(--fw-gray-300);
@ -259,7 +259,8 @@ watch(() => props.websocketHandlers.includes('Listen'), (to) => {
} }
> i { > i {
font-size: 36px; font-size: 40px;
line-height: 36px;
} }
> .play-button { > .play-button {

View File

@ -90,20 +90,22 @@ fetchData()
<Section <Section
alignLeft alignLeft
:h2="t('components.library.Home.header.recentlyListened')" :h2="t('components.library.Home.header.recentlyListened')"
/> >
<track-widget <track-widget
:url="'history/listenings/'" :url="'history/listenings/'"
:filters="{ scope, ordering: '-creation_date', ...qualityFilters}" :filters="{ scope, ordering: '-creation_date', ...qualityFilters}"
:websocket-handlers="['Listen']" :websocket-handlers="['Listen']"
/> />
</Section>
<Section <Section
alignLeft alignLeft
:h2="t('components.library.Home.header.recentlyFavorited')" :h2="t('components.library.Home.header.recentlyFavorited')"
/> >
<track-widget <track-widget
:url="'favorites/tracks/'" :url="'favorites/tracks/'"
:filters="{scope: scope, ordering: '-creation_date'}" :filters="{scope: scope, ordering: '-creation_date'}"
/> />
</Section>
<Section <Section
alignLeft alignLeft
:h2="t('components.library.Home.header.recentlyAdded')" :h2="t('components.library.Home.header.recentlyAdded')"

View File

@ -8,7 +8,7 @@ const size = Object.entries(props).find(([key, value]) => value && key!==level)?
</script> </script>
<template> <template>
<component :is="level" :class="size" style="margin: 0; padding:0; line-height: 40px; vertical-align: baseline;"> <component :is="level" :class="size" style="margin: 0; padding: 0; vertical-align: baseline;">
{{ title }} {{ title }}
<slot /> <slot />
</component> </component>
@ -28,7 +28,7 @@ const size = Object.entries(props).find(([key, value]) => value && key!==level)?
.caption {font-size: 14px; font-weight: 600; letter-spacing: .25px; } .caption {font-size: 14px; font-weight: 600; letter-spacing: .25px; }
/* Tab title, Channel title, Card title, Activity title */ /* Tab title, Channel title, Card title, Activity title */
.title { font-size: 16px; font-weight: 700; } .title { font-size: 16px; font-weight: 700; line-height: 18px; }
/* Primary radio title */ /* Primary radio title */
.radio { font-size: 28px; font-weight: 900; letter-spacing: -.5px; } .radio { font-size: 28px; font-weight: 900; letter-spacing: -.5px; }

View File

@ -15,6 +15,7 @@ const props = withDefaults(defineProps<Props>(), {
<template> <template>
<Button <Button
icon="bi-three-dots-vertical" icon="bi-three-dots-vertical"
v-bind="$attrs"
:class="['options-button', {'is-ghost': isGhost}]" :class="['options-button', {'is-ghost': isGhost}]"
:secondary="!isGhost" :secondary="!isGhost"
:ghost="isGhost" :ghost="isGhost"