2022-04-17 22:43:58 +00:00
|
|
|
<script setup lang="ts">
|
2022-04-23 07:37:43 +00:00
|
|
|
import AudioPlayer from '~/components/audio/Player.vue'
|
|
|
|
import Queue from '~/components/Queue.vue'
|
|
|
|
import PlaylistModal from '~/components/playlists/PlaylistModal.vue'
|
|
|
|
import ChannelUploadModal from '~/components/channels/UploadModal.vue'
|
|
|
|
import Sidebar from '~/components/Sidebar.vue'
|
|
|
|
import ServiceMessages from '~/components/ServiceMessages.vue'
|
|
|
|
import SetInstanceModal from '~/components/SetInstanceModal.vue'
|
|
|
|
import ShortcutsModal from '~/components/ShortcutsModal.vue'
|
|
|
|
import FilterModal from '~/components/moderation/FilterModal.vue'
|
|
|
|
import ReportModal from '~/components/moderation/ReportModal.vue'
|
2022-04-19 18:51:23 +00:00
|
|
|
import { useIntervalFn, useToggle, useWindowSize } from '@vueuse/core'
|
2022-04-17 22:43:58 +00:00
|
|
|
|
2022-04-18 08:24:47 +00:00
|
|
|
import { computed, nextTick, onMounted, ref, watchEffect } from 'vue'
|
2022-04-23 07:37:43 +00:00
|
|
|
import store from '~/store'
|
2022-04-17 22:53:53 +00:00
|
|
|
import {
|
|
|
|
ListenWSEvent,
|
|
|
|
PendingReviewEditsWSEvent,
|
|
|
|
PendingReviewReportsWSEvent,
|
|
|
|
PendingReviewRequestsWSEvent,
|
|
|
|
Track
|
2022-04-23 07:37:43 +00:00
|
|
|
} from '~/types'
|
2022-04-17 22:43:58 +00:00
|
|
|
import useWebSocketHandler from '~/composables/useWebSocketHandler'
|
2022-04-23 07:37:43 +00:00
|
|
|
import { getClientOnlyRadio } from '~/radios'
|
2022-04-19 18:51:23 +00:00
|
|
|
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
2022-04-17 22:43:58 +00:00
|
|
|
|
|
|
|
// Tracks
|
|
|
|
const currentTrack = computed(() => store.getters['queue/currentTrack'])
|
|
|
|
const getTrackInformationText = (track: Track | undefined) => {
|
|
|
|
if (!track) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
const artist = track.artist ?? track.album?.artist
|
|
|
|
return `♫ ${track.title} – ${artist?.name} ♫`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update title
|
|
|
|
const initialTitle = document.title
|
|
|
|
watchEffect(() => {
|
|
|
|
const parts = [
|
|
|
|
getTrackInformationText(currentTrack.value),
|
|
|
|
store.state.ui.pageTitle,
|
|
|
|
initialTitle || 'Funkwhale'
|
|
|
|
]
|
|
|
|
|
|
|
|
document.title = parts.filter(i => i).join(' – ')
|
|
|
|
})
|
|
|
|
|
|
|
|
// Styles
|
|
|
|
const customStylesheets = computed(() => {
|
|
|
|
return store.state.instance?.frontSettings?.additionalStylesheets ?? []
|
|
|
|
})
|
|
|
|
|
|
|
|
// Fake content
|
|
|
|
onMounted(async () => {
|
|
|
|
await nextTick()
|
|
|
|
document.getElementById('fake-content')?.classList.add('loaded')
|
|
|
|
})
|
|
|
|
|
|
|
|
// WebSocket handlers
|
|
|
|
useWebSocketHandler('inbox.item_added', () => {
|
|
|
|
store.commit('ui/incrementNotifications', { type: 'inbox', count: 1 })
|
|
|
|
})
|
|
|
|
|
|
|
|
useWebSocketHandler('mutation.created', (event) => {
|
2022-04-17 22:53:53 +00:00
|
|
|
store.commit('ui/incrementNotifications', {
|
|
|
|
type: 'pendingReviewEdits',
|
|
|
|
value: (event as PendingReviewEditsWSEvent).pending_review_count
|
|
|
|
})
|
2022-04-17 22:43:58 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
useWebSocketHandler('mutation.updated', (event) => {
|
2022-04-17 22:53:53 +00:00
|
|
|
store.commit('ui/incrementNotifications', {
|
|
|
|
type: 'pendingReviewEdits',
|
|
|
|
value: (event as PendingReviewEditsWSEvent).pending_review_count
|
|
|
|
})
|
2022-04-17 22:43:58 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
useWebSocketHandler('report.created', (event) => {
|
2022-04-17 22:53:53 +00:00
|
|
|
store.commit('ui/incrementNotifications', {
|
|
|
|
type: 'pendingReviewReports',
|
|
|
|
value: (event as PendingReviewReportsWSEvent).unresolved_count
|
|
|
|
})
|
2022-04-17 22:43:58 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
useWebSocketHandler('user_request.created', (event) => {
|
2022-04-17 22:53:53 +00:00
|
|
|
store.commit('ui/incrementNotifications', {
|
|
|
|
type: 'pendingReviewRequests',
|
|
|
|
value: (event as PendingReviewRequestsWSEvent).pending_count
|
|
|
|
})
|
2022-04-17 22:43:58 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
useWebSocketHandler('Listen', (event) => {
|
|
|
|
if (store.state.radios.current && store.state.radios.running) {
|
|
|
|
const { current } = store.state.radios
|
|
|
|
|
|
|
|
if (current.clientOnly && current.type === 'account') {
|
2022-04-17 22:53:53 +00:00
|
|
|
getClientOnlyRadio(current).handleListen(current, event as ListenWSEvent, store)
|
2022-04-17 22:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Time ago
|
2022-04-19 18:51:23 +00:00
|
|
|
// TODO (wvffle): Migrate to useTimeAgo
|
2022-04-17 22:43:58 +00:00
|
|
|
useIntervalFn(() => {
|
|
|
|
// used to redraw ago dates every minute
|
|
|
|
store.commit('ui/computeLastDate')
|
|
|
|
}, 1000 * 60)
|
|
|
|
|
2022-04-19 18:51:23 +00:00
|
|
|
// Shortcuts
|
|
|
|
const [showShortcutsModal, toggleShortcutsModal] = useToggle(false)
|
|
|
|
onKeyboardShortcut('h', () => toggleShortcutsModal())
|
|
|
|
|
2022-04-17 22:43:58 +00:00
|
|
|
const { width } = useWindowSize()
|
|
|
|
const player = ref()
|
|
|
|
const showSetInstanceModal = ref(false)
|
|
|
|
</script>
|
|
|
|
|
2017-06-23 21:00:42 +00:00
|
|
|
<template>
|
2021-11-26 11:01:58 +00:00
|
|
|
<div
|
2022-04-17 22:43:58 +00:00
|
|
|
:key="String(store.state.instance.instanceUrl)"
|
|
|
|
:class="[store.state.ui.queueFocused ? 'queue-focused' : '',
|
|
|
|
{'has-bottom-player': store.state.queue.tracks.length > 0}]"
|
2021-11-26 11:01:58 +00:00
|
|
|
>
|
2018-07-26 17:51:55 +00:00
|
|
|
<!-- here, we display custom stylesheets, if any -->
|
2018-12-04 14:13:37 +00:00
|
|
|
<link
|
|
|
|
v-for="url in customStylesheets"
|
2021-11-26 11:01:58 +00:00
|
|
|
:key="url"
|
2018-12-04 14:13:37 +00:00
|
|
|
rel="stylesheet"
|
|
|
|
property="stylesheet"
|
|
|
|
:href="url"
|
|
|
|
>
|
2022-05-01 11:45:07 +00:00
|
|
|
|
2021-11-26 11:01:58 +00:00
|
|
|
<sidebar
|
|
|
|
:width="width"
|
|
|
|
@show:set-instance-modal="showSetInstanceModal = !showSetInstanceModal"
|
2022-04-19 18:51:23 +00:00
|
|
|
@show:shortcuts-modal="toggleShortcutsModal"
|
2021-11-26 11:01:58 +00:00
|
|
|
/>
|
2022-05-01 11:45:07 +00:00
|
|
|
<set-instance-modal v-model:show="showSetInstanceModal" />
|
2021-11-26 11:01:58 +00:00
|
|
|
<service-messages />
|
|
|
|
<transition name="queue">
|
|
|
|
<queue
|
2022-04-17 22:43:58 +00:00
|
|
|
v-if="store.state.ui.queueFocused"
|
|
|
|
@touch-progress="player.setCurrentTime($event)"
|
2021-11-26 11:01:58 +00:00
|
|
|
/>
|
|
|
|
</transition>
|
2022-04-18 16:17:51 +00:00
|
|
|
|
2021-11-26 11:01:58 +00:00
|
|
|
<router-view
|
2022-04-19 18:51:23 +00:00
|
|
|
v-slot="{ Component }"
|
2021-11-26 11:01:58 +00:00
|
|
|
role="main"
|
2022-04-18 16:17:51 +00:00
|
|
|
>
|
2022-05-01 11:45:07 +00:00
|
|
|
<template v-if="Component">
|
|
|
|
<Suspense>
|
|
|
|
<component :is="Component" />
|
|
|
|
<template #fallback>
|
|
|
|
<!-- TODO (wvffle): Add loader -->
|
|
|
|
Loading...
|
|
|
|
</template>
|
|
|
|
</Suspense>
|
|
|
|
</template>
|
2022-04-18 16:17:51 +00:00
|
|
|
</router-view>
|
|
|
|
|
2022-04-17 22:43:58 +00:00
|
|
|
<audio-player ref="player" />
|
|
|
|
<playlist-modal v-if="store.state.auth.authenticated" />
|
|
|
|
<channel-upload-modal v-if="store.state.auth.authenticated" />
|
|
|
|
<filter-modal v-if="store.state.auth.authenticated" />
|
2021-11-26 11:01:58 +00:00
|
|
|
<report-modal />
|
2022-05-01 11:45:07 +00:00
|
|
|
<shortcuts-modal v-model:show="showShortcutsModal" />
|
2017-06-23 21:00:42 +00:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<style lang="scss">
|
2018-12-19 21:04:35 +00:00
|
|
|
@import "style/_main";
|
2017-06-23 21:00:42 +00:00
|
|
|
</style>
|