fix(front): [WIP] favourites page

This commit is contained in:
ArneBo 2025-01-06 18:06:40 +01:00 committed by upsiflu
parent 13af438026
commit 404b6f5f7a
4 changed files with 107 additions and 108 deletions

View File

@ -12,6 +12,8 @@ import axios from 'axios'
import TrackMobileRow from '~/components/audio/track/MobileRow.vue' import TrackMobileRow from '~/components/audio/track/MobileRow.vue'
import Pagination from '~/components/vui/Pagination.vue' import Pagination from '~/components/vui/Pagination.vue'
import TrackRow from '~/components/audio/track/Row.vue' import TrackRow from '~/components/audio/track/Row.vue'
import Input from '~/components/ui/Input.vue'
import Spacer from '~/components/ui/layout/Spacer.vue'
import useErrorHandler from '~/composables/useErrorHandler' import useErrorHandler from '~/composables/useErrorHandler'
@ -91,7 +93,8 @@ const store = useStore()
const labels = computed(() => ({ const labels = computed(() => ({
title: t('components.audio.track.Table.table.header.title'), title: t('components.audio.track.Table.table.header.title'),
album: t('components.audio.track.Table.table.header.album'), album: t('components.audio.track.Table.table.header.album'),
artist: t('components.audio.track.Table.table.header.artist') artist: t('components.audio.track.Table.table.header.artist'),
searchPlaceholder: t('components.library.Podcasts.placeholder.search'),
})) }))
const isLoading = ref(false) const isLoading = ref(false)
@ -144,11 +147,14 @@ const updatePage = (page: number) => {
<template> <template>
<div> <div>
<!-- Show the search bar if search is true --> <!-- Show the search bar if search is true -->
<inline-search-bar <Input search
v-if="search" v-if="search"
v-model="query" v-model="query"
@search="performSearch" @search="performSearch"
autofocus
:placeholder="labels.searchPlaceholder"
/> />
<Spacer v-if="search" />
<!-- Add a header if needed --> <!-- Add a header if needed -->

View File

@ -2,6 +2,7 @@
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import Button from '~/components/ui/Button.vue' import Button from '~/components/ui/Button.vue'
import Alert from '~/components/ui/Alert.vue'
interface Events { interface Events {
(e: 'refresh'): void (e: 'refresh'): void
@ -20,11 +21,11 @@ withDefaults(defineProps<Props>(), {
</script> </script>
<template> <template>
<div class="ui small placeholder segment component-placeholder component-empty-state"> <Alert blue style="text-align: center;">
<h4 class="ui header"> <h4 class="ui header">
<div class="content"> <div class="content">
<slot name="title"> <slot name="title">
<i class="search icon" /> <i class="bi bi-search" style="margin-right: 8px;" />
{{ t('components.common.EmptyState.header.noResults') }} {{ t('components.common.EmptyState.header.noResults') }}
</slot> </slot>
</div> </div>
@ -32,11 +33,12 @@ withDefaults(defineProps<Props>(), {
<div class="inline center aligned text"> <div class="inline center aligned text">
<slot /> <slot />
<Button <Button
primary
v-if="refresh" v-if="refresh"
@click="emit('refresh')" @click="emit('refresh')"
> >
{{ t('components.common.EmptyState.button.refresh') }} {{ t('components.common.EmptyState.button.refresh') }}
</Button> </Button>
</div> </div>
</div> </Alert>
</template> </template>

View File

@ -10,11 +10,17 @@ import { sortedUniq } from 'lodash-es'
import { useStore } from '~/store' import { useStore } from '~/store'
import axios from 'axios' import axios from 'axios'
import $ from 'jquery'
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 Pagination from '~/components/ui/Pagination.vue'
import Layout from '~/components/ui/Layout.vue'
import Section from '~/components/ui/layout/Section.vue'
import Spacer from '~/components/ui/layout/Spacer.vue'
import Button from '~/components/ui/Button.vue'
import Link from '~/components/ui/Link.vue'
import Alert from '~/components/ui/Alert.vue'
import Loader from '~/components/ui/Loader.vue'
import useSharedLabels from '~/composables/locale/useSharedLabels' import useSharedLabels from '~/composables/locale/useSharedLabels'
import useOrdering from '~/composables/navigation/useOrdering' import useOrdering from '~/composables/navigation/useOrdering'
@ -94,8 +100,6 @@ onOrderingUpdate(() => {
fetchFavorites() fetchFavorites()
}) })
onMounted(() => $('.ui.dropdown').dropdown())
const { t } = useI18n() const { t } = useI18n()
const labels = computed(() => ({ const labels = computed(() => ({
title: t('components.favorites.List.title') title: t('components.favorites.List.title')
@ -105,42 +109,38 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
</script> </script>
<template> <template>
<main <Layout main stack
v-title="labels.title" v-title="labels.title"
class="main"
> >
<section class="ui vertical center aligned stripe segment"> <Section
<div :class="['ui', { 'active': isLoading }, 'inverted', 'dimmer']">
<div class="ui text loader">
{{ t('components.favorites.List.loader.loading') }}
</div>
</div>
<h2
v-if="results" v-if="results"
class="ui center aligned icon header" :h1="t('components.favorites.List.title', store.state.favorites.count)"
> >
<i class="circular inverted heart pink icon" /> <RadioButton
{{ t('components.favorites.List.header.favorites', store.state.favorites.count) }}
</h2>
<radio-button
v-if="store.state.favorites.count > 0" v-if="store.state.favorites.count > 0"
type="favorites" type="favorites"
/> />
</Section>
<section class="center">
<div :class="['ui', { 'active': isLoading }, 'inverted', 'dimmer']">
<div v-if="isLoading" class="ui text loader">
{{ t('components.favorites.List.loader.loading') }}
</div>
<Loader v-if="isLoading"/>
</div>
</section> </section>
<section <Layout
v-if="store.state.favorites.count > 0" v-if="store.state.favorites.count > 0"
class="ui vertical stripe segment" form
stack
:class="['ui', { 'loading': isLoading }, 'form']"
> >
<div :class="['ui', { 'loading': isLoading }, 'form']"> <Layout flex style="justify-content: flex-end;">
<div class="fields">
<div class="field">
<label for="favorites-ordering">
{{ t('components.favorites.List.ordering.label') }}
</label>
<select <select
id="favorites-ordering" id="favorites-ordering"
v-model="ordering" v-model="ordering"
class="ui dropdown" :label="t('components.favorites.List.ordering.label')"
class="dropdown"
> >
<option <option
v-for="option in orderingOptions" v-for="option in orderingOptions"
@ -150,15 +150,11 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
{{ sharedLabels.filters[option[1]] }} {{ sharedLabels.filters[option[1]] }}
</option> </option>
</select> </select>
</div>
<div class="field">
<label for="favorites-ordering-direction">
{{ t('components.favorites.List.ordering.direction.label') }}
</label>
<select <select
id="favorites-ordering-direction" id="favorites-ordering-direction"
:label="t('components.favorites.List.ordering.direction.label')"
v-model="orderingDirection" v-model="orderingDirection"
class="ui dropdown" class="dropdown"
> >
<option value="+"> <option value="+">
{{ t('components.favorites.List.ordering.direction.ascending') }} {{ t('components.favorites.List.ordering.direction.ascending') }}
@ -167,15 +163,11 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
{{ t('components.favorites.List.ordering.direction.descending') }} {{ t('components.favorites.List.ordering.direction.descending') }}
</option> </option>
</select> </select>
</div>
<div class="field">
<label for="favorites-results">
{{ t('components.favorites.List.pagination.results') }}
</label>
<select <select
id="favorites-results" id="favorites-results"
v-model="paginateBy" v-model="paginateBy"
class="ui dropdown" :label="t('components.favorites.List.pagination.results')"
class="dropdown"
> >
<option <option
v-for="opt in paginateOptions" v-for="opt in paginateOptions"
@ -185,39 +177,37 @@ const paginateOptions = computed(() => sortedUniq([12, 25, 50, paginateBy.value]
{{ opt }} {{ opt }}
</option> </option>
</select> </select>
</div> </Layout>
</div> <TrackTable
</div>
<track-table
v-if="results" v-if="results"
:search="true"
:show-artist="true" :show-artist="true"
:show-album="true" :show-album="true"
:tracks="results" :tracks="results"
/> />
<div class="ui center aligned basic segment"> <Spacer grow />
<pagination <Pagination
v-if="results && count > paginateBy" v-if="result && result.count > paginateBy"
v-model:current="page" :page="page"
:paginate-by="paginateBy" :pages="Math.ceil((result?.results.length || 0)/paginateBy)"
:total="count"
/> />
</div> </Layout>
</section> <Alert blue style="text-align: center;"
<div
v-else v-else
class="ui placeholder segment"
> >
<div class="ui icon header"> <i class="bi bi-heartbreak-fill" style="font-size: 100px;" />
<i class="broken heart icon" /> <Spacer />
{{ t('components.favorites.List.empty.noFavorites') }} {{ t('components.favorites.List.empty.noFavorites') }}
</div> <Spacer size="40"/>
<router-link <Link
:to="'/library'" to="/library"
class="ui success labeled icon button" solid
primary
icon="bi-headphones"
align-self="center"
> >
<i class="headphones icon" />
{{ t('components.favorites.List.link.library') }} {{ t('components.favorites.List.link.library') }}
</router-link> </Link>
</div> </Alert>
</main> </Layout>
</template> </template>

View File

@ -25,6 +25,7 @@ import Input from '~/components/ui/Input.vue'
import Alert from '~/components/ui/Alert.vue' import Alert from '~/components/ui/Alert.vue'
import Spacer from '~/components/ui/layout/Spacer.vue' import Spacer from '~/components/ui/layout/Spacer.vue'
import Pills from '~/components/ui/Pills.vue' import Pills from '~/components/ui/Pills.vue'
import Loader from '~/components/ui/Loader.vue'
import useSharedLabels from '~/composables/locale/useSharedLabels' import useSharedLabels from '~/composables/locale/useSharedLabels'
import useOrdering from '~/composables/navigation/useOrdering' import useOrdering from '~/composables/navigation/useOrdering'