refactor(front): Radio detail, radio cards and radio page

This commit is contained in:
ArneBo 2025-02-05 00:12:47 +01:00
parent 79ac7d826c
commit 6fbe027876
3 changed files with 214 additions and 218 deletions

View File

@ -113,144 +113,148 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
</script> </script>
<template> <template>
<Layout main stack> <Layout main stack gap-64>
<Header :h1="t('components.library.Radios.header.browse')" /> <Header :h1="t('components.library.Radios.header.browse')" />
<Section alignLeft :h2="t('components.library.Radios.header.instance')"> <Section alignLeft :h2="t('components.library.Radios.header.instance')">
</Section> <radio-card
<Layout flex> v-if="isAuthenticated"
<radio-card :type="'actor-content'"
v-if="isAuthenticated" :object-id="store.state.auth.fullUsername"
:type="'actor-content'"
:object-id="store.state.auth.fullUsername"
/>
<radio-card
v-if="isAuthenticated && hasFavorites"
:type="'favorites'"
/>
<radio-card
v-if="scope === 'all'"
:type="'random'"
/>
<radio-card
v-if="scope === 'me'"
:type="'random_library'"
/>
<radio-card :type="'recently-added'" />
<radio-card
v-if="store.state.auth.authenticated && scope === 'all'"
:type="'less-listened'"
/>
<radio-card
v-if="store.state.auth.authenticated && scope === 'me'"
:type="'less-listened_library'"
/>
</Layout>
<Spacer />
<Section alignLeft :h2="t('components.library.Radios.header.user')" :action="{ text:t('components.library.Radios.button.create'), to:'/library/radios/build' }" />
<Layout flex form
:class="['ui', {'loading': isLoading}, 'form']"
@submit.prevent="search"
>
<Input search
id="radios-search"
v-model="query"
name="search"
:label="t('components.library.Radios.label.search')"
:placeholder="labels.searchPlaceholder"
/>
<Layout stack noGap label for="radios-ordering">
<span class="label">
{{ t('components.library.Radios.ordering.label') }}
</span>
<select
id="radios-ordering"
v-model="ordering"
class="dropdown"
>
<option
v-for="(option, key) in orderingOptions"
:key="key"
:value="option[0]"
>
{{ sharedLabels.filters[option[1]] }}
</option>
</select>
</Layout>
<Layout stack noGap label for="radios-ordering-direction">
<span class="label">
{{ t('components.library.Radios.ordering.direction.label') }}
</span>
<select
id="radios-ordering-direction"
v-model="orderingDirection"
class="dropdown"
>
<option value="+">
{{ t('components.library.Radios.ordering.direction.ascending') }}
</option>
<option value="-">
{{ t('components.library.Radios.ordering.direction.descending') }}
</option>
</select>
</Layout>
<Layout stack noGap label for="radios-results">
<span class="label">
{{ t('components.library.Radios.pagination.results') }}
</span>
<select
id="radios-results"
v-model="paginateBy"
class="dropdown"
>
<option
v-for="opt in paginateOptions"
:key="opt"
:value="opt"
>
{{ opt }}
</option>
</select>
</Layout>
</Layout>
<Alert
blue
style="align-items: center;"
v-if="result && result.results.length === 0"
>
<i class="bi bi-broadcast-pin" style="font-size: 80px" />
<Spacer />
{{ t('components.library.Radios.empty.noResults') }}
<Spacer />
<Button
v-if="store.state.auth.authenticated"
primary
style="align-self:center;"
:to="{name: 'library.radios.build'}"
icon="bi-boombox-fill"
>
{{ t('components.library.Radios.button.add') }}
</Button>
</Alert>
<div
v-if="result && result.results.length > 0"
class="ui cards"
>
<Pagination
v-if="result && result.count > paginateBy"
v-model:page="page"
:pages="Math.ceil(result.count / paginateBy)"
/> />
<radio-card <radio-card
v-for="radio in result.results" v-if="isAuthenticated && hasFavorites"
:key="radio.id" :type="'favorites'"
type="custom"
:custom-radio="radio"
/> />
<Pagination <radio-card
v-if="result && result.count > paginateBy" v-if="scope === 'all'"
v-model:page="page" :type="'random'"
:pages="Math.ceil(result.count / paginateBy)"
/> />
</div> <radio-card
v-if="scope === 'me'"
:type="'random_library'"
/>
<radio-card :type="'recently-added'" />
<radio-card
v-if="store.state.auth.authenticated && scope === 'all'"
:type="'less-listened'"
/>
<radio-card
v-if="store.state.auth.authenticated && scope === 'me'"
:type="'less-listened_library'"
/>
</Section>
<Section
alignLeft
no-items
solid
primary
icon="bi-plus"
:h2="t('components.library.Radios.header.user')"
:action="{ text:t('components.library.Radios.button.create'), to:'/library/radios/build' }"
/>
<Layout flex form
:class="['ui', {'loading': isLoading}, 'form']"
@submit.prevent="search"
>
<Input search
id="radios-search"
v-model="query"
name="search"
:label="t('components.library.Radios.label.search')"
:placeholder="labels.searchPlaceholder"
/>
<Layout stack noGap label for="radios-ordering">
<span class="label">
{{ t('components.library.Radios.ordering.label') }}
</span>
<select
id="radios-ordering"
v-model="ordering"
class="dropdown"
>
<option
v-for="(option, key) in orderingOptions"
:key="key"
:value="option[0]"
>
{{ sharedLabels.filters[option[1]] }}
</option>
</select>
</Layout>
<Layout stack noGap label for="radios-ordering-direction">
<span class="label">
{{ t('components.library.Radios.ordering.direction.label') }}
</span>
<select
id="radios-ordering-direction"
v-model="orderingDirection"
class="dropdown"
>
<option value="+">
{{ t('components.library.Radios.ordering.direction.ascending') }}
</option>
<option value="-">
{{ t('components.library.Radios.ordering.direction.descending') }}
</option>
</select>
</Layout>
<Layout stack noGap label for="radios-results">
<span class="label">
{{ t('components.library.Radios.pagination.results') }}
</span>
<select
id="radios-results"
v-model="paginateBy"
class="dropdown"
>
<option
v-for="opt in paginateOptions"
:key="opt"
:value="opt"
>
{{ opt }}
</option>
</select>
</Layout>
</Layout>
<Alert
blue
style="align-items: center;"
v-if="result && result.results.length === 0"
>
<i class="bi bi-broadcast-pin" style="font-size: 80px" />
<Spacer />
{{ t('components.library.Radios.empty.noResults') }}
<Spacer />
<Button
v-if="store.state.auth.authenticated"
primary
style="align-self:center;"
:to="{name: 'library.radios.build'}"
icon="bi-boombox-fill"
>
{{ t('components.library.Radios.button.add') }}
</Button>
</Alert>
<Layout flex
v-if="result && result.results.length > 0"
>
<Pagination
v-if="result && result.count > paginateBy"
v-model:page="page"
:pages="Math.ceil(result.count / paginateBy)"
/>
<radio-card
v-for="radio in result.results"
:key="radio.id"
type="custom"
:custom-radio="radio"
/>
<Pagination
v-if="result && result.count > paginateBy"
v-model:page="page"
:pages="Math.ceil(result.count / paginateBy)"
/>
</Layout>
</Layout> </Layout>
</template> </template>

View File

@ -39,6 +39,7 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
<Card <Card
v-if="radio.id" v-if="radio.id"
small small
blue
:title="radio.name" :title="radio.name"
:to="{name: 'library.radios.detail', params: {id: radio.id}}" :to="{name: 'library.radios.detail', params: {id: radio.id}}"
> >
@ -82,19 +83,20 @@ const customRadioId = computed(() => props.customRadio?.id ?? null)
<Card <Card
v-else v-else
small small
solid
blue
icon="bi-boombox-fill"
:title="radio.name" :title="radio.name"
> >
<template #topright>
</template>
<template #default> <template #default style="background-color: red;">
<user-link <user-link
v-if="radio.user" v-if="radio.user"
discrete discrete
:user="radio.user" :user="radio.user"
:avatar="false" :avatar="false"
/> />
<Spacer /> <Spacer v-if="radio.user" />
<div <div
class="description" class="description"
:class="{expanded: isDescriptionExpanded}" :class="{expanded: isDescriptionExpanded}"

View File

@ -10,7 +10,13 @@ import axios from 'axios'
import TrackTable from '~/components/audio/track/Table.vue' import TrackTable from '~/components/audio/track/Table.vue'
import RadioButton from '~/components/radios/Button.vue' import RadioButton from '~/components/radios/Button.vue'
import Pagination from '~/components/vui/Pagination.vue' import Layout from '~/components/ui/Layout.vue'
import Header from '~/components/ui/Header.vue'
import Section from '~/components/ui/Section.vue'
import Spacer from '~/components/ui/Spacer.vue'
import Pagination from '~/components/ui/Pagination.vue'
import Alert from '~/components/ui/Alert.vue'
import Button from '~/components/ui/Button.vue'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
@ -66,99 +72,83 @@ const deleteRadio = async () => {
</script> </script>
<template> <template>
<main> <Layout stack main>
<div <Loader
v-if="isLoading" v-if="isLoading"
v-title="labels.title" v-title="labels.title"
class="ui vertical segment" />
> <Header
<div :class="['ui', 'centered', 'active', 'inline', 'loader']" />
</div>
<section
v-if="!isLoading && radio" v-if="!isLoading && radio"
v-title="radio.name" v-title="radio.name"
class="ui head vertical center aligned stripe segment" :h1="radio.name"
> />
<div class="segment-content"> <h2 class="sub header">
<h2 class="ui center aligned icon header"> {{ t('views.radios.Detail.header.radio', {tracks: totalTracks}) }}<username :username="radio?.user.username" />
<i class="circular inverted feed primary icon" /> </h2>
<div class="content"> <Layout flex>
{{ radio.name }} <radio-button
<div class="sub header"> :custom-radio-id="radio?.id"
{{ t('views.radios.Detail.header.radio', {tracks: totalTracks}) }}<username :username="radio.user.username" /> />
</div> <template v-if="store.state.auth.username === radio?.user.username">
</div> <Button
</h2> icon="bi-pencil"
<div class="ui hidden divider" /> secondary
<radio-button :to="{name: 'library.radios.edit', params: {id: radio?.id}}"
type="custom" >
:custom-radio-id="radio.id" {{ t('views.radios.Detail.button.edit') }}
/> </Button>
<template v-if="store.state.auth.username === radio.user.username"> <dangerous-button
<router-link class="ui labeled danger icon button"
class="ui icon labeled button" :action="deleteRadio"
:to="{name: 'library.radios.edit', params: {id: radio.id}}" >
> <i class="bi bi-trash" /> {{ t('views.radios.Detail.button.delete') }}
<i class="pencil icon" /> <template #modal-header>
{{ t('views.radios.Detail.button.edit') }} <p>
</router-link> {{ t('views.radios.Detail.modal.delete.header', {radio: radio.name}) }}
<dangerous-button </p>
class="ui labeled danger icon button" </template>
:action="deleteRadio" <template #modal-content>
> <p>
<i class="trash icon" /> {{ t('views.radios.Detail.button.delete') }} {{ t('views.radios.Detail.modal.delete.content.warning') }}
<template #modal-header> </p>
<p> </template>
{{ t('views.radios.Detail.modal.delete.header', {radio: radio.name}) }} <template #modal-confirm>
</p> <p>
</template> {{ t('views.radios.Detail.button.confirm') }}
<template #modal-content> </p>
<p> </template>
{{ t('views.radios.Detail.modal.delete.content.warning') }} </dangerous-button>
</p> </template>
</template> </Layout>
<template #modal-confirm> <Section
<p>
{{ t('views.radios.Detail.button.confirm') }}
</p>
</template>
</dangerous-button>
</template>
</div>
</section>
<section
v-if="totalTracks > 0" v-if="totalTracks > 0"
class="ui vertical stripe segment" :h2="t('views.radios.Detail.header.tracks')"
> >
<h2>
{{ t('views.radios.Detail.header.tracks') }}
</h2>
<track-table :tracks="tracks" /> <track-table :tracks="tracks" />
<div class="ui center aligned basic segment"> <Pagination
<pagination
v-if="totalTracks > 25" v-if="totalTracks > 25"
v-model:current="page" v-model:current="page"
:paginate-by="25" :paginate-by="25"
:total="totalTracks" :total="totalTracks"
/> />
</div> </Section>
</section> <Alert
<div blue
v-else-if="!isLoading && totalTracks === 0" v-else-if="!isLoading && totalTracks === 0"
class="ui placeholder segment"
> >
<div class="ui icon header"> <Layout stack style="text-align: center;">
<i class="rss icon" /> <i class="bi bi-broadcast-pin" style="font-size: 5em;" />
{{ t('views.radios.Detail.empty.noTracks') }} {{ t('views.radios.Detail.empty.noTracks') }}
</div> <Button
<router-link v-if="store.state.auth.username === radio?.user.username"
v-if="store.state.auth.username === radio?.user.username" primary
class="ui success icon labeled button" icon="bi-pencil"
:to="{name: 'library.radios.edit', params: { id: radio?.id }}" style="align-self: center;"
> :to="{name: 'library.radios.edit', params: { id: radio?.id }}"
<i class="pencil icon" /> >
{{ t('views.radios.Detail.button.edit') }} {{ t('views.radios.Detail.button.edit') }}
</router-link> </Button>
</div> </Layout>
</main> </Alert>
</Layout>
</template> </template>