@xen-orchestra/web-core 0.0.3 → 0.0.5
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/env.d.ts +0 -1
- package/lib/assets/css/_typography.pcss +1 -0
- package/lib/assets/css/typography/_utils.pcss +6 -0
- package/lib/components/LegendTitle.vue +9 -7
- package/lib/components/UiTag.vue +3 -7
- package/lib/components/backdrop/Backdrop.vue +11 -0
- package/lib/components/cell-object/CellObject.vue +54 -0
- package/lib/components/cell-text/CellText.vue +40 -0
- package/lib/components/chip/UiChip.vue +3 -4
- package/lib/components/console/RemoteConsole.vue +1 -1
- package/lib/components/divider/Divider.vue +25 -0
- package/lib/components/{DonutChart.vue → donut-chart/DonutChart.vue} +28 -24
- package/lib/components/donut-chart-with-legend/DonutChartWithLegend.vue +27 -0
- package/lib/components/dropdown/DropdownItem.vue +1 -4
- package/lib/components/head-bar/HeadBar.vue +78 -0
- package/lib/components/input/UiInput.vue +133 -0
- package/lib/components/legend/LegendGroup.vue +44 -0
- package/lib/components/{UiLegend.vue → legend/LegendItem.vue} +35 -17
- package/lib/components/legend/LegendList.vue +19 -0
- package/lib/components/object-link/ObjectLink.vue +87 -0
- package/lib/components/search-bar/SearchBar.vue +60 -0
- package/lib/components/stacked-bar/StackedBarSegment.vue +2 -8
- package/lib/components/state-hero/ComingSoonHero.vue +6 -2
- package/lib/components/state-hero/LoadingHero.vue +8 -2
- package/lib/components/state-hero/ObjectNotFoundHero.vue +1 -1
- package/lib/components/state-hero/StateHero.vue +27 -9
- package/lib/components/tab/TabList.vue +1 -0
- package/lib/components/table/UiTable.vue +6 -0
- package/lib/components/task/QuickTaskButton.vue +62 -0
- package/lib/components/task/QuickTaskItem.vue +91 -0
- package/lib/components/task/QuickTaskList.vue +48 -0
- package/lib/components/task/QuickTaskPanel.vue +65 -0
- package/lib/components/task/QuickTaskTabBar.vue +46 -0
- package/lib/components/tree/TreeItem.vue +8 -8
- package/lib/components/tree/TreeItemLabel.vue +28 -16
- package/lib/composables/item-counter.composable.md +25 -0
- package/lib/composables/item-counter.composable.ts +32 -0
- package/lib/composables/tab-list.composable.ts +33 -0
- package/lib/composables/tree/branch.ts +5 -5
- package/lib/i18n.ts +53 -0
- package/lib/layouts/CoreLayout.vue +2 -11
- package/lib/locales/de.json +7 -1
- package/lib/locales/en.json +23 -1
- package/lib/locales/fa.json +46 -0
- package/lib/locales/fr.json +23 -1
- package/lib/types/novnc.d.ts +342 -0
- package/lib/types/tab.type.ts +17 -0
- package/lib/types/task.type.ts +13 -0
- package/lib/types/utility.type.ts +1 -1
- package/lib/utils/if-else.utils.ts +3 -3
- package/lib/utils/open-url.utils.ts +3 -0
- package/package.json +3 -3
- package/lib/components/UiSeparator.vue +0 -11
package/env.d.ts
CHANGED
|
@@ -2,18 +2,24 @@
|
|
|
2
2
|
<template>
|
|
3
3
|
<div class="legend-title typo c3-semi-bold">
|
|
4
4
|
<slot />
|
|
5
|
-
<UiIcon v-tooltip="iconTooltip ?? false" :icon color="info"
|
|
5
|
+
<UiIcon v-tooltip="iconTooltip ?? false" :icon color="info" />
|
|
6
6
|
</div>
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
|
-
<script
|
|
9
|
+
<script lang="ts" setup>
|
|
10
10
|
import UiIcon from '@core/components/icon/UiIcon.vue'
|
|
11
11
|
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
12
12
|
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
export type LegendTitleProps = {
|
|
15
15
|
iconTooltip?: string
|
|
16
16
|
icon?: IconDefinition
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
defineProps<LegendTitleProps>()
|
|
20
|
+
|
|
21
|
+
defineSlots<{
|
|
22
|
+
default(): void
|
|
17
23
|
}>()
|
|
18
24
|
</script>
|
|
19
25
|
|
|
@@ -24,8 +30,4 @@ defineProps<{
|
|
|
24
30
|
gap: 0.8rem;
|
|
25
31
|
align-items: center;
|
|
26
32
|
}
|
|
27
|
-
|
|
28
|
-
.tooltip-icon {
|
|
29
|
-
font-size: 1.2rem;
|
|
30
|
-
}
|
|
31
33
|
</style>
|
package/lib/components/UiTag.vue
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<slot name="icon">
|
|
5
5
|
<UiIcon :icon fixed-width />
|
|
6
6
|
</slot>
|
|
7
|
-
<span class="
|
|
7
|
+
<span class="text-ellipsis"><slot /></span>
|
|
8
8
|
</span>
|
|
9
9
|
</template>
|
|
10
10
|
|
|
@@ -78,7 +78,7 @@ withDefaults(
|
|
|
78
78
|
|
|
79
79
|
/* IMPLEMENTATION */
|
|
80
80
|
.ui-tag {
|
|
81
|
-
display:
|
|
81
|
+
display: flex;
|
|
82
82
|
justify-content: center;
|
|
83
83
|
align-items: center;
|
|
84
84
|
gap: 0.8rem;
|
|
@@ -88,10 +88,6 @@ withDefaults(
|
|
|
88
88
|
padding: 0.2rem 0.8rem;
|
|
89
89
|
border-radius: 0.4rem;
|
|
90
90
|
vertical-align: middle;
|
|
91
|
-
|
|
92
|
-
.content {
|
|
93
|
-
overflow: hidden;
|
|
94
|
-
text-overflow: ellipsis;
|
|
95
|
-
}
|
|
91
|
+
min-width: 0;
|
|
96
92
|
}
|
|
97
93
|
</style>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!-- v1.0 -->
|
|
2
|
+
<template>
|
|
3
|
+
<td class="cell-object">
|
|
4
|
+
<div class="data">
|
|
5
|
+
<slot />
|
|
6
|
+
<template v-if="id !== undefined">
|
|
7
|
+
<span v-tooltip class="id typo p4-regular-italic text-ellipsis">
|
|
8
|
+
{{ id }}
|
|
9
|
+
</span>
|
|
10
|
+
<UiButton
|
|
11
|
+
v-if="isSupported && copiableId"
|
|
12
|
+
:left-icon="faCopy"
|
|
13
|
+
level="secondary"
|
|
14
|
+
size="extra-small"
|
|
15
|
+
:color="copied ? 'success' : 'info'"
|
|
16
|
+
@click="copy(id)"
|
|
17
|
+
>
|
|
18
|
+
{{ copied ? $t('core.copied') : $t('core.copy-id') }}
|
|
19
|
+
</UiButton>
|
|
20
|
+
</template>
|
|
21
|
+
</div>
|
|
22
|
+
</td>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script lang="ts" setup>
|
|
26
|
+
import UiButton from '@core/components/button/UiButton.vue'
|
|
27
|
+
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
28
|
+
import { faCopy } from '@fortawesome/free-solid-svg-icons'
|
|
29
|
+
import { useClipboard } from '@vueuse/core'
|
|
30
|
+
|
|
31
|
+
defineProps<{
|
|
32
|
+
id?: string
|
|
33
|
+
copiableId?: boolean
|
|
34
|
+
}>()
|
|
35
|
+
|
|
36
|
+
const { isSupported, copy, copied } = useClipboard()
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<style lang="postcss" scoped>
|
|
40
|
+
.cell-object {
|
|
41
|
+
padding: 0.8rem;
|
|
42
|
+
border: 0.1rem solid var(--color-grey-500);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.data {
|
|
46
|
+
display: flex;
|
|
47
|
+
gap: 1.6rem;
|
|
48
|
+
align-items: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.id {
|
|
52
|
+
color: var(--color-grey-300);
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!-- v1.0 -->
|
|
2
|
+
<template>
|
|
3
|
+
<td class="cell-text">
|
|
4
|
+
<div class="data typo p2-regular">
|
|
5
|
+
<span v-tooltip class="text-ellipsis">
|
|
6
|
+
<slot />
|
|
7
|
+
</span>
|
|
8
|
+
<span v-if="slots.secondary" class="info typo p4-regular">
|
|
9
|
+
<slot name="secondary" />
|
|
10
|
+
</span>
|
|
11
|
+
</div>
|
|
12
|
+
</td>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script lang="ts" setup>
|
|
16
|
+
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
17
|
+
|
|
18
|
+
const slots = defineSlots<{
|
|
19
|
+
default: () => any
|
|
20
|
+
secondary?: () => any
|
|
21
|
+
}>()
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<style lang="postcss" scoped>
|
|
25
|
+
.cell-text {
|
|
26
|
+
padding: 0.8rem;
|
|
27
|
+
border: 0.1rem solid var(--color-grey-500);
|
|
28
|
+
color: var(--color-grey-000);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.data {
|
|
32
|
+
display: flex;
|
|
33
|
+
gap: 1.6rem;
|
|
34
|
+
align-items: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.info {
|
|
38
|
+
color: var(--color-grey-300);
|
|
39
|
+
}
|
|
40
|
+
</style>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<template>
|
|
3
3
|
<span :class="[color, { disabled }]" class="ui-chip typo p3-regular" @click="emit('edit')">
|
|
4
4
|
<ChipIcon :color :disabled :icon />
|
|
5
|
-
<span class="content">
|
|
5
|
+
<span class="content text-ellipsis">
|
|
6
6
|
<slot />
|
|
7
7
|
</span>
|
|
8
8
|
<ChipRemoveIcon v-if="!disabled" :color @click.stop="emit('remove')" />
|
|
@@ -113,7 +113,7 @@ const emit = defineEmits<{
|
|
|
113
113
|
|
|
114
114
|
/* IMPLEMENTATION */
|
|
115
115
|
.ui-chip {
|
|
116
|
-
display:
|
|
116
|
+
display: flex;
|
|
117
117
|
align-items: center;
|
|
118
118
|
gap: 0.8rem;
|
|
119
119
|
padding: 0.4rem 0.8rem;
|
|
@@ -124,6 +124,7 @@ const emit = defineEmits<{
|
|
|
124
124
|
min-height: 2.4rem;
|
|
125
125
|
vertical-align: middle;
|
|
126
126
|
white-space: nowrap;
|
|
127
|
+
min-width: 0;
|
|
127
128
|
|
|
128
129
|
&.disabled {
|
|
129
130
|
pointer-events: none;
|
|
@@ -131,8 +132,6 @@ const emit = defineEmits<{
|
|
|
131
132
|
|
|
132
133
|
.content {
|
|
133
134
|
line-height: 1.6rem;
|
|
134
|
-
overflow: hidden;
|
|
135
|
-
text-overflow: ellipsis;
|
|
136
135
|
}
|
|
137
136
|
}
|
|
138
137
|
</style>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<script lang="ts" setup>
|
|
8
8
|
import { useUiStore } from '@core/stores/ui.store'
|
|
9
|
-
import VncClient from '@novnc/novnc/
|
|
9
|
+
import VncClient from '@novnc/novnc/lib/rfb'
|
|
10
10
|
import { promiseTimeout } from '@vueuse/shared'
|
|
11
11
|
import { fibonacci } from 'iterable-backoff'
|
|
12
12
|
import { onBeforeUnmount, ref, watchEffect } from 'vue'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="vts-divider" :class="type" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script setup lang="ts">
|
|
6
|
+
defineProps<{
|
|
7
|
+
type: 'stretch' | 'tab'
|
|
8
|
+
}>()
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<style scoped lang="postcss">
|
|
12
|
+
.vts-divider {
|
|
13
|
+
border-left: 0.1rem solid var(--color-grey-500);
|
|
14
|
+
border-bottom: 0.1rem solid var(--color-grey-500);
|
|
15
|
+
|
|
16
|
+
&.tab {
|
|
17
|
+
height: 2.4rem;
|
|
18
|
+
align-self: center;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&.stretch {
|
|
22
|
+
align-self: stretch;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
</style>
|
|
@@ -17,51 +17,47 @@
|
|
|
17
17
|
</svg>
|
|
18
18
|
</template>
|
|
19
19
|
|
|
20
|
-
<script
|
|
20
|
+
<script lang="ts" setup>
|
|
21
21
|
import UiIcon from '@core/components/icon/UiIcon.vue'
|
|
22
22
|
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
23
23
|
import { computed } from 'vue'
|
|
24
24
|
|
|
25
|
-
type
|
|
25
|
+
export type DonutSegmentColor = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'disabled'
|
|
26
|
+
|
|
27
|
+
export type DonutSegment = {
|
|
26
28
|
value: number
|
|
27
|
-
color:
|
|
29
|
+
color: DonutSegmentColor
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
type
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
offset: number
|
|
32
|
+
export type DonutChartProps = {
|
|
33
|
+
segments: DonutSegment[]
|
|
34
|
+
icon?: IconDefinition
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
const props = defineProps<
|
|
37
|
-
segments: Segment[]
|
|
38
|
-
maxValue?: number
|
|
39
|
-
icon?: IconDefinition
|
|
40
|
-
}>()
|
|
37
|
+
const props = defineProps<DonutChartProps>()
|
|
41
38
|
|
|
42
39
|
const circumference = Math.PI * 80
|
|
43
40
|
|
|
44
|
-
const totalValue = computed(() =>
|
|
45
|
-
const sumOfValues = props.segments.reduce((acc, segment) => acc + segment.value, 0)
|
|
46
|
-
return Math.max(props.maxValue ?? 0, sumOfValues)
|
|
47
|
-
})
|
|
41
|
+
const totalValue = computed(() => props.segments.reduce((total, segment) => total + segment.value, 0))
|
|
48
42
|
|
|
49
|
-
const computedSegments = computed
|
|
43
|
+
const computedSegments = computed(() => {
|
|
50
44
|
let nextOffset = circumference / 4
|
|
45
|
+
|
|
51
46
|
return props.segments.map(segment => {
|
|
47
|
+
const offset = nextOffset
|
|
52
48
|
const percent = (segment.value / totalValue.value) * circumference
|
|
53
|
-
|
|
49
|
+
nextOffset -= percent
|
|
50
|
+
|
|
51
|
+
return {
|
|
54
52
|
color: segment.color,
|
|
55
53
|
percent,
|
|
56
|
-
offset
|
|
54
|
+
offset,
|
|
57
55
|
}
|
|
58
|
-
nextOffset -= percent
|
|
59
|
-
return currentSegment
|
|
60
56
|
})
|
|
61
57
|
})
|
|
62
58
|
</script>
|
|
63
59
|
|
|
64
|
-
<style
|
|
60
|
+
<style lang="postcss" scoped>
|
|
65
61
|
.donut-chart {
|
|
66
62
|
width: 100px;
|
|
67
63
|
height: 100px;
|
|
@@ -73,6 +69,14 @@ const computedSegments = computed<ComputedSegment[]>(() => {
|
|
|
73
69
|
fill: transparent;
|
|
74
70
|
--stroke-color: var(--color-grey-100);
|
|
75
71
|
|
|
72
|
+
&.primary {
|
|
73
|
+
--stroke-color: var(--color-purple-base);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&.secondary {
|
|
77
|
+
--stroke-color: var(--color-grey-100);
|
|
78
|
+
}
|
|
79
|
+
|
|
76
80
|
&.success {
|
|
77
81
|
--stroke-color: var(--color-green-base);
|
|
78
82
|
}
|
|
@@ -81,11 +85,11 @@ const computedSegments = computed<ComputedSegment[]>(() => {
|
|
|
81
85
|
--stroke-color: var(--color-orange-base);
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
&.
|
|
88
|
+
&.danger {
|
|
85
89
|
--stroke-color: var(--color-red-base);
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
&.
|
|
92
|
+
&.disabled {
|
|
89
93
|
--stroke-color: var(--color-grey-400);
|
|
90
94
|
}
|
|
91
95
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="donut-chart-with-legend">
|
|
3
|
+
<DonutChart :icon :segments />
|
|
4
|
+
<LegendGroup :items="segments" :title />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import DonutChart, { type DonutChartProps } from '@core/components/donut-chart/DonutChart.vue'
|
|
10
|
+
import LegendGroup, { type LegendGroupProps } from '@core/components/legend/LegendGroup.vue'
|
|
11
|
+
|
|
12
|
+
export type DonutChartWithLegendProps = {
|
|
13
|
+
segments: (DonutChartProps['segments'][number] & LegendGroupProps['items'][number])[]
|
|
14
|
+
title?: LegendGroupProps['title']
|
|
15
|
+
icon?: DonutChartProps['icon']
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
defineProps<DonutChartWithLegendProps>()
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<style lang="postcss" scoped>
|
|
22
|
+
.donut-chart-with-legend {
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: 3.2rem;
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<slot name="icon">
|
|
5
5
|
<UiIcon :icon />
|
|
6
6
|
</slot>
|
|
7
|
-
<div class="label p2 medium">
|
|
7
|
+
<div class="label p2 medium text-ellipsis">
|
|
8
8
|
<slot />
|
|
9
9
|
</div>
|
|
10
10
|
<div v-if="info" class="info-text p3 italic">{{ info }}</div>
|
|
@@ -181,9 +181,6 @@ const checkbox = inject(
|
|
|
181
181
|
|
|
182
182
|
.label {
|
|
183
183
|
margin-right: auto;
|
|
184
|
-
white-space: nowrap;
|
|
185
|
-
overflow: hidden;
|
|
186
|
-
text-overflow: ellipsis;
|
|
187
184
|
}
|
|
188
185
|
|
|
189
186
|
.info-text {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<!-- v1.0 -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="head-bar">
|
|
4
|
+
<div class="label-wrapper">
|
|
5
|
+
<span v-if="slots.icon || icon" class="icon">
|
|
6
|
+
<slot name="icon">
|
|
7
|
+
<UiIcon :icon />
|
|
8
|
+
</slot>
|
|
9
|
+
</span>
|
|
10
|
+
<h4 v-tooltip class="typo h4-medium label text-ellipsis">
|
|
11
|
+
<slot />
|
|
12
|
+
</h4>
|
|
13
|
+
</div>
|
|
14
|
+
<div v-if="slots.status" class="status typo c3-regular">
|
|
15
|
+
<slot name="status" />
|
|
16
|
+
</div>
|
|
17
|
+
<div v-if="slots.actions" class="actions">
|
|
18
|
+
<slot name="actions" />
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script lang="ts" setup>
|
|
24
|
+
import UiIcon from '@core/components/icon/UiIcon.vue'
|
|
25
|
+
import { vTooltip } from '@core/directives/tooltip.directive'
|
|
26
|
+
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
27
|
+
|
|
28
|
+
defineProps<{
|
|
29
|
+
icon?: IconDefinition
|
|
30
|
+
}>()
|
|
31
|
+
|
|
32
|
+
const slots = defineSlots<{
|
|
33
|
+
default: () => any
|
|
34
|
+
icon?: () => any
|
|
35
|
+
status?: () => any
|
|
36
|
+
actions?: () => any
|
|
37
|
+
}>()
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<style lang="postcss" scoped>
|
|
41
|
+
.head-bar {
|
|
42
|
+
padding: 0.8rem 1.6rem;
|
|
43
|
+
display: flex;
|
|
44
|
+
gap: 4.8rem;
|
|
45
|
+
align-items: center;
|
|
46
|
+
border-bottom: 0.1rem solid var(--color-grey-500);
|
|
47
|
+
background-color: var(--background-color-primary);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.label-wrapper {
|
|
51
|
+
display: flex;
|
|
52
|
+
gap: 1.6rem;
|
|
53
|
+
align-items: center;
|
|
54
|
+
min-width: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.label {
|
|
58
|
+
color: var(--color-grey-100);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.icon {
|
|
62
|
+
font-size: 2.4rem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.status {
|
|
66
|
+
color: var(--color-grey-200);
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 1.6rem;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.actions {
|
|
73
|
+
margin-inline-start: auto;
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: 0.8rem;
|
|
77
|
+
}
|
|
78
|
+
</style>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<!-- WIP -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="ui-input">
|
|
4
|
+
<UiIcon :icon class="before" />
|
|
5
|
+
<input :id v-model.trim="modelValue" class="typo p1-regular input" type="search" v-bind="$attrs" />
|
|
6
|
+
<UiIcon v-if="!$attrs.disabled && modelValue" :icon="faXmark" class="after" color="info" @click="modelValue = ''" />
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script lang="ts" setup>
|
|
11
|
+
import UiIcon from '@core/components/icon/UiIcon.vue'
|
|
12
|
+
import { uniqueId } from '@core/utils/unique-id.util'
|
|
13
|
+
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
14
|
+
import { faXmark } from '@fortawesome/free-solid-svg-icons'
|
|
15
|
+
import { computed } from 'vue'
|
|
16
|
+
|
|
17
|
+
defineOptions({
|
|
18
|
+
inheritAttrs: false,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
defineProps<{
|
|
22
|
+
icon?: IconDefinition
|
|
23
|
+
}>()
|
|
24
|
+
|
|
25
|
+
const modelValue = defineModel<string>({ required: true })
|
|
26
|
+
|
|
27
|
+
const id = computed(() => uniqueId('input-'))
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<style lang="postcss" scoped>
|
|
31
|
+
/* COLOR VARIANTS */
|
|
32
|
+
.input {
|
|
33
|
+
& {
|
|
34
|
+
--border-color: var(--color-grey-500);
|
|
35
|
+
--background-color: var(--background-color-primary);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&:is(:hover, :focus-visible) {
|
|
39
|
+
--border-color: var(--color-purple-d20);
|
|
40
|
+
--background-color: var(--background-color-primary);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&:focus {
|
|
44
|
+
--border-color: var(--color-purple-base);
|
|
45
|
+
--background-color: var(--background-color-primary);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&:active {
|
|
49
|
+
--border-color: var(--color-purple-d40);
|
|
50
|
+
--background-color: var(--background-color-primary);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&:disabled {
|
|
54
|
+
--border-color: var(--color-grey-500);
|
|
55
|
+
--background-color: var(--background-color-secondary);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* BORDER VARIANTS */
|
|
60
|
+
.input {
|
|
61
|
+
--border-width: 0.1rem;
|
|
62
|
+
|
|
63
|
+
&:is(:hover, :focus-visible) {
|
|
64
|
+
--border-width: 0.1rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&:focus {
|
|
68
|
+
--border-width: 0.2rem;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&:active {
|
|
72
|
+
--border-width: 0.1rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
&:disabled {
|
|
76
|
+
--border-width: 0.1rem;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* IMPLEMENTATION */
|
|
81
|
+
.ui-input {
|
|
82
|
+
position: relative;
|
|
83
|
+
|
|
84
|
+
.before + .input {
|
|
85
|
+
padding-inline-start: 4.8rem;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.input {
|
|
90
|
+
border: var(--border-width) solid var(--border-color);
|
|
91
|
+
border-radius: 0.8rem;
|
|
92
|
+
outline: none;
|
|
93
|
+
width: 100%;
|
|
94
|
+
height: 4rem;
|
|
95
|
+
padding: 0.8rem 1.6rem;
|
|
96
|
+
color: var(--color-grey-000);
|
|
97
|
+
background-color: var(--background-color);
|
|
98
|
+
|
|
99
|
+
&:has(+ .after) {
|
|
100
|
+
padding-inline-end: 4.8rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&:disabled {
|
|
104
|
+
cursor: not-allowed;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&::placeholder {
|
|
108
|
+
color: var(--color-grey-300);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&[type='search']::-webkit-search-cancel-button {
|
|
112
|
+
display: none;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.before,
|
|
117
|
+
.after {
|
|
118
|
+
position: absolute;
|
|
119
|
+
inset-block: 1.2rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.before {
|
|
123
|
+
color: var(--color-grey-400);
|
|
124
|
+
inset-inline-start: 1.6rem;
|
|
125
|
+
pointer-events: none;
|
|
126
|
+
z-index: 1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.after {
|
|
130
|
+
inset-inline-end: 1.6rem;
|
|
131
|
+
cursor: pointer;
|
|
132
|
+
}
|
|
133
|
+
</style>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="legend-group">
|
|
3
|
+
<LegendTitle v-if="title" :icon="title.icon" :icon-tooltip="title.iconTooltip">
|
|
4
|
+
{{ title.label }}
|
|
5
|
+
</LegendTitle>
|
|
6
|
+
<LegendList class="list">
|
|
7
|
+
<LegendItem
|
|
8
|
+
v-for="item in items"
|
|
9
|
+
:key="item.label"
|
|
10
|
+
:color="item.color"
|
|
11
|
+
:tooltip="item.tooltip"
|
|
12
|
+
:unit="item.unit"
|
|
13
|
+
:value="item.value"
|
|
14
|
+
>
|
|
15
|
+
{{ item.label }}
|
|
16
|
+
</LegendItem>
|
|
17
|
+
</LegendList>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script lang="ts" setup>
|
|
22
|
+
import LegendItem, { type LegendItemProps } from '@core/components/legend/LegendItem.vue'
|
|
23
|
+
import LegendList from '@core/components/legend/LegendList.vue'
|
|
24
|
+
import LegendTitle, { type LegendTitleProps } from '@core/components/LegendTitle.vue'
|
|
25
|
+
|
|
26
|
+
export type LegendGroupProps = {
|
|
27
|
+
items: (LegendItemProps & { label: string })[]
|
|
28
|
+
title?: LegendTitleProps & { label: string }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
defineProps<LegendGroupProps>()
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<style lang="postcss" scoped>
|
|
35
|
+
.legend-group {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
gap: 0.8rem;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.list {
|
|
42
|
+
padding-left: 1.6rem;
|
|
43
|
+
}
|
|
44
|
+
</style>
|