chore(front): [WIP] new toplevel channels page
This commit is contained in:
parent
4a9f2f99ae
commit
b1ac6612fd
|
@ -145,7 +145,7 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
{{ t('components.Sidebar.link.artists') }}
|
{{ t('components.Sidebar.link.artists') }}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link to="/subscriptions"
|
<Link to="/channels"
|
||||||
ghost
|
ghost
|
||||||
full
|
full
|
||||||
align-text="left"
|
align-text="left"
|
||||||
|
|
|
@ -124,6 +124,12 @@ export default [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'channels',
|
||||||
|
name: 'channels',
|
||||||
|
component: () => import('~/views/channels/List.vue'),
|
||||||
|
props: route => ({ defaultQuery: route.query.q })
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'subscriptions',
|
path: 'subscriptions',
|
||||||
name: 'subscriptions',
|
name: 'subscriptions',
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Channel } from '~/types'
|
||||||
|
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import ChannelsWidget from '~/components/audio/ChannelsWidget.vue'
|
||||||
|
import RemoteSearchForm from '~/components/RemoteSearchForm.vue'
|
||||||
|
import Layout from '~/components/ui/Layout.vue'
|
||||||
|
import Header from '~/components/ui/Header.vue'
|
||||||
|
import Modal from '~/components/ui/Modal.vue'
|
||||||
|
import Button from '~/components/ui/Button.vue'
|
||||||
|
|
||||||
|
import useErrorHandler from '~/composables/useErrorHandler'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
defaultQuery?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
defaultQuery: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const query = ref(props.defaultQuery)
|
||||||
|
const widgetKey = ref(new Date().toLocaleString())
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const labels = computed(() => ({
|
||||||
|
searchPlaceholder: t('views.channels.SubscriptionsList.placeholder.search')
|
||||||
|
}))
|
||||||
|
|
||||||
|
const previousPage = ref()
|
||||||
|
const nextPage = ref()
|
||||||
|
const channels = ref([] as Channel[])
|
||||||
|
const count = ref(0)
|
||||||
|
const isLoading = ref(false)
|
||||||
|
const fetchData = async () => {
|
||||||
|
isLoading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.get('channels/', { params: { q: query.value } })
|
||||||
|
previousPage.value = response.data.previous
|
||||||
|
nextPage.value = response.data.next
|
||||||
|
channels.value.push(...response.data.results)
|
||||||
|
count.value = response.data.count
|
||||||
|
} catch (error) {
|
||||||
|
useErrorHandler(error as Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
fetchData()
|
||||||
|
|
||||||
|
const reloadWidget = () => (widgetKey.value = new Date().toLocaleString())
|
||||||
|
const showSubscribeModal = ref(false)
|
||||||
|
const showCreateModal = ref(false)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Layout stack main
|
||||||
|
>
|
||||||
|
<Header
|
||||||
|
:h1="t('views.channels.SubscriptionsList.title')"
|
||||||
|
:action="{
|
||||||
|
text: t('views.channels.SubscriptionsList.link.addNew'),
|
||||||
|
onClick: ()=> showSubscribeModal = true
|
||||||
|
}"
|
||||||
|
icon="bi-plus"
|
||||||
|
primary
|
||||||
|
/>
|
||||||
|
<Modal
|
||||||
|
v-model="showSubscribeModal"
|
||||||
|
:title="t('views.channels.SubscriptionsList.modal.subscription.header')"
|
||||||
|
class="tiny"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref="modalContent"
|
||||||
|
class="scrolling content"
|
||||||
|
>
|
||||||
|
<remote-search-form
|
||||||
|
initial-type="both"
|
||||||
|
:show-submit="false"
|
||||||
|
:standalone="false"
|
||||||
|
:redirect="true"
|
||||||
|
@subscribed="showSubscribeModal = false; reloadWidget()"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<template #actions>
|
||||||
|
<Button
|
||||||
|
secondary
|
||||||
|
@click="showSubscribeModal = false"
|
||||||
|
>
|
||||||
|
{{ t('views.channels.SubscriptionsList.button.cancel') }}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
form="remote-search"
|
||||||
|
type="submit"
|
||||||
|
icon="bi-bookmark-check-fill"
|
||||||
|
primary
|
||||||
|
>
|
||||||
|
{{ t('views.channels.SubscriptionsList.button.subscribe') }}
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<inline-search-bar
|
||||||
|
v-model="query"
|
||||||
|
:placeholder="labels.searchPlaceholder"
|
||||||
|
@search="reloadWidget"
|
||||||
|
/>
|
||||||
|
<channels-widget
|
||||||
|
:key="widgetKey"
|
||||||
|
:limit="50"
|
||||||
|
:show-modification-date="true"
|
||||||
|
:filters="{q: query, ordering: '-name'}"
|
||||||
|
/>
|
||||||
|
<!-- TODO: Translations -->
|
||||||
|
<Header
|
||||||
|
:h1="t('views.auth.ProfileOverview.header.channels')"
|
||||||
|
:action="{
|
||||||
|
text: t('views.channels.SubscriptionsList.link.addNew'),
|
||||||
|
onClick: ()=> showCreateModal = true
|
||||||
|
}"
|
||||||
|
icon="bi-plus"
|
||||||
|
primary
|
||||||
|
/>
|
||||||
|
<channels-widget
|
||||||
|
:show-modification-date="true"
|
||||||
|
:limit="12"
|
||||||
|
:filters="{ordering: '-creation_date', external: 'true'}"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
{{ t('components.library.Home.header.newChannels') }}
|
||||||
|
</template>
|
||||||
|
</channels-widget>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<Modal v-model="showCreateModal"
|
||||||
|
:title="t(`views.auth.ProfileOverview.modal.createChannel.${
|
||||||
|
step === 1 ?
|
||||||
|
'header' :
|
||||||
|
category === 'podcast' ?
|
||||||
|
'podcast.header'
|
||||||
|
:
|
||||||
|
'artist.header'
|
||||||
|
}`)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref="modalContent"
|
||||||
|
class="scrolling content"
|
||||||
|
>
|
||||||
|
<channel-form
|
||||||
|
ref="createForm"
|
||||||
|
:object="null"
|
||||||
|
:step="step"
|
||||||
|
@loading="loading = $event"
|
||||||
|
@submittable="submittable = $event"
|
||||||
|
@category="category = $event"
|
||||||
|
@errored="modalContent.scrollTop = 0"
|
||||||
|
@created="router.push({name: 'channels.detail', params: {id: $event.actor.preferred_username}})"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<template #actions>
|
||||||
|
<Button secondary
|
||||||
|
v-if="step === 1"
|
||||||
|
autofocus
|
||||||
|
>
|
||||||
|
{{ t('views.auth.ProfileOverview.button.cancel') }}
|
||||||
|
</Button>
|
||||||
|
<Button secondary
|
||||||
|
v-if="step > 1"
|
||||||
|
@click.stop.prevent="step -= 1"
|
||||||
|
>
|
||||||
|
{{ t('views.auth.ProfileOverview.button.previous') }}
|
||||||
|
</Button>
|
||||||
|
<Button primary
|
||||||
|
v-if="step === 1"
|
||||||
|
@click.stop.prevent="step += 1"
|
||||||
|
>
|
||||||
|
{{ t('views.auth.ProfileOverview.button.next') }}
|
||||||
|
</Button>
|
||||||
|
<Button primary
|
||||||
|
v-if="step === 2"
|
||||||
|
type="submit"
|
||||||
|
:disabled="!submittable && !loading"
|
||||||
|
:isLoading="loading"
|
||||||
|
@click.prevent.stop="createForm.submit"
|
||||||
|
>
|
||||||
|
{{ t('views.auth.ProfileOverview.button.createChannel') }}
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
Loading…
Reference in New Issue