ketekny-ui-kit 1.0.98 → 1.0.100
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/package.json
CHANGED
|
@@ -137,10 +137,16 @@ export default {
|
|
|
137
137
|
methods: {
|
|
138
138
|
syncActiveFromMenu() {
|
|
139
139
|
const routePath = this.$route?.path
|
|
140
|
+
const routeFullPath = this.$route?.fullPath
|
|
140
141
|
const findMatch = (items, parentIds = []) => {
|
|
141
142
|
for (const item of items) {
|
|
142
143
|
const itemPath = item?.link?.to ?? item?.to ?? null
|
|
143
|
-
|
|
144
|
+
const normalizedItemPath = typeof itemPath === 'string' ? itemPath.split('?')[0] : null
|
|
145
|
+
const matchesPath =
|
|
146
|
+
(routeFullPath && itemPath === routeFullPath) ||
|
|
147
|
+
(routePath && normalizedItemPath === routePath)
|
|
148
|
+
|
|
149
|
+
if (matchesPath) {
|
|
144
150
|
return {
|
|
145
151
|
id: item.id,
|
|
146
152
|
parentIds,
|
|
@@ -261,14 +267,14 @@ export default {
|
|
|
261
267
|
v-if="collapsed"
|
|
262
268
|
src="https://s3.ketekny.gr/public/web-apps/logos/logo-icon-dark.png"
|
|
263
269
|
alt="Ketekny logo"
|
|
264
|
-
class="size-9 shrink-0 rounded-lg object-contain"
|
|
270
|
+
class="size-9 shrink-0 rounded-lg object-contain cursor-pointer"
|
|
265
271
|
@click="handleLogoClick"
|
|
266
272
|
/>
|
|
267
273
|
<img
|
|
268
274
|
v-else
|
|
269
275
|
src="https://support.ketekny.gr/logo-dark.png"
|
|
270
276
|
alt="Ketekny logo"
|
|
271
|
-
class="
|
|
277
|
+
class="min-w-0 flex-1 object-contain cursor-pointer"
|
|
272
278
|
@click="handleLogoClick"
|
|
273
279
|
/>
|
|
274
280
|
</div>
|
package/src/ui/kOptionGroup.vue
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<div
|
|
19
19
|
v-if="option.icon"
|
|
20
20
|
class="shrink-0"
|
|
21
|
-
:class="iconWrapperClass(option)"
|
|
21
|
+
:class="[iconWrapperClass(option), { [intentStyles(option).text]: isColored(option) }]"
|
|
22
22
|
>
|
|
23
23
|
<kIcon
|
|
24
24
|
v-if="typeof option.icon === 'string'"
|
|
@@ -35,7 +35,10 @@
|
|
|
35
35
|
<div class="min-w-0 flex-1">
|
|
36
36
|
<div :class="contentRowClass">
|
|
37
37
|
<div class="min-w-0">
|
|
38
|
-
<div
|
|
38
|
+
<div
|
|
39
|
+
class="truncate text-sm font-semibold"
|
|
40
|
+
:class="{ [intentStyles(option).text]: isColored(option) }"
|
|
41
|
+
>
|
|
39
42
|
{{ option.label }}
|
|
40
43
|
</div>
|
|
41
44
|
<div
|
|
@@ -45,11 +48,28 @@
|
|
|
45
48
|
{{ option.description }}
|
|
46
49
|
</div>
|
|
47
50
|
</div>
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
<div class="flex shrink-0 items-center gap-2">
|
|
52
|
+
<span
|
|
53
|
+
v-if="option.badge !== null && option.badge !== ''"
|
|
54
|
+
:class="badgeClass(option)"
|
|
55
|
+
>
|
|
56
|
+
{{ option.badge }}
|
|
57
|
+
</span>
|
|
58
|
+
<span
|
|
59
|
+
v-if="showIndicator()"
|
|
60
|
+
:class="indicatorClass(option)"
|
|
61
|
+
>
|
|
62
|
+
<span
|
|
63
|
+
v-if="indicator === 'radio'"
|
|
64
|
+
v-show="isSelected(option)"
|
|
65
|
+
class="h-2 w-2 rounded-full"
|
|
66
|
+
:class="radioDotClass(option)"
|
|
67
|
+
/>
|
|
68
|
+
<template v-else>
|
|
69
|
+
✓
|
|
70
|
+
</template>
|
|
71
|
+
</span>
|
|
72
|
+
</div>
|
|
53
73
|
</div>
|
|
54
74
|
</div>
|
|
55
75
|
</button>
|
|
@@ -59,6 +79,7 @@
|
|
|
59
79
|
|
|
60
80
|
<script>
|
|
61
81
|
import kIcon from "./kIcon.vue";
|
|
82
|
+
import { OPTION_INTENT_STYLES, OPTION_INTENTS } from "./themes/kOptionGroup.theme";
|
|
62
83
|
|
|
63
84
|
export default {
|
|
64
85
|
name: "kOptionGroup",
|
|
@@ -82,7 +103,25 @@ export default {
|
|
|
82
103
|
variant: {
|
|
83
104
|
type: String,
|
|
84
105
|
default: "table",
|
|
85
|
-
validator: (value) => ["table", "card"].includes(value),
|
|
106
|
+
validator: (value) => ["table", "card", "list"].includes(value),
|
|
107
|
+
},
|
|
108
|
+
indicator: {
|
|
109
|
+
type: String,
|
|
110
|
+
default: "check",
|
|
111
|
+
validator: (value) => ["check", "checkbox", "radio", "none"].includes(value),
|
|
112
|
+
},
|
|
113
|
+
color: {
|
|
114
|
+
type: String,
|
|
115
|
+
default: "primary",
|
|
116
|
+
validator: (value) => OPTION_INTENTS.includes(value),
|
|
117
|
+
},
|
|
118
|
+
colorKey: {
|
|
119
|
+
type: String,
|
|
120
|
+
default: "color",
|
|
121
|
+
},
|
|
122
|
+
badgeKey: {
|
|
123
|
+
type: String,
|
|
124
|
+
default: "badge",
|
|
86
125
|
},
|
|
87
126
|
title: {
|
|
88
127
|
type: String,
|
|
@@ -113,6 +152,9 @@ export default {
|
|
|
113
152
|
isTableVariant() {
|
|
114
153
|
return this.variant === "table";
|
|
115
154
|
},
|
|
155
|
+
isListVariant() {
|
|
156
|
+
return this.variant === "list";
|
|
157
|
+
},
|
|
116
158
|
normalizedSelection() {
|
|
117
159
|
return Array.isArray(this.modelValue) ? this.modelValue : [];
|
|
118
160
|
},
|
|
@@ -123,9 +165,13 @@ export default {
|
|
|
123
165
|
label: option?.[this.labelKey] ?? "",
|
|
124
166
|
description: option?.[this.descriptionKey] ?? "",
|
|
125
167
|
icon: option?.[this.iconKey] ?? null,
|
|
168
|
+
color: option?.[this.colorKey] ?? null,
|
|
169
|
+
badge: option?.[this.badgeKey] ?? null,
|
|
126
170
|
}));
|
|
127
171
|
},
|
|
128
172
|
containerClass() {
|
|
173
|
+
if (this.isListVariant) return "flex flex-col gap-2";
|
|
174
|
+
|
|
129
175
|
return this.isTableVariant
|
|
130
176
|
? "overflow-hidden rounded-xl border border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900"
|
|
131
177
|
: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3";
|
|
@@ -173,16 +219,59 @@ export default {
|
|
|
173
219
|
resolveKey(option, index) {
|
|
174
220
|
return `${String(option.value ?? option.label)}-${index}`;
|
|
175
221
|
},
|
|
222
|
+
optionIntent(option) {
|
|
223
|
+
const key = option.color || this.color;
|
|
224
|
+
return OPTION_INTENT_STYLES[key] ? key : "primary";
|
|
225
|
+
},
|
|
226
|
+
intentStyles(option) {
|
|
227
|
+
return OPTION_INTENT_STYLES[this.optionIntent(option)];
|
|
228
|
+
},
|
|
229
|
+
isColored(option) {
|
|
230
|
+
return !!option.color;
|
|
231
|
+
},
|
|
232
|
+
isTinted(option) {
|
|
233
|
+
return !!option.color || this.color !== "primary";
|
|
234
|
+
},
|
|
176
235
|
buttonClass(option) {
|
|
236
|
+
if (this.isListVariant) {
|
|
237
|
+
const selected = this.isSelected(option);
|
|
238
|
+
const colored = this.isColored(option);
|
|
239
|
+
const styles = this.intentStyles(option);
|
|
240
|
+
const pieces = ["items-center gap-3 rounded-lg border px-3 py-2.5 transition"];
|
|
241
|
+
|
|
242
|
+
if (selected) {
|
|
243
|
+
pieces.push(styles.selBg);
|
|
244
|
+
if (colored) pieces.push(`border-l-2 ${styles.accent}`);
|
|
245
|
+
} else if (colored) {
|
|
246
|
+
pieces.push(styles.text);
|
|
247
|
+
pieces.push(`border-l-2 ${styles.accent}`);
|
|
248
|
+
pieces.push("bg-white border-slate-200 hover:bg-slate-50 dark:bg-slate-900 dark:border-slate-700 dark:hover:bg-slate-800");
|
|
249
|
+
} else {
|
|
250
|
+
pieces.push("bg-white border-slate-200 text-gray-700 hover:bg-slate-50 dark:bg-slate-900 dark:border-slate-700 dark:text-slate-200 dark:hover:bg-slate-800");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return pieces.join(" ");
|
|
254
|
+
}
|
|
255
|
+
|
|
177
256
|
if (this.isTableVariant) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
257
|
+
if (this.isSelected(option)) {
|
|
258
|
+
if (this.isTinted(option)) {
|
|
259
|
+
const styles = this.intentStyles(option);
|
|
260
|
+
return `items-center gap-3 border-b border-slate-200 px-3 py-3 last:border-b-0 dark:border-slate-700 ${styles.softBg} ${styles.text}`;
|
|
261
|
+
}
|
|
262
|
+
return "items-center gap-3 border-b border-slate-200 bg-primary/10 px-3 py-3 text-primary last:border-b-0 dark:border-slate-700 dark:bg-primary/15 dark:text-slate-100";
|
|
263
|
+
}
|
|
264
|
+
return "items-center gap-3 border-b border-slate-200 bg-white px-3 py-3 text-gray-700 hover:bg-slate-50 last:border-b-0 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800";
|
|
181
265
|
}
|
|
182
266
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
267
|
+
if (this.isSelected(option)) {
|
|
268
|
+
if (this.isTinted(option)) {
|
|
269
|
+
const styles = this.intentStyles(option);
|
|
270
|
+
return `items-start gap-3 rounded-xl border p-3 ${styles.selBg} ${styles.text}`;
|
|
271
|
+
}
|
|
272
|
+
return "items-start gap-3 rounded-xl border border-primary bg-primary/10 p-3 text-primary dark:border-primary dark:bg-primary/15 dark:text-slate-100";
|
|
273
|
+
}
|
|
274
|
+
return "items-start gap-3 rounded-xl border border-gray-200 bg-white p-3 text-gray-700 hover:border-primary/40 hover:bg-primary/5 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 dark:hover:border-primary/50 dark:hover:bg-primary/10";
|
|
186
275
|
},
|
|
187
276
|
iconWrapperClass(option) {
|
|
188
277
|
if (this.isTableVariant) {
|
|
@@ -194,15 +283,52 @@ export default {
|
|
|
194
283
|
return "flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10 text-primary";
|
|
195
284
|
},
|
|
196
285
|
checkClass(option) {
|
|
286
|
+
const selected = this.isSelected(option);
|
|
287
|
+
const colored = this.isTinted(option);
|
|
288
|
+
const marker = this.intentStyles(option).marker;
|
|
289
|
+
|
|
197
290
|
if (this.isTableVariant) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
291
|
+
if (selected) {
|
|
292
|
+
const fill = colored ? marker : "bg-primary";
|
|
293
|
+
return `inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full ${fill} text-[11px] font-semibold text-white`;
|
|
294
|
+
}
|
|
295
|
+
return "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-slate-300 text-[11px] font-semibold text-transparent dark:border-slate-600";
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (selected) {
|
|
299
|
+
const fill = colored ? marker : "border-primary bg-primary";
|
|
300
|
+
return `mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border ${fill} text-[11px] font-semibold text-white`;
|
|
301
|
+
}
|
|
302
|
+
return "mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-gray-300 text-[11px] font-semibold text-transparent dark:border-slate-600";
|
|
303
|
+
},
|
|
304
|
+
showIndicator() {
|
|
305
|
+
return this.indicator !== "none";
|
|
306
|
+
},
|
|
307
|
+
indicatorClass(option) {
|
|
308
|
+
const selected = this.isSelected(option);
|
|
309
|
+
const marker = this.intentStyles(option).marker;
|
|
310
|
+
|
|
311
|
+
if (this.indicator === "checkbox") {
|
|
312
|
+
const base = "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md border text-[11px] font-semibold";
|
|
313
|
+
return selected
|
|
314
|
+
? `${base} ${marker} text-white`
|
|
315
|
+
: `${base} border-slate-300 text-transparent dark:border-slate-600`;
|
|
201
316
|
}
|
|
202
317
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
318
|
+
if (this.indicator === "radio") {
|
|
319
|
+
const base = "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border";
|
|
320
|
+
return selected
|
|
321
|
+
? `${base} ${marker.split(" ")[1]}`
|
|
322
|
+
: `${base} border-slate-300 dark:border-slate-600`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return this.checkClass(option);
|
|
326
|
+
},
|
|
327
|
+
radioDotClass(option) {
|
|
328
|
+
return this.intentStyles(option).marker.split(" ")[0];
|
|
329
|
+
},
|
|
330
|
+
badgeClass(option) {
|
|
331
|
+
return `text-sm font-semibold ${this.intentStyles(option).text}`;
|
|
206
332
|
},
|
|
207
333
|
},
|
|
208
334
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// intent -> pieces the row/marker/badge compose from
|
|
2
|
+
export const OPTION_INTENT_STYLES = {
|
|
3
|
+
primary: { text: "text-sky-700 dark:text-sky-300", accent: "border-l-sky-500", softBg: "bg-sky-100 dark:bg-sky-500/15", selBg: "bg-sky-100 border-sky-300 dark:bg-sky-500/15 dark:border-sky-500/50", marker: "bg-sky-600 border-sky-600" },
|
|
4
|
+
secondary: { text: "text-slate-700 dark:text-slate-200", accent: "border-l-slate-500", softBg: "bg-slate-100 dark:bg-slate-700/50", selBg: "bg-slate-100 border-slate-300 dark:bg-slate-700/50 dark:border-slate-500", marker: "bg-slate-700 border-slate-700" },
|
|
5
|
+
success: { text: "text-emerald-700 dark:text-emerald-300", accent: "border-l-emerald-500", softBg: "bg-emerald-100 dark:bg-emerald-500/15", selBg: "bg-emerald-100 border-emerald-300 dark:bg-emerald-500/15 dark:border-emerald-500/50", marker: "bg-emerald-600 border-emerald-600" },
|
|
6
|
+
warning: { text: "text-amber-700 dark:text-amber-300", accent: "border-l-amber-500", softBg: "bg-amber-100 dark:bg-amber-500/15", selBg: "bg-amber-100 border-amber-300 dark:bg-amber-500/15 dark:border-amber-500/50", marker: "bg-amber-600 border-amber-600" },
|
|
7
|
+
danger: { text: "text-rose-700 dark:text-rose-300", accent: "border-l-rose-500", softBg: "bg-rose-100 dark:bg-rose-500/15", selBg: "bg-rose-100 border-rose-300 dark:bg-rose-500/15 dark:border-rose-500/50", marker: "bg-rose-600 border-rose-600" },
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const OPTION_INTENTS = Object.keys(OPTION_INTENT_STYLES);
|