@xen-orchestra/web-core 0.54.0 → 0.56.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.
Files changed (107) hide show
  1. package/lib/components/button-group/VtsButtonGroup.vue +11 -1
  2. package/lib/components/card-object-title/VtsCardObjectTitle.vue +36 -0
  3. package/lib/components/code-snippet/VtsCodeSnippet.vue +11 -5
  4. package/lib/components/drawer/VtsDrawer.vue +89 -0
  5. package/lib/components/drawer/VtsDrawerButton.vue +22 -0
  6. package/lib/components/drawer/VtsDrawerCancelButton.vue +33 -0
  7. package/lib/components/drawer/VtsDrawerConfirmButton.vue +32 -0
  8. package/lib/components/drawer/VtsDrawerList.vue +34 -0
  9. package/lib/components/icon/VtsIcon.vue +3 -1
  10. package/lib/components/layout/VtsContentSidePanel.vue +41 -0
  11. package/lib/components/layout/VtsLayoutSidebar.vue +5 -2
  12. package/lib/components/menu/VtsActionsMenu.vue +37 -3
  13. package/lib/components/modal/VtsModalButton.vue +0 -1
  14. package/lib/components/operation-card/VtsOperationCard.vue +2 -1
  15. package/lib/components/panel/VtsPanel.vue +80 -0
  16. package/lib/components/panel/VtsSidePanel.vue +140 -0
  17. package/lib/components/query-builder/VtsQueryBuilderModal.vue +0 -1
  18. package/lib/components/select/VtsSelect.vue +1 -0
  19. package/lib/components/state-hero/VtsStateHero.vue +26 -24
  20. package/lib/components/table/VtsTable.vue +2 -1
  21. package/lib/components/table/cells/VtsActionCell.vue +7 -0
  22. package/lib/components/table/cells/VtsHeaderCell.vue +1 -17
  23. package/lib/components/table/cells/VtsLinkCell.vue +3 -1
  24. package/lib/components/table/cells/VtsTagCell.vue +4 -2
  25. package/lib/components/tree/VtsTreeItem.vue +9 -3
  26. package/lib/components/tree/VtsTreeList.vue +6 -3
  27. package/lib/components/tree/VtsTreeLoadingItem.vue +3 -3
  28. package/lib/components/ui/drawer/UiDrawer.vue +123 -0
  29. package/lib/components/ui/head-bar/UiHeadBar.vue +1 -1
  30. package/lib/components/ui/input/UiInput.vue +3 -1
  31. package/lib/components/ui/link/UiLink.vue +3 -1
  32. package/lib/components/ui/modal/UiModal.vue +10 -18
  33. package/lib/components/ui/panel/UiPanel.vue +7 -24
  34. package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +1 -1
  35. package/lib/composables/default-tab.composable.ts +4 -0
  36. package/lib/composables/table-state.composable.ts +1 -1
  37. package/lib/icons/action-icons.ts +20 -2
  38. package/lib/icons/custom-icons.ts +16 -0
  39. package/lib/icons/object-icons.ts +33 -18
  40. package/lib/locales/cs.json +110 -11
  41. package/lib/locales/da.json +1 -3
  42. package/lib/locales/de.json +1 -12
  43. package/lib/locales/en.json +76 -12
  44. package/lib/locales/es.json +15 -6
  45. package/lib/locales/fa.json +0 -1
  46. package/lib/locales/fr.json +76 -12
  47. package/lib/locales/it.json +0 -1
  48. package/lib/locales/ko.json +0 -2
  49. package/lib/locales/nb-NO.json +18 -20
  50. package/lib/locales/nl.json +0 -11
  51. package/lib/locales/pt-BR.json +0 -4
  52. package/lib/locales/pt.json +0 -4
  53. package/lib/locales/ru.json +0 -1
  54. package/lib/locales/sk.json +110 -11
  55. package/lib/locales/sv.json +2 -13
  56. package/lib/locales/uk.json +0 -1
  57. package/lib/locales/zh-Hans.json +79 -16
  58. package/lib/packages/drawer/DrawerProvider.vue +17 -0
  59. package/lib/packages/drawer/README.md +189 -0
  60. package/lib/packages/drawer/create-drawer-opener.ts +119 -0
  61. package/lib/packages/drawer/drawer.store.ts +22 -0
  62. package/lib/packages/drawer/types.ts +93 -0
  63. package/lib/packages/drawer/use-drawer.ts +53 -0
  64. package/lib/packages/modal/create-modal-opener.ts +12 -10
  65. package/lib/packages/remote-resource/define-remote-resource.ts +64 -29
  66. package/lib/packages/tree/types.ts +6 -0
  67. package/lib/packages/tree/use-tree.ts +38 -37
  68. package/lib/stores/panel.store.ts +56 -5
  69. package/lib/tables/column-definitions/action-column.ts +22 -10
  70. package/lib/tables/column-definitions/address-column.ts +1 -1
  71. package/lib/tables/column-definitions/button-column.ts +1 -1
  72. package/lib/tables/column-definitions/button-icon-column.ts +1 -1
  73. package/lib/tables/column-definitions/collapsed-list-column.ts +1 -1
  74. package/lib/tables/column-definitions/date-column.ts +1 -1
  75. package/lib/tables/column-definitions/double-link-column.ts +1 -1
  76. package/lib/tables/column-definitions/info-column.ts +1 -1
  77. package/lib/tables/column-definitions/input-column.ts +1 -5
  78. package/lib/tables/column-definitions/link-column.ts +1 -1
  79. package/lib/tables/column-definitions/link-or-text-column.ts +1 -1
  80. package/lib/tables/column-definitions/literal-column.ts +1 -1
  81. package/lib/tables/column-definitions/number-column.ts +1 -1
  82. package/lib/tables/column-definitions/percent-column.ts +1 -1
  83. package/lib/tables/column-definitions/progress-bar-column.ts +1 -1
  84. package/lib/tables/column-definitions/select-column.ts +1 -1
  85. package/lib/tables/column-definitions/status-column.ts +2 -2
  86. package/lib/tables/column-definitions/tag-column.ts +3 -2
  87. package/lib/tables/column-definitions/text-column.ts +1 -1
  88. package/lib/tables/column-definitions/truncated-text-column.ts +1 -1
  89. package/lib/tables/column-sets/backup-job-schedule-columns.ts +2 -2
  90. package/lib/tables/column-sets/backup-log-columns.ts +1 -1
  91. package/lib/tables/column-sets/new-vm-network-columns.ts +0 -2
  92. package/lib/tables/column-sets/new-vm-sr-columns.ts +0 -1
  93. package/lib/tables/column-sets/server-columns.ts +1 -1
  94. package/lib/tables/column-sets/snapshot-columns.ts +1 -1
  95. package/lib/tables/column-sets/sr-columns.ts +2 -2
  96. package/lib/tables/column-sets/traffic-rules-columns.ts +5 -7
  97. package/lib/tables/column-sets/vif-network-columns.ts +24 -0
  98. package/lib/tables/column-sets/vm-columns.ts +2 -3
  99. package/lib/tables/helpers/render-head-cell.ts +2 -4
  100. package/lib/tables/types.ts +0 -2
  101. package/lib/types/connection.ts +14 -0
  102. package/lib/types/state-hero.type.ts +19 -0
  103. package/lib/types/storage-repository.type.ts +14 -0
  104. package/lib/types/vue-virtual-scroller.d.ts +8 -2
  105. package/lib/utils/injection-keys.util.ts +1 -1
  106. package/lib/utils/sr.utils.ts +34 -0
  107. package/package.json +4 -4
@@ -0,0 +1,140 @@
1
+ <!-- v5 -->
2
+ <template>
3
+ <div class="vts-side-panel-sticky" :class="{ mobile: uiStore.isSmall }">
4
+ <VtsPanel
5
+ :closable="hasSelection"
6
+ :close-icon="uiStore.isSmall ? 'fa:angle-left' : 'action:close-cancel-clear'"
7
+ class="vts-side-panel"
8
+ :class="{
9
+ locked: panelStore.isLocked && !uiStore.isSmall,
10
+ mobile: uiStore.isSmall,
11
+ }"
12
+ @close="handleClose"
13
+ >
14
+ <template v-if="slots.actions" #actions>
15
+ <slot name="actions" />
16
+ </template>
17
+
18
+ <template v-if="slots['more-actions']" #more-actions>
19
+ <slot name="more-actions" />
20
+ </template>
21
+
22
+ <template v-if="slots['corner-actions'] || !uiStore.isSmall" #corner-actions>
23
+ <slot v-if="slots['corner-actions']" name="corner-actions" />
24
+ <UiButtonIcon
25
+ v-if="!uiStore.isSmall"
26
+ v-tooltip="{
27
+ content: panelStore.isLocked ? t('action:sidebar-unlock') : t('action:sidebar-lock'),
28
+ placement: 'left',
29
+ }"
30
+ accent="brand"
31
+ size="small"
32
+ :icon="panelStore.isLocked ? 'action:pin-panel-hide' : 'action:pin-panel'"
33
+ @click="panelStore.toggleLock()"
34
+ />
35
+ </template>
36
+
37
+ <VtsStateHero v-if="!hasSelection" format="panel" type="no-selection" size="medium" />
38
+ <slot v-else />
39
+ </VtsPanel>
40
+ </div>
41
+ </template>
42
+
43
+ <script setup lang="ts">
44
+ import VtsPanel from '@core/components/panel/VtsPanel.vue'
45
+ import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
46
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
47
+ import { vTooltip } from '@core/directives/tooltip.directive'
48
+ import { usePanelStore } from '@core/stores/panel.store'
49
+ import { useUiStore } from '@core/stores/ui.store'
50
+ import { watch } from 'vue'
51
+ import { useI18n } from 'vue-i18n'
52
+
53
+ const { hasSelection } = defineProps<{
54
+ hasSelection?: boolean
55
+ }>()
56
+
57
+ const emit = defineEmits<{
58
+ close: []
59
+ }>()
60
+
61
+ const slots = defineSlots<{
62
+ default(): any
63
+ actions?(): any
64
+ 'more-actions'?(): any
65
+ 'corner-actions'?(): any
66
+ }>()
67
+
68
+ const panelStore = usePanelStore()
69
+ const uiStore = useUiStore()
70
+
71
+ const { t } = useI18n()
72
+
73
+ watch(
74
+ [() => hasSelection, () => panelStore.isLocked, () => uiStore.isSmall],
75
+ ([hasSelection]) => {
76
+ if (hasSelection === undefined) {
77
+ return
78
+ }
79
+
80
+ panelStore.syncWithSelection(hasSelection)
81
+ },
82
+ { immediate: true }
83
+ )
84
+
85
+ function handleClose() {
86
+ if (panelStore.syncsOpenStateWithSelection) {
87
+ panelStore.collapse()
88
+ }
89
+
90
+ emit('close')
91
+ }
92
+ </script>
93
+
94
+ <style scoped lang="postcss">
95
+ .vts-side-panel-sticky:not(.mobile) {
96
+ position: sticky;
97
+ top: 0;
98
+ align-self: start;
99
+ }
100
+
101
+ .vts-side-panel {
102
+ width: var(--side-panel-width, 40rem);
103
+ transition: transform 0.25s;
104
+
105
+ &:not(.mobile) {
106
+ --panel-viewport-height: calc(100dvh - 5.6rem);
107
+ --panel-min-height: calc(100dvh - 16.6rem);
108
+
109
+ min-height: var(--panel-min-height);
110
+ max-height: var(--panel-viewport-height);
111
+ overflow: hidden;
112
+ transform: translateX(v-bind('panelStore.cssHorizontalOffset'));
113
+
114
+ :deep(> .content) {
115
+ flex: 1 1 auto;
116
+ min-height: 0;
117
+ overflow-y: auto;
118
+ }
119
+ }
120
+
121
+ &.mobile {
122
+ z-index: 1010;
123
+ position: fixed;
124
+ width: 100dvw;
125
+ height: 100dvh;
126
+ inset: 0;
127
+ transform: translateX(v-bind('panelStore.cssHorizontalOffset'));
128
+
129
+ :deep(.corner-actions) {
130
+ margin-inline-start: 0;
131
+ margin-inline-end: auto;
132
+ order: -1;
133
+ }
134
+
135
+ :deep(> .content) {
136
+ overflow: auto;
137
+ }
138
+ }
139
+ }
140
+ </style>
@@ -44,7 +44,6 @@ const uiStore = useUiStore()
44
44
  }
45
45
 
46
46
  &:deep(.modal) {
47
- background-color: var(--color-neutral-background-primary) !important;
48
47
  padding: 0;
49
48
  gap: 0;
50
49
 
@@ -24,6 +24,7 @@
24
24
  :placeholder="searchPlaceholder"
25
25
  right-icon="fa:magnifying-glass"
26
26
  accent="brand"
27
+ detached
27
28
  />
28
29
  </div>
29
30
  </template>
@@ -1,38 +1,34 @@
1
1
  <template>
2
- <div :class="[className, { horizontal, error, success, 'no-background': noBackground }]" class="vts-state-hero">
2
+ <div
3
+ :class="[className, { horizontal: isHorizontal, error, success, 'no-background': noBackground }]"
4
+ class="vts-state-hero"
5
+ >
3
6
  <UiLoader v-if="type === 'busy'" class="loader" />
4
7
  <img v-else-if="imageSrc" :src="imageSrc" :alt="type" class="image" />
5
- <div v-if="slots.default || success" :class="typoClass" class="content">
8
+ <div v-if="slots.default || success" :class="[typoClass, { mobile: isMobile }]" class="content">
6
9
  <div v-if="success">{{ t('all-good!') }}</div>
7
10
  <slot />
8
11
  </div>
12
+ <div v-else-if="type === 'no-selection'" :class="typoClass" class="content">
13
+ <I18nT keypath="select-to-see-details" scope="global" tag="p">
14
+ <template #icon>
15
+ <VtsIcon name="fa:eye" size="current" />
16
+ </template>
17
+ </I18nT>
18
+ </div>
9
19
  </div>
10
20
  </template>
11
21
 
12
22
  <script lang="ts" setup>
13
23
  import UiLoader from '@core/components/ui/loader/UiLoader.vue'
24
+ import { useUiStore } from '@core/stores/ui.store'
25
+ import type { StateHeroFormat, StateHeroSize, StateHeroType } from '@core/types/state-hero.type.ts'
14
26
  import { toVariants } from '@core/utils/to-variants.util.ts'
15
27
  import { computed } from 'vue'
16
28
  import { useI18n } from 'vue-i18n'
29
+ import VtsIcon from '../icon/VtsIcon.vue'
17
30
 
18
- export type StateHeroFormat = 'page' | 'card' | 'panel' | 'table'
19
-
20
- export type StateHeroSize = 'extra-small' | 'small' | 'medium' | 'large'
21
-
22
- export type StateHeroType =
23
- | 'busy'
24
- | 'no-result'
25
- | 'under-construction'
26
- | 'no-data'
27
- | 'no-selection'
28
- | 'error'
29
- | 'not-found'
30
- | 'offline'
31
- | 'all-good'
32
- | 'all-done'
33
- | 'creating'
34
-
35
- const { format, type, size } = defineProps<{
31
+ const { format, type, size, horizontal } = defineProps<{
36
32
  format: StateHeroFormat
37
33
  type: StateHeroType
38
34
  size: StateHeroSize
@@ -44,8 +40,14 @@ const slots = defineSlots<{
44
40
  default?(): any
45
41
  }>()
46
42
 
43
+ const uiStore = useUiStore()
44
+
47
45
  const { t } = useI18n()
48
46
 
47
+ const isHorizontal = computed(() => horizontal && !uiStore.isSmall)
48
+
49
+ const isMobile = computed(() => uiStore.isSmall)
50
+
49
51
  const typoClass = computed(() => (format === 'page' ? 'typo-h2' : 'typo-h4'))
50
52
 
51
53
  const className = computed(() => toVariants({ size, format }))
@@ -73,10 +75,6 @@ const imageSrc = computed(() => {
73
75
 
74
76
  &:not(.horizontal) {
75
77
  flex-direction: column;
76
-
77
- .content {
78
- align-items: center;
79
- }
80
78
  }
81
79
 
82
80
  .image {
@@ -88,6 +86,10 @@ const imageSrc = computed(() => {
88
86
  flex-direction: column;
89
87
  gap: 1.6rem;
90
88
 
89
+ &:not(.mobile) {
90
+ text-align: center;
91
+ }
92
+
91
93
  &:empty {
92
94
  display: none;
93
95
  }
@@ -16,9 +16,10 @@
16
16
  </template>
17
17
 
18
18
  <script lang="ts" setup>
19
- import VtsStateHero, { type StateHeroSize, type StateHeroType } from '@core/components/state-hero/VtsStateHero.vue'
19
+ import VtsStateHero from '@core/components/state-hero/VtsStateHero.vue'
20
20
  import UiTablePagination from '@core/components/ui/table-pagination/UiTablePagination.vue'
21
21
  import type { PaginationBindings } from '@core/composables/pagination.composable'
22
+ import type { StateHeroType, StateHeroSize } from '@core/types/state-hero.type.ts'
22
23
  import { hasEllipsis } from '@core/utils/has-ellipsis.util'
23
24
  import { toVariants } from '@core/utils/to-variants.util'
24
25
  import { useResizeObserver, useScroll } from '@vueuse/core'
@@ -9,6 +9,9 @@
9
9
  @click="emit('click')"
10
10
  />
11
11
  <VtsActionsMenu v-if="actions.length" :actions />
12
+ <VtsActionsMenu v-else>
13
+ <slot />
14
+ </VtsActionsMenu>
12
15
  </div>
13
16
  </UiTableCell>
14
17
  </template>
@@ -34,6 +37,10 @@ const {
34
37
  const emit = defineEmits<{
35
38
  click: []
36
39
  }>()
40
+
41
+ defineSlots<{
42
+ default(): any
43
+ }>()
37
44
  </script>
38
45
 
39
46
  <style scoped lang="postcss">
@@ -1,31 +1,15 @@
1
1
  <template>
2
2
  <UiColumnHeader class="vts-header-cell">
3
- <div class="cell-content">
4
- <VtsIcon v-if="icon" :name="icon" size="medium" />
5
- <slot />
6
- </div>
3
+ <slot />
7
4
  </UiColumnHeader>
8
5
  </template>
9
6
 
10
7
  <script lang="ts" setup>
11
- import VtsIcon from '@core/components/icon/VtsIcon.vue'
12
8
  import UiColumnHeader from '@core/components/ui/column-header/UiColumnHeader.vue'
13
- import type { IconName } from '@core/icons'
14
-
15
- defineProps<{
16
- icon?: IconName
17
- }>()
18
9
  </script>
19
10
 
20
11
  <style lang="postcss" scoped>
21
12
  .vts-header-cell {
22
13
  max-width: 30rem;
23
-
24
- .cell-content {
25
- display: flex;
26
- align-items: center;
27
- gap: 0.8rem;
28
- white-space: nowrap;
29
- }
30
14
  }
31
15
  </style>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <UiTableCell>
3
3
  <div class="vts-link-cell">
4
- <UiLink size="medium" :icon :to :href :target class="link">
4
+ <UiLink size="medium" :icon :busy :busy-tooltip :to :href :target class="link">
5
5
  <slot />
6
6
  <VtsIcon v-if="rightIcon" v-tooltip="rightIcon.tooltip ?? false" :name="rightIcon.icon" size="medium" />
7
7
  </UiLink>
@@ -21,6 +21,8 @@ import type { IconName } from '@core/icons'
21
21
 
22
22
  export type VtsLinkCellProps = LinkOptions & {
23
23
  icon?: IconName
24
+ busy?: boolean
25
+ busyTooltip?: string
24
26
  rightIcon?: {
25
27
  icon: IconName
26
28
  tooltip?: string
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <UiTableCell>
3
3
  <UiTagsList>
4
- <VtsTag v-for="tagItem of tags" :key="tagItem" :value="tagItem" />
4
+ <VtsTag v-for="tagItem of tags" :key="tagItem" :value="tagItem" :accent />
5
5
  </UiTagsList>
6
6
  </UiTableCell>
7
7
  </template>
@@ -9,13 +9,15 @@
9
9
  <script setup lang="ts">
10
10
  import VtsTag from '@core/components/tag/VtsTag.vue'
11
11
  import UiTableCell from '@core/components/ui/table-cell/UiTableCell.vue'
12
+ import type { TagAccent } from '@core/components/ui/tag/UiTag.vue'
12
13
  import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
13
14
  import type { MaybeArray } from '@core/types/utility.type'
14
15
  import { toArray } from '@core/utils/to-array.utils'
15
16
  import { computed } from 'vue'
16
17
 
17
- const { tag } = defineProps<{
18
+ const { tag, accent } = defineProps<{
18
19
  tag: MaybeArray<string>
20
+ accent: TagAccent
19
21
  }>()
20
22
 
21
23
  const tags = computed(() => toArray(tag).filter(tagItem => tagItem.trim() !== ''))
@@ -15,6 +15,7 @@ import { onBeforeMount, onBeforeUpdate, provide, ref, toRef, useSlots } from 'vu
15
15
  const props = defineProps<{
16
16
  nodeId?: TreeNodeId
17
17
  expanded?: boolean
18
+ hasChildren?: boolean
18
19
  }>()
19
20
 
20
21
  defineSlots<{
@@ -24,11 +25,16 @@ defineSlots<{
24
25
 
25
26
  const sidebar = useSidebarStore()
26
27
  const uiStore = useUiStore()
27
- const hasChildren = ref(false)
28
+ const hasChildrenState = ref(false)
28
29
 
29
30
  const updateHasChildren = () => {
31
+ if (props.hasChildren !== undefined) {
32
+ hasChildrenState.value = props.hasChildren
33
+ return
34
+ }
35
+
30
36
  const { sublist } = useSlots()
31
- hasChildren.value = sublist !== undefined
37
+ hasChildrenState.value = sublist !== undefined
32
38
  }
33
39
 
34
40
  const handleClick = () => {
@@ -40,6 +46,6 @@ const handleClick = () => {
40
46
  onBeforeMount(() => updateHasChildren())
41
47
  onBeforeUpdate(() => updateHasChildren())
42
48
 
43
- provide(IK_TREE_ITEM_HAS_CHILDREN, hasChildren)
49
+ provide(IK_TREE_ITEM_HAS_CHILDREN, hasChildrenState)
44
50
  provide(IK_TREE_ITEM_EXPANDED, toRef(props, 'expanded'))
45
51
  </script>
@@ -6,12 +6,15 @@
6
6
 
7
7
  <script lang="ts" setup>
8
8
  import { IK_TREE_LIST_DEPTH } from '@core/utils/injection-keys.util'
9
- import { inject, provide } from 'vue'
9
+ import { computed, inject, provide, ref } from 'vue'
10
10
 
11
11
  defineSlots<{
12
12
  default(): any
13
13
  }>()
14
14
 
15
- const depth = inject(IK_TREE_LIST_DEPTH, 0)
16
- provide(IK_TREE_LIST_DEPTH, depth + 1)
15
+ const depth = inject(IK_TREE_LIST_DEPTH, ref(0))
16
+ provide(
17
+ IK_TREE_LIST_DEPTH,
18
+ computed(() => depth.value + 1)
19
+ )
17
20
  </script>
@@ -3,7 +3,7 @@
3
3
  <div class="label-placeholder">
4
4
  <div class="link-placeholder">
5
5
  <template v-if="depth > 1">
6
- <VtsTreeLine v-for="i in depth - 1" :key="i" :right="i === depth - 1" full-height />
6
+ <VtsTreeLine v-for="i in depth - 1" :key="i" :right="i === depth - 1" />
7
7
  </template>
8
8
  <VtsIcon :name="icon" size="medium" />
9
9
  <div class="loader">&nbsp;</div>
@@ -17,13 +17,13 @@ import VtsIcon from '@core/components/icon/VtsIcon.vue'
17
17
  import VtsTreeLine from '@core/components/tree/VtsTreeLine.vue'
18
18
  import type { IconName } from '@core/icons'
19
19
  import { IK_TREE_LIST_DEPTH } from '@core/utils/injection-keys.util'
20
- import { inject } from 'vue'
20
+ import { inject, ref } from 'vue'
21
21
 
22
22
  defineProps<{
23
23
  icon: IconName
24
24
  }>()
25
25
 
26
- const depth = inject(IK_TREE_LIST_DEPTH, 0)
26
+ const depth = inject(IK_TREE_LIST_DEPTH, ref(0))
27
27
  </script>
28
28
 
29
29
  <style lang="postcss" scoped>
@@ -0,0 +1,123 @@
1
+ <template>
2
+ <Transition name="drawer" @after-leave="emit('afterLeave')">
3
+ <div v-if="isOpen" class="ui-drawer" aria-modal="true" role="dialog" @click.self="isDismissible && emit('dismiss')">
4
+ <aside class="drawer">
5
+ <div class="header">
6
+ <div v-if="slots.title || title !== undefined" class="typo-h4">
7
+ <slot name="title">
8
+ {{ title }}
9
+ </slot>
10
+ </div>
11
+ <UiButtonIcon
12
+ v-if="isDismissible"
13
+ :target-scale="2"
14
+ icon="action:close-cancel-clear"
15
+ accent="brand"
16
+ size="small"
17
+ @click="emit('dismiss')"
18
+ />
19
+ </div>
20
+ <div class="content">
21
+ <slot name="content" />
22
+ </div>
23
+ <VtsButtonGroup v-if="slots.buttons" no-stack class="buttons">
24
+ <slot name="buttons" />
25
+ </VtsButtonGroup>
26
+ </aside>
27
+ </div>
28
+ </Transition>
29
+ </template>
30
+
31
+ <script lang="ts" setup>
32
+ import VtsButtonGroup from '@core/components/button-group/VtsButtonGroup.vue'
33
+ import UiButtonIcon from '@core/components/ui/button-icon/UiButtonIcon.vue'
34
+
35
+ defineProps<{
36
+ isOpen: boolean
37
+ isDismissible?: boolean
38
+ title?: string
39
+ }>()
40
+
41
+ const emit = defineEmits<{
42
+ dismiss: []
43
+ afterLeave: []
44
+ }>()
45
+
46
+ const slots = defineSlots<{
47
+ content(): any
48
+ title?(): any
49
+ buttons?(): any
50
+ }>()
51
+ </script>
52
+
53
+ <style lang="postcss" scoped>
54
+ /* Slide-in from right */
55
+ .drawer-enter-active.ui-drawer,
56
+ .drawer-leave-active.ui-drawer {
57
+ transition: opacity 0.3s ease;
58
+ }
59
+
60
+ .drawer-enter-active .drawer,
61
+ .drawer-leave-active .drawer {
62
+ transition: transform 0.3s ease;
63
+ }
64
+
65
+ .drawer-enter-from.ui-drawer,
66
+ .drawer-leave-to.ui-drawer {
67
+ opacity: 0;
68
+ }
69
+
70
+ .drawer-enter-from .drawer,
71
+ .drawer-leave-to .drawer {
72
+ transform: translateX(100%);
73
+
74
+ &:dir(rtl) {
75
+ transform: translateX(-100%);
76
+ }
77
+ }
78
+
79
+ .ui-drawer {
80
+ position: fixed;
81
+ display: flex;
82
+ inset: 0;
83
+ justify-content: flex-end;
84
+ align-items: stretch;
85
+
86
+ .drawer {
87
+ display: flex;
88
+ flex-direction: column;
89
+ min-width: 100%;
90
+ max-width: 100%;
91
+ min-height: 100dvh;
92
+ background-color: var(--color-neutral-background-secondary);
93
+
94
+ .header {
95
+ display: flex;
96
+ justify-content: space-between;
97
+ align-items: center;
98
+ padding: 1.6rem;
99
+ background-color: var(--color-neutral-background-primary);
100
+ border-block-end: 0.1rem solid var(--color-neutral-border);
101
+ }
102
+
103
+ .content {
104
+ overflow: auto;
105
+ flex: 1;
106
+ padding: 2.4rem;
107
+ }
108
+
109
+ .buttons {
110
+ margin-block-start: auto;
111
+ padding: 1.6rem;
112
+ background-color: var(--color-neutral-background-primary);
113
+ border-block-start: 0.1rem solid var(--color-neutral-border);
114
+ }
115
+
116
+ @media (--medium-or-large) {
117
+ min-width: 50%;
118
+ max-width: 50%;
119
+ border-inline-start: 0.1rem solid var(--color-neutral-border);
120
+ }
121
+ }
122
+ }
123
+ </style>
@@ -37,7 +37,7 @@ const slots = defineSlots<{
37
37
 
38
38
  <style lang="postcss" scoped>
39
39
  .ui-head-bar {
40
- min-height: 5.6rem;
40
+ min-height: 6rem;
41
41
  padding: 0.8rem 1.6rem;
42
42
  display: flex;
43
43
  gap: 1.6rem;
@@ -52,12 +52,14 @@ const {
52
52
  required,
53
53
  disabled,
54
54
  id,
55
+ detached,
55
56
  } = defineProps<{
56
57
  accent: InputAccent
57
58
  id?: string
58
59
  required?: boolean
59
60
  disabled?: boolean
60
61
  readonly?: boolean
62
+ detached?: boolean
61
63
  type?: InputType
62
64
  icon?: IconName
63
65
  rightIcon?: IconName
@@ -82,7 +84,7 @@ const attrs = useAttrs()
82
84
 
83
85
  const inputRef = ref<HTMLInputElement>()
84
86
 
85
- const wrapperController = inject(IK_INPUT_WRAPPER_CONTROLLER, undefined)
87
+ const wrapperController = detached ? undefined : inject(IK_INPUT_WRAPPER_CONTROLLER, undefined)
86
88
 
87
89
  const accent = useMapper<LabelAccent, InputAccent>(
88
90
  () => wrapperController?.labelAccent,
@@ -1,7 +1,7 @@
1
1
  <!-- v6 -->
2
2
  <template>
3
3
  <component :is="component" :class="classes" class="ui-link" v-bind="attributes">
4
- <VtsIcon :name="icon" size="medium" />
4
+ <VtsIcon :name="icon" :busy :busy-tooltip size="medium" />
5
5
  <slot />
6
6
  <VtsIcon v-if="attributes.target === '_blank'" name="action:open-in-new-tab" size="medium" class="external-icon" />
7
7
  <VtsIcon v-if="isPrimary" v-tooltip="primaryTooltip" name="status:primary-circle" size="medium" />
@@ -19,6 +19,8 @@ const props = defineProps<
19
19
  LinkOptions & {
20
20
  size: 'small' | 'medium'
21
21
  icon?: IconName
22
+ busy?: boolean
23
+ busyTooltip?: string
22
24
  isPrimary?: boolean
23
25
  primaryTooltip?: string
24
26
  }