# All files / js/components/ui/sidebar SidebarProvider.vue

0% Statements 0/18
0% Branches 0/11
0% Functions 0/6
0% Lines 0/17

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82

     <script setup lang="ts">
    import { cn } from '@/lib/utils'
    import { useEventListener, useMediaQuery, useVModel } from '@vueuse/core'
    import { TooltipProvider } from 'reka-ui'
    import { computed, type HTMLAttributes, type Ref, ref } from 'vue'
    import { provideSidebarContext, SIDEBAR_COOKIE_MAX_AGE, SIDEBAR_COOKIE_NAME, SIDEBAR_KEYBOARD_SHORTCUT, SIDEBAR_WIDTH, SIDEBAR_WIDTH_ICON } from './utils'

    const props = withDefaults(defineProps<{
      defaultOpen?: boolean
      open?: boolean
      class?: HTMLAttributes['class']
    }>(), {
      defaultOpen: true,
      open: undefined,
    })

    const emits = defineEmits<{
      'update:open': [open: boolean]
    }>()

    const isMobile = useMediaQuery('(max-width: 768px)')
    const openMobile = ref(false)

    const open = useVModel(props, 'open', emits, {
      defaultValue: props.defaultOpen ?? false,
      passive: (props.open === undefined) as false,
    }) as Ref<boolean>

    function setOpen(value: boolean) {
      open.value = value // emits('update:open', value)

      // This sets the cookie to keep the sidebar state.
      document.cookie = `${SIDEBAR_COOKIE_NAME}=${open.value}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
    }

    function setOpenMobile(value: boolean) {
      openMobile.value = value
    }

    // Helper to toggle the sidebar.
    function toggleSidebar() {
      return isMobile.value ? setOpenMobile(!openMobile.value) : setOpen(!open.value)
    }

    useEventListener('keydown', (event: KeyboardEvent) => {
      if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
        event.preventDefault()
        toggleSidebar()
      }
    })

    // We add a state so that we can do data-state="expanded" or "collapsed".
    // This makes it easier to style the sidebar with Tailwind classes.
    const state = computed(() => open.value ? 'expanded' : 'collapsed')

    provideSidebarContext({
      state,
      open,
      setOpen,
      isMobile,
      openMobile,
      setOpenMobile,
      toggleSidebar,
    })
    </script>

    <template>
      <TooltipProvider :delay-duration="0">
        <div
          data-slot="sidebar-wrapper"
          :style="{
            '--sidebar-width': SIDEBAR_WIDTH,
            '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
          }"
          :class="cn('group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full', props.class)"
          v-bind="$attrs"
        >
          <slot />
        </div>
      </TooltipProvider>
    </template>