@dolanske/vui 0.3.3 → 0.4.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": "0.3.3",
4
+ "version": "0.4.0",
5
5
  "private": false,
6
6
  "description": "Brother in Christ there's a new UI library ",
7
7
  "author": "dolanske",
package/src/App.vue CHANGED
@@ -1,124 +1,156 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue'
3
3
  import Avatar from './components/Avatar/Avatar.vue'
4
+ import Button from './components/Button/Button.vue'
5
+
4
6
  import Divider from './components/Divider/Divider.vue'
7
+ import Dropdown from './components/Dropdown/Dropdown.vue'
8
+ import DropdownItem from './components/Dropdown/DropdownItem.vue'
5
9
  import Flex from './components/Flex/Flex.vue'
10
+ import Sidebar from './components/Sidebar/Sidebar.vue'
6
11
  import Tab from './components/Tabs/Tab.vue'
7
-
8
12
  import Tabs from './components/Tabs/Tabs.vue'
13
+
9
14
  import Tooltip from './components/Tooltip/Tooltip.vue'
10
15
 
11
16
  const tab = ref('components')
17
+ const sidebarOpen = ref(false)
12
18
  </script>
13
19
 
14
20
  <template>
15
- <main vaul-drawer-wrapper>
16
- <Tabs v-model="tab" expand>
17
- <Tab id="home" label="Home" icon="ph:house" />
18
- <Tab id="components" label="Components" />
19
- <Tab id="typography" label="Typography" />
20
- </Tabs>
21
- <div style="margin-bottom: 64px;" />
22
- <div v-if="tab === 'home'">
23
- home
24
- </div>
21
+ <div class="vui-sidebar-layout">
22
+ <Sidebar v-model="sidebarOpen" appear floaty>
23
+ <template #header>
24
+ <img class="p-xs" style="background:white;border-radius: 16px;width:40px" src="https://dolansky.dev/backgrounds/star.svg" alt="">
25
+ </template>
26
+ <DropdownItem icon="ph:house">
27
+ Home
28
+ </DropdownItem>
29
+ <DropdownItem icon="ph:signpost">
30
+ Routing
31
+ </DropdownItem>
32
+ <template #footer>
33
+ <Button size="l" expand>
34
+ Sign out
35
+ </Button>
36
+ </template>
37
+ </Sidebar>
38
+
39
+ <main vaul-drawer-wrapper>
40
+ <Button icon="ph:sidebar-simple-bold" square @click="sidebarOpen = !sidebarOpen" />
41
+ <Tabs v-model="tab" expand>
42
+ <Tab id="home" label="Home" icon="ph:house" />
43
+ <Tab id="components" label="Components" />
44
+ <Tab id="typography" label="Typography" />
45
+ </Tabs>
46
+ <div style="margin-bottom: 64px;" />
47
+ <div v-if="tab === 'home'">
48
+ home
49
+ </div>
50
+
51
+ <div v-if="tab === 'components'">
52
+ <h1 class="mb-xl">
53
+ Hii
54
+ <span class="counter text-color-accent">129</span>
55
+ </h1>
56
+ <p>I am down</p>
25
57
 
26
- <div v-if="tab === 'components'">
27
- <h1 class="mb-xl">
28
- Hii
29
- <span class="counter text-color-accent">129</span>
30
- </h1>
31
- <p>I am down</p>
58
+ <Flex>
59
+ <Avatar size="s" />
60
+ <Avatar size="m" />
61
+ <Avatar size="l" />
62
+ <Avatar :size="80" />
63
+ </Flex>
32
64
 
33
- <Flex>
34
- <Avatar size="s" />
35
- <Avatar size="m" />
36
- <Avatar size="l" />
37
- <Avatar :size="128" />
38
- </Flex>
65
+ <Divider />
39
66
 
40
- <Divider />
67
+ <Tooltip>
68
+ <span class="block mb-xl">Hello world</span>
69
+ <template #tooltip>
70
+ <p>
71
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro, animi! Nobis maxime neque cumque, in a amet voluptatibus tenetur dicta eos delectus illo soluta aliquam voluptatum nulla? In, incidunt asperiores?
72
+ </p>
73
+ </template>
74
+ </Tooltip>
41
75
 
42
- <Tooltip>
43
- <span cl>Hello world</span>
44
- <template #tooltip>
45
- <p>
46
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro, animi! Nobis maxime neque cumque, in a amet voluptatibus tenetur dicta eos delectus illo soluta aliquam voluptatum nulla? In, incidunt asperiores?
47
- </p>
48
- </template>
49
- </Tooltip>
50
- </div>
51
- <div v-else-if="tab === 'typography'" class="typeset" :style="{ maxWidth: '688px', margin: 'auto' }">
52
- <h1>The Joke Tax Chronicles</h1>
53
- <p>Once upon a time, in a far-off land, there <code>was a very lazy</code> king who spent all day lounging on his throne. One day, his advisors came to him with a problem: the kingdom was running out of money</p>
54
- <h2>The King's Plan</h2>
55
- <p>The king thought long and hard, and finally came up with <a href="#">a brilliant plan</a>: he would tax the jokes in the kingdom.</p>
56
- <blockquote>"After all," he said, "everyone enjoys a good joke, so it's only fair that they should pay for the privilege."</blockquote>
57
- <h3>The Joke Tax</h3>
58
- <p>The king's subjects were not amused. They grumbled and complained, but the king was firm:</p>
59
- <ul class="ul">
60
- <li>
61
- I am an item
62
- <ul>
63
- <li>1st level of puns: 5 gold coins</li>
64
- <li>2nd level of jokes: 10 gold coins</li>
65
- <li>
66
- 3rd level of one-liners : 20 gold coins
67
- <ul>
68
- <li>1st level of puns: 5 gold coins</li>
69
- <li>2nd level of jokes: 10 gold coins</li>
70
- <li>3rd level of one-liners : 20 gold coins</li>
71
- </ul>
72
- </li>
73
- </ul>
74
- </li>
75
- <li>2nd level of jokes: 10 gold coins</li>
76
- <li>3rd level of one-liners : 20 gold coins</li>
77
- </ul>
78
- <p>As a result, people stopped telling jokes, and the kingdom fell into a gloom. But there was one person who refused to let the king's foolishness get him down: a court jester named Jokester.</p>
76
+ <Dropdown>
77
+ <template #trigger="{ toggle }">
78
+ <Button aria-label="Dropdown menu trigger" square icon="ph:x" @click="toggle" />
79
+ </template>
80
+ <DropdownItem>Hiiii</DropdownItem>
81
+ </Dropdown>
82
+ </div>
83
+ <div v-else-if="tab === 'typography'" class="typeset" :style="{ maxWidth: '688px', margin: 'auto' }">
84
+ <h1>The Joke Tax Chronicles</h1>
85
+ <p>Once upon a time, in a far-off land, there <code>was a very lazy</code> king who spent all day lounging on his throne. One day, his advisors came to him with a problem: the kingdom was running out of money</p>
86
+ <h2>The King's Plan</h2>
87
+ <p>The king thought long and hard, and finally came up with <a href="#">a brilliant plan</a>: he would tax the jokes in the kingdom.</p>
88
+ <blockquote>"After all," he said, "everyone enjoys a good joke, so it's only fair that they should pay for the privilege."</blockquote>
89
+ <h3>The Joke Tax</h3>
90
+ <p>The king's subjects were not amused. They grumbled and complained, but the king was firm:</p>
91
+ <ul class="ul">
92
+ <li>
93
+ I am an item
94
+ <ul>
95
+ <li>1st level of puns: 5 gold coins</li>
96
+ <li>2nd level of jokes: 10 gold coins</li>
97
+ <li>
98
+ 3rd level of one-liners : 20 gold coins
99
+ <ul>
100
+ <li>1st level of puns: 5 gold coins</li>
101
+ <li>2nd level of jokes: 10 gold coins</li>
102
+ <li>3rd level of one-liners : 20 gold coins</li>
103
+ </ul>
104
+ </li>
105
+ </ul>
106
+ </li>
107
+ <li>2nd level of jokes: 10 gold coins</li>
108
+ <li>3rd level of one-liners : 20 gold coins</li>
109
+ </ul>
110
+ <p>As a result, people stopped telling jokes, and the kingdom fell into a gloom. But there was one person who refused to let the king's foolishness get him down: a court jester named Jokester.</p>
79
111
 
80
- <figure>
81
- <img src="https://i.imgur.com/6WQYrfN.jpeg" alt="">
82
- <figcaption>Woah look at these mountains</figcaption>
83
- </figure>
112
+ <figure>
113
+ <img src="https://i.imgur.com/6WQYrfN.jpeg" alt="">
114
+ <figcaption>Woah look at these mountains</figcaption>
115
+ </figure>
84
116
 
85
- <h3>Jokester's Revolt</h3>
86
- <p>Jokester began sneaking into the castle in the middle of the night and leaving jokes all over the place: under the king's pillow, in his soup, even in the royal toilet. The king was furious, but he couldn't seem to stop Jokester.</p>
87
- <hr>
88
- <p>And then, one day, the people of the kingdom discovered that the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started laughing, they couldn't stop.</p>
89
- <ol>
90
- <li>But the kind was stupid</li>
91
- <li>He was ratioed 5 times</li>
92
- </ol>
93
- <h3>The People's Rebellion</h3>
94
- <p>The people of the kingdom, feeling uplifted by the laughter, started to tell jokes and puns again, and soon the entire kingdom was in on the joke.</p>
117
+ <h3>Jokester's Revolt</h3>
118
+ <p>Jokester began sneaking into the castle in the middle of the night and leaving jokes all over the place: under the king's pillow, in his soup, even in the royal toilet. The king was furious, but he couldn't seem to stop Jokester.</p>
119
+ <hr>
120
+ <p>And then, one day, the people of the kingdom discovered that the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started laughing, they couldn't stop.</p>
121
+ <ol>
122
+ <li>But the kind was stupid</li>
123
+ <li>He was ratioed 5 times</li>
124
+ </ol>
125
+ <h3>The People's Rebellion</h3>
126
+ <p>The people of the kingdom, feeling uplifted by the laughter, started to tell jokes and puns again, and soon the entire kingdom was in on the joke.</p>
95
127
 
96
- <table>
97
- <thead>
98
- <tr>
99
- <th>King's Treasury</th>
100
- <th>People's happiness</th>
101
- </tr>
102
- </thead>
103
- <tbody>
104
- <tr>
105
- <td>Empty</td>
106
- <td>And then, one day, the people of the kingdom discovered that the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started laughing, they couldn't stop.</td>
107
- </tr>
108
- <tr>
109
- <td>Modest</td>
110
- <td>Satisfied</td>
111
- </tr>
112
- <tr>
113
- <td>Full</td>
114
- <td>Ecstatic</td>
115
- </tr>
116
- </tbody>
117
- </table>
118
- <p>The king, seeing how much happier his subjects were, realized the error of his ways and repealed the joke tax. Jokester was declared a hero, and the kingdom lived happily ever after.</p>
119
- <p>The moral of the story is: never <code>underestimate</code> the power of a good laugh and always be careful of bad ideas.</p>
128
+ <table>
129
+ <thead>
130
+ <tr>
131
+ <th>King's Treasury</th>
132
+ <th>People's happiness</th>
133
+ </tr>
134
+ </thead>
135
+ <tbody>
136
+ <tr>
137
+ <td>Empty</td>
138
+ <td>And then, one day, the people of the kingdom discovered that the jokes left by Jokester were so funny that they couldn't help but laugh. And once they started laughing, they couldn't stop.</td>
139
+ </tr>
140
+ <tr>
141
+ <td>Modest</td>
142
+ <td>Satisfied</td>
143
+ </tr>
144
+ <tr>
145
+ <td>Full</td>
146
+ <td>Ecstatic</td>
147
+ </tr>
148
+ </tbody>
149
+ </table>
150
+ <p>The king, seeing how much happier his subjects were, realized the error of his ways and repealed the joke tax. Jokester was declared a hero, and the kingdom lived happily ever after.</p>
151
+ <p>The moral of the story is: never <code>underestimate</code> the power of a good laugh and always be careful of bad ideas.</p>
120
152
 
121
- <pre data-lang="JSON">
153
+ <pre data-lang="JSON">
122
154
  {
123
155
  "type": "Feature",
124
156
  "properties": {
@@ -160,6 +192,7 @@ const tab = ref('components')
160
192
  "id": "ak022eit4nup"
161
193
  },
162
194
  </pre>
163
- </div>
164
- </main>
195
+ </div>
196
+ </main>
197
+ </div>
165
198
  </template>
@@ -11,12 +11,14 @@ interface Props {
11
11
  url?: string
12
12
  fallback?: string
13
13
  icon?: string
14
+ alt?: string
14
15
  }
15
16
 
16
17
  const {
17
18
  size = Size.m,
18
19
  url,
19
20
  fallback,
21
+ alt = 'avatar',
20
22
  } = defineProps<Props>()
21
23
 
22
24
  const showFallback = ref(false)
@@ -32,7 +34,12 @@ const showFallback = ref(false)
32
34
  }),
33
35
  }"
34
36
  >
35
- <img v-if="url && !showFallback" :src="url" @error="showFallback = true">
37
+ <img
38
+ v-if="url && !showFallback"
39
+ :alt
40
+ :src="url"
41
+ @error="showFallback = true"
42
+ >
36
43
  <strong v-else>
37
44
  <template v-if="showFallback">
38
45
  {{ fallback }}
@@ -73,13 +73,10 @@ const w = computed(() => expand ? `${anchorWidth.value}px` : 'initial')
73
73
  <div
74
74
  ref="anchor"
75
75
  class="vui-dropdown-trigger-wrap"
76
- :style="{
77
- minWidth: mW,
78
- width: w,
79
- }"
80
76
  role="button"
81
77
  :aria-expanded="showMenu"
82
78
  :aria-haspopup="true"
79
+ name="Dropdown menu"
83
80
  >
84
81
  <slot name="trigger" :open :is-open="showMenu" :close :toggle />
85
82
  </div>
@@ -91,6 +88,10 @@ const w = computed(() => expand ? `${anchorWidth.value}px` : 'initial')
91
88
  :anchor="anchorRef"
92
89
  class="vui-dropdown"
93
90
  :placement
91
+ :style="{
92
+ minWidth: mW,
93
+ width: w,
94
+ }"
94
95
  >
95
96
  <slot :open :close :toggle :is-open="showMenu" />
96
97
  </Popout>
@@ -4,6 +4,7 @@ import { Icon } from '@iconify/vue'
4
4
  interface Props {
5
5
  disabled?: boolean
6
6
  icon?: string
7
+ iconEnd?: string
7
8
  }
8
9
 
9
10
  const props = defineProps<Props>()
@@ -13,9 +14,7 @@ const props = defineProps<Props>()
13
14
  <button class="vui-dropdown-item" :class="{ disabled }">
14
15
  <!-- This should always be here to offset items which dont have icons -->
15
16
  <div class="vui-dropdown-item-icon">
16
- <Transition name="fade" appear>
17
- <Icon v-if="props.icon" :icon="props.icon" />
18
- </Transition>
17
+ <Icon v-if="props.icon" :icon="props.icon" />
19
18
  </div>
20
19
 
21
20
  <div class="vui-dropdown-item-slot">
@@ -25,5 +24,9 @@ const props = defineProps<Props>()
25
24
  <div class="vui-dropdown-item-hint">
26
25
  <slot name="hint" />
27
26
  </div>
27
+
28
+ <div v-if="props.iconEnd" class="vui-dropdown-item-icon">
29
+ <Icon :icon="props.iconEnd" />
30
+ </div>
28
31
  </button>
29
32
  </template>
@@ -1,5 +1,6 @@
1
1
  .vui-dropdown-trigger-wrap {
2
- display: inline-block;
2
+ // display: inline-block;
3
+ width: fit-content;
3
4
  }
4
5
 
5
6
  .vui-dropdown {
@@ -16,6 +17,7 @@
16
17
  width: fit-content;
17
18
  gap: var(--space-xs);
18
19
  width: 100%;
20
+ // TODO: make button-height variable global and use it here and everywhere else
19
21
  height: 34px;
20
22
  border-radius: var(--border-radius-m);
21
23
  font-size: var(--font-size-s);
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { Space } from '../../shared/types'
3
3
  import { computed } from 'vue'
4
+ import { formatUnitValue } from '../../shared/helpers'
4
5
 
5
6
  export interface FlexProps {
6
7
  inline?: boolean
@@ -34,7 +35,10 @@ export interface FlexProps {
34
35
  const props = defineProps<FlexProps>()
35
36
 
36
37
  // Flex gap
37
- const ag = computed(() => `var(--space-${props.gap})`)
38
+ const ag = computed(() => typeof props.gap === 'number'
39
+ ? formatUnitValue(props.gap)
40
+ : `var(--space-${props.gap})`,
41
+ )
38
42
 
39
43
  // Flex direction
40
44
  const ad = computed(() => {
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import type { Space } from '../../shared/types'
3
3
  import { computed } from 'vue'
4
- import { createArray } from '../../shared/helpers'
4
+ import { createArray, formatUnitValue } from '../../shared/helpers'
5
5
 
6
6
  /**
7
7
  * This component is not meant for complex grids
@@ -17,7 +17,10 @@ interface Props {
17
17
 
18
18
  const props = defineProps<Props>()
19
19
 
20
- const ag = computed(() => `var(--space-${props.gap})`)
20
+ const ag = computed(() => typeof props.gap === 'number'
21
+ ? formatUnitValue(props.gap)
22
+ : `var(--space-${props.gap})`,
23
+ )
21
24
 
22
25
  const aTC = computed(() => {
23
26
  if (typeof props.columns === 'number') {
@@ -1,6 +1,6 @@
1
1
  <script setup lang='ts'>
2
2
  import type { Placement, PopoutMaybeElement } from '../../shared/types'
3
- import { autoPlacement, offset, useFloating } from '@floating-ui/vue'
3
+ import { autoPlacement, offset, shift, useFloating } from '@floating-ui/vue'
4
4
  import { toRef, useTemplateRef } from 'vue'
5
5
  import './popout.scss'
6
6
 
@@ -28,6 +28,9 @@ const { floatingStyles } = useFloating(anchorRef, popoutRef, {
28
28
  middleware: [
29
29
  ...(props.placement ? [] : [autoPlacement()]),
30
30
  offset(props.offset),
31
+ shift({
32
+ padding: 8,
33
+ }),
31
34
  ],
32
35
  })
33
36
  </script>
@@ -0,0 +1,85 @@
1
+ <script setup lang='ts'>
2
+ import { useCssVar, useMouse } from '@vueuse/core'
3
+ import { computed, useSlots, useTemplateRef, watch } from 'vue'
4
+ import './sidebar.scss'
5
+
6
+ const props = withDefaults(defineProps<Props>(), {
7
+ width: 224,
8
+ mini: false,
9
+ })
10
+
11
+ interface Props {
12
+ width?: number
13
+ /**
14
+ * Controls wether the sidebar is displayed in full size, or a small version
15
+ */
16
+ mini?: boolean
17
+ /**
18
+ * Allow sidebar showing up, when user hovers at very left of the screen. The
19
+ * sidebar will apear over content, not pushing anything over
20
+ */
21
+ appear?: boolean
22
+ /**
23
+ * Add edges of background around sidebar
24
+ */
25
+ floaty?: boolean
26
+ }
27
+
28
+ const sidebar = useTemplateRef('sidebar')
29
+ const open = defineModel<boolean>()
30
+ const slots = useSlots()
31
+ const offset = useCssVar('--vui-sidebar-float-offset', sidebar, {
32
+ initialValue: '8px',
33
+ })
34
+
35
+ const width = computed(() => {
36
+ if (props.mini)
37
+ return `65px`
38
+ if (!props.floaty)
39
+ return `${props.width}px`
40
+ return `calc(${props.width}px - ${offset.value})`
41
+ })
42
+
43
+ const slotProps = computed(() => ({
44
+ mini: props.mini,
45
+ floaty: props.floaty,
46
+ width: props.width,
47
+ open,
48
+ }))
49
+
50
+ const { x } = useMouse()
51
+
52
+ let appearActive = true
53
+ watch(x, (pos) => {
54
+ if (!props.appear)
55
+ return
56
+
57
+ if (pos < 20 && !open.value) {
58
+ open.value = true
59
+ appearActive = true
60
+ }
61
+ else if (appearActive && pos > props.width) {
62
+ open.value = false
63
+ appearActive = false
64
+ }
65
+ })
66
+ </script>
67
+
68
+ <template>
69
+ <div class="vui-sidebar-outer" :style="{ width }" :class="{ open }">
70
+ <aside ref="sidebar" class="vui-sidebar" :class="{ open, floaty: props.floaty, mini: props.mini }" :style="{ width: `${props.mini ? 65 : props.width}px` }">
71
+ <div v-if="slots.header" class="vui-sidebar-header">
72
+ <slot name="header" v-bind="slotProps" />
73
+ </div>
74
+ <div class="vui-sidebar-content">
75
+ <div class="vui-sidebar-content-wrap">
76
+ <slot v-bind="slotProps" />
77
+ </div>
78
+ </div>
79
+
80
+ <div v-if="slots.footer" class="vui-sidebar-footer">
81
+ <slot name="footer" v-bind="slotProps" />
82
+ </div>
83
+ </aside>
84
+ </div>
85
+ </template>
@@ -0,0 +1,123 @@
1
+ // TODO: flesh out better
2
+ .vui-sidebar-layout {
3
+ display: flex;
4
+ flex-wrap: nowrap;
5
+ gap: 32px;
6
+ position: relative;
7
+
8
+ main {
9
+ flex: 1;
10
+ padding: 2rem;
11
+ }
12
+
13
+ .vui-sidebar-outer {
14
+ transition: var(--transition-slow);
15
+
16
+ &:not(.open) {
17
+ width: 0px !important;
18
+ }
19
+ }
20
+ }
21
+
22
+ .vui-sidebar {
23
+ --vui-sidebar-float-offset: 8px;
24
+ display: flex;
25
+ flex-direction: column;
26
+ gap: var(--space-sm);
27
+ height: 100vh;
28
+ width: 224px;
29
+ position: fixed;
30
+ top: 0;
31
+ z-index: 50;
32
+ background-color: var(--color-bg);
33
+ border-right: 1px solid var(--color-border);
34
+ transition: var(--transition-slow);
35
+ transform: translateX(-100%);
36
+ will-change: transform;
37
+
38
+ &.open {
39
+ transform: translateX(0);
40
+
41
+ &.floaty {
42
+ transform: translateX(0);
43
+ }
44
+ }
45
+
46
+ &.floaty {
47
+ top: var(--vui-sidebar-float-offset);
48
+ left: var(--vui-sidebar-float-offset);
49
+ bottom: var(--vui-sidebar-float-offset);
50
+ height: calc(100vh - calc(var(--vui-sidebar-float-offset) * 2));
51
+ border-radius: var(--border-radius-m);
52
+ border: 1px solid var(--color-border);
53
+ transform: translateX(calc(-100% - calc(var(--vui-sidebar-float-offset) * 2)));
54
+ box-shadow: var(--box-shadow);
55
+ }
56
+
57
+ .vui-sidebar-header,
58
+ .vui-sidebar-footer,
59
+ .vui-sidebar-content .vui-sidebar-content-wrap {
60
+ padding: var(--space-s);
61
+ }
62
+
63
+ .vui-sidebar-header:not(:only-child) {
64
+ padding-bottom: 0;
65
+ }
66
+
67
+ .vui-sidebar-footer:not(:only-child) {
68
+ padding-top: 0;
69
+ }
70
+
71
+ .vui-sidebar-content {
72
+ flex: 1;
73
+ position: relative;
74
+
75
+ .vui-sidebar-content-wrap {
76
+ position: absolute;
77
+ inset: 0;
78
+ overflow-y: auto;
79
+ }
80
+ }
81
+
82
+ // Note: elements in sidebar (& mini) should have a slight modification
83
+
84
+ // Accordion
85
+ // Does not have a border under content
86
+ .vui-accordion {
87
+ border-bottom: 0;
88
+ }
89
+
90
+ // DropdownItems (sidebar items
91
+ // Should have a bit less spacing between slots
92
+ .vui-dropdown-item {
93
+ padding-inline: var(--space-xs);
94
+ }
95
+
96
+ &.mini {
97
+ .vui-dropdown-item .vui-dropdown-item-icon {
98
+ width: 20px;
99
+ height: 20px;
100
+ }
101
+
102
+ .vui-dropdown-item,
103
+ .vui-button {
104
+ --button-height: 40px;
105
+ width: var(--button-height) !important;
106
+ height: var(--button-height) !important;
107
+ justify-content: center;
108
+ align-items: center;
109
+
110
+ svg {
111
+ width: 20px;
112
+ height: 20px;
113
+ }
114
+
115
+ .vui-dropdown-item-slot,
116
+ .vui-dropdown-item-hint,
117
+ .vui-button-slot-end,
118
+ .vui-button-slot-start {
119
+ display: none;
120
+ }
121
+ }
122
+ }
123
+ }
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { TabProps } from './Tab.vue'
3
- import { useEventListener } from '@vueuse/core'
3
+ import { useResizeObserver } from '@vueuse/core'
4
4
  import { onMounted, useTemplateRef, type VNode, watch } from 'vue'
5
5
  import './tabs.scss'
6
6
 
@@ -42,7 +42,7 @@ function computeUnderlinePosition() {
42
42
  }
43
43
 
44
44
  onMounted(() => {
45
- useEventListener(window, 'resize', computeUnderlinePosition)
45
+ useResizeObserver(tabsRef, computeUnderlinePosition)
46
46
 
47
47
  watch(
48
48
  [active, () => expand],