@livestorm/ui-vue 2.0.4 → 3.0.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/README.md +8 -5
- package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-LpdvGf5X.mjs +6093 -0
- package/dist/a11y-BhF_nl7L.mjs +159 -0
- package/dist/components.mjs +105 -96
- package/dist/index.mjs +68 -64
- package/dist/layouts.mjs +16 -16
- package/dist/types/index.d.ts +5 -1
- package/dist/types/src/components/UiActionBar/UiActionBar.vue.d.ts +3 -1
- package/dist/types/src/components/UiActionBar/UiActionBarItem.vue.d.ts +18 -3
- package/dist/types/src/components/UiActionBar/types.d.ts +3 -1
- package/dist/types/src/components/UiButton/UiButton.vue.d.ts +17 -13
- package/dist/types/src/components/UiButtonGroup/UiButtonGroupItem.vue.d.ts +3 -0
- package/dist/types/src/components/UiButtonGroup/types.d.ts +1 -1
- package/dist/types/src/components/UiDropdown/UiDropdownItem.vue.d.ts +6 -4
- package/dist/types/src/components/UiInputEmoji/UiInputEmoji.vue.d.ts +45 -0
- package/dist/types/src/components/UiInputEmoji/index.d.ts +1 -0
- package/dist/types/src/components/UiInputRadio/UiInputRadio.vue.d.ts +67 -0
- package/dist/types/src/components/UiInputRadio/UiInputRadioGroup.vue.d.ts +81 -0
- package/dist/types/src/components/UiInputRadio/index.d.ts +3 -0
- package/dist/types/src/components/UiInputRadio/types.d.ts +19 -0
- package/dist/types/src/components/UiLoader/UiLoader.vue.d.ts +6 -5
- package/dist/types/src/components/UiLogo/UiLogo.vue.d.ts +9 -3
- package/dist/types/src/components/UiPage/UiPage.vue.d.ts +34 -0
- package/dist/types/src/components/UiProgress/UiProgress.vue.d.ts +1 -1
- package/dist/types/src/components/UiSwitch/UiSwitch.vue.d.ts +109 -0
- package/dist/types/src/components/UiSwitch/index.d.ts +2 -0
- package/dist/types/src/components/UiSwitch/types.d.ts +3 -0
- package/dist/types/src/components/UiTabs/UiTabs.vue.d.ts +5 -2
- package/dist/types/src/composables/useContentMode.d.ts +25 -0
- package/dist/types/src/composables/useIconSize.d.ts +11 -0
- package/dist/types/src/constants/sizes.d.ts +1 -1
- package/dist/ui-vue.css +1 -1
- package/dist/{useThemeAndModes-CUK56j0z.mjs → useThemeAndModes-BzYwSOEv.mjs} +1 -1
- package/dist/utils.mjs +154 -99
- package/index.d.ts +4 -0
- package/index.js +8 -0
- package/package.json +11 -3
- package/src/components/Toast/ToastMessage.vue +6 -6
- package/src/components/UiActionBar/UiActionBar.vue +11 -2
- package/src/components/UiActionBar/UiActionBarItem.vue +56 -32
- package/src/components/UiActionBar/types.ts +3 -1
- package/src/components/UiAvatar/UiAvatar.vue +1 -1
- package/src/components/UiBanner/UiBanner.vue +7 -7
- package/src/components/UiButton/UiButton.vue +9 -9
- package/src/components/UiButtonGroup/UiButtonGroup.vue +4 -0
- package/src/components/UiButtonGroup/UiButtonGroupItem.vue +14 -0
- package/src/components/UiButtonGroup/types.ts +1 -1
- package/src/components/UiCarousel/UiCarousel.vue +2 -2
- package/src/components/UiColorPicker/UiColorPicker.vue +5 -5
- package/src/components/UiDialog/MarketplaceHeaderExample.vue +2 -2
- package/src/components/UiDialog/UiDialogClose.vue +1 -1
- package/src/components/UiDropdown/UiDropdownContent.vue +2 -2
- package/src/components/UiDropdown/UiDropdownItem.vue +8 -1
- package/src/components/UiDropdown/UiDropdownTrigger.vue +6 -7
- package/src/components/UiFieldWrapper/UiFieldWrapper.vue +1 -1
- package/src/components/UiInputCheckbox/UiInputCheckbox.vue +2 -2
- package/src/components/UiInputEmoji/UiInputEmoji.vue +173 -0
- package/src/components/UiInputEmoji/index.ts +1 -0
- package/src/components/UiInputRadio/UiInputRadio.vue +374 -0
- package/src/components/UiInputRadio/UiInputRadioGroup.vue +156 -0
- package/src/components/UiInputRadio/index.ts +3 -0
- package/src/components/UiInputRadio/types.ts +25 -0
- package/src/components/UiLoader/UiLoader.vue +8 -10
- package/src/components/UiLogo/UiLogo.vue +41 -7
- package/src/components/UiMenu/UiMenuContent.vue +1 -1
- package/src/components/UiMenu/UiMenuGroup.vue +1 -1
- package/src/components/UiMenu/UiMenuItem.vue +1 -1
- package/src/components/UiMenu/UiMenuSubContent.vue +1 -1
- package/src/components/UiMenu/UiMenuSubTrigger.vue +2 -2
- package/src/components/UiPage/UiPage.vue +102 -29
- package/src/components/UiPageHeader/UiPageHeader.vue +29 -9
- package/src/components/UiRoomButton/UiRoomButton.vue +4 -4
- package/src/components/UiShell/UiShell.vue +1 -1
- package/src/components/UiSideMenu/UiSideMenu.vue +13 -10
- package/src/components/UiSideMenu/UiSideMenuItemContent.vue +2 -2
- package/src/components/UiStepper/UiStepperIndicator.vue +8 -11
- package/src/components/UiSwitch/UiSwitch.vue +359 -0
- package/src/components/UiSwitch/index.ts +2 -0
- package/src/components/UiSwitch/types.ts +5 -0
- package/src/components/UiTabs/UiTabs.vue +7 -4
- package/src/components/UiTextField/UiTextField.vue +6 -11
- package/src/components/UiTimeline/README.md +6 -6
- package/src/components/UiTimeline/UiTimelineItem.vue +3 -3
- package/src/composables/useContentMode.ts +53 -0
- package/src/composables/useIconSize.ts +28 -0
- package/src/constants/sizes.ts +1 -1
- package/src/global.d.ts +8 -0
- package/dist/UiTimelineItem.vue_vue_type_style_index_0_lang-BtG5oABt.mjs +0 -5454
- package/dist/a11y--y7uaY4j.mjs +0 -217
|
@@ -16,7 +16,7 @@ const forwarded = useForwardPropsEmits(props, emits)
|
|
|
16
16
|
<DropdownMenuPortal>
|
|
17
17
|
<DropdownMenuContent
|
|
18
18
|
v-bind="{ ...forwarded, ...$attrs }"
|
|
19
|
-
class="bg-surface-neutral-bg-main rounded-xl border border-borders-neutral-light shadow-lg p-1 z-50"
|
|
19
|
+
class="bg-surface-neutral-bg-main rounded-xl border border-borders-neutral-light shadow-lg p-1.5 flex flex-col gap-0.5 z-50"
|
|
20
20
|
data-colors-semantic="light"
|
|
21
21
|
>
|
|
22
22
|
<slot />
|
|
@@ -10,7 +10,7 @@ defineProps<{
|
|
|
10
10
|
<DropdownMenuGroup v-bind="$attrs">
|
|
11
11
|
<DropdownMenuLabel
|
|
12
12
|
v-if="label"
|
|
13
|
-
class="text-content-legends-bold-md text-text-neutral-
|
|
13
|
+
class="text-content-legends-bold-md text-text-neutral-secondary px-3 pt-3 pb-1"
|
|
14
14
|
>
|
|
15
15
|
{{ label }}
|
|
16
16
|
</DropdownMenuLabel>
|
|
@@ -11,7 +11,7 @@ const forwarded = useForwardPropsEmits(props, emits)
|
|
|
11
11
|
<template>
|
|
12
12
|
<DropdownMenuItem
|
|
13
13
|
v-bind="{ ...forwarded, ...$attrs }"
|
|
14
|
-
class="w-full flex items-center gap-2 px-3 py-
|
|
14
|
+
class="w-full flex items-center gap-2 min-h-10 px-3 py-1.5 rounded-lg hover:bg-actions-neutral-hover-overlay data-[highlighted]:bg-actions-neutral-hover-overlay transition-colors text-left outline-none cursor-pointer text-content-text-md-regular text-text-neutral-base"
|
|
15
15
|
>
|
|
16
16
|
<slot />
|
|
17
17
|
</DropdownMenuItem>
|
|
@@ -14,7 +14,7 @@ const forwarded = useForwardPropsEmits(props, emits)
|
|
|
14
14
|
<DropdownMenuPortal>
|
|
15
15
|
<DropdownMenuSubContent
|
|
16
16
|
v-bind="{ ...forwarded, ...$attrs }"
|
|
17
|
-
class="bg-surface-neutral-bg-main rounded-xl border border-borders-neutral-light shadow-lg p-1 z-50"
|
|
17
|
+
class="bg-surface-neutral-bg-main rounded-xl border border-borders-neutral-light shadow-lg p-1.5 flex flex-col gap-0.5 z-50"
|
|
18
18
|
data-colors-semantic="light"
|
|
19
19
|
>
|
|
20
20
|
<slot />
|
|
@@ -9,9 +9,9 @@ const forwarded = useForwardProps(props)
|
|
|
9
9
|
<template>
|
|
10
10
|
<DropdownMenuSubTrigger
|
|
11
11
|
v-bind="{ ...forwarded, ...$attrs }"
|
|
12
|
-
class="w-full flex items-center justify-between gap-3 px-3 py-
|
|
12
|
+
class="w-full flex items-center justify-between gap-3 min-h-10 px-3 py-1.5 rounded-lg hover:bg-actions-neutral-hover-overlay data-[highlighted]:bg-actions-neutral-hover-overlay data-[state=open]:bg-actions-neutral-hover-overlay transition-colors text-left outline-none cursor-pointer"
|
|
13
13
|
>
|
|
14
14
|
<slot />
|
|
15
|
-
<span class="i-
|
|
15
|
+
<span class="i-ph-caret-right w-4 h-4 text-text-neutral-tertiary shrink-0" />
|
|
16
16
|
</DropdownMenuSubTrigger>
|
|
17
17
|
</template>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, onBeforeUnmount,
|
|
2
|
+
import { computed, onBeforeUnmount, ref, watch, getCurrentInstance, type Slot } from 'vue'
|
|
3
3
|
import { BREAKPOINT_LG } from '../../utils/breakpoints'
|
|
4
4
|
import { useResponsive } from '../../utils/responsive'
|
|
5
|
-
import
|
|
5
|
+
import { useContentMode } from '../../composables/useContentMode'
|
|
6
6
|
import { useMobileMenu } from '../../composables/useMobileMenu'
|
|
7
7
|
import UiLoader from '../UiLoader/UiLoader.vue'
|
|
8
8
|
|
|
@@ -36,6 +36,24 @@ import UiLoader from '../UiLoader/UiLoader.vue'
|
|
|
36
36
|
// │ │ └─────────────────────────────────────────────────┘ │
|
|
37
37
|
// └─┴─────────────────────────────────────────────────────┘
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Headroom sizes, in px: the gap above the content card that lets the shell
|
|
41
|
+
* background show through. One map so the page frame has a single source of
|
|
42
|
+
* truth — retune here rather than at call sites.
|
|
43
|
+
*/
|
|
44
|
+
const HEADROOM_GAP_PX = {
|
|
45
|
+
none: 0,
|
|
46
|
+
sm: 4,
|
|
47
|
+
md: 10,
|
|
48
|
+
lg: 16,
|
|
49
|
+
xl: 24,
|
|
50
|
+
} as const
|
|
51
|
+
|
|
52
|
+
type HeadroomGap = keyof typeof HEADROOM_GAP_PX
|
|
53
|
+
|
|
54
|
+
/** Used when the card sits flush at the top and no size is given. */
|
|
55
|
+
const DEFAULT_HEADROOM_GAP: HeadroomGap = 'md'
|
|
56
|
+
|
|
39
57
|
const props = withDefaults(defineProps<{
|
|
40
58
|
/**
|
|
41
59
|
* Extra classes for the inner content `<section>`. Use to override the
|
|
@@ -50,9 +68,30 @@ const props = withDefaults(defineProps<{
|
|
|
50
68
|
* menu row — e.g. "Home" — without reaching into useMobileMenu directly.
|
|
51
69
|
*/
|
|
52
70
|
title?: string
|
|
71
|
+
/**
|
|
72
|
+
* The shape of the page inside the content card.
|
|
73
|
+
* - `document` (default): the card scrolls as a single column. The common
|
|
74
|
+
* dashboard page — lists, forms, detail views.
|
|
75
|
+
* - `app`: the card fills the available height and never scrolls itself;
|
|
76
|
+
* the page owns its own scroll regions. For editor-style pages (split
|
|
77
|
+
* panes, canvases) that would otherwise opt out of UiPage entirely.
|
|
78
|
+
*/
|
|
79
|
+
variant?: 'document' | 'app'
|
|
80
|
+
/**
|
|
81
|
+
* Headroom above the content card, letting the shell background show
|
|
82
|
+
* through. Sizes map to px via `HEADROOM_GAP_PX`.
|
|
83
|
+
*
|
|
84
|
+
* Left unset, the card gets `DEFAULT_HEADROOM_GAP` only when it sits flush
|
|
85
|
+
* at the top — i.e. there is no page header or left slot already offsetting
|
|
86
|
+
* it. Naming a size applies it in either case, and `none` removes the gap
|
|
87
|
+
* on a page that would otherwise get the default.
|
|
88
|
+
*/
|
|
89
|
+
headroomGap?: HeadroomGap
|
|
53
90
|
}>(), {
|
|
54
91
|
pageContentClasses: '',
|
|
55
92
|
title: undefined,
|
|
93
|
+
variant: 'document',
|
|
94
|
+
headroomGap: undefined,
|
|
56
95
|
})
|
|
57
96
|
|
|
58
97
|
const slots = defineSlots<{
|
|
@@ -65,6 +104,12 @@ const slots = defineSlots<{
|
|
|
65
104
|
default?(): Slot
|
|
66
105
|
}>()
|
|
67
106
|
|
|
107
|
+
// An `app` page manages its own scrolling, so every level from the page
|
|
108
|
+
// content down to the card must stop scrolling and stop growing past the
|
|
109
|
+
// viewport — otherwise a split-pane editor gets a second, outer scrollbar.
|
|
110
|
+
const isApp = computed(() => props.variant === 'app')
|
|
111
|
+
const scrollClass = computed(() => (isApp.value ? 'overflow-hidden' : 'overflow-y-auto'))
|
|
112
|
+
|
|
68
113
|
// Check for slot presence
|
|
69
114
|
const bannerSlot = computed(() => !!slots.banner)
|
|
70
115
|
const pageHeaderSlot = computed(() => !!slots.pageHeader)
|
|
@@ -73,6 +118,38 @@ const leftSlot = computed(() => !!slots.leftSlot)
|
|
|
73
118
|
const headerSlot = computed(() => !!slots.header)
|
|
74
119
|
const footerSlot = computed(() => !!slots.footer)
|
|
75
120
|
|
|
121
|
+
// Row track for the card grid. An `app` page needs its main row to take the
|
|
122
|
+
// leftover height and be allowed to shrink (minmax(0,1fr)), so nested
|
|
123
|
+
// overflow containers resolve against a real height instead of growing.
|
|
124
|
+
// Spelled out as literals: Tailwind only generates classes it can see as
|
|
125
|
+
// complete strings in the source.
|
|
126
|
+
const cardRowsClass = computed(() => {
|
|
127
|
+
if (!isApp.value) { return headerSlot.value ? 'grid-rows-[min-content]' : '' }
|
|
128
|
+
if (headerSlot.value && footerSlot.value) { return 'grid-rows-[min-content_minmax(0,1fr)_min-content]' }
|
|
129
|
+
if (headerSlot.value) { return 'grid-rows-[min-content_minmax(0,1fr)]' }
|
|
130
|
+
if (footerSlot.value) { return 'grid-rows-[minmax(0,1fr)_min-content]' }
|
|
131
|
+
return 'grid-rows-[minmax(0,1fr)]'
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
// A named size always wins; otherwise fall back to the default, and only when
|
|
135
|
+
// the card is flush at the top (a page header or left slot already provides
|
|
136
|
+
// the offset). Applied as an inline style rather than a utility so the value
|
|
137
|
+
// does not depend on Tailwind's `--spacing` fallback resolving to 0.25rem.
|
|
138
|
+
// A zero gap emits no style at all, so `none` and "already offset" produce
|
|
139
|
+
// identical markup.
|
|
140
|
+
//
|
|
141
|
+
// Padding on the clipping wrapper rather than a margin on the card: the card
|
|
142
|
+
// is `h-full`, so a margin would push a full-height box down inside a fixed
|
|
143
|
+
// height, overflowing by exactly the gap and clipping that much off the
|
|
144
|
+
// bottom. As padding it shrinks the box the card measures itself against.
|
|
145
|
+
const headroomGapStyle = computed(() => {
|
|
146
|
+
const size = props.headroomGap ?? (
|
|
147
|
+
!pageHeaderSlot.value && !leftSlot.value ? DEFAULT_HEADROOM_GAP : 'none'
|
|
148
|
+
)
|
|
149
|
+
const px = HEADROOM_GAP_PX[size]
|
|
150
|
+
return px ? { paddingTop: `${px}px` } : undefined
|
|
151
|
+
})
|
|
152
|
+
|
|
76
153
|
// Feed the page title to UiShell's fallback mobile menu topbar. Watched so a
|
|
77
154
|
// reactive title updates live, and cleared on unmount so it doesn't leak to
|
|
78
155
|
// the next route.
|
|
@@ -92,23 +169,9 @@ const displayLeftSlot = computed(() => responsive.value.width >= BREAKPOINT_LG)
|
|
|
92
169
|
const UiPage = ref<HTMLElement | undefined>()
|
|
93
170
|
const PageContent = ref<HTMLElement | undefined>()
|
|
94
171
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// the internal theming tooling is enabled, so the stored content mode
|
|
99
|
-
// (driven by the ThemePicker) can apply; for everyone else the content
|
|
100
|
-
// stays light regardless of what localStorage may hold.
|
|
101
|
-
const isInternalThemingEnabled = localStorage.getItem('ls-internal-theming') === 'true'
|
|
102
|
-
|
|
103
|
-
onMounted(() => {
|
|
104
|
-
addElementToWatch(
|
|
105
|
-
'content',
|
|
106
|
-
{
|
|
107
|
-
selector: '[data-name="ui-page-content"]',
|
|
108
|
-
element: PageContent.value!,
|
|
109
|
-
...(isInternalThemingEnabled ? {} : { modeOverride: 'light' }),
|
|
110
|
-
})
|
|
111
|
-
})
|
|
172
|
+
// Follow the stored content mode via the shared composable (also used by the
|
|
173
|
+
// settings shell), so the page content's data-colors-semantic stays in sync.
|
|
174
|
+
const { contentMode } = useContentMode(PageContent, '[data-name="ui-page-content"]')
|
|
112
175
|
|
|
113
176
|
</script>
|
|
114
177
|
|
|
@@ -132,7 +195,7 @@ onMounted(() => {
|
|
|
132
195
|
v-if="pageHeaderSlot"
|
|
133
196
|
ref="pageHeader"
|
|
134
197
|
data-name="pageHeader"
|
|
135
|
-
class="page-header p-4 md:
|
|
198
|
+
class="page-header p-4 md:px-8 md:py-6 md:pl-0 relative"
|
|
136
199
|
>
|
|
137
200
|
<slot name="pageHeader" />
|
|
138
201
|
</section>
|
|
@@ -150,8 +213,11 @@ onMounted(() => {
|
|
|
150
213
|
<section
|
|
151
214
|
ref="PageContent"
|
|
152
215
|
data-name="pageContent"
|
|
153
|
-
class="
|
|
154
|
-
|
|
216
|
+
:class="[
|
|
217
|
+
'page-content flex-1 w-full grid has-[>:nth-child(2)]:lg:grid-cols-[1fr_2fr] lg:gap-x-8 min-h-0',
|
|
218
|
+
scrollClass,
|
|
219
|
+
]"
|
|
220
|
+
:data-colors-semantic="contentMode"
|
|
155
221
|
>
|
|
156
222
|
<aside
|
|
157
223
|
v-if="leftSlot && displayLeftSlot"
|
|
@@ -161,14 +227,15 @@ onMounted(() => {
|
|
|
161
227
|
<slot name="leftSlot" />
|
|
162
228
|
</aside>
|
|
163
229
|
|
|
164
|
-
<div
|
|
230
|
+
<div
|
|
231
|
+
class="min-w-0 overflow-hidden rounded-tl-xl"
|
|
232
|
+
:style="headroomGapStyle"
|
|
233
|
+
>
|
|
165
234
|
<section
|
|
166
235
|
:class="[
|
|
167
|
-
'content min-w-0
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
!pageHeaderSlot && !leftSlot ? 'mt-1' : '',
|
|
171
|
-
headerSlot ? 'grid-rows-[min-content]' : '',
|
|
236
|
+
'content min-w-0 h-full bg-surface-neutral-bg-main grid shadow-shadows-drop-shadow-2xl rounded-tl-xl',
|
|
237
|
+
scrollClass,
|
|
238
|
+
cardRowsClass,
|
|
172
239
|
props.pageContentClasses,
|
|
173
240
|
]"
|
|
174
241
|
data-name="ui-shell-content"
|
|
@@ -183,7 +250,13 @@ onMounted(() => {
|
|
|
183
250
|
|
|
184
251
|
<section
|
|
185
252
|
data-name="main-content"
|
|
186
|
-
class="
|
|
253
|
+
:class="[
|
|
254
|
+
'route-content w-full min-w-0 flex flex-col',
|
|
255
|
+
// Let the row shrink so an editor's own overflow containers
|
|
256
|
+
// resolve against a real height. Scoped to `app` so the 15
|
|
257
|
+
// existing document pages keep their current growth behaviour.
|
|
258
|
+
isApp ? 'min-h-0' : '',
|
|
259
|
+
]"
|
|
187
260
|
>
|
|
188
261
|
<slot>
|
|
189
262
|
<UiLoader />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, onBeforeUnmount, useSlots, watch, type Slot } from 'vue'
|
|
3
|
-
import LivestormLogo from '@livestorm/ui-tokens/output/vectors/logos/livestorm-white.svg'
|
|
4
3
|
import UiButton from '../UiButton/UiButton.vue'
|
|
4
|
+
import UiLogo from '../UiLogo/UiLogo.vue'
|
|
5
5
|
import { useMobileMenu } from '../../composables/useMobileMenu'
|
|
6
6
|
import type { RouteLocationRaw } from 'vue-router'
|
|
7
7
|
|
|
@@ -65,8 +65,15 @@ onBeforeUnmount(() => syncTrigger(false))
|
|
|
65
65
|
</script>
|
|
66
66
|
|
|
67
67
|
<template>
|
|
68
|
+
<!--
|
|
69
|
+
min-h-10 keeps the header a stable height whether or not a page fills the
|
|
70
|
+
action slots. Without it the row is sized by its tallest child — a bare
|
|
71
|
+
title is 32px but an action button is 40px — so the header, and the content
|
|
72
|
+
card below it, shifted by 8px between pages like Events and People.
|
|
73
|
+
A floor, not a fixed height: taller or wrapped content still grows.
|
|
74
|
+
-->
|
|
68
75
|
<div
|
|
69
|
-
class="flex flex-1 min-w-0 justify-between gap-5 md:gap-8 items-center"
|
|
76
|
+
class="flex flex-1 min-w-0 justify-between gap-5 md:gap-8 items-center min-h-10"
|
|
70
77
|
>
|
|
71
78
|
<div class="flex min-w-0 items-center gap-2">
|
|
72
79
|
<div v-if="showLogo">
|
|
@@ -74,11 +81,13 @@ onBeforeUnmount(() => syncTrigger(false))
|
|
|
74
81
|
:to="logoTo ? logoTo : '#'"
|
|
75
82
|
class="grid items-center w-8 h-8"
|
|
76
83
|
>
|
|
77
|
-
<
|
|
78
|
-
:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
<UiLogo
|
|
85
|
+
:height="1.5"
|
|
86
|
+
:width="1.5"
|
|
87
|
+
:themed="false"
|
|
88
|
+
:animated="false"
|
|
89
|
+
inverted="auto"
|
|
90
|
+
/>
|
|
82
91
|
</router-link>
|
|
83
92
|
</div>
|
|
84
93
|
<div
|
|
@@ -88,7 +97,7 @@ onBeforeUnmount(() => syncTrigger(false))
|
|
|
88
97
|
<UiButton
|
|
89
98
|
color="neutral"
|
|
90
99
|
variant="tertiary"
|
|
91
|
-
icon="i-
|
|
100
|
+
icon="i-ph-list"
|
|
92
101
|
@click="toggle"
|
|
93
102
|
/>
|
|
94
103
|
</div>
|
|
@@ -96,7 +105,7 @@ onBeforeUnmount(() => syncTrigger(false))
|
|
|
96
105
|
<UiButton
|
|
97
106
|
color="neutral"
|
|
98
107
|
variant="tertiary"
|
|
99
|
-
icon="i-
|
|
108
|
+
icon="i-ph-arrow-left"
|
|
100
109
|
/>
|
|
101
110
|
</div>
|
|
102
111
|
<div
|
|
@@ -124,5 +133,16 @@ onBeforeUnmount(() => syncTrigger(false))
|
|
|
124
133
|
>
|
|
125
134
|
<slot name="slotB" />
|
|
126
135
|
</div>
|
|
136
|
+
|
|
137
|
+
<!--
|
|
138
|
+
Teleport target for page-level actions, so a component deep inside the
|
|
139
|
+
page content (e.g. a settings section) can surface its primary action
|
|
140
|
+
here without threading props up. `contents` keeps the empty target out
|
|
141
|
+
of the flex layout, so pages that don't use it are unaffected.
|
|
142
|
+
-->
|
|
143
|
+
<div
|
|
144
|
+
id="ui-page-header-actions-teleport-target"
|
|
145
|
+
class="contents"
|
|
146
|
+
/>
|
|
127
147
|
</div>
|
|
128
148
|
</template>
|
|
@@ -57,7 +57,7 @@ const isIconOnly = computed(() => !slots.default);
|
|
|
57
57
|
>
|
|
58
58
|
<svg
|
|
59
59
|
v-if="loading"
|
|
60
|
-
class="
|
|
60
|
+
class="size-5 shrink-0 animate-spin"
|
|
61
61
|
xmlns="http://www.w3.org/2000/svg"
|
|
62
62
|
fill="none"
|
|
63
63
|
viewBox="0 0 24 24"
|
|
@@ -78,7 +78,7 @@ const isIconOnly = computed(() => !slots.default);
|
|
|
78
78
|
</svg>
|
|
79
79
|
<div
|
|
80
80
|
v-else-if="icon"
|
|
81
|
-
class="
|
|
81
|
+
class="size-5 shrink-0"
|
|
82
82
|
:class="icon"
|
|
83
83
|
/>
|
|
84
84
|
<slot />
|
|
@@ -117,7 +117,7 @@ const isIconOnly = computed(() => !slots.default);
|
|
|
117
117
|
>
|
|
118
118
|
<svg
|
|
119
119
|
v-if="loading"
|
|
120
|
-
class="
|
|
120
|
+
class="size-5 shrink-0 animate-spin"
|
|
121
121
|
xmlns="http://www.w3.org/2000/svg"
|
|
122
122
|
fill="none"
|
|
123
123
|
viewBox="0 0 24 24"
|
|
@@ -138,7 +138,7 @@ const isIconOnly = computed(() => !slots.default);
|
|
|
138
138
|
</svg>
|
|
139
139
|
<div
|
|
140
140
|
v-else-if="icon"
|
|
141
|
-
class="
|
|
141
|
+
class="size-5 shrink-0"
|
|
142
142
|
:class="icon"
|
|
143
143
|
/>
|
|
144
144
|
<slot />
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import LivestormLogo from '@livestorm/ui-tokens/output/vectors/logos/livestorm-white.svg'
|
|
3
2
|
import type { Slot } from 'vue'
|
|
4
3
|
import type { SideMenuCollapsedItem, SideMenuItemProps, SideMenuMoreItem } from './types'
|
|
5
4
|
import UiSideMenuItem from './UiSideMenuItem.vue'
|
|
5
|
+
import UiLogo from '../UiLogo/UiLogo.vue'
|
|
6
6
|
import UiButton from '../UiButton/UiButton.vue'
|
|
7
7
|
import UiPopover from '../UiPopover/UiPopover.vue'
|
|
8
8
|
import UiPopoverTrigger from '../UiPopover/UiPopoverTrigger.vue'
|
|
@@ -189,17 +189,20 @@ function handleLogoClick (event: MouseEvent) {
|
|
|
189
189
|
<!-- Top -->
|
|
190
190
|
<div class="flex flex-col md:items-center gap-8">
|
|
191
191
|
<div class="flex items-center justify-between">
|
|
192
|
-
<
|
|
192
|
+
<UiLogo
|
|
193
193
|
v-if="showLivestormLogo"
|
|
194
|
-
:
|
|
195
|
-
:
|
|
196
|
-
|
|
197
|
-
|
|
194
|
+
:height="2.5"
|
|
195
|
+
:width="2.5"
|
|
196
|
+
:themed="false"
|
|
197
|
+
:animated="false"
|
|
198
|
+
inverted="auto"
|
|
199
|
+
:label="logoAlt"
|
|
200
|
+
class="ml-4 md:ml-0"
|
|
198
201
|
@click="handleLogoClick"
|
|
199
|
-
|
|
202
|
+
/>
|
|
200
203
|
<div class="md:hidden">
|
|
201
204
|
<UiButton
|
|
202
|
-
icon="i-
|
|
205
|
+
icon="i-ph-x"
|
|
203
206
|
variant="tertiary"
|
|
204
207
|
color="neutral"
|
|
205
208
|
size="lg"
|
|
@@ -289,7 +292,7 @@ function handleLogoClick (event: MouseEvent) {
|
|
|
289
292
|
<UiPopoverTrigger class="w-full cursor-pointer">
|
|
290
293
|
<UiSideMenuItem
|
|
291
294
|
:label="translate('room_bottom-bar_controls-label_more')"
|
|
292
|
-
icon="i-
|
|
295
|
+
icon="i-ph-dots-three"
|
|
293
296
|
:is-active="false"
|
|
294
297
|
:inside-interactive="true"
|
|
295
298
|
:badge="moreBadge"
|
|
@@ -420,7 +423,7 @@ function handleLogoClick (event: MouseEvent) {
|
|
|
420
423
|
<UiPopoverTrigger class="cursor-pointer">
|
|
421
424
|
<UiSideMenuItem
|
|
422
425
|
:label="translate('room_bottom-bar_controls-label_more')"
|
|
423
|
-
icon="i-
|
|
426
|
+
icon="i-ph-dots-three-vertical"
|
|
424
427
|
:is-active="false"
|
|
425
428
|
:inside-interactive="true"
|
|
426
429
|
/>
|
|
@@ -103,7 +103,7 @@ const textAlignClass = computed(() => {
|
|
|
103
103
|
isActive ? 'bg-actions-neutral-active-overlay text-actions-neutral-idle' : 'text-actions-neutral-idle-alpha-strong',
|
|
104
104
|
// Avatar box is 40px; on mobile `p-1` makes its total height (48px)
|
|
105
105
|
// match icon items (`p-3` + 24px icon). Both are 40px on desktop.
|
|
106
|
-
hasAvatarSlot ? 'p-1 md:p-0' : 'p-
|
|
106
|
+
hasAvatarSlot ? 'p-1 md:p-0' : 'p-2.5',
|
|
107
107
|
]"
|
|
108
108
|
>
|
|
109
109
|
<!-- Icon/avatar wrapper: anchors the notification badge to the icon's
|
|
@@ -119,7 +119,7 @@ const textAlignClass = computed(() => {
|
|
|
119
119
|
<div
|
|
120
120
|
v-if="icon"
|
|
121
121
|
:class="[
|
|
122
|
-
'w-6 h-6 md:w-
|
|
122
|
+
'w-6 h-6 md:w-5 md:h-5',
|
|
123
123
|
icon
|
|
124
124
|
]"
|
|
125
125
|
aria-hidden="true"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { StepperIndicatorProps } from 'reka-ui'
|
|
3
3
|
import { StepperIndicator } from 'reka-ui'
|
|
4
|
+
import { useIconSize } from '../../composables/useIconSize'
|
|
4
5
|
|
|
5
6
|
type Size = 'sm' | 'md' | 'lg'
|
|
6
7
|
|
|
@@ -13,16 +14,12 @@ interface UiStepperIndicatorProps extends StepperIndicatorProps {
|
|
|
13
14
|
const { size = 'md', showCheckmark = true, icon } = defineProps<UiStepperIndicatorProps>()
|
|
14
15
|
|
|
15
16
|
const sizeClasses = {
|
|
16
|
-
sm: 'size-
|
|
17
|
-
md: 'size-
|
|
18
|
-
lg: 'size-
|
|
17
|
+
sm: 'size-8 text-content-text-md-regular',
|
|
18
|
+
md: 'size-10 text-content-text-md-regular',
|
|
19
|
+
lg: 'size-12 text-content-text-lg-regular',
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const
|
|
22
|
-
sm: 'size-3',
|
|
23
|
-
md: 'size-4',
|
|
24
|
-
lg: 'size-5',
|
|
25
|
-
}
|
|
22
|
+
const iconSizeClass = useIconSize(() => size)
|
|
26
23
|
</script>
|
|
27
24
|
|
|
28
25
|
<template>
|
|
@@ -34,13 +31,13 @@ const iconSizeClasses = {
|
|
|
34
31
|
<span
|
|
35
32
|
v-if="icon"
|
|
36
33
|
class="stepper-custom-icon"
|
|
37
|
-
:class="[
|
|
34
|
+
:class="[iconSizeClass, icon]"
|
|
38
35
|
/>
|
|
39
36
|
|
|
40
37
|
<span
|
|
41
38
|
v-if="showCheckmark"
|
|
42
|
-
class="stepper-checkmark i-
|
|
43
|
-
:class="
|
|
39
|
+
class="stepper-checkmark i-ph-check"
|
|
40
|
+
:class="iconSizeClass"
|
|
44
41
|
/>
|
|
45
42
|
|
|
46
43
|
<span class="stepper-number">
|