@raclettejs/workbench 0.1.19 → 0.1.20
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/.raclette/backend/raclette.config.js +519 -0
- package/{yarn.lock → .raclette/backend/yarn.lock} +1014 -796
- package/.raclette/frontend/raclette.config.js +47 -0
- package/.raclette/frontend/yarn.lock +3428 -0
- package/.raclette/raclette.config.js +643 -0
- package/.raclette/virtual/backend/README.md +172 -0
- package/.raclette/virtual/backend/raclette.config.js +519 -0
- package/.raclette/virtual/backend/yarn.lock +3773 -0
- package/.raclette/virtual/frontend/README.md +511 -0
- package/.raclette/virtual/frontend/raclette.config.js +47 -0
- package/.raclette/virtual/frontend/src/core/lib/eggs/readme.md +75 -0
- package/.raclette/virtual/frontend/yarn.lock +3428 -0
- package/CHANGELOG.md +5 -0
- package/i18n/de-DE.json +17 -1
- package/i18n/en-EU.json +17 -1
- package/i18n/sk-SK.json +17 -1
- package/package.json +4 -2
- package/packages.json +3 -1
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/CompositionWidgetsLayout.vue +8 -3
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetContextMenu.vue +60 -0
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetIcon.vue +4 -7
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetList.vue +34 -117
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetListFlat.vue +20 -0
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetListGrouped.vue +50 -0
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetListHeader.vue +213 -0
- package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetListItem.vue +56 -0
- package/plugins/pacifico__compositions/frontend/composables/useWidgetList.ts +288 -0
- package/raclette.config.js +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- widgetId is now configurable in composition layout screen
|
|
13
|
+
- WidgetList.vue (used in the Widget Layout) has a new design, and options for searching and filtering for widgets.
|
|
14
|
+
|
|
10
15
|
## [0.1.19] - 12.12.2025 <a href="https://gitlab.com/raclettejs/workbench/-/compare/v0.1.18...v0.1.19" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
|
|
11
16
|
|
|
12
17
|
### Added
|
package/i18n/de-DE.json
CHANGED
|
@@ -100,6 +100,22 @@
|
|
|
100
100
|
"slotLayout": {
|
|
101
101
|
"title": "Slot Layout",
|
|
102
102
|
"description": "Beschreibt das Zusammenspiel der einzelnen Widgets auf der Seite (Abstände sowie Rahmen pro Widget)"
|
|
103
|
+
},
|
|
104
|
+
"widgetLayout": {
|
|
105
|
+
"widgetList": {
|
|
106
|
+
"searchLabel": "Widgets durchsuchen",
|
|
107
|
+
"menuAriaLabel": "Liste filtern und sortieren",
|
|
108
|
+
"menuTitle": "Liste anpassen",
|
|
109
|
+
"sortingTitle": "Sortierung",
|
|
110
|
+
"pluginFilterTitle": "Plugins anzeigen",
|
|
111
|
+
"sortOptions": {
|
|
112
|
+
"group": "Gruppiert",
|
|
113
|
+
"name": "Nach Name",
|
|
114
|
+
"author": "Nach Autor"
|
|
115
|
+
},
|
|
116
|
+
"countAll": "{count} Widgets",
|
|
117
|
+
"countFiltered": "{visible} von {total} Widgets"
|
|
118
|
+
}
|
|
103
119
|
}
|
|
104
120
|
},
|
|
105
121
|
"interactionLinkList": {
|
|
@@ -274,4 +290,4 @@
|
|
|
274
290
|
}
|
|
275
291
|
}
|
|
276
292
|
}
|
|
277
|
-
}
|
|
293
|
+
}
|
package/i18n/en-EU.json
CHANGED
|
@@ -100,6 +100,22 @@
|
|
|
100
100
|
"slotLayout": {
|
|
101
101
|
"title": "Slot Layout",
|
|
102
102
|
"description": "Describes the interaction of the individual widgets on the page (spacing and borders per widget)"
|
|
103
|
+
},
|
|
104
|
+
"widgetLayout": {
|
|
105
|
+
"widgetList": {
|
|
106
|
+
"searchLabel": "Search widgets",
|
|
107
|
+
"menuAriaLabel": "Filter and sort list",
|
|
108
|
+
"menuTitle": "Adjust list",
|
|
109
|
+
"sortingTitle": "Sorting",
|
|
110
|
+
"pluginFilterTitle": "Show plugins",
|
|
111
|
+
"sortOptions": {
|
|
112
|
+
"group": "Grouped",
|
|
113
|
+
"name": "By name",
|
|
114
|
+
"author": "By author"
|
|
115
|
+
},
|
|
116
|
+
"countAll": "{count} widgets",
|
|
117
|
+
"countFiltered": "{visible} of {total} widgets"
|
|
118
|
+
}
|
|
103
119
|
}
|
|
104
120
|
},
|
|
105
121
|
"interactionLinkList": {
|
|
@@ -274,4 +290,4 @@
|
|
|
274
290
|
}
|
|
275
291
|
}
|
|
276
292
|
}
|
|
277
|
-
}
|
|
293
|
+
}
|
package/i18n/sk-SK.json
CHANGED
|
@@ -95,6 +95,22 @@
|
|
|
95
95
|
"pathname": {
|
|
96
96
|
"title": "Cesta (Pathname)",
|
|
97
97
|
"description": "Popisuje technický názov používaný ako URL cesta, parameter dotazu alebo iný odkaz. Nesmie obsahovať medzery."
|
|
98
|
+
},
|
|
99
|
+
"widgetLayout": {
|
|
100
|
+
"widgetList": {
|
|
101
|
+
"searchLabel": "Hľadať widgety",
|
|
102
|
+
"menuAriaLabel": "Filtrovať a triediť zoznam",
|
|
103
|
+
"menuTitle": "Upraviť zoznam",
|
|
104
|
+
"sortingTitle": "Triedenie",
|
|
105
|
+
"pluginFilterTitle": "Zobraziť pluginy",
|
|
106
|
+
"sortOptions": {
|
|
107
|
+
"group": "Zoskupené",
|
|
108
|
+
"name": "Podľa názvu",
|
|
109
|
+
"author": "Podľa autora"
|
|
110
|
+
},
|
|
111
|
+
"countAll": "{count} widgetov",
|
|
112
|
+
"countFiltered": "{visible} z {total} widgetov"
|
|
113
|
+
}
|
|
98
114
|
}
|
|
99
115
|
},
|
|
100
116
|
"interactionLinkList": {
|
|
@@ -269,4 +285,4 @@
|
|
|
269
285
|
}
|
|
270
286
|
}
|
|
271
287
|
}
|
|
272
|
-
}
|
|
288
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raclettejs/workbench",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "racletteJS Workbench - used to configure your application, for dev and prod",
|
|
6
6
|
"repository": "https://gitlab.com/raclettejs/workbench",
|
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@raclettejs/core": "0.1.19",
|
|
35
|
+
"@vueuse/integrations": "14.2.1",
|
|
36
|
+
"fuse.js": "7.1.0",
|
|
35
37
|
"three": "0.180.0",
|
|
36
38
|
"vanta": "0.5.24"
|
|
37
39
|
},
|
|
@@ -64,4 +66,4 @@
|
|
|
64
66
|
"vuetify": "3.10.2"
|
|
65
67
|
},
|
|
66
68
|
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
|
|
67
|
-
}
|
|
69
|
+
}
|
package/packages.json
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
@resize="onResize($event, dropzoneIndex, widgetIndex)"
|
|
27
27
|
@update-config="onConfigChanges($event, dropzoneIndex, widgetIndex)"
|
|
28
28
|
@remove-widget="removeWidget(widgetSlot.widget.uuid)"
|
|
29
|
-
@open-settings="
|
|
29
|
+
@open-settings="toggleSettings(widgetSlot.widget)"
|
|
30
30
|
/>
|
|
31
31
|
</DropzoneElement>
|
|
32
32
|
</div>
|
|
@@ -60,9 +60,14 @@ import DropzoneElement from "@raclettejs/core/orchestrator/components/dragAndDro
|
|
|
60
60
|
const composition = defineModel<CompositionCreate | CompositionUpdate>({
|
|
61
61
|
required: true,
|
|
62
62
|
})
|
|
63
|
-
|
|
64
63
|
const showSettingsForWidget = ref<WidgetBase | null>()
|
|
65
|
-
|
|
64
|
+
const toggleSettings = (widget) => {
|
|
65
|
+
if (showSettingsForWidget.value == widget) {
|
|
66
|
+
showSettingsForWidget.value = null
|
|
67
|
+
} else {
|
|
68
|
+
showSettingsForWidget.value = widget
|
|
69
|
+
}
|
|
70
|
+
}
|
|
66
71
|
const createNewWidget = (widgetName: string, pluginKey: string) => ({
|
|
67
72
|
column: 12,
|
|
68
73
|
widget: {
|
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="tw:z-50">
|
|
3
3
|
<div class="tw:flex tw:gap-1">
|
|
4
|
+
<!-- UUID Edit Button/Input -->
|
|
5
|
+
<div v-if="!isEditingUuid" class="tw:flex">
|
|
6
|
+
<v-btn
|
|
7
|
+
class="tw:rounded"
|
|
8
|
+
icon="mdi-identifier"
|
|
9
|
+
color="grey-darken-3"
|
|
10
|
+
@click="startEditingUuid()"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
13
|
+
<div v-else class="tw:flex tw:gap-1 tw:items-center">
|
|
14
|
+
<v-text-field
|
|
15
|
+
v-model="editableUuid"
|
|
16
|
+
density="compact"
|
|
17
|
+
hide-details
|
|
18
|
+
class="tw:min-w-[200px]"
|
|
19
|
+
variant="outlined"
|
|
20
|
+
@keyup.enter="saveUuid()"
|
|
21
|
+
@keyup.esc="cancelEditingUuid()"
|
|
22
|
+
/>
|
|
23
|
+
<v-btn
|
|
24
|
+
class="tw:rounded"
|
|
25
|
+
icon="mdi-check"
|
|
26
|
+
color="success"
|
|
27
|
+
size="small"
|
|
28
|
+
@click="saveUuid()"
|
|
29
|
+
/>
|
|
30
|
+
<v-btn
|
|
31
|
+
class="tw:rounded"
|
|
32
|
+
icon="mdi-close"
|
|
33
|
+
color="grey"
|
|
34
|
+
size="small"
|
|
35
|
+
@click="cancelEditingUuid()"
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<!-- Settings Button -->
|
|
4
40
|
<v-btn
|
|
5
41
|
v-if="Object.keys(configurableParameteters || {}).length"
|
|
6
42
|
class="tw:rounded"
|
|
@@ -8,6 +44,8 @@
|
|
|
8
44
|
color="grey-darken-3"
|
|
9
45
|
@click="openWidgetSettings()"
|
|
10
46
|
/>
|
|
47
|
+
|
|
48
|
+
<!-- Delete Button -->
|
|
11
49
|
<v-btn
|
|
12
50
|
class="tw:rounded"
|
|
13
51
|
icon="mdi-delete-outline"
|
|
@@ -45,6 +83,28 @@ const widget = computed(() => findWidgetByName(widgetConfig.widget.name))
|
|
|
45
83
|
const configurableParameteters = computed(
|
|
46
84
|
() => widget.value?.configurableParameters,
|
|
47
85
|
)
|
|
86
|
+
|
|
87
|
+
// UUID editing state
|
|
88
|
+
const isEditingUuid = ref(false)
|
|
89
|
+
const editableUuid = ref("")
|
|
90
|
+
|
|
91
|
+
const startEditingUuid = () => {
|
|
92
|
+
editableUuid.value = widgetConfig.widget.uuid
|
|
93
|
+
isEditingUuid.value = true
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const saveUuid = () => {
|
|
97
|
+
const updatedConfig = clone(editableConfig.value)
|
|
98
|
+
updatedConfig.widget.uuid = editableUuid.value
|
|
99
|
+
emit("updateConfig", updatedConfig)
|
|
100
|
+
isEditingUuid.value = false
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const cancelEditingUuid = () => {
|
|
104
|
+
isEditingUuid.value = false
|
|
105
|
+
editableUuid.value = ""
|
|
106
|
+
}
|
|
107
|
+
|
|
48
108
|
const openWidgetSettings = () => emit("openSettings")
|
|
49
109
|
|
|
50
110
|
const removeWidget = () => emit("removeWidget")
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<figure class="tw:flex tw:
|
|
3
|
+
<figure class="tw:flex tw:items-center tw:gap-2">
|
|
4
4
|
<span
|
|
5
|
-
class="tw:flex tw:h-
|
|
5
|
+
class="tw:flex tw:h-8 tw:w-8 tw:items-center tw:justify-center tw:rounded tw:shadow-none"
|
|
6
6
|
:style="{
|
|
7
7
|
backgroundColor: module.color,
|
|
8
8
|
}"
|
|
9
9
|
>
|
|
10
10
|
<span
|
|
11
11
|
v-if="svgContent"
|
|
12
|
-
class="tw:flex tw:h-
|
|
12
|
+
class="tw:flex tw:h-6 tw:w-6 tw:items-center tw:justify-center"
|
|
13
13
|
:style="{
|
|
14
14
|
'--highlight-color': module.color,
|
|
15
15
|
'--base-color': baseColor,
|
|
@@ -21,12 +21,9 @@
|
|
|
21
21
|
v-else
|
|
22
22
|
:src="module.icon"
|
|
23
23
|
:alt="`${module.title} icon`"
|
|
24
|
-
class="tw:size-
|
|
24
|
+
class="tw:size-6"
|
|
25
25
|
/>
|
|
26
26
|
</span>
|
|
27
|
-
<figcaption class="tw:text-center tw:no-underline">
|
|
28
|
-
{{ module.title }}
|
|
29
|
-
</figcaption>
|
|
30
27
|
</figure>
|
|
31
28
|
</div>
|
|
32
29
|
</template>
|
|
@@ -1,122 +1,39 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
v-
|
|
7
|
-
:
|
|
8
|
-
:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
v-bind="props"
|
|
21
|
-
:title="deslugify(pluginKey.split('__')[1])"
|
|
22
|
-
></v-list-item>
|
|
23
|
-
</template>
|
|
24
|
-
|
|
25
|
-
<DraggableElement
|
|
26
|
-
v-for="widget in pluginWidgets"
|
|
27
|
-
:key="widget.title"
|
|
28
|
-
class="tw:py-4"
|
|
29
|
-
:draggable-config="{
|
|
30
|
-
type: 'widget',
|
|
31
|
-
widgetName: widget.name,
|
|
32
|
-
pluginKey: widget.pluginKey,
|
|
33
|
-
}"
|
|
34
|
-
>
|
|
35
|
-
<WidgetIcon :module="widget" />
|
|
36
|
-
</DraggableElement>
|
|
37
|
-
<v-divider></v-divider>
|
|
38
|
-
</v-list-group>
|
|
39
|
-
</v-list-group>
|
|
40
|
-
</v-list>
|
|
2
|
+
<div>
|
|
3
|
+
<WidgetListHeader
|
|
4
|
+
v-model:searchQuery="searchQuery"
|
|
5
|
+
v-model:sortMode="sortMode"
|
|
6
|
+
v-model:visiblePluginKeys="visiblePluginKeys"
|
|
7
|
+
:sort-options="sortOptions"
|
|
8
|
+
:plugin-filter-options="pluginFilterOptions"
|
|
9
|
+
:widgets-count="widgetsCount"
|
|
10
|
+
:visible-widgets-count="visibleWidgetsCount"
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<WidgetListGrouped
|
|
14
|
+
v-if="sortMode === 'group' && !(searchQuery ?? '').trim()"
|
|
15
|
+
:grouped-widgets="filteredGroupedWidgets"
|
|
16
|
+
/>
|
|
17
|
+
|
|
18
|
+
<WidgetListFlat v-else :widgets="filteredWidgetsFlat" />
|
|
19
|
+
</div>
|
|
41
20
|
</template>
|
|
42
21
|
|
|
43
22
|
<script setup lang="ts">
|
|
44
|
-
import
|
|
45
|
-
import
|
|
46
|
-
import
|
|
47
|
-
import {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
widgets.value.forEach((widget) => {
|
|
62
|
-
if (!unsortedResult[widget.author]) {
|
|
63
|
-
unsortedResult[widget.author] = {}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!unsortedResult[widget.author][widget.pluginKey]) {
|
|
67
|
-
unsortedResult[widget.author][widget.pluginKey] = []
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
unsortedResult[widget.author][widget.pluginKey].push(widget)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
const sortedAuthors = Object.keys(unsortedResult).sort((a, b) => {
|
|
74
|
-
if (a === "pacifico") {
|
|
75
|
-
return 1
|
|
76
|
-
}
|
|
77
|
-
if (b === "pacifico") {
|
|
78
|
-
return -1
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return a.localeCompare(b)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
const sortedResult: Record<
|
|
85
|
-
string,
|
|
86
|
-
Record<string, RegisteredWidgetDeclaration[]>
|
|
87
|
-
> = {}
|
|
88
|
-
|
|
89
|
-
sortedAuthors.forEach((author) => {
|
|
90
|
-
const plugins = Object.keys(unsortedResult[author]).sort((a, b) => {
|
|
91
|
-
if (a === "core") {
|
|
92
|
-
return 1
|
|
93
|
-
}
|
|
94
|
-
if (b === "core") {
|
|
95
|
-
return -1
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return a.localeCompare(b)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
sortedResult[author] = {}
|
|
102
|
-
plugins.forEach((pluginKey) => {
|
|
103
|
-
sortedResult[author][pluginKey] = unsortedResult[author][pluginKey]
|
|
104
|
-
})
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
return sortedResult
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
const initOpenListItems = () => {
|
|
111
|
-
const keys: string[] = []
|
|
112
|
-
|
|
113
|
-
widgets.value.forEach((widget) => {
|
|
114
|
-
keys.push(widget.author)
|
|
115
|
-
keys.push(widget.pluginKey)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
openListItems.value = [...new Set(keys)]
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
initOpenListItems()
|
|
23
|
+
import WidgetListHeader from "./WidgetListHeader.vue"
|
|
24
|
+
import WidgetListGrouped from "./WidgetListGrouped.vue"
|
|
25
|
+
import WidgetListFlat from "./WidgetListFlat.vue"
|
|
26
|
+
import { useWidgetList } from "../../../composables/useWidgetList"
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
searchQuery,
|
|
30
|
+
sortMode,
|
|
31
|
+
visiblePluginKeys,
|
|
32
|
+
sortOptions,
|
|
33
|
+
pluginFilterOptions,
|
|
34
|
+
widgetsCount,
|
|
35
|
+
visibleWidgetsCount,
|
|
36
|
+
filteredWidgetsFlat,
|
|
37
|
+
filteredGroupedWidgets,
|
|
38
|
+
} = useWidgetList()
|
|
122
39
|
</script>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-list>
|
|
3
|
+
<WidgetListItem
|
|
4
|
+
v-for="widget in widgets"
|
|
5
|
+
:key="widget.title"
|
|
6
|
+
:widget="widget"
|
|
7
|
+
outer-class="tw:py-2"
|
|
8
|
+
/>
|
|
9
|
+
</v-list>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
import type { RegisteredWidgetDeclaration } from "@raclettejs/core"
|
|
14
|
+
import WidgetListItem from "./WidgetListItem.vue"
|
|
15
|
+
|
|
16
|
+
const props = defineProps<{
|
|
17
|
+
widgets: RegisteredWidgetDeclaration[]
|
|
18
|
+
}>()
|
|
19
|
+
</script>
|
|
20
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-list>
|
|
3
|
+
<div
|
|
4
|
+
v-for="(authorPlugins, authorName) in groupedWidgets"
|
|
5
|
+
:key="authorName"
|
|
6
|
+
class="tw:mb-3"
|
|
7
|
+
>
|
|
8
|
+
<div
|
|
9
|
+
class="tw:px-3 tw:py-1 tw:text-[11px] tw:font-medium tw:uppercase tw:tracking-wide tw:text-slate-500"
|
|
10
|
+
>
|
|
11
|
+
{{ authorName }}
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div
|
|
15
|
+
v-for="(pluginWidgets, pluginKey) in authorPlugins"
|
|
16
|
+
:key="pluginKey"
|
|
17
|
+
class="tw:mb-1"
|
|
18
|
+
>
|
|
19
|
+
<div
|
|
20
|
+
class="tw:px-3 tw:py-0.5 tw:text-[11px] tw:uppercase tw:text-slate-400"
|
|
21
|
+
>
|
|
22
|
+
{{ pluginLabel(pluginKey) }}
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<WidgetListItem
|
|
26
|
+
v-for="widget in pluginWidgets"
|
|
27
|
+
:key="widget.title"
|
|
28
|
+
:widget="widget"
|
|
29
|
+
outer-class="tw:py-1"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</v-list>
|
|
34
|
+
</template>
|
|
35
|
+
|
|
36
|
+
<script setup lang="ts">
|
|
37
|
+
import { deslugify } from "@shared/helper/pluginHelper"
|
|
38
|
+
import type { GroupedWidgets } from "../../../composables/useWidgetList"
|
|
39
|
+
import WidgetListItem from "./WidgetListItem.vue"
|
|
40
|
+
|
|
41
|
+
const props = defineProps<{
|
|
42
|
+
groupedWidgets: GroupedWidgets
|
|
43
|
+
}>()
|
|
44
|
+
|
|
45
|
+
const pluginLabel = (pluginKey: string) => {
|
|
46
|
+
const parts = pluginKey.split("__")
|
|
47
|
+
const slug = parts[1] ?? parts[0]
|
|
48
|
+
return deslugify(slug)
|
|
49
|
+
}
|
|
50
|
+
</script>
|