mirror of
https://github.com/koel/koel
synced 2024-11-24 13:13:05 +00:00
fix: sidebar menu collapse/expand on mobile
This commit is contained in:
parent
b994f2dc94
commit
bb47d5fb3b
4 changed files with 53 additions and 39 deletions
|
@ -10,7 +10,9 @@
|
||||||
py-0 px-6 h-k-header-height"
|
py-0 px-6 h-k-header-height"
|
||||||
>
|
>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<SidebarMenuToggleButton />
|
<ExtraDrawerButton @click.prevent="expandSidebar">
|
||||||
|
<Icon :icon="faBars" fixed-width />
|
||||||
|
</ExtraDrawerButton>
|
||||||
<ExtraDrawerTabHeader v-if="songPlaying" v-model="activeTab" />
|
<ExtraDrawerTabHeader v-if="songPlaying" v-model="activeTab" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -70,16 +72,17 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import isMobile from 'ismobilejs'
|
import isMobile from 'ismobilejs'
|
||||||
|
import { faBars } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { computed, defineAsyncComponent, onMounted, ref, Ref, watch } from 'vue'
|
import { computed, defineAsyncComponent, onMounted, ref, Ref, watch } from 'vue'
|
||||||
import { albumStore, artistStore, preferenceStore } from '@/stores'
|
import { albumStore, artistStore, preferenceStore } from '@/stores'
|
||||||
import { useErrorHandler, useThirdPartyServices } from '@/composables'
|
import { useErrorHandler, useThirdPartyServices } from '@/composables'
|
||||||
import { isSong, requireInjection } from '@/utils'
|
import { eventBus, isSong, requireInjection } from '@/utils'
|
||||||
import { CurrentPlayableKey } from '@/symbols'
|
import { CurrentPlayableKey } from '@/symbols'
|
||||||
|
|
||||||
import ProfileAvatar from '@/components/ui/ProfileAvatar.vue'
|
import ProfileAvatar from '@/components/ui/ProfileAvatar.vue'
|
||||||
import SidebarMenuToggleButton from '@/components/ui/SidebarMenuToggleButton.vue'
|
|
||||||
import AboutKoelButton from '@/components/layout/main-wrapper/extra-drawer/AboutKoelButton.vue'
|
import AboutKoelButton from '@/components/layout/main-wrapper/extra-drawer/AboutKoelButton.vue'
|
||||||
import LogoutButton from '@/components/layout/main-wrapper/extra-drawer/LogoutButton.vue'
|
import LogoutButton from '@/components/layout/main-wrapper/extra-drawer/LogoutButton.vue'
|
||||||
|
import ExtraDrawerButton from '@/components/layout/main-wrapper/extra-drawer/ExtraDrawerButton.vue'
|
||||||
|
|
||||||
const LyricsPane = defineAsyncComponent(() => import('@/components/ui/LyricsPane.vue'))
|
const LyricsPane = defineAsyncComponent(() => import('@/components/ui/LyricsPane.vue'))
|
||||||
const ArtistInfo = defineAsyncComponent(() => import('@/components/artist/ArtistInfo.vue'))
|
const ArtistInfo = defineAsyncComponent(() => import('@/components/artist/ArtistInfo.vue'))
|
||||||
|
@ -119,6 +122,7 @@ watch(playable, song => {
|
||||||
watch(activeTab, tab => (preferenceStore.active_extra_panel_tab = tab))
|
watch(activeTab, tab => (preferenceStore.active_extra_panel_tab = tab))
|
||||||
|
|
||||||
const onProfileLinkClick = () => isMobile.any && (activeTab.value = null)
|
const onProfileLinkClick = () => isMobile.any && (activeTab.value = null)
|
||||||
|
const expandSidebar = () => eventBus.emit('TOGGLE_SIDEBAR')
|
||||||
|
|
||||||
onMounted(() => isMobile.any || (activeTab.value = preferenceStore.active_extra_panel_tab))
|
onMounted(() => isMobile.any || (activeTab.value = preferenceStore.active_extra_panel_tab))
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
exports[`renders without a current song 1`] = `
|
exports[`renders without a current song 1`] = `
|
||||||
<aside data-v-847f0b60="" class="fixed sm:relative top-0 w-screen md:w-auto flex flex-col md:flex-row-reverse z-[2] text-k-text-secondary">
|
<aside data-v-847f0b60="" class="fixed sm:relative top-0 w-screen md:w-auto flex flex-col md:flex-row-reverse z-[2] text-k-text-secondary">
|
||||||
<div data-v-847f0b60="" class="controls flex md:flex-col justify-between items-center md:w-[64px] md:py-6 tw:px-0 bg-black/5 md:border-l border-solid md:border-l-white/5 md:border-b-0 md:shadow-none z-[2] w-screen flex-row border-b border-b-white/5 border-l-0 shadow-xl py-0 px-6 h-k-header-height">
|
<div data-v-847f0b60="" class="controls flex md:flex-col justify-between items-center md:w-[64px] md:py-6 tw:px-0 bg-black/5 md:border-l border-solid md:border-l-white/5 md:border-b-0 md:shadow-none z-[2] w-screen flex-row border-b border-b-white/5 border-l-0 shadow-xl py-0 px-6 h-k-header-height">
|
||||||
<div data-v-847f0b60="" class="btn-group"><button data-v-5e31283f="" data-v-847f0b60="" class="relative flex items-center justify-center h-[42px] aspect-square rounded-full bg-none md:bg-black/30 text-xl opacity-70 transition-opacity duration-200 ease-in-out text-current cursor-pointer hover:active-state active:scale-90 block md:hidden" type="button"><br data-testid="Icon" icon="[object Object]" fixed-width=""></button>
|
<div data-v-847f0b60="" class="btn-group"><button data-v-5e31283f="" data-v-847f0b60="" class="relative flex items-center justify-center h-[42px] aspect-square rounded-full bg-none md:bg-black/30 text-xl opacity-70 transition-opacity duration-200 ease-in-out text-current cursor-pointer hover:active-state active:scale-90" type="button"><br data-v-847f0b60="" data-testid="Icon" icon="[object Object]" fixed-width=""></button>
|
||||||
<!--v-if-->
|
<!--v-if-->
|
||||||
</div>
|
</div>
|
||||||
<div data-v-847f0b60="" class="btn-group"><button data-v-5e31283f="" data-v-847f0b60="" class="relative flex items-center justify-center h-[42px] aspect-square rounded-full bg-none md:bg-black/30 text-xl opacity-70 transition-opacity duration-200 ease-in-out text-current cursor-pointer hover:active-state active:scale-90" type="button" title="About Koel"><br data-testid="Icon" icon="[object Object]">
|
<div data-v-847f0b60="" class="btn-group"><button data-v-5e31283f="" data-v-847f0b60="" class="relative flex items-center justify-center h-[42px] aspect-square rounded-full bg-none md:bg-black/30 text-xl opacity-70 transition-opacity duration-200 ease-in-out text-current cursor-pointer hover:active-state active:scale-90" type="button" title="About Koel"><br data-testid="Icon" icon="[object Object]">
|
||||||
|
|
|
@ -1,45 +1,55 @@
|
||||||
<template>
|
<template>
|
||||||
<nav
|
<nav
|
||||||
:class="{ collapsed: !expanded, 'tmp-showing': tmpShowing, showing: mobileShowing }"
|
:class="{ collapsed: !expanded, 'tmp-showing': tmpShowing, showing: mobileShowing }"
|
||||||
class="group flex flex-col fixed md:relative w-full md:w-k-sidebar-width z-10"
|
class="group left-0 top-0 flex flex-col fixed h-full w-full md:relative md:w-k-sidebar-width z-[999] md:z-10"
|
||||||
@mouseenter="onMouseEnter"
|
@mouseenter="onMouseEnter"
|
||||||
@mouseleave="onMouseLeave"
|
@mouseleave="onMouseLeave"
|
||||||
>
|
>
|
||||||
<section class="home-search-block p-6 flex gap-2">
|
<section class="btn-collapse-block flex md:hidden items-center border-b border-b-white/5 h-k-header-height px-6">
|
||||||
<HomeButton />
|
<div class="bg-white/5 rounded-full">
|
||||||
<SearchForm class="flex-1" />
|
<ExtraDrawerButton @click.prevent="collapseSidebar">
|
||||||
</section>
|
<Icon :icon="faTimes" fixed-width />
|
||||||
|
</ExtraDrawerButton>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section v-koel-overflow-fade class="pt-2 pb-10 overflow-y-auto space-y-8">
|
<section class="home-search-block p-6 flex gap-2">
|
||||||
<SidebarYourMusicSection />
|
<HomeButton />
|
||||||
<SidebarPlaylistsSection />
|
<SearchForm class="flex-1" />
|
||||||
<SidebarManageSection v-if="showManageSection" />
|
</section>
|
||||||
</section>
|
|
||||||
|
|
||||||
<section v-if="!isPlus && isAdmin" class="p-6 flex-1 flex flex-col-reverse">
|
<section v-koel-overflow-fade class="pt-2 pb-10 overflow-y-auto space-y-8">
|
||||||
<BtnUpgradeToPlus />
|
<SidebarYourMusicSection />
|
||||||
</section>
|
<SidebarPlaylistsSection />
|
||||||
|
<SidebarManageSection v-if="showManageSection" />
|
||||||
|
</section>
|
||||||
|
|
||||||
<SidebarToggleButton
|
<section v-if="!isPlus && isAdmin" class="p-6 flex-1 flex flex-col-reverse">
|
||||||
class="opacity-0 no-hover:hidden group-hover:opacity-100 transition"
|
<BtnUpgradeToPlus />
|
||||||
v-model="expanded"
|
</section>
|
||||||
:class="expanded || 'opacity-100'"
|
|
||||||
/>
|
<SidebarToggleButton
|
||||||
</nav>
|
class="opacity-0 no-hover:hidden group-hover:opacity-100 transition"
|
||||||
|
v-model="expanded"
|
||||||
|
:class="expanded || 'opacity-100'"
|
||||||
|
/>
|
||||||
|
</nav>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import { eventBus } from '@/utils'
|
import { eventBus } from '@/utils'
|
||||||
import { useAuthorization, useKoelPlus, useLocalStorage, useRouter, useUpload } from '@/composables'
|
import { useAuthorization, useKoelPlus, useLocalStorage, useRouter, useUpload } from '@/composables'
|
||||||
|
|
||||||
import SidebarPlaylistsSection from './SidebarPlaylistsSection.vue'
|
|
||||||
import SearchForm from '@/components/ui/SearchForm.vue'
|
|
||||||
import BtnUpgradeToPlus from '@/components/koel-plus/BtnUpgradeToPlus.vue'
|
import BtnUpgradeToPlus from '@/components/koel-plus/BtnUpgradeToPlus.vue'
|
||||||
import SidebarYourMusicSection from './SidebarYourLibrarySection.vue'
|
import ExtraDrawerButton from '@/components/layout/main-wrapper/extra-drawer/ExtraDrawerButton.vue'
|
||||||
import SidebarManageSection from './SidebarManageSection.vue'
|
|
||||||
import SidebarToggleButton from '@/components/layout/main-wrapper/sidebar/SidebarToggleButton.vue'
|
|
||||||
import HomeButton from '@/components/layout/main-wrapper/sidebar/HomeButton.vue'
|
import HomeButton from '@/components/layout/main-wrapper/sidebar/HomeButton.vue'
|
||||||
|
import SearchForm from '@/components/ui/SearchForm.vue'
|
||||||
|
import SidebarManageSection from './SidebarManageSection.vue'
|
||||||
|
import SidebarPlaylistsSection from './SidebarPlaylistsSection.vue'
|
||||||
|
import SidebarToggleButton from '@/components/layout/main-wrapper/sidebar/SidebarToggleButton.vue'
|
||||||
|
import SidebarYourMusicSection from './SidebarYourLibrarySection.vue'
|
||||||
|
|
||||||
const { onRouteChanged } = useRouter()
|
const { onRouteChanged } = useRouter()
|
||||||
const { isAdmin } = useAuthorization()
|
const { isAdmin } = useAuthorization()
|
||||||
|
@ -81,6 +91,8 @@ const onMouseLeave = (e: MouseEvent) => {
|
||||||
|
|
||||||
onRouteChanged(_ => (mobileShowing.value = false))
|
onRouteChanged(_ => (mobileShowing.value = false))
|
||||||
|
|
||||||
|
const collapseSidebar = () => (mobileShowing.value = false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen to toggle sidebar event to show or hide the sidebar.
|
* Listen to toggle sidebar event to show or hide the sidebar.
|
||||||
* This should only be triggered on a mobile device.
|
* This should only be triggered on a mobile device.
|
||||||
|
@ -104,9 +116,9 @@ nav {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.tmp-showing {
|
&.tmp-showing {
|
||||||
@apply absolute h-screen z-50 bg-k-bg-primary w-k-sidebar-width shadow-2xl;
|
@apply fixed h-screen bg-k-bg-primary w-k-sidebar-width shadow-2xl z-[999];
|
||||||
|
|
||||||
> *:not(.btn-toggle) {
|
> *:not(.btn-toggle, .btn-collapse-block) {
|
||||||
@apply block;
|
@apply block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,11 +130,9 @@ nav {
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
@mixin themed-background;
|
@mixin themed-background;
|
||||||
z-index: 999;
|
|
||||||
|
|
||||||
transform: translateX(-100vw);
|
transform: translateX(-100vw);
|
||||||
transition: transform .2s ease-in-out;
|
transition: transform .2s ease-in-out;
|
||||||
height: calc(100vh - var(--header-height));
|
|
||||||
|
|
||||||
&.showing {
|
&.showing {
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
|
|
|
@ -20,8 +20,8 @@ new class extends UnitTestCase {
|
||||||
expect(screen.getByTestId('sidebar-item').classList.contains('current')).toBe(true)
|
expect(screen.getByTestId('sidebar-item').classList.contains('current')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it ('emits the sidebar toggle event when clicked', async () => {
|
it('emits the sidebar toggle event when clicked', async () => {
|
||||||
const mock = this.mock(eventBus, 'emit')
|
const mock = this.mock(eventBus, 'emit')
|
||||||
this.renderComponent()
|
this.renderComponent()
|
||||||
await this.user.click(screen.getByTestId('sidebar-item'))
|
await this.user.click(screen.getByTestId('sidebar-item'))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue