koel/resources/assets/js/components/screens/HomeScreen.vue

143 lines
3.9 KiB
Vue
Raw Normal View History

2022-04-15 14:24:30 +00:00
<template>
<section id="homeWrapper">
2022-07-16 15:44:45 +00:00
<ScreenHeader layout="collapsed">{{ greeting }}</ScreenHeader>
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
<div class="main-scroll-wrap" @scroll="scrolling">
2022-07-12 09:05:12 +00:00
<ScreenEmptyState v-if="libraryEmpty">
<template v-slot:icon>
2022-07-15 07:23:55 +00:00
<icon :icon="faVolumeOff"/>
2022-07-12 09:05:12 +00:00
</template>
No songs found.
<span class="secondary d-block">
{{ isAdmin ? 'Have you set up your library yet?' : 'Contact your administrator to set up your library.' }}
</span>
</ScreenEmptyState>
<template v-else>
<div class="two-cols">
<MostPlayedSongs data-testid="most-played-songs" :loading="loading"/>
<RecentlyPlayedSongs data-testid="recently-played-songs" :loading="loading"/>
2022-07-12 09:05:12 +00:00
</div>
<div class="two-cols">
<RecentlyAddedAlbums data-testid="recently-added-albums" :loading="loading"/>
<RecentlyAddedSongs data-testid="recently-added-songs" :loading="loading"/>
2022-07-12 09:05:12 +00:00
</div>
<MostPlayedArtists data-testid="most-played-artists" :loading="loading"/>
<MostPlayedAlbums data-testid="most-played-albums" :loading="loading"/>
2022-07-12 09:05:12 +00:00
<ToTopButton/>
</template>
2022-04-15 14:24:30 +00:00
</div>
</section>
</template>
2022-04-15 17:00:08 +00:00
<script lang="ts" setup>
2022-07-15 07:23:55 +00:00
import { faVolumeOff } from '@fortawesome/free-solid-svg-icons'
2022-04-15 14:24:30 +00:00
import { sample } from 'lodash'
import { computed, ref } from 'vue'
import { eventBus, logger, noop, requireInjection } from '@/utils'
2022-07-12 09:05:12 +00:00
import { commonStore, overviewStore, userStore } from '@/stores'
import { useAuthorization, useInfiniteScroll, useScreen } from '@/composables'
import { DialogBoxKey } from '@/symbols'
2022-06-10 10:47:46 +00:00
import MostPlayedSongs from '@/components/screens/home/MostPlayedSongs.vue'
import RecentlyPlayedSongs from '@/components/screens/home/RecentlyPlayedSongs.vue'
import RecentlyAddedAlbums from '@/components/screens/home/RecentlyAddedAlbums.vue'
import RecentlyAddedSongs from '@/components/screens/home/RecentlyAddedSongs.vue'
import MostPlayedArtists from '@/components/screens/home/MostPlayedArtists.vue'
2022-07-10 16:12:04 +00:00
import MostPlayedAlbums from '@/components/screens/home/MostPlayedAlbums.vue'
import ScreenHeader from '@/components/ui/ScreenHeader.vue'
2022-07-12 09:05:12 +00:00
import ScreenEmptyState from '@/components/ui/ScreenEmptyState.vue'
2022-04-15 17:00:08 +00:00
2022-06-10 10:47:46 +00:00
const { ToTopButton, scrolling } = useInfiniteScroll(() => noop())
2022-04-15 17:00:08 +00:00
2022-07-12 09:05:12 +00:00
const { isAdmin } = useAuthorization()
const dialog = requireInjection(DialogBoxKey)
2022-04-15 17:00:08 +00:00
const greetings = [
'Oh hai!',
'Hey, %s!',
'Howdy, %s!',
'Yo!',
'Hows it going, %s?',
'Sup, %s?',
'Hows life, %s?',
'Hows your day, %s?',
'How have you been, %s?'
]
const greeting = computed(() => sample(greetings)!.replace('%s', userStore.current?.name))
2022-07-12 09:05:12 +00:00
const libraryEmpty = computed(() => commonStore.state.song_length === 0)
2022-04-15 17:00:08 +00:00
const loading = ref(false)
2022-06-10 10:47:46 +00:00
let initialized = false
2022-04-15 14:24:30 +00:00
eventBus.on('SONGS_DELETED', () => overviewStore.refresh())
.on('SONGS_UPDATED', () => overviewStore.refresh())
useScreen('Home').onScreenActivated(async () => {
if (!initialized) {
loading.value = true
try {
await overviewStore.init()
initialized = true
} catch (e) {
dialog.value.error('Failed to load home screen data. Please try again.')
logger.error(e)
} finally {
loading.value = false
}
2022-06-10 10:47:46 +00:00
}
})
2022-04-15 14:24:30 +00:00
</script>
<style lang="scss">
#homeWrapper {
.two-cols {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-gap: .7em 1em;
}
.recent {
h1 button {
float: right;
padding: 6px 10px;
margin-top: -3px;
}
}
ol {
display: grid;
grid-gap: .7em 1em;
align-content: start;
}
.main-scroll-wrap {
2022-10-13 15:18:47 +00:00
section:not(:last-of-type) {
2022-04-15 14:24:30 +00:00
margin-bottom: 48px;
}
h1 {
font-size: 1.4rem;
margin: 0 0 1.8rem;
font-weight: var(--font-weight-thin);
}
}
2022-08-03 21:01:47 +00:00
li {
overflow: hidden;
padding: 1px; // make space for focus outline
2022-08-03 21:01:47 +00:00
}
2022-04-15 14:24:30 +00:00
@media only screen and (max-width: 768px) {
.two-cols {
grid-template-columns: 1fr;
}
}
}
</style>