fix: collapsible sidebar

This commit is contained in:
Shariq Ansari 2023-09-20 23:27:30 +05:30
parent ffc8070c42
commit cb9b4a6347
8 changed files with 190 additions and 62 deletions

View File

@ -1,32 +1,38 @@
<template>
<div class="flex flex-col h-full justify-between">
<div
class="flex flex-col h-full justify-between transition-all duration-300 ease-in-out"
:class="isSidebarCollapsed ? 'w-12' : 'w-56'"
>
<div>
<div class="flex p-2">
<UserDropdown />
<UserDropdown :isCollapsed="isSidebarCollapsed" />
</div>
<div class="flex-1">
<nav class="space-y-0.5 px-2">
<NavLinks
:links="navigations"
class="flex items-center rounded px-2 py-1 text-gray-800 transition-all duration-300 ease-in-out"
active="bg-white shadow-sm"
inactive="hover:bg-gray-100"
>
<template v-slot="{ link }">
<div class="flex w-full items-center space-x-2">
<span class="grid h-5 w-6 place-items-center">
<component
:is="link.icon"
class="h-4.5 w-4.5 text-gray-700"
/>
</span>
<span class="text-base">{{ link.name }}</span>
</div>
</template>
</NavLinks>
</nav>
<div v-for="link in links">
<SidebarLink
:icon="link.icon"
:label="link.label"
:to="link.to"
:isCollapsed="isSidebarCollapsed"
class="my-0.5 mx-2"
/>
</div>
</div>
<SidebarLink
:label="isSidebarCollapsed ? 'Expand' : 'Collapse'"
:isCollapsed="isSidebarCollapsed"
@click="isSidebarCollapsed = !isSidebarCollapsed"
class="m-2"
>
<template #icon>
<span class="grid h-5 w-6 place-items-center flex-shrink-0">
<component
:is="CollapseSidebar"
class="h-4.5 w-4.5 text-gray-700 duration-300 ease-in-out"
:class="{ '[transform:rotateY(180deg)]': isSidebarCollapsed }"
/>
</span>
</template>
</SidebarLink>
</div>
</template>
@ -38,7 +44,42 @@ import ContactsIcon from '@/components/Icons/ContactsIcon.vue'
import NoteIcon from '@/components/Icons/NoteIcon.vue'
import DashboardIcon from '@/components/Icons/DashboardIcon.vue'
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
import NavLinks from '@/components/NavLinks.vue'
import CollapseSidebar from '@/components/Icons/CollapseSidebar.vue'
import SidebarLink from '@/components/SidebarLink.vue'
import { ref } from 'vue'
const links = [
{
label: 'Leads',
icon: LeadsIcon,
to: 'Leads',
},
{
label: 'Deals',
icon: DealsIcon,
to: 'Deals',
},
{
label: 'Contacts',
icon: ContactsIcon,
to: 'Contacts',
},
{
label: 'Notes',
icon: NoteIcon,
to: 'Notes',
},
{
label: 'Call Logs',
icon: PhoneIcon,
to: 'Call Logs',
},
// {
// label: 'Dashboard',
// icon: DashboardIcon,
// to: 'Dashboard',
// },
]
const navigations = [
{
@ -72,4 +113,6 @@ const navigations = [
// route: { name: 'Dashboard' },
// },
]
const isSidebarCollapsed = ref(false)
</script>

View File

@ -1,6 +1,6 @@
<template>
<div class="flex h-screen w-screen">
<div class="h-full border-r bg-gray-50 w-[220px]">
<div class="h-full border-r bg-gray-50">
<AppSidebar />
</div>
<div class="flex-1 flex flex-col h-full overflow-auto">

View File

@ -0,0 +1,27 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.875 9.06223L3 9.06232"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M6.74537 5.31699L3 9.06236L6.74527 12.8076"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M14.1423 4L14.1423 14.125"
stroke="currentColor"
stroke-linecap="round"
/>
</svg>
</template>

View File

@ -0,0 +1,23 @@
<template>
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.26733 9.06277L14.1423 9.06268"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M10.397 12.808L14.1423 9.06264L10.3971 5.31737"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path d="M3 14.125L3 4" stroke="currentColor" stroke-linecap="round" />
</svg>
</template>

View File

@ -1,16 +0,0 @@
<template>
<router-link custom :to="link.route" v-slot="{ href, isActive, navigate }">
<a
:href="href"
@click="navigate"
:class="[isActive ? active : inactive, $attrs.class]"
>
<slot :link="link">
{{ link.name }}
</slot>
</a>
</router-link>
</template>
<script setup>
const props = defineProps(['link', 'active', 'inactive'])
</script>

View File

@ -1,17 +0,0 @@
<template>
<NavLink
v-for="link in links"
:key="link.name"
:class="$attrs.class"
v-bind="{ link, active, inactive }"
>
<slot :link="link">
{{ link.name }}
</slot>
</NavLink>
</template>
<script setup>
import NavLink from '@/components/NavLink.vue'
const props = defineProps(['links', 'active', 'inactive'])
</script>

View File

@ -0,0 +1,57 @@
<template>
<div
class="flex items-center rounded text-gray-800 cursor-pointer transition-all duration-300 ease-in-out"
:class="isActive ? 'bg-white shadow-sm' : 'hover:bg-gray-100'"
@click="handleClick"
>
<div class="flex items-center p-1">
<component :is="isCollapsed ? Tooltip : 'div'" :text="label" placement="right">
<slot name="icon">
<span class="grid h-5 w-6 place-items-center flex-shrink-0">
<component :is="icon" class="h-4.5 w-4.5 text-gray-700" />
</span>
</slot>
</component>
<span
class="flex-shrink-0 text-base duration-300 ease-in-out"
:class="isCollapsed ? 'opacity-0 ml-0' : 'opacity-100 ml-2'"
>
{{ label }}
</span>
</div>
</div>
</template>
<script setup>
import { Tooltip } from 'frappe-ui'
import { computed } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter()
const props = defineProps({
icon: {
type: Object,
},
label: {
type: String,
default: '',
},
to: {
type: String,
default: '',
},
isCollapsed: {
type: Boolean,
default: false,
},
})
function handleClick() {
router.push({ name: props.to })
}
let isActive = computed(() => {
return router.currentRoute.value.name === props.to
})
</script>

View File

@ -2,17 +2,21 @@
<Dropdown :options="userDropdownOptions">
<template v-slot="{ open }">
<button
class="flex w-full items-center space-x-2 rounded-md p-2 text-left"
class="flex w-full items-center rounded-md px-1 py-2 text-left"
:class="open ? 'bg-gray-300' : 'hover:bg-gray-200'"
v-if="user"
>
<UserAvatar :user="user.name" size="md" />
<span class="hidden text-base font-medium text-gray-900 sm:inline">
<UserAvatar class="flex-shrink-0" :user="user.name" size="md" />
<span
class="hidden text-base font-medium text-gray-900 sm:inline duration-300 ease-in-out"
:class="isCollapsed ? 'opacity-0 ml-0' : 'opacity-100 ml-2'"
>
{{ user.full_name }}
</span>
<FeatherIcon
name="chevron-down"
class="h-4 w-4 sm:inline"
class="h-4 w-4 sm:inline duration-300 ease-in-out"
:class="isCollapsed ? 'opacity-0 ml-0' : 'opacity-100 ml-2'"
aria-hidden="true"
/>
</button>
@ -27,6 +31,13 @@ import { usersStore } from '@/stores/users'
import { Dropdown, FeatherIcon } from 'frappe-ui'
import { computed } from 'vue'
const props = defineProps({
isCollapsed: {
type: Boolean,
default: false,
},
})
const { logout } = sessionStore()
const { getUser } = usersStore()