ketekny-ui-kit 1.0.95 → 1.0.97
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/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import kTable from './src/ui/kTable.vue'
|
|
|
14
14
|
import kTabs from './src/ui/kTabs.vue'
|
|
15
15
|
import kToggle from './src/ui/kToggle.vue'
|
|
16
16
|
import kForm from './src/ui/kForm.vue'
|
|
17
|
+
import kOptionGroup from './src/ui/kOptionGroup.vue'
|
|
17
18
|
import kUploader from './src/ui/kUploader.vue'
|
|
18
19
|
import kEditor from './src/ui/kEditor.vue'
|
|
19
20
|
import kSpinner from './src/ui/kSpinner.vue'
|
|
@@ -57,7 +58,7 @@ export {
|
|
|
57
58
|
kMessage, kCode, kToolbar, kTable, kTabs, kChip, kSpinner, kDatatable, kIcon, kMenu, kSkeleton, kProgressBar, kPagination, kTree,
|
|
58
59
|
|
|
59
60
|
// Form Components
|
|
60
|
-
kButton, kCheckbox, kSelect, kUploader, kToggle, kInput, kDateSelector, kEditor, kSelectButton, kTags, kSearch, kArrayList, kList, kTextArea, kForm,
|
|
61
|
+
kButton, kCheckbox, kSelect, kUploader, kToggle, kInput, kDateSelector, kEditor, kSelectButton, kTags, kSearch, kArrayList, kList, kTextArea, kForm, kOptionGroup,
|
|
61
62
|
|
|
62
63
|
// Dialogs
|
|
63
64
|
kDialog, kDrawer,
|
package/package.json
CHANGED
package/src/style/style.css
CHANGED
|
@@ -314,7 +314,7 @@ export default {
|
|
|
314
314
|
type="text"
|
|
315
315
|
placeholder="Αναζήτηση μενού..."
|
|
316
316
|
aria-label="Αναζήτηση μενού"
|
|
317
|
-
class="w-full
|
|
317
|
+
class="w-full border rounded-md border-sidebar-border/35 bg-sidebar-accent/40 py-2 pl-8 pr-9 text-sidebar-foreground placeholder:text-sidebar-muted focus:border-white/15 focus:outline-none focus:ring-1 focus:ring-white/10"
|
|
318
318
|
/>
|
|
319
319
|
<button
|
|
320
320
|
v-if="query"
|
|
@@ -348,7 +348,7 @@ export default {
|
|
|
348
348
|
</ul>
|
|
349
349
|
<p
|
|
350
350
|
v-if="!collapsed && filteredMenu.length === 0"
|
|
351
|
-
class="px-3 py-6 text-
|
|
351
|
+
class="px-3 py-6 text-center text-sidebar-muted"
|
|
352
352
|
>
|
|
353
353
|
Δεν βρέθηκαν αποτελέσματα.
|
|
354
354
|
</p>
|
|
@@ -359,7 +359,7 @@ export default {
|
|
|
359
359
|
<div v-if="!collapsed" class="flex items-center gap-2">
|
|
360
360
|
<button
|
|
361
361
|
type="button"
|
|
362
|
-
class="sidebar-footer-item flex min-h-[38px] flex-1 items-center gap-2.5 rounded-md bg-transparent px-2 py-2 text-left
|
|
362
|
+
class="sidebar-footer-item flex min-h-[38px] flex-1 items-center gap-2.5 rounded-md bg-transparent px-2 py-2 text-left font-medium text-sidebar-foreground/80 outline-none transition-colors duration-150 hover:bg-sidebar-accent hover:text-sidebar-foreground"
|
|
363
363
|
@click="handleFooterSelect('my-profile')"
|
|
364
364
|
>
|
|
365
365
|
<CircleUser class="sidebar-footer-item-icon size-4 shrink-0" :stroke-width="1.9" />
|
|
@@ -382,7 +382,7 @@ export default {
|
|
|
382
382
|
v-if="collapsed"
|
|
383
383
|
type="button"
|
|
384
384
|
v-tooltip.right="link.label"
|
|
385
|
-
class="flex items-center w-full
|
|
385
|
+
class="flex items-center w-full rounded-md transition-colors duration-150"
|
|
386
386
|
:class="[
|
|
387
387
|
'justify-center px-0 py-2',
|
|
388
388
|
activeId === link.id
|
|
@@ -412,7 +412,7 @@ export default {
|
|
|
412
412
|
:key="`${link.id}-expanded`"
|
|
413
413
|
v-else
|
|
414
414
|
type="button"
|
|
415
|
-
class="flex items-center w-full
|
|
415
|
+
class="flex items-center w-full rounded-md transition-colors duration-150"
|
|
416
416
|
:class="[
|
|
417
417
|
'gap-2.5 px-2 py-2 text-left',
|
|
418
418
|
activeId === link.id
|
|
@@ -82,7 +82,7 @@ export default {
|
|
|
82
82
|
<button
|
|
83
83
|
type="button"
|
|
84
84
|
:style="isCollapsedTop ? undefined : indentStyle"
|
|
85
|
-
class="group relative flex w-full items-center rounded-md text-left
|
|
85
|
+
class="group relative flex w-full items-center rounded-md text-left transition-colors duration-150"
|
|
86
86
|
:class="[
|
|
87
87
|
isCollapsedTop ? 'h-10 justify-center px-0' : 'gap-2.5 py-2 pr-2',
|
|
88
88
|
isActiveLeaf || (isCollapsedTop && isActive)
|
|
@@ -181,7 +181,7 @@ export default {
|
|
|
181
181
|
>
|
|
182
182
|
<button
|
|
183
183
|
type="button"
|
|
184
|
-
class="mb-1 flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left
|
|
184
|
+
class="mb-1 flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left font-semibold"
|
|
185
185
|
:class="isActive ? 'text-brand' : 'text-sidebar-foreground hover:bg-sidebar-accent'"
|
|
186
186
|
@click="!hasChildren && $emit('select', item)"
|
|
187
187
|
>
|
package/src/ui/kList.vue
CHANGED
|
@@ -7,7 +7,13 @@
|
|
|
7
7
|
<div
|
|
8
8
|
v-for="(stat, index) in normalizedStats"
|
|
9
9
|
:key="resolveKey(stat, index)"
|
|
10
|
-
class="flex items-center gap-3
|
|
10
|
+
class="flex items-center gap-3 border border-gray-200 rounded-xl bg-white p-3 dark:border-slate-700 dark:bg-slate-800"
|
|
11
|
+
:class="entryClass(stat)"
|
|
12
|
+
:role="stat.action ? 'button' : undefined"
|
|
13
|
+
:tabindex="stat.action ? 0 : undefined"
|
|
14
|
+
@click="handleAction(stat, index)"
|
|
15
|
+
@keydown.enter.prevent="handleAction(stat, index)"
|
|
16
|
+
@keydown.space.prevent="handleAction(stat, index)"
|
|
11
17
|
>
|
|
12
18
|
<div
|
|
13
19
|
v-if="stat.icon"
|
|
@@ -39,6 +45,12 @@
|
|
|
39
45
|
v-for="(stat, index) in normalizedStats"
|
|
40
46
|
:key="resolveKey(stat, index)"
|
|
41
47
|
class="border-b border-gray-200 last:border-b-0 dark:border-slate-700"
|
|
48
|
+
:class="entryClass(stat)"
|
|
49
|
+
:role="stat.action ? 'button' : undefined"
|
|
50
|
+
:tabindex="stat.action ? 0 : undefined"
|
|
51
|
+
@click="handleAction(stat, index)"
|
|
52
|
+
@keydown.enter.prevent="handleAction(stat, index)"
|
|
53
|
+
@keydown.space.prevent="handleAction(stat, index)"
|
|
42
54
|
>
|
|
43
55
|
<td class="px-4 py-3 text-sm text-gray-600 dark:text-slate-400">
|
|
44
56
|
<div class="flex items-center gap-2">
|
|
@@ -89,15 +101,18 @@ export default {
|
|
|
89
101
|
validator: (value) => ['col', 'row'].includes(value),
|
|
90
102
|
},
|
|
91
103
|
},
|
|
104
|
+
emits: ['action'],
|
|
92
105
|
computed: {
|
|
93
106
|
isRowFormat() {
|
|
94
107
|
return this.format === 'row'
|
|
95
108
|
},
|
|
96
109
|
normalizedStats() {
|
|
97
110
|
return this.stats.map((stat) => ({
|
|
111
|
+
raw: stat,
|
|
98
112
|
label: stat?.label ?? '',
|
|
99
113
|
value: stat?.value ?? '-',
|
|
100
114
|
icon: stat?.icon ?? null,
|
|
115
|
+
action: typeof stat?.action === 'function' ? stat.action : null,
|
|
101
116
|
}))
|
|
102
117
|
},
|
|
103
118
|
},
|
|
@@ -105,6 +120,16 @@ export default {
|
|
|
105
120
|
resolveKey(stat, index) {
|
|
106
121
|
return `${String(stat.label)}-${index}`
|
|
107
122
|
},
|
|
123
|
+
entryClass(stat) {
|
|
124
|
+
return stat.action
|
|
125
|
+
? 'cursor-pointer transition hover:border-primary/40 hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-primary/20 dark:hover:bg-slate-700/70'
|
|
126
|
+
: ''
|
|
127
|
+
},
|
|
128
|
+
handleAction(stat, index) {
|
|
129
|
+
if (!stat.action) return
|
|
130
|
+
stat.action(stat.raw, index)
|
|
131
|
+
this.$emit('action', stat.raw, index)
|
|
132
|
+
},
|
|
108
133
|
},
|
|
109
134
|
}
|
|
110
135
|
</script>
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="w-full">
|
|
3
|
+
<div
|
|
4
|
+
v-if="title"
|
|
5
|
+
:class="titleClass"
|
|
6
|
+
>
|
|
7
|
+
{{ title }}
|
|
8
|
+
</div>
|
|
9
|
+
<div :class="containerClass">
|
|
10
|
+
<button
|
|
11
|
+
v-for="(option, index) in normalizedOptions"
|
|
12
|
+
:key="resolveKey(option, index)"
|
|
13
|
+
type="button"
|
|
14
|
+
class="flex w-full text-left transition"
|
|
15
|
+
:class="buttonClass(option)"
|
|
16
|
+
@click="toggleOption(option)"
|
|
17
|
+
>
|
|
18
|
+
<div
|
|
19
|
+
v-if="option.icon"
|
|
20
|
+
class="shrink-0"
|
|
21
|
+
:class="iconWrapperClass(option)"
|
|
22
|
+
>
|
|
23
|
+
<kIcon
|
|
24
|
+
v-if="typeof option.icon === 'string'"
|
|
25
|
+
:name="option.icon"
|
|
26
|
+
:size="iconSize"
|
|
27
|
+
/>
|
|
28
|
+
<component
|
|
29
|
+
:is="option.icon"
|
|
30
|
+
v-else
|
|
31
|
+
:class="iconComponentClass"
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="min-w-0 flex-1">
|
|
36
|
+
<div :class="contentRowClass">
|
|
37
|
+
<div class="min-w-0">
|
|
38
|
+
<div class="truncate text-sm font-semibold">
|
|
39
|
+
{{ option.label }}
|
|
40
|
+
</div>
|
|
41
|
+
<div
|
|
42
|
+
v-if="option.description"
|
|
43
|
+
:class="descriptionClass"
|
|
44
|
+
>
|
|
45
|
+
{{ option.description }}
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<span
|
|
49
|
+
:class="checkClass(option)"
|
|
50
|
+
>
|
|
51
|
+
✓
|
|
52
|
+
</span>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script>
|
|
61
|
+
import kIcon from "./kIcon.vue";
|
|
62
|
+
|
|
63
|
+
export default {
|
|
64
|
+
name: "kOptionGroup",
|
|
65
|
+
components: {
|
|
66
|
+
kIcon,
|
|
67
|
+
},
|
|
68
|
+
props: {
|
|
69
|
+
modelValue: {
|
|
70
|
+
type: Array,
|
|
71
|
+
default: () => [],
|
|
72
|
+
},
|
|
73
|
+
options: {
|
|
74
|
+
type: Array,
|
|
75
|
+
default: () => [],
|
|
76
|
+
},
|
|
77
|
+
selection: {
|
|
78
|
+
type: String,
|
|
79
|
+
default: "multiple",
|
|
80
|
+
validator: (value) => ["single", "multiple"].includes(value),
|
|
81
|
+
},
|
|
82
|
+
variant: {
|
|
83
|
+
type: String,
|
|
84
|
+
default: "table",
|
|
85
|
+
validator: (value) => ["table", "card"].includes(value),
|
|
86
|
+
},
|
|
87
|
+
title: {
|
|
88
|
+
type: String,
|
|
89
|
+
default: "",
|
|
90
|
+
},
|
|
91
|
+
valueKey: {
|
|
92
|
+
type: String,
|
|
93
|
+
default: "value",
|
|
94
|
+
},
|
|
95
|
+
labelKey: {
|
|
96
|
+
type: String,
|
|
97
|
+
default: "label",
|
|
98
|
+
},
|
|
99
|
+
descriptionKey: {
|
|
100
|
+
type: String,
|
|
101
|
+
default: "description",
|
|
102
|
+
},
|
|
103
|
+
iconKey: {
|
|
104
|
+
type: String,
|
|
105
|
+
default: "icon",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
emits: ["update:modelValue", "change"],
|
|
109
|
+
computed: {
|
|
110
|
+
isMultiple() {
|
|
111
|
+
return this.selection === "multiple";
|
|
112
|
+
},
|
|
113
|
+
isTableVariant() {
|
|
114
|
+
return this.variant === "table";
|
|
115
|
+
},
|
|
116
|
+
normalizedSelection() {
|
|
117
|
+
return Array.isArray(this.modelValue) ? this.modelValue : [];
|
|
118
|
+
},
|
|
119
|
+
normalizedOptions() {
|
|
120
|
+
return this.options.map((option) => ({
|
|
121
|
+
raw: option,
|
|
122
|
+
value: option?.[this.valueKey],
|
|
123
|
+
label: option?.[this.labelKey] ?? "",
|
|
124
|
+
description: option?.[this.descriptionKey] ?? "",
|
|
125
|
+
icon: option?.[this.iconKey] ?? null,
|
|
126
|
+
}));
|
|
127
|
+
},
|
|
128
|
+
containerClass() {
|
|
129
|
+
return this.isTableVariant
|
|
130
|
+
? "overflow-hidden rounded-xl border border-slate-200 bg-white dark:border-slate-700 dark:bg-slate-900"
|
|
131
|
+
: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3";
|
|
132
|
+
},
|
|
133
|
+
titleClass() {
|
|
134
|
+
return this.isTableVariant
|
|
135
|
+
? "mb-2 text-xs font-semibold uppercase tracking-[0.12em] text-slate-500 dark:text-slate-400"
|
|
136
|
+
: "mb-3 text-sm font-semibold text-slate-800 dark:text-slate-100";
|
|
137
|
+
},
|
|
138
|
+
contentRowClass() {
|
|
139
|
+
return this.isTableVariant ? "flex items-center justify-between gap-3" : "flex items-start justify-between gap-3";
|
|
140
|
+
},
|
|
141
|
+
descriptionClass() {
|
|
142
|
+
return this.isTableVariant
|
|
143
|
+
? "mt-0.5 text-xs text-gray-500 dark:text-slate-400"
|
|
144
|
+
: "mt-1 text-xs text-gray-500 dark:text-slate-400";
|
|
145
|
+
},
|
|
146
|
+
iconSize() {
|
|
147
|
+
return this.isTableVariant ? 16 : 18;
|
|
148
|
+
},
|
|
149
|
+
iconComponentClass() {
|
|
150
|
+
return this.isTableVariant ? "h-4 w-4" : "h-[18px] w-[18px]";
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
methods: {
|
|
154
|
+
isSelected(option) {
|
|
155
|
+
return this.normalizedSelection.includes(option.value);
|
|
156
|
+
},
|
|
157
|
+
toggleOption(option) {
|
|
158
|
+
let nextSelection = [];
|
|
159
|
+
|
|
160
|
+
if (this.isMultiple) {
|
|
161
|
+
nextSelection = [...this.normalizedSelection];
|
|
162
|
+
const selectedIndex = nextSelection.indexOf(option.value);
|
|
163
|
+
|
|
164
|
+
if (selectedIndex === -1) nextSelection.push(option.value);
|
|
165
|
+
else nextSelection.splice(selectedIndex, 1);
|
|
166
|
+
} else {
|
|
167
|
+
nextSelection = this.isSelected(option) ? [] : [option.value];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.$emit("update:modelValue", nextSelection);
|
|
171
|
+
this.$emit("change", nextSelection);
|
|
172
|
+
},
|
|
173
|
+
resolveKey(option, index) {
|
|
174
|
+
return `${String(option.value ?? option.label)}-${index}`;
|
|
175
|
+
},
|
|
176
|
+
buttonClass(option) {
|
|
177
|
+
if (this.isTableVariant) {
|
|
178
|
+
return this.isSelected(option)
|
|
179
|
+
? "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"
|
|
180
|
+
: "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
|
+
}
|
|
182
|
+
|
|
183
|
+
return this.isSelected(option)
|
|
184
|
+
? "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"
|
|
185
|
+
: "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
|
+
},
|
|
187
|
+
iconWrapperClass(option) {
|
|
188
|
+
if (this.isTableVariant) {
|
|
189
|
+
return this.isSelected(option)
|
|
190
|
+
? "flex h-8 w-8 items-center justify-center rounded-md bg-primary/15 text-primary"
|
|
191
|
+
: "flex h-8 w-8 items-center justify-center rounded-md bg-slate-100 text-slate-500 dark:bg-slate-800 dark:text-slate-300";
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return "flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10 text-primary";
|
|
195
|
+
},
|
|
196
|
+
checkClass(option) {
|
|
197
|
+
if (this.isTableVariant) {
|
|
198
|
+
return this.isSelected(option)
|
|
199
|
+
? "inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-primary text-[11px] font-semibold text-white"
|
|
200
|
+
: "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";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return this.isSelected(option)
|
|
204
|
+
? "mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-primary bg-primary text-[11px] font-semibold text-white"
|
|
205
|
+
: "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";
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
</script>
|