@xen-orchestra/web-core 0.20.1 → 0.21.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/lib/components/backup-state/VtsBackupState.vue +20 -17
- package/lib/components/cell-object/VtsCellObject.vue +4 -1
- package/lib/components/console/VtsActionsConsole.vue +7 -4
- package/lib/components/console/VtsClipboardConsole.vue +9 -6
- package/lib/components/copy-button/VtsCopyButton.vue +7 -14
- package/lib/components/dropdown/DropdownTitle.vue +5 -2
- package/lib/components/icon/NewVtsIcon.vue +49 -0
- package/lib/components/input-group/VtsInputGroup.vue +41 -0
- package/lib/components/input-wrapper/VtsInputWrapper.vue +2 -2
- package/lib/components/layout/VtsLayoutSidebar.vue +6 -3
- package/lib/components/linear-chart/VtsLinearChart.vue +4 -0
- package/lib/components/object-icon/VtsObjectIcon.vue +22 -0
- package/lib/components/quick-info-card/VtsQuickInfoCard.vue +4 -1
- package/lib/components/select/VtsOption.vue +10 -6
- package/lib/components/select/VtsSelect.vue +74 -50
- package/lib/components/state-hero/VtsAllDoneHero.vue +4 -1
- package/lib/components/state-hero/VtsAllGoodHero.vue +4 -1
- package/lib/components/state-hero/VtsComingSoonHero.vue +4 -1
- package/lib/components/state-hero/VtsErrorNoDataHero.vue +4 -1
- package/lib/components/state-hero/VtsLoadingHero.vue +4 -1
- package/lib/components/state-hero/VtsNoDataHero.vue +4 -1
- package/lib/components/state-hero/VtsNoSelectionHero.vue +4 -1
- package/lib/components/state-hero/VtsObjectNotFoundHero.vue +4 -1
- package/lib/components/state-hero/VtsOfflineHero.vue +4 -1
- package/lib/components/state-hero/VtsPageNotFoundHero.vue +4 -1
- package/lib/components/table/ColumnTitle.vue +2 -2
- package/lib/components/task/VtsQuickTaskButton.vue +4 -1
- package/lib/components/task/VtsQuickTaskList.vue +5 -2
- package/lib/components/task/VtsQuickTaskTabBar.vue +8 -5
- package/lib/components/ui/card-numbers/UiCardNumbers.vue +4 -1
- package/lib/components/ui/character-limit/UiCharacterLimit.vue +4 -1
- package/lib/components/ui/input/UiInput.vue +2 -2
- package/lib/components/ui/label/UiLabel.vue +4 -1
- package/lib/components/ui/progress-bar/UiProgressBar.vue +5 -2
- package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +9 -6
- package/lib/components/ui/quick-task-item/UiQuickTaskItem.vue +6 -3
- package/lib/components/ui/stacked-bar/StackedBarSegment.vue +4 -1
- package/lib/components/ui/table-pagination/UiTablePagination.vue +6 -3
- package/lib/components/ui/text-area/UiTextarea.vue +4 -1
- package/lib/components/ui/top-bottom-table/UiTopBottomTable.vue +6 -3
- package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +4 -1
- package/lib/composables/local-time-ago.composable.ts +53 -0
- package/lib/composables/locale-time-ago.composable.ts +53 -0
- package/lib/icons/fa-icons.ts +164 -0
- package/lib/icons/index.ts +15 -0
- package/lib/icons/legacy-icons.ts +80 -0
- package/lib/icons/object-icons.ts +187 -0
- package/lib/layouts/CoreLayout.vue +7 -3
- package/lib/locales/cs.json +0 -1
- package/lib/locales/de.json +1 -1
- package/lib/locales/en.json +32 -4
- package/lib/locales/es.json +1 -1
- package/lib/locales/fr.json +31 -3
- package/lib/locales/it.json +1 -1
- package/lib/locales/nl.json +1 -1
- package/lib/locales/ru.json +1 -1
- package/lib/locales/sv.json +1 -2
- package/lib/packages/collection/README.md +23 -18
- package/lib/packages/collection/create-collection.ts +22 -21
- package/lib/packages/collection/create-item.ts +21 -20
- package/lib/packages/collection/create-use-subset.ts +23 -0
- package/lib/packages/collection/guess-item-id.ts +26 -16
- package/lib/packages/collection/index.ts +4 -0
- package/lib/packages/collection/types.ts +65 -37
- package/lib/packages/collection/use-collection.ts +68 -18
- package/lib/packages/collection/use-flag-registry.ts +38 -17
- package/lib/packages/form-select/guess-label.ts +45 -0
- package/lib/packages/form-select/guess-value.ts +23 -0
- package/lib/packages/form-select/index.ts +6 -0
- package/lib/packages/form-select/normalize-search-term.ts +11 -0
- package/lib/packages/form-select/types.ts +90 -42
- package/lib/packages/form-select/use-form-option-controller.ts +7 -3
- package/lib/packages/form-select/use-form-select-controller.ts +38 -27
- package/lib/packages/form-select/use-form-select-keyboard-navigation.ts +1 -1
- package/lib/packages/form-select/use-form-select.ts +308 -130
- package/lib/packages/icon/DisplayIcon.vue +25 -0
- package/lib/packages/icon/DisplayIconAny.vue +16 -0
- package/lib/packages/icon/DisplayIconSingle.vue +35 -0
- package/lib/packages/icon/DisplayIconStack.vue +34 -0
- package/lib/packages/icon/README.md +286 -0
- package/lib/packages/icon/create-icon-bindings.ts +27 -0
- package/lib/packages/icon/define-icon-pack.ts +23 -0
- package/lib/packages/icon/define-icon-single.ts +17 -0
- package/lib/packages/icon/define-icon-stack.ts +20 -0
- package/lib/packages/icon/define-icon.ts +40 -0
- package/lib/packages/icon/generate-icon-variants.ts +17 -0
- package/lib/packages/icon/index.ts +8 -0
- package/lib/packages/icon/is-icon-stack.ts +5 -0
- package/lib/packages/icon/merge-icons.ts +25 -0
- package/lib/packages/icon/merge-transforms.ts +12 -0
- package/lib/packages/icon/normalize-icon.ts +25 -0
- package/lib/packages/icon/to-tuple.ts +7 -0
- package/lib/packages/icon/types.ts +72 -0
- package/lib/packages/job/README.md +2 -2
- package/lib/packages/mapper/README.md +166 -0
- package/lib/packages/mapper/convert-to-map.ts +5 -0
- package/lib/packages/mapper/create-mapper.ts +30 -0
- package/lib/packages/mapper/index.ts +4 -0
- package/lib/packages/mapper/types.ts +1 -0
- package/lib/packages/mapper/use-mapper.ts +31 -0
- package/lib/stores/sidebar.store.ts +1 -1
- package/lib/types/chart.ts +2 -2
- package/lib/types/utility.type.ts +9 -0
- package/lib/utils/object.util.ts +16 -0
- package/lib/utils/size.util.ts +4 -2
- package/package.json +2 -1
- package/lib/components/backup-item/VtsBackupItem.vue +0 -47
- package/lib/composables/mapper.composable.md +0 -74
- package/lib/composables/mapper.composable.ts +0 -18
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# Icon System
|
|
2
|
+
|
|
3
|
+
A flexible icon system for Vue applications supporting single icons, icon stacks, icon packs, and transformations.
|
|
4
|
+
|
|
5
|
+
Currently supported icon format: FontAwesome, SimpleIcons
|
|
6
|
+
|
|
7
|
+
## Core Concepts
|
|
8
|
+
|
|
9
|
+
- **Icon**: A single SVG icon with transformations
|
|
10
|
+
- **Icon Stack**: Multiple icons layered on top of each other
|
|
11
|
+
- **Icon Pack**: A collection of related icons
|
|
12
|
+
- **Transformations**: Size, color, rotation, flip, and other visual modifications
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
### Basic Icon
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<template>
|
|
20
|
+
<DisplayIcon :icon />
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script lang="ts" setup>
|
|
24
|
+
const icon = defineIcon({
|
|
25
|
+
icon: faUser,
|
|
26
|
+
color: 'blue',
|
|
27
|
+
size: 24,
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Icon Stack
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<template>
|
|
36
|
+
<DisplayIcon :icon="stackedIcon" />
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script lang="ts" setup>
|
|
40
|
+
const stackedIcon = defineIcon([
|
|
41
|
+
{ icon: faCircle, size: 24, color: 'blue' },
|
|
42
|
+
{ icon: faStar, size: 18, color: 'white' },
|
|
43
|
+
])
|
|
44
|
+
</script>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Icon Pack
|
|
48
|
+
|
|
49
|
+
```vue
|
|
50
|
+
<template>
|
|
51
|
+
<DisplayIcon :icon="icons.user" />
|
|
52
|
+
<DisplayIcon :icon="icons.star" />
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script lang="ts" setup>
|
|
56
|
+
const icons = defineIconPack({
|
|
57
|
+
user: { icon: faUser, color: 'blue' },
|
|
58
|
+
star: { icon: faStar, color: 'gold' },
|
|
59
|
+
})
|
|
60
|
+
</script>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Icon Variants
|
|
64
|
+
|
|
65
|
+
```vue
|
|
66
|
+
<template>
|
|
67
|
+
<DisplayIcon :icon="alerts['error:triangle']" />
|
|
68
|
+
<DisplayIcon :icon="alerts['warning:circle']" />
|
|
69
|
+
</template>
|
|
70
|
+
|
|
71
|
+
<script lang="ts" setup>
|
|
72
|
+
const alerts = defineIcon(
|
|
73
|
+
[
|
|
74
|
+
['error', 'warning'],
|
|
75
|
+
['circle', 'triangle'],
|
|
76
|
+
],
|
|
77
|
+
(status, shape) => {
|
|
78
|
+
const colors = {
|
|
79
|
+
error: 'red',
|
|
80
|
+
warning: 'orange',
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const shapes = {
|
|
84
|
+
circle: faCircle,
|
|
85
|
+
triangle: defineIcon({ icon: faPlay, rotate: 90, size: 20 }),
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return [
|
|
89
|
+
{ icon: shapes[shape], color: colors[status] },
|
|
90
|
+
{ icon: faExclamation, color: 'white' },
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
</script>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API Reference
|
|
98
|
+
|
|
99
|
+
### Functions
|
|
100
|
+
|
|
101
|
+
#### `defineIcon`
|
|
102
|
+
|
|
103
|
+
Create a single icon, an icon stack, or an icon pack with variants.
|
|
104
|
+
|
|
105
|
+
**Signature 1: Single Icon or Icon Stack**
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
defineIcon(config: IconSingleConfig): Icon
|
|
109
|
+
defineIcon(icons: (IconSingleConfig | Icon)[], config?: IconStackConfig): IconStack
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Signature 2: Icon Variants**
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
defineIcon(
|
|
116
|
+
args: string[][],
|
|
117
|
+
builder: (...args: string[]) => DefineIconConfig,
|
|
118
|
+
stackConfig?: IconStackConfig
|
|
119
|
+
): IconPack<string>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### `defineIconPack`
|
|
123
|
+
|
|
124
|
+
Create a collection of related icons.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
defineIconPack(config: IconPackConfig): IconPack<string>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Components
|
|
131
|
+
|
|
132
|
+
#### `DisplayIcon`
|
|
133
|
+
|
|
134
|
+
Root component that renders either a single icon or an icon stack.
|
|
135
|
+
|
|
136
|
+
```vue
|
|
137
|
+
<DisplayIcon :icon />
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Types
|
|
141
|
+
|
|
142
|
+
#### `IconTransforms`
|
|
143
|
+
|
|
144
|
+
Transformations that can be applied to icons.
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
type IconTransforms = {
|
|
148
|
+
borderColor?: string // Add a border around the icon
|
|
149
|
+
translate?: number | [number, number] // Move the icon
|
|
150
|
+
size?: number | [number, number] // Resize the icon
|
|
151
|
+
rotate?: number // Rotate the icon (in degrees)
|
|
152
|
+
flip?: 'horizontal' | 'vertical' | 'both' // Flip the icon
|
|
153
|
+
color?: string // Change icon color
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### `IconSingleConfig`
|
|
158
|
+
|
|
159
|
+
Configuration for a single icon.
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
type IconSingleConfig = {
|
|
163
|
+
icon?: IconDefinition | SimpleIcon | IconSingle | IconStack
|
|
164
|
+
} & IconTransforms
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### `IconStackConfig`
|
|
168
|
+
|
|
169
|
+
Configuration for an icon stack.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
type IconStackConfig = IconTransforms
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Examples
|
|
176
|
+
|
|
177
|
+
### Basic Transformations
|
|
178
|
+
|
|
179
|
+
```vue
|
|
180
|
+
<script lang="ts" setup>
|
|
181
|
+
// Color
|
|
182
|
+
const blueIcon = defineIcon({ icon: faUser, color: 'blue' })
|
|
183
|
+
|
|
184
|
+
// Size
|
|
185
|
+
const largeIcon = defineIcon({ icon: faUser, size: 32 })
|
|
186
|
+
|
|
187
|
+
// Rotate
|
|
188
|
+
const rotatedIcon = defineIcon({ icon: faUser, rotate: 45 })
|
|
189
|
+
|
|
190
|
+
// Flip
|
|
191
|
+
const flippedIcon = defineIcon({ icon: faUser, flip: 'horizontal' })
|
|
192
|
+
|
|
193
|
+
// Multiple transformations
|
|
194
|
+
const customIcon = defineIcon({
|
|
195
|
+
icon: faUser,
|
|
196
|
+
color: 'green',
|
|
197
|
+
size: 24,
|
|
198
|
+
rotate: 15,
|
|
199
|
+
translate: [2, 0],
|
|
200
|
+
})
|
|
201
|
+
</script>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Complex Icon Stack
|
|
205
|
+
|
|
206
|
+
```vue
|
|
207
|
+
<script lang="ts" setup>
|
|
208
|
+
import { defineIcon, DisplayIconAny } from '@core/packages/icon'
|
|
209
|
+
import { faCircle, faSquare, faStar } from '@fortawesome/free-solid-svg-icons'
|
|
210
|
+
|
|
211
|
+
const notificationIcon = defineIcon(
|
|
212
|
+
[
|
|
213
|
+
{ icon: faCircle, size: 24, color: 'red' },
|
|
214
|
+
{ icon: faSquare, size: 16, color: 'white', rotate: 45 },
|
|
215
|
+
{ icon: faStar, size: 10, color: 'gold' },
|
|
216
|
+
],
|
|
217
|
+
{ translate: [2, 0] } // Global transforms applied to the entire stack
|
|
218
|
+
)
|
|
219
|
+
</script>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Icon Variants
|
|
223
|
+
|
|
224
|
+
```vue
|
|
225
|
+
<script lang="ts" setup>
|
|
226
|
+
const icon = defineIcon(
|
|
227
|
+
[
|
|
228
|
+
['circle', 'square'],
|
|
229
|
+
['!', '?'],
|
|
230
|
+
],
|
|
231
|
+
(shape, type) => [
|
|
232
|
+
{ icon: shape === 'circle' ? faCircle : faSquare },
|
|
233
|
+
{
|
|
234
|
+
icon: type === '!' ? faExclamation : faQuestion,
|
|
235
|
+
color: 'white',
|
|
236
|
+
size: 12,
|
|
237
|
+
},
|
|
238
|
+
]
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
// You can now use icon['circle:!'], icon['circle:?'], icon['square:!'], icon['square:?']
|
|
242
|
+
</script>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Icon Pack with Namespaces
|
|
246
|
+
|
|
247
|
+
```vue
|
|
248
|
+
<script lang="ts" setup>
|
|
249
|
+
import { defineIconPack, DisplayIconAny } from '@core/packages/icon'
|
|
250
|
+
import { faUser, faUsers, faUserPlus } from '@fortawesome/free-solid-svg-icons'
|
|
251
|
+
import { faFile, faFolder, faImage } from '@fortawesome/free-solid-svg-icons'
|
|
252
|
+
|
|
253
|
+
const icons = defineIconPack({
|
|
254
|
+
user: defineIconPack({
|
|
255
|
+
single: { icon: faUser },
|
|
256
|
+
group: { icon: faUsers },
|
|
257
|
+
add: { icon: faUserPlus },
|
|
258
|
+
}),
|
|
259
|
+
file: defineIconPack({
|
|
260
|
+
document: { icon: faFile },
|
|
261
|
+
folder: { icon: faFolder },
|
|
262
|
+
image: { icon: faImage },
|
|
263
|
+
}),
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
// Access icons with namespace
|
|
267
|
+
// icons['user:single']
|
|
268
|
+
// icons['file:folder']
|
|
269
|
+
</script>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Reusable Icon with Different Transformations
|
|
273
|
+
|
|
274
|
+
```vue
|
|
275
|
+
<script lang="ts" setup>
|
|
276
|
+
import { defineIcon, DisplayIconAny } from '@core/packages/icon'
|
|
277
|
+
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'
|
|
278
|
+
|
|
279
|
+
// Define base icon
|
|
280
|
+
const warningIcon = defineIcon({ icon: faExclamationTriangle })
|
|
281
|
+
|
|
282
|
+
// Create variations with different transformations
|
|
283
|
+
const smallWarningIcon = defineIcon({ icon: warningIcon, size: 12 })
|
|
284
|
+
const redWarningIcon = defineIcon({ icon: warningIcon, color: 'red' })
|
|
285
|
+
</script>
|
|
286
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { IconBindings, IconTransforms } from './types.ts'
|
|
2
|
+
import { toTuple } from './to-tuple.ts'
|
|
3
|
+
|
|
4
|
+
export function createIconBindings(transforms: IconTransforms): IconBindings {
|
|
5
|
+
const [translateX, translateY] = toTuple(transforms.translate, [0, 0])
|
|
6
|
+
|
|
7
|
+
const shouldTranslate = translateX !== 0 || translateY !== 0
|
|
8
|
+
|
|
9
|
+
const [sizeX, sizeY] = toTuple(transforms.size, [16, 16])
|
|
10
|
+
|
|
11
|
+
const flipX = transforms.flip === 'horizontal' || transforms.flip === 'both' ? -1 : 1
|
|
12
|
+
|
|
13
|
+
const flipY = transforms.flip === 'vertical' || transforms.flip === 'both' ? -1 : 1
|
|
14
|
+
|
|
15
|
+
const [scaleX, scaleY] = [(sizeX / 16) * flipX, (sizeY / 16) * flipY]
|
|
16
|
+
|
|
17
|
+
const shouldScale = scaleX !== 1 || scaleY !== 1
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
style: {
|
|
21
|
+
color: transforms.color,
|
|
22
|
+
translate: shouldTranslate ? `${(translateX / 16) * 100}% ${(translateY / 16) * 100}%` : undefined,
|
|
23
|
+
rotate: transforms.rotate ? `${transforms.rotate}deg` : undefined,
|
|
24
|
+
scale: shouldScale ? `${scaleX} ${scaleY}` : undefined,
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { defineIcon } from './define-icon.ts'
|
|
2
|
+
import { type Icon, ICON_SYMBOL, type IconPack, type IconPackConfig, type IconPackKeys } from './types.ts'
|
|
3
|
+
|
|
4
|
+
export function defineIconPack<TConfig extends IconPackConfig>(
|
|
5
|
+
config: TConfig
|
|
6
|
+
): IconPack<IconPackKeys<NoInfer<TConfig>>> {
|
|
7
|
+
const result: Record<string, Icon> = Object.fromEntries(
|
|
8
|
+
Object.entries(config).flatMap(([key, value]) => {
|
|
9
|
+
if (!(ICON_SYMBOL in value)) {
|
|
10
|
+
return [[key, defineIcon(value)]]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return value[ICON_SYMBOL] === 'pack'
|
|
14
|
+
? Object.entries(value).map(([subKey, subValue]) => [`${key}:${subKey}`, subValue])
|
|
15
|
+
: [[key, value as Icon]]
|
|
16
|
+
})
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
...result,
|
|
21
|
+
[ICON_SYMBOL]: 'pack',
|
|
22
|
+
} as IconPack<IconPackKeys<TConfig>>
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createIconBindings } from './create-icon-bindings.ts'
|
|
2
|
+
import { mergeIcons } from './merge-icons.ts'
|
|
3
|
+
import { normalizeIcon } from './normalize-icon.ts'
|
|
4
|
+
import { type Icon, ICON_SYMBOL, type IconSingleConfig } from './types.ts'
|
|
5
|
+
|
|
6
|
+
export function defineIconSingle(config: IconSingleConfig): Icon {
|
|
7
|
+
if (config.icon !== undefined && ICON_SYMBOL in config.icon) {
|
|
8
|
+
return mergeIcons(config.icon, config)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
[ICON_SYMBOL]: 'icon',
|
|
13
|
+
...normalizeIcon(config.icon),
|
|
14
|
+
config,
|
|
15
|
+
bindings: createIconBindings(config),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createIconBindings } from './create-icon-bindings.ts'
|
|
2
|
+
import { defineIconSingle } from './define-icon-single.ts'
|
|
3
|
+
import { mergeIcons } from './merge-icons.ts'
|
|
4
|
+
import { type Icon, ICON_SYMBOL, type IconSingleConfig, type IconStack, type IconStackConfig } from './types.ts'
|
|
5
|
+
|
|
6
|
+
export function defineIconStack(
|
|
7
|
+
icons: IconStack | (IconSingleConfig | Icon)[],
|
|
8
|
+
config: IconStackConfig = {}
|
|
9
|
+
): IconStack {
|
|
10
|
+
if (ICON_SYMBOL in icons) {
|
|
11
|
+
return mergeIcons(icons, config)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
[ICON_SYMBOL]: 'stack',
|
|
16
|
+
config,
|
|
17
|
+
icons: icons.map(icon => (ICON_SYMBOL in icon ? icon : defineIconSingle(icon))),
|
|
18
|
+
bindings: createIconBindings(config),
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { defineIconSingle } from './define-icon-single.ts'
|
|
2
|
+
import { defineIconStack } from './define-icon-stack.ts'
|
|
3
|
+
import { generateIconVariants } from './generate-icon-variants.ts'
|
|
4
|
+
import {
|
|
5
|
+
type DefineIconConfig,
|
|
6
|
+
type Icon,
|
|
7
|
+
ICON_SYMBOL,
|
|
8
|
+
type IconArgsToNames,
|
|
9
|
+
type IconPack,
|
|
10
|
+
type IconStackConfig,
|
|
11
|
+
type ArgsConfigToBuilderArgs,
|
|
12
|
+
} from './types.ts'
|
|
13
|
+
|
|
14
|
+
type ArgsValue = string[][]
|
|
15
|
+
|
|
16
|
+
export function defineIcon(configOrIcons: DefineIconConfig, stackConfig?: IconStackConfig): Icon
|
|
17
|
+
|
|
18
|
+
export function defineIcon<
|
|
19
|
+
const TArgsConfig extends ArgsValue,
|
|
20
|
+
TArgs extends ArgsConfigToBuilderArgs<TArgsConfig>,
|
|
21
|
+
TNames extends IconArgsToNames<TArgs>,
|
|
22
|
+
>(args: TArgsConfig, builder: (...args: TArgs) => DefineIconConfig, stackConfig?: IconStackConfig): IconPack<TNames>
|
|
23
|
+
|
|
24
|
+
export function defineIcon(
|
|
25
|
+
configOrIconsOrArgs: DefineIconConfig | ArgsValue,
|
|
26
|
+
stackConfigOrBuilder?: IconStackConfig | ((...args: string[]) => DefineIconConfig),
|
|
27
|
+
stackConfigOrNone?: IconStackConfig
|
|
28
|
+
): Icon | IconPack<any> {
|
|
29
|
+
if (typeof stackConfigOrBuilder === 'function') {
|
|
30
|
+
return generateIconVariants(configOrIconsOrArgs as ArgsValue, stackConfigOrBuilder, stackConfigOrNone)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const configOrIcons = configOrIconsOrArgs as DefineIconConfig
|
|
34
|
+
|
|
35
|
+
if (Array.isArray(configOrIcons) || ICON_SYMBOL in configOrIcons) {
|
|
36
|
+
return defineIconStack(configOrIcons, stackConfigOrBuilder)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return defineIconSingle(configOrIcons)
|
|
40
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineIconPack } from './define-icon-pack.ts'
|
|
2
|
+
import { defineIcon } from './define-icon.ts'
|
|
3
|
+
import { type DefineIconConfig, type IconPack, type IconStackConfig } from './types.ts'
|
|
4
|
+
|
|
5
|
+
export function generateIconVariants<TArgs extends string[][]>(
|
|
6
|
+
argsConfigs: TArgs,
|
|
7
|
+
setup: (...args: any[]) => DefineIconConfig,
|
|
8
|
+
stackConfig: IconStackConfig | undefined
|
|
9
|
+
): IconPack<any> {
|
|
10
|
+
const argsCombinations = argsConfigs.reduce((acc, arr) => acc.flatMap(prefix => arr.map(item => [...prefix, item])), [
|
|
11
|
+
[],
|
|
12
|
+
] as string[][])
|
|
13
|
+
|
|
14
|
+
return defineIconPack(
|
|
15
|
+
Object.fromEntries(argsCombinations.map(args => [args.join(':'), defineIcon(setup(...args), stackConfig)]))
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './define-icon.ts'
|
|
2
|
+
export * from './define-icon-pack.ts'
|
|
3
|
+
export * from './types.ts'
|
|
4
|
+
|
|
5
|
+
export { default as DisplayIcon } from './DisplayIcon.vue'
|
|
6
|
+
export { default as DisplayIconAny } from './DisplayIconAny.vue'
|
|
7
|
+
export { default as DisplayIconSingle } from './DisplayIconSingle.vue'
|
|
8
|
+
export { default as DisplayIconStack } from './DisplayIconStack.vue'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineIconSingle } from './define-icon-single.ts'
|
|
2
|
+
import { defineIconStack } from './define-icon-stack.ts'
|
|
3
|
+
import { mergeTransforms } from './merge-transforms.ts'
|
|
4
|
+
import {
|
|
5
|
+
type Icon,
|
|
6
|
+
ICON_SYMBOL,
|
|
7
|
+
type IconSingle,
|
|
8
|
+
type IconSingleConfig,
|
|
9
|
+
type IconStack,
|
|
10
|
+
type IconStackConfig,
|
|
11
|
+
} from './types.ts'
|
|
12
|
+
|
|
13
|
+
export function mergeIcons<TOriginal extends Icon>(
|
|
14
|
+
original: TOriginal,
|
|
15
|
+
newConfig: TOriginal extends IconSingle ? IconSingleConfig : IconSingleConfig | IconStackConfig
|
|
16
|
+
): TOriginal extends IconSingle ? Icon : IconStack {
|
|
17
|
+
if (original[ICON_SYMBOL] === 'stack') {
|
|
18
|
+
return defineIconStack(original.icons, mergeTransforms(original.config, newConfig))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return defineIconSingle({
|
|
22
|
+
icon: original.config.icon,
|
|
23
|
+
...mergeTransforms(original.config, newConfig),
|
|
24
|
+
}) as TOriginal extends IconSingle ? Icon : IconStack
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IconTransforms } from './types.ts'
|
|
2
|
+
|
|
3
|
+
export function mergeTransforms(source: IconTransforms, target: IconTransforms): IconTransforms {
|
|
4
|
+
return {
|
|
5
|
+
translate: target.translate ?? source.translate,
|
|
6
|
+
size: target.size ?? source.size,
|
|
7
|
+
rotate: target.rotate ?? source.rotate,
|
|
8
|
+
flip: target.flip ?? source.flip,
|
|
9
|
+
color: target.color ?? source.color,
|
|
10
|
+
borderColor: target.borderColor ?? source.borderColor,
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { toArray } from '@core/utils/to-array.utils.ts'
|
|
2
|
+
import type { NormalizedIcon } from './types.ts'
|
|
3
|
+
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
4
|
+
import type { SimpleIcon } from 'simple-icons'
|
|
5
|
+
|
|
6
|
+
export function normalizeIcon(icon: IconDefinition | SimpleIcon | undefined): NormalizedIcon {
|
|
7
|
+
if (icon === undefined) {
|
|
8
|
+
return {
|
|
9
|
+
viewBox: '',
|
|
10
|
+
paths: [],
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if ('icon' in icon) {
|
|
15
|
+
return {
|
|
16
|
+
viewBox: `0 0 ${icon.icon[0]} ${icon.icon[1]}`,
|
|
17
|
+
paths: toArray(icon.icon[4]),
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
viewBox: '0 0 24 24',
|
|
23
|
+
paths: toArray(icon.path),
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { IconDefinition } from '@fortawesome/fontawesome-common-types'
|
|
2
|
+
import type { SimpleIcon } from 'simple-icons'
|
|
3
|
+
|
|
4
|
+
export const ICON_SYMBOL = Symbol('Icon')
|
|
5
|
+
|
|
6
|
+
export type IconTransforms = {
|
|
7
|
+
borderColor?: string
|
|
8
|
+
translate?: number | [number, number]
|
|
9
|
+
size?: number | [number, number]
|
|
10
|
+
rotate?: number
|
|
11
|
+
flip?: 'horizontal' | 'vertical' | 'both'
|
|
12
|
+
color?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type IconSingleConfig = {
|
|
16
|
+
icon?: IconDefinition | SimpleIcon | IconSingle | IconStack
|
|
17
|
+
} & IconTransforms
|
|
18
|
+
|
|
19
|
+
export type IconStackConfig = IconTransforms
|
|
20
|
+
|
|
21
|
+
export type IconBindings = {
|
|
22
|
+
style?: {
|
|
23
|
+
color?: string
|
|
24
|
+
rotate?: string
|
|
25
|
+
translate?: string
|
|
26
|
+
scale?: string
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type IconSingle = NormalizedIcon & {
|
|
31
|
+
[ICON_SYMBOL]: 'icon'
|
|
32
|
+
config: IconSingleConfig
|
|
33
|
+
bindings: IconBindings
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type IconStack = {
|
|
37
|
+
[ICON_SYMBOL]: 'stack'
|
|
38
|
+
icons: Icon[]
|
|
39
|
+
config: IconStackConfig
|
|
40
|
+
bindings: IconBindings
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type Icon = IconSingle | IconStack
|
|
44
|
+
|
|
45
|
+
export type IconPackKeys<TConfig extends object> = keyof {
|
|
46
|
+
[K in keyof TConfig as TConfig[K] extends IconPack<infer TKey> ? `${K & string}:${TKey}` : K]: true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type IconPackConfig = Record<string, Icon | IconPack<string> | DefineIconConfig>
|
|
50
|
+
|
|
51
|
+
export type IconPack<TKeys extends string> = {
|
|
52
|
+
[ICON_SYMBOL]: 'pack'
|
|
53
|
+
} & {
|
|
54
|
+
[K in TKeys]: Icon
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type ArgsConfigToBuilderArgs<T extends string[][]> = {
|
|
58
|
+
[K in keyof T]: T[K][number]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type IconArgsToNames<TArgs extends any[]> = TArgs extends [infer TFirst, ...infer TRest]
|
|
62
|
+
? TRest extends []
|
|
63
|
+
? TFirst
|
|
64
|
+
: `${TFirst & string}:${IconArgsToNames<TRest>}`
|
|
65
|
+
: never
|
|
66
|
+
|
|
67
|
+
export type DefineIconConfig = IconSingleConfig | IconStack | (IconSingleConfig | IconStack)[]
|
|
68
|
+
|
|
69
|
+
export type NormalizedIcon = {
|
|
70
|
+
viewBox: string
|
|
71
|
+
paths: string[]
|
|
72
|
+
}
|
|
@@ -42,7 +42,7 @@ const forceArg = defineJobArg<boolean>({
|
|
|
42
42
|
```typescript
|
|
43
43
|
const myJob = defineJob('processItems', [userIdArg, itemsArg, optionsArg], () => ({
|
|
44
44
|
validate(isRunning, userId, items) {
|
|
45
|
-
// You can use custom running check
|
|
45
|
+
// You can use custom running check additional to internal one
|
|
46
46
|
if (isRunning || isProcessingItems(userId, items)) {
|
|
47
47
|
throw new JobRunningError('Items are being processed')
|
|
48
48
|
}
|
|
@@ -57,7 +57,7 @@ const myJob = defineJob('processItems', [userIdArg, itemsArg, optionsArg], () =>
|
|
|
57
57
|
},
|
|
58
58
|
run(userId, items, force) {
|
|
59
59
|
// Job implementation
|
|
60
|
-
return
|
|
60
|
+
return processItems(userId, items, force)
|
|
61
61
|
},
|
|
62
62
|
}))
|
|
63
63
|
```
|