@dolanske/vui 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dolanske/vui",
3
3
  "type": "module",
4
- "version": "1.1.4",
4
+ "version": "1.2.0",
5
5
  "private": false,
6
6
  "description": "Brother in Christ there's a new UI library",
7
7
  "author": "dolanske",
@@ -14,7 +14,9 @@
14
14
  "keywords": [
15
15
  "vue",
16
16
  "vue3",
17
- "component"
17
+ "component",
18
+ "component library",
19
+ "vue3 components"
18
20
  ],
19
21
  "exports": {
20
22
  ".": {
@@ -49,25 +51,25 @@
49
51
  },
50
52
  "dependencies": {
51
53
  "@floating-ui/vue": "^1.1.6",
52
- "@types/node": "^22.14.1",
54
+ "@types/node": "^22.15.14",
53
55
  "@vuepic/vue-datepicker": "^11.0.2",
54
56
  "@vueuse/core": "^13.1.0",
55
- "sass": "^1.86.3",
57
+ "sass": "^1.87.0",
56
58
  "vaul-vue": "^0.4.1",
57
59
  "vite-plugin-dts": "^4.5.3",
58
60
  "vue": "^3.5.13"
59
61
  },
60
62
  "devDependencies": {
61
- "@antfu/eslint-config": "^4.12.0",
62
- "@iconify/vue": "^4.3.0",
63
+ "@antfu/eslint-config": "^4.13.0",
64
+ "@iconify/vue": "^5.0.0",
63
65
  "@vitejs/plugin-vue": "^5.2.3",
64
66
  "@vue/test-utils": "^2.4.6",
65
- "eslint": "^9.25.0",
67
+ "eslint": "^9.26.0",
66
68
  "eslint-plugin-format": "^1.0.1",
67
69
  "jsdom": "^26.1.0",
68
70
  "typescript": "^5.8.3",
69
- "vite": "^6.3.2",
70
- "vitest": "^3.1.1",
71
- "vue-tsc": "^2.2.8"
71
+ "vite": "^6.3.5",
72
+ "vitest": "^3.1.3",
73
+ "vue-tsc": "^2.2.10"
72
74
  }
73
75
  }
@@ -1,8 +1,7 @@
1
1
  <script setup lang="ts">
2
- import type { VNode } from 'vue'
3
2
  import type { AccordionProps } from './Accordion.vue'
4
- import type Accordion from './Accordion.vue'
5
- import { useTemplateRef } from 'vue'
3
+ import { useId } from 'vue'
4
+ import { enforceSlotType, useFlattenedSlot } from '../../shared/slots'
6
5
  // Renderless component which is used to house multiple accordions which can be triggered together in some way
7
6
 
8
7
  interface Props {
@@ -14,30 +13,37 @@ interface Props {
14
13
 
15
14
  const props = defineProps<Props>()
16
15
 
17
- const slots = defineSlots<{
18
- default: () => Array<VNode & { props: AccordionProps }>
19
- }>()
16
+ const slots = defineSlots()
20
17
 
21
- const accordionRefs = useTemplateRef<InstanceType<typeof Accordion>[]>('accordion')
18
+ // Since accordions do not have a child parent, we need to group them by a
19
+ // common id
20
+ const id = useId()
21
+
22
+ const flattened = useFlattenedSlot<AccordionProps>(slots.default)
22
23
 
23
24
  function handleAccordionOpen(newIndex: number) {
24
- if (!accordionRefs.value || !props.single)
25
+ if (!props.single)
25
26
  return
26
27
 
27
- accordionRefs.value.forEach((item, index) => {
28
+ const grouped = document.querySelectorAll(`[data-accordion-group-id=${id}]`)
29
+
30
+ grouped.forEach((item, index) => {
28
31
  if (index !== newIndex) {
29
- item.close()
32
+ // @ts-expect-error We do a little accessin'
33
+ item.__vnode.ctx.exposed.close()
30
34
  }
31
35
  })
32
36
  }
37
+
38
+ enforceSlotType(flattened, 'Accordion')
33
39
  </script>
34
40
 
35
41
  <template>
36
42
  <component
37
43
  :is="item"
38
- v-for="(item, index) of slots.default()"
39
- ref="accordion"
44
+ v-for="(item, index) of flattened"
40
45
  :key="item"
46
+ :data-accordion-group-id="id"
41
47
  @open="handleAccordionOpen(index)"
42
48
  />
43
49
  </template>
@@ -1,7 +1,6 @@
1
1
  <script setup lang='ts'>
2
- import type { VNode } from 'vue'
3
- import type { BreadcrumbItemProps } from './BreadcrumbItem.vue'
4
2
  import { Icon } from '@iconify/vue'
3
+ import { enforceSlotType, useFlattenedSlot } from '../../shared/slots'
5
4
  import './breadcrumbs.scss'
6
5
 
7
6
  interface Props {
@@ -12,16 +11,16 @@ const {
12
11
  separator = 'ph:caret-right',
13
12
  } = defineProps<Props>()
14
13
 
15
- const slots = defineSlots<{
16
- default: () => Array<VNode & { props: BreadcrumbItemProps }>
17
- }>()
14
+ const slots = defineSlots()
15
+ const flattened = useFlattenedSlot(slots.default)
16
+ enforceSlotType(flattened, 'BreadcrumbItem')
18
17
  </script>
19
18
 
20
19
  <template>
21
20
  <ul class="vui-breadcrumbs">
22
- <template v-for="(vnode, index) of slots.default()" :key="vnode.props?.label || index">
21
+ <template v-for="(vnode, index) of flattened" :key="vnode.props?.label || index">
23
22
  <component :is="vnode" />
24
- <template v-if="index !== slots.default().length - 1">
23
+ <template v-if="index !== flattened.length - 1">
25
24
  <Icon v-if="separator.length > 1 && separator.includes(':')" class="vui-breadcrumb-custom-separator" :icon="separator" />
26
25
  <span v-else class="vui-breadcrumb-custom-separator">{{ separator }}</span>
27
26
  </template>
@@ -95,6 +95,7 @@
95
95
  opacity: 0;
96
96
  position: absolute;
97
97
  pointer-events: none;
98
+ --spinner-color: var(--color-text);
98
99
  }
99
100
 
100
101
  // Variants
@@ -166,6 +167,10 @@
166
167
  color: var(--color-text-invert);
167
168
  background-color: var(--color-button-fill);
168
169
 
170
+ .vui-spinner {
171
+ --spinner-color: var(--color-text-invert);
172
+ }
173
+
169
174
  svg,
170
175
  path {
171
176
  color: var(--color-text-invert);
@@ -30,7 +30,7 @@
30
30
  left: 50%;
31
31
  transform: translate(-50%, -50%);
32
32
 
33
- & > *:first-child {
33
+ & > *:first-child {
34
34
  outline: 3px solid var(--color-bg);
35
35
  }
36
36
  }
@@ -113,7 +113,6 @@ onMounted(() => {
113
113
  :placement
114
114
  :style="{
115
115
  minWidth: expand ? w : mW,
116
- width: w,
117
116
  maxHeight: formatUnitValue(maxHeight),
118
117
  }"
119
118
  >
@@ -1,6 +1,6 @@
1
1
  <script setup lang='ts'>
2
- import type Kbd from './Kbd.vue'
3
2
  import { useMagicKeys, whenever } from '@vueuse/core'
3
+ import { enforceSlotType, useFlattenedSlot } from '../../shared/slots'
4
4
 
5
5
  /**
6
6
  * Can be used to wrap multiple <Kbd /> elements and triggers the callback when
@@ -11,13 +11,14 @@ const emits = defineEmits<{
11
11
  trigger: []
12
12
  }>()
13
13
 
14
- const slots = defineSlots<{
15
- default: () => Array<typeof Kbd>
16
- }>()
14
+ const slots = defineSlots()
17
15
  const keys = useMagicKeys()
18
16
 
17
+ const flattened = useFlattenedSlot(slots.default)
18
+ enforceSlotType(flattened, 'Kbd')
19
+
19
20
  whenever(
20
- keys[slots.default().map(vnode => vnode.props.keys).join('+')],
21
+ keys[flattened.value.map(vnode => vnode.props.keys).join('+')],
21
22
  () => emits('trigger'),
22
23
  )
23
24
  </script>
@@ -1,7 +1,6 @@
1
1
  <script setup lang='ts'>
2
2
  import type { FlexProps } from '../Flex/Flex.vue'
3
- import type Radio from './Radio.vue'
4
- import { watchEffect } from 'vue'
3
+ import { enforceSlotType, useFlattenedSlot } from '../../shared/slots'
5
4
  import Flex from '../Flex/Flex.vue'
6
5
 
7
6
  interface Props extends FlexProps {
@@ -13,24 +12,19 @@ const {
13
12
  ...flexProps
14
13
  } = defineProps<Props>()
15
14
 
16
- const slots = defineSlots<{
17
- default: () => Array<typeof Radio>
18
- }>()
15
+ const slots = defineSlots()
19
16
 
20
17
  const checked = defineModel()
21
18
 
22
- watchEffect(() => {
23
- if (slots.default().some(s => s.type.__name !== 'Radio')) {
24
- console.error('You can only pass `<Radio />` components as children.')
25
- }
26
- })
19
+ const flattened = useFlattenedSlot(slots.default)
20
+ enforceSlotType(flattened, 'Radio')
27
21
  </script>
28
22
 
29
23
  <template>
30
24
  <Flex v-bind="flexProps">
31
25
  <Component
32
26
  :is="vnode"
33
- v-for="vnode of slots.default()"
27
+ v-for="vnode of flattened"
34
28
  :key="vnode.props.value"
35
29
  v-bind="vnode.props"
36
30
  v-model="checked"
@@ -48,7 +48,7 @@ const {
48
48
  } = defineProps<Props>()
49
49
 
50
50
  const selected = defineModel<SelectOption[] | undefined>()
51
- const trigger = useTemplateRef('trigger')
51
+ const triggerRef = useTemplateRef('trigger')
52
52
 
53
53
  //
54
54
  function setValue(option: SelectOption) {
@@ -128,7 +128,7 @@ const id = useId()
128
128
 
129
129
  <template>
130
130
  <div class="vui-input-container vui-select" :class="{ expand, required, readonly, disabled, 'has-errors': errors.length > 0 }">
131
- <Dropdown ref="dropdown" :expand @close="trigger?.focus({ preventScroll: true })">
131
+ <Dropdown ref="dropdown" :expand @close="triggerRef?.focus({ preventScroll: true })">
132
132
  <template #trigger="{ toggle, isOpen }">
133
133
  <div class="vui-input vui-select-trigger-content">
134
134
  <label v-if="label" :for="id">{{ label }}</label>
@@ -1,6 +1,7 @@
1
1
  .vui-input-container {
2
2
  &.vui-select {
3
3
  width: auto;
4
+ min-width: 96px;
4
5
 
5
6
  &.expand {
6
7
  .vui-dropdown-trigger-wrap,
@@ -1,6 +1,6 @@
1
1
  <script setup lang='ts'>
2
2
  import { useCssVar, useMouseInElement, useTimeoutFn, watchThrottled } from '@vueuse/core'
3
- import { computed, onMounted, useSlots, useTemplateRef } from 'vue'
3
+ import { computed, onBeforeMount, useSlots, useTemplateRef } from 'vue'
4
4
  import { isNil } from '../../shared/helpers'
5
5
  import './sidebar.scss'
6
6
 
@@ -26,12 +26,12 @@ interface Props {
26
26
  floaty?: boolean
27
27
  }
28
28
 
29
- const sidebar = useTemplateRef('sidebar')
29
+ const sidebarRef = useTemplateRef('sidebar')
30
30
  const open = defineModel<boolean>({
31
31
  default: true,
32
32
  })
33
33
  const slots = useSlots()
34
- const offset = useCssVar('--vui-sidebar-float-offset', sidebar, {
34
+ const offset = useCssVar('--vui-sidebar-float-offset', sidebarRef, {
35
35
  initialValue: '8px',
36
36
  })
37
37
 
@@ -61,10 +61,10 @@ const { start, stop, isPending } = useTimeoutFn(() => {
61
61
 
62
62
  const APPEAR_OFFSET = 32
63
63
 
64
- const wrap = useTemplateRef('wrap')
65
- const { elementX } = useMouseInElement(wrap)
64
+ const wrapEl = useTemplateRef('wrap')
65
+ const { elementX } = useMouseInElement(wrapEl)
66
66
 
67
- onMounted(() => {
67
+ onBeforeMount(() => {
68
68
  if (props.appear && open.value) {
69
69
  open.value = false
70
70
  }
@@ -92,6 +92,7 @@ watchThrottled(elementX, (pos) => {
92
92
  }
93
93
  }, {
94
94
  throttle: 100,
95
+ immediate: true,
95
96
  })
96
97
  </script>
97
98
 
@@ -3,23 +3,23 @@ import { Icon } from '@iconify/vue'
3
3
 
4
4
  export interface TabProps {
5
5
  disabled?: boolean
6
- label?: string
6
+ value: string
7
7
  icon?: string
8
8
  }
9
+
9
10
  const props = defineProps<TabProps>()
10
11
  </script>
11
12
 
12
13
  <template>
13
14
  <button
14
15
  class="vui-tab"
15
- :data-tab-id="label"
16
16
  :class="{ disabled: props.disabled }"
17
17
  role="tab"
18
- :name="label"
18
+ :name="value"
19
19
  >
20
20
  <slot>
21
21
  <Icon v-if="props.icon" :icon="props.icon" />
22
- {{ props.label }}
22
+ {{ props.value }}
23
23
  </slot>
24
24
  </button>
25
25
  </template>
@@ -1,8 +1,8 @@
1
1
  <script setup lang="ts">
2
- import type { VNode } from 'vue'
3
2
  import type { TabProps } from './Tab.vue'
4
3
  import { useResizeObserver } from '@vueuse/core'
5
4
  import { onMounted, useTemplateRef, watch } from 'vue'
5
+ import { enforceSlotType, useFlattenedSlot } from '../../shared/slots'
6
6
  import './tabs.scss'
7
7
 
8
8
  interface Props {
@@ -17,11 +17,7 @@ const {
17
17
  variant = 'default',
18
18
  } = defineProps<Props>()
19
19
 
20
- const slots = defineSlots<{
21
- default: () => Array<VNode & { props: TabProps }>
22
- start: unknown
23
- end: unknown
24
- }>()
20
+ const slots = defineSlots()
25
21
 
26
22
  const active = defineModel()
27
23
 
@@ -56,6 +52,10 @@ onMounted(() => {
56
52
  },
57
53
  )
58
54
  })
55
+
56
+ const flattened = useFlattenedSlot<TabProps>(slots.default)
57
+
58
+ enforceSlotType(flattened, 'Tab')
59
59
  </script>
60
60
 
61
61
  <template>
@@ -71,14 +71,14 @@ onMounted(() => {
71
71
  ]"
72
72
  >
73
73
  <slot name="start" />
74
- <Component
75
- :is="vnode"
76
- v-for="vnode of slots.default()"
77
- :key="vnode.props.label"
78
- :class="{ active: vnode.props.label === active }"
79
- @click="active = vnode.props.label"
80
- />
81
- <template v-if="slots.end">
74
+ <template v-for="vnode of flattened" :key="vnode.props.value">
75
+ <Component
76
+ :is="vnode"
77
+ :class="{ active: vnode.props.value === active }"
78
+ @click="active = vnode.props.value"
79
+ />
80
+ </template>
81
+ <template v-if="$slots.end">
82
82
  <div v-if="!!!expand" class="flex-1" />
83
83
  <slot name="end" />
84
84
  </template>
@@ -16,8 +16,8 @@
16
16
  .vui-tab-underline {
17
17
  border-bottom: none;
18
18
  background-color: var(--color-bg-lowered);
19
- top: 4px;
20
- bottom: 4px;
19
+ top: 3px;
20
+ bottom: 3px;
21
21
  z-index: -1;
22
22
  border-radius: var(--border-radius-m);
23
23
  }
@@ -1,7 +1,14 @@
1
1
  <script setup lang='ts'>
2
+ import { ref } from 'vue'
2
3
  import Accordion from '../components/Accordion/Accordion.vue'
3
4
  import AccordionGroup from '../components/Accordion/AccordionGroup.vue'
4
5
  import Grid from '../components/Grid/Grid.vue'
6
+
7
+ const dynamicAccordions = ref([
8
+ 'First',
9
+ 'Second',
10
+ 'Third',
11
+ ])
5
12
  </script>
6
13
 
7
14
  <template>
@@ -16,18 +23,15 @@ import Grid from '../components/Grid/Grid.vue'
16
23
  <Accordion label="Open details" class="mb-xl">
17
24
  <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Excepturi nostrum aspernatur nam earum vitae deleniti, odio atque esse sequi, in harum! Sint dolorum quis excepturi odio eum aspernatur aliquid harum.</p>
18
25
  </Accordion>
26
+ <Accordion label="Open Two" class="mb-xl">
27
+ <p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Excepturi nostrum aspernatur nam earum vitae deleniti, odio atque esse sequi, in harum! Sint dolorum quis excepturi odio eum aspernatur aliquid harum.</p>
28
+ </Accordion>
19
29
 
20
30
  <div class="mb-xl" />
21
31
 
22
32
  <strong class="block mb-s">Group</strong>
23
- <AccordionGroup single>
24
- <Accordion label="First">
25
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nostrum aliquam ad dicta nesciunt exercitationem? Quas vitae suscipit aliquam numquam incidunt corporis ullam, nihil dolores perferendis ipsa velit tempora accusantium cupiditate.
26
- </Accordion>
27
- <Accordion label="Second">
28
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nostrum aliquam ad dicta nesciunt exercitationem? Quas vitae suscipit aliquam numquam incidunt corporis ullam, nihil dolores perferendis ipsa velit tempora accusantium cupiditate.
29
- </Accordion>
30
- <Accordion label="Third">
33
+ <AccordionGroup>
34
+ <Accordion v-for="item in dynamicAccordions" :key="item" :label="item">
31
35
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Nostrum aliquam ad dicta nesciunt exercitationem? Quas vitae suscipit aliquam numquam incidunt corporis ullam, nihil dolores perferendis ipsa velit tempora accusantium cupiditate.
32
36
  </Accordion>
33
37
  </AccordionGroup>
@@ -42,13 +46,7 @@ import Grid from '../components/Grid/Grid.vue'
42
46
 
43
47
  <strong class="block mb-s">Card group</strong>
44
48
  <AccordionGroup single>
45
- <Accordion card label="First" class="mb-xs">
46
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nostrum aliquam ad dicta nesciunt exercitationem? Quas vitae suscipit aliquam numquam incidunt corporis ullam, nihil dolores perferendis ipsa velit tempora accusantium cupiditate.
47
- </Accordion>
48
- <Accordion card label="Second" class="mb-xs">
49
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nostrum aliquam ad dicta nesciunt exercitationem? Quas vitae suscipit aliquam numquam incidunt corporis ullam, nihil dolores perferendis ipsa velit tempora accusantium cupiditate.
50
- </Accordion>
51
- <Accordion card label="Third" class="mb-xs">
49
+ <Accordion v-for="item in dynamicAccordions" :key="item" :label="item" card class="mb-xs">
52
50
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Nostrum aliquam ad dicta nesciunt exercitationem? Quas vitae suscipit aliquam numquam incidunt corporis ullam, nihil dolores perferendis ipsa velit tempora accusantium cupiditate.
53
51
  </Accordion>
54
52
  </AccordionGroup>
@@ -75,7 +75,7 @@ const variants = ['gray', 'fill', 'danger', 'success', 'link', 'accent'] as cons
75
75
  </td>
76
76
  </tr>
77
77
  <tr>
78
- <th>Squar + icon</th>
78
+ <th>Square + icon</th>
79
79
  <td>
80
80
  <Flex gap="s">
81
81
  <Button v-for="btn in variants" :key="btn" :variant="btn" square icon="ph:info" />
@@ -83,7 +83,7 @@ const variants = ['gray', 'fill', 'danger', 'success', 'link', 'accent'] as cons
83
83
  </td>
84
84
  </tr>
85
85
  <tr>
86
- <th>Squar + icon + small</th>
86
+ <th>Square + icon + small</th>
87
87
  <td>
88
88
  <Flex gap="s">
89
89
  <Button v-for="btn in variants" :key="btn" :variant="btn" square icon="ph:info" size="s" />
@@ -91,13 +91,21 @@ const variants = ['gray', 'fill', 'danger', 'success', 'link', 'accent'] as cons
91
91
  </td>
92
92
  </tr>
93
93
  <tr>
94
- <th>Squar + icon + large</th>
94
+ <th>Square + icon + large</th>
95
95
  <td>
96
96
  <Flex gap="s">
97
97
  <Button v-for="btn in variants" :key="btn" :variant="btn" square icon="ph:info" size="l" />
98
98
  </Flex>
99
99
  </td>
100
100
  </tr>
101
+ <tr>
102
+ <th>Loading</th>
103
+ <td>
104
+ <Flex gap="s">
105
+ <Button v-for="btn in variants" :key="btn" :variant="btn" loading size="l" />
106
+ </Flex>
107
+ </td>
108
+ </tr>
101
109
  <tr>
102
110
  <th>Icon + text</th>
103
111
  <td>
@@ -59,8 +59,8 @@ const cols = ref(3)
59
59
  <th>Justify props</th>
60
60
  <td>
61
61
  <Flex>
62
- <code>justify-start</code><code>justify-end</code><code>justify-center</code>
63
- <code>space-between</code><code>space-around</code><code>space-evenly</code>
62
+ <code>x-start</code><code>x-end</code><code>x-center</code>
63
+ <code>x-between</code><code>x-around</code><code>x-evenly</code>
64
64
  </Flex>
65
65
  </td>
66
66
  </tr>
@@ -68,8 +68,8 @@ const cols = ref(3)
68
68
  <th>Align props</th>
69
69
  <td>
70
70
  <Flex>
71
- <code>align-start</code><code>align-end</code><code>y-center</code>
72
- <code>align-baseline</code>
71
+ <code>y-start</code><code>y-end</code><code>y-center</code>
72
+ <code>y-baseline</code>
73
73
  </Flex>
74
74
  </td>
75
75
  </tr>
@@ -184,8 +184,10 @@ const selected2 = ref([])
184
184
  </option>
185
185
  </select>
186
186
  </Grid>
187
+ <div class="inline-block">
188
+ <Select :options="longOptions" label="Short" show-clear />
189
+ </div>
187
190
  <Divider :size="48" />
188
-
189
191
  <h6 class="mb-l">
190
192
  OTP
191
193
  </h6>
@@ -4,7 +4,7 @@ import Button from '../components/Button/Button.vue'
4
4
  import Flex from '../components/Flex/Flex.vue'
5
5
  import Popout from '../components/Popout/Popout.vue'
6
6
 
7
- const anch = useTemplateRef('anch')
7
+ const anchRef = useTemplateRef('anch')
8
8
  const open = ref(false)
9
9
  </script>
10
10
 
@@ -26,7 +26,7 @@ const open = ref(false)
26
26
  This popout has offset of <code>32</code> and its placement is <code>bottom-start</code>. It also has an attached event to <code>clickOutside</code> which is fired when user clicks outside of the popout. In that case, we manually close it.
27
27
  </p>
28
28
  </Flex>
29
- <Popout v-if="open" :anchor="anch" class="test-popout" :offset="32" placement="bottom-start" @click-outside="open = false">
29
+ <Popout v-if="open" :anchor="anchRef" class="test-popout" :offset="32" placement="bottom-start" @click-outside="open = false">
30
30
  <h3>Popout content</h3>
31
31
  <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Dolorem facere eligendi ex, alias itaque molestiae, vero animi, vitae vel fuga corporis aut consectetur temporibus ipsum placeat dolores perferendis. Deleniti, et!</p>
32
32
  </Popout>
@@ -1,4 +1,5 @@
1
1
  <script setup lang='ts'>
2
+ import { useStorage } from '@vueuse/core'
2
3
  import { ref } from 'vue'
3
4
  import Avatar from '../components/Avatar/Avatar.vue'
4
5
  import Button from '../components/Button/Button.vue'
@@ -6,8 +7,11 @@ import DropdownItem from '../components/Dropdown/DropdownItem.vue'
6
7
  import Flex from '../components/Flex/Flex.vue'
7
8
  import Grid from '../components/Grid/Grid.vue'
8
9
  import Sidebar from '../components/Sidebar/Sidebar.vue'
10
+ import Switch from '../components/Switch/Switch.vue'
11
+
12
+ const s1 = useStorage('sidebar-open', false)
13
+ const s1Mini = useStorage('sidebar-mini', true)
9
14
 
10
- const s1 = ref(true)
11
15
  const s2 = ref(true)
12
16
  const s3 = ref(true)
13
17
  </script>
@@ -38,7 +42,6 @@ const s3 = ref(true)
38
42
  <DropdownItem icon="ph:phone">
39
43
  Contact
40
44
  </DropdownItem>
41
-
42
45
  <template #footer>
43
46
  <Flex y-center>
44
47
  <Avatar size="m" />
@@ -107,9 +110,12 @@ const s3 = ref(true)
107
110
  </div>
108
111
 
109
112
  <div>
110
- <span class="mb-m block">Mini </span>
113
+ <Flex y-center x-star class="mb-m">
114
+ <span class="block">Mini</span>
115
+ <Switch v-model="s1Mini" />
116
+ </Flex>
111
117
  <div class="vui-sidebar-layout" :style="{ height: '512px' }">
112
- <Sidebar v-model="s2" mini>
118
+ <Sidebar v-model="s2" :mini="s1Mini">
113
119
  <template #header>
114
120
  <Flex y-center>
115
121
  <img src="https://dolansky.dev/backgrounds/star.png" class="sidebar-logo" width="40" alt="">