Sidebar.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. <script setup lang="ts">
  2. import type { SidebarProps } from "."
  3. import { cn } from '@/Packages/Shadcn/Lib/utils'
  4. import { Sheet, SheetContent } from '@/Packages/Shadcn/Components/ui/sheet'
  5. import SheetDescription from '@/Packages/Shadcn/Components/ui/sheet/SheetDescription.vue'
  6. import SheetHeader from '@/Packages/Shadcn/Components/ui/sheet/SheetHeader.vue'
  7. import SheetTitle from '@/Packages/Shadcn/Components/ui/sheet/SheetTitle.vue'
  8. import { SIDEBAR_WIDTH_MOBILE, useSidebar } from "./utils"
  9. defineOptions({
  10. inheritAttrs: false,
  11. })
  12. const props = withDefaults(defineProps<SidebarProps>(), {
  13. side: "left",
  14. variant: "sidebar",
  15. collapsible: "offcanvas",
  16. })
  17. const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
  18. </script>
  19. <template>
  20. <div
  21. v-if="collapsible === 'none'"
  22. data-slot="sidebar"
  23. :class="cn('bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col', props.class)"
  24. v-bind="$attrs"
  25. >
  26. <slot />
  27. </div>
  28. <Sheet v-else-if="isMobile" :open="openMobile" v-bind="$attrs" @update:open="setOpenMobile">
  29. <SheetContent
  30. data-sidebar="sidebar"
  31. data-slot="sidebar"
  32. data-mobile="true"
  33. :side="side"
  34. class="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
  35. :style="{
  36. '--sidebar-width': SIDEBAR_WIDTH_MOBILE,
  37. }"
  38. >
  39. <SheetHeader class="sr-only">
  40. <SheetTitle>Sidebar</SheetTitle>
  41. <SheetDescription>Displays the mobile sidebar.</SheetDescription>
  42. </SheetHeader>
  43. <div class="flex h-full w-full flex-col">
  44. <slot />
  45. </div>
  46. </SheetContent>
  47. </Sheet>
  48. <div
  49. v-else
  50. class="group peer text-sidebar-foreground hidden md:block"
  51. data-slot="sidebar"
  52. :data-state="state"
  53. :data-collapsible="state === 'collapsed' ? collapsible : ''"
  54. :data-variant="variant"
  55. :data-side="side"
  56. >
  57. <!-- This is what handles the sidebar gap on desktop -->
  58. <div
  59. :class="cn(
  60. 'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',
  61. 'group-data-[collapsible=offcanvas]:w-0',
  62. 'group-data-[side=right]:rotate-180',
  63. variant === 'floating' || variant === 'inset'
  64. ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
  65. : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
  66. )"
  67. />
  68. <div
  69. :class="cn(
  70. 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',
  71. side === 'left'
  72. ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
  73. : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
  74. // Adjust the padding for floating and inset variants.
  75. variant === 'floating' || variant === 'inset'
  76. ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
  77. : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
  78. props.class,
  79. )"
  80. v-bind="$attrs"
  81. >
  82. <div
  83. data-sidebar="sidebar"
  84. class="bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow-sm"
  85. >
  86. <slot />
  87. </div>
  88. </div>
  89. </div>
  90. </template>