glib-web 4.35.12 → 4.36.1
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/AGENT.md +8 -0
- package/CLAUDE.md +2 -0
- package/components/fields/radio/_subtitle.vue +28 -0
- package/components/fields/radio.vue +4 -1
- package/components/panels/vertical.vue +20 -8
- package/nav/drawer.vue +40 -2
- package/package.json +1 -1
package/AGENT.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
* System architecture
|
|
2
|
+
* Read [ui_architecture.md](doc/common/ui_architecture.md)
|
|
3
|
+
* This project implements the frontend components of the `glib` UI framework mentioned
|
|
4
|
+
in the architecture above.
|
|
5
|
+
|
|
6
|
+
* Project guidelines
|
|
7
|
+
* For working examples on how to use `glib` UI components, see all the jbuilder
|
|
8
|
+
files located in `doc/garage/`.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-radio
|
|
3
|
+
:value="(spec.value || '').presence() || vuetifyEmptyString"
|
|
4
|
+
:readonly="spec.readOnly"
|
|
5
|
+
:on-icon="spec.onIcon"
|
|
6
|
+
:off-icon="spec.offIcon"
|
|
7
|
+
@click="$onClick()"
|
|
8
|
+
:color="gcolor"
|
|
9
|
+
>
|
|
10
|
+
<template v-slot:label>
|
|
11
|
+
<div class="flex flex-col">
|
|
12
|
+
<span>{{ spec.label }}</span>
|
|
13
|
+
<span v-if="spec.subtitle" class="text-sm text-gray-500 mt-1">
|
|
14
|
+
{{ spec.subtitle }}
|
|
15
|
+
</span>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
</v-radio>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
export default {
|
|
23
|
+
props: {
|
|
24
|
+
spec: { type: Object, required: true }
|
|
25
|
+
},
|
|
26
|
+
inject: ['radioGroupCtx'],
|
|
27
|
+
};
|
|
28
|
+
</script>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="cls" :style="$styles()" v-if="loadIf">
|
|
3
|
+
<subtitle-radio v-if="spec.subtitle" :spec="spec" />
|
|
3
4
|
<v-radio :label="spec.label" :value="(spec.value || '').presence() || vuetifyEmptyString" :readonly="spec.readOnly"
|
|
4
5
|
:on-icon="spec.onIcon" :off-icon="spec.offIcon" @click="$onClick()" :color="gcolor"
|
|
5
|
-
v-if="!spec.image && !spec.icon">
|
|
6
|
+
v-if="!spec.image && !spec.icon && !spec.subtitle">
|
|
6
7
|
</v-radio>
|
|
7
8
|
<thumbnail-radio v-if="spec.image && spec.image.template == 'thumbnail'" :spec=this.spec></thumbnail-radio>
|
|
8
9
|
<featured-radio v-if="spec.icon && spec.icon.template == 'featured'" :spec=this.spec></featured-radio>
|
|
@@ -19,11 +20,13 @@
|
|
|
19
20
|
|
|
20
21
|
import ThumbnailRadio from "../fields/radio/_thumbnail.vue";
|
|
21
22
|
import FeaturedRadio from "../fields/radio/_featured.vue";
|
|
23
|
+
import SubtitleRadio from "../fields/radio/_subtitle.vue";
|
|
22
24
|
|
|
23
25
|
export default {
|
|
24
26
|
components: {
|
|
25
27
|
"thumbnail-radio": ThumbnailRadio,
|
|
26
28
|
"featured-radio": FeaturedRadio,
|
|
29
|
+
"subtitle-radio": SubtitleRadio,
|
|
27
30
|
},
|
|
28
31
|
props: {
|
|
29
32
|
spec: { type: Object, required: true }
|
|
@@ -28,21 +28,20 @@ export default {
|
|
|
28
28
|
classes.push("layouts-vertical--space-equally");
|
|
29
29
|
break;
|
|
30
30
|
}
|
|
31
|
-
return classes;
|
|
32
|
-
},
|
|
33
|
-
cssStyles: function () {
|
|
34
|
-
const styles = this.$styles();
|
|
35
31
|
switch (this.spec.align) {
|
|
36
32
|
case "center":
|
|
37
|
-
|
|
33
|
+
classes.push("layouts-vertical--align-center");
|
|
38
34
|
break;
|
|
39
35
|
case "right":
|
|
40
|
-
|
|
36
|
+
classes.push("layouts-vertical--align-right");
|
|
41
37
|
break;
|
|
42
38
|
default:
|
|
43
|
-
|
|
39
|
+
classes.push("layouts-vertical--align-left");
|
|
44
40
|
}
|
|
45
|
-
return
|
|
41
|
+
return classes;
|
|
42
|
+
},
|
|
43
|
+
cssStyles: function () {
|
|
44
|
+
return this.$styles();
|
|
46
45
|
},
|
|
47
46
|
componentName() {
|
|
48
47
|
return this.spec.onClick ? "a" : "div";
|
|
@@ -95,4 +94,17 @@ a.panels-vertical {
|
|
|
95
94
|
.layouts-vertical--space-equally>* {
|
|
96
95
|
flex: initial;
|
|
97
96
|
}
|
|
97
|
+
|
|
98
|
+
.layouts-vertical--align-left {
|
|
99
|
+
align-items: flex-start;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.layouts-vertical--align-center {
|
|
103
|
+
align-items: center;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.layouts-vertical--align-right {
|
|
107
|
+
align-items: flex-end;
|
|
108
|
+
}
|
|
109
|
+
|
|
98
110
|
</style>
|
package/nav/drawer.vue
CHANGED
|
@@ -14,9 +14,24 @@
|
|
|
14
14
|
|
|
15
15
|
<v-list :dense="true">
|
|
16
16
|
<div v-for="(item, index) in spec.rows" :key="index" class="nav-item">
|
|
17
|
-
<div v-if="item.type == 'button'" class="indicator"></div>
|
|
17
|
+
<div v-if="item.type == 'button' && !item.childButtons" class="indicator"></div>
|
|
18
18
|
<v-divider v-if="item.type == 'divider'" />
|
|
19
19
|
<nav-drawerLabel v-else-if="item.type == 'label'" :spec="rowSpec(item)" />
|
|
20
|
+
<template v-else-if="item.childButtons && item.childButtons.length > 0">
|
|
21
|
+
<v-list-group>
|
|
22
|
+
<template v-slot:activator="{ props }">
|
|
23
|
+
<v-list-item v-bind="props">
|
|
24
|
+
<div class="parent-item">
|
|
25
|
+
<common-icon v-if="item.icon" :spec="item.icon || {}" />
|
|
26
|
+
<span>{{ item.text }}</span>
|
|
27
|
+
</div>
|
|
28
|
+
</v-list-item>
|
|
29
|
+
</template>
|
|
30
|
+
<div v-for="(child, childIndex) in item.childButtons" :key="childIndex" class="child-item">
|
|
31
|
+
<nav-drawerButton :spec="child" />
|
|
32
|
+
</div>
|
|
33
|
+
</v-list-group>
|
|
34
|
+
</template>
|
|
20
35
|
<nav-drawerButton v-else :spec="item" />
|
|
21
36
|
</div>
|
|
22
37
|
</v-list>
|
|
@@ -60,7 +75,7 @@ export default {
|
|
|
60
75
|
// Using null as the starting value for its v-model will initialize the drawer as closed on mobile and as open on desktop.
|
|
61
76
|
// See https://vuetifyjs.com/en/components/navigation-drawers
|
|
62
77
|
state: null,
|
|
63
|
-
isExpand: false
|
|
78
|
+
isExpand: false
|
|
64
79
|
};
|
|
65
80
|
},
|
|
66
81
|
computed: {
|
|
@@ -146,6 +161,13 @@ export default {
|
|
|
146
161
|
align-items: center;
|
|
147
162
|
background-color: white;
|
|
148
163
|
}
|
|
164
|
+
|
|
165
|
+
.parent-item {
|
|
166
|
+
padding-left: 16px;
|
|
167
|
+
display: flex;
|
|
168
|
+
align-items: center;
|
|
169
|
+
gap: 8px;
|
|
170
|
+
}
|
|
149
171
|
</style>
|
|
150
172
|
|
|
151
173
|
<style lang="scss">
|
|
@@ -171,4 +193,20 @@ export default {
|
|
|
171
193
|
// margin: 8px 0;
|
|
172
194
|
// }
|
|
173
195
|
}
|
|
196
|
+
|
|
197
|
+
// .v-list-group__items {
|
|
198
|
+
.child-item {
|
|
199
|
+
.v-list-item.drawer-button {
|
|
200
|
+
// padding-left: 0;
|
|
201
|
+
// padding-right: 0;
|
|
202
|
+
padding-inline-start: 0 !important;
|
|
203
|
+
padding-inline-end: 0;
|
|
204
|
+
|
|
205
|
+
.views-button {
|
|
206
|
+
padding-left: 32px;
|
|
207
|
+
padding-right: 32px;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// }
|
|
174
212
|
</style>
|