ketekny-ui-kit 1.0.15 → 1.0.16
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 +1 -1
- package/src/layout/kAppFooter.vue +1 -1
- package/src/layout/kAppMain.vue +1 -1
- package/src/layout/kHero.vue +1 -1
- package/src/ui/kAlert.vue +1 -1
- package/src/ui/kArrayList.vue +3 -3
- package/src/ui/kCode.vue +1 -1
- package/src/ui/kConfirmDialog.vue +3 -3
- package/src/ui/kDatatable.vue +4 -4
- package/src/ui/kDateSelector.vue +10 -10
- package/src/ui/kEditor.vue +5 -5
- package/src/ui/kIcon.vue +1 -1
- package/src/ui/kInput.vue +1 -1
- package/src/ui/kMenu.vue +183 -25
- package/src/ui/kMessage.vue +1 -1
- package/src/ui/kSearch.vue +2 -2
- package/src/ui/kSelect.vue +1 -1
- package/src/ui/kSelectButton.vue +3 -3
- package/src/ui/kSkeleton.vue +1 -1
- package/src/ui/kSpinner.vue +5 -5
- package/src/ui/kTags.vue +4 -4
- package/src/ui/kTextArea.vue +3 -3
- package/src/ui/kToast.vue +2 -2
- package/src/ui/kToggle.vue +3 -3
- package/src/ui/kToolbar.vue +19 -9
- package/src/ui/kTree.vue +3 -3
- package/src/ui/kUploader.vue +4 -4
- package/src/ui/themes/kInput.theme.js +4 -4
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template lang="">
|
|
2
|
-
<footer class="py-4 mt-auto text-
|
|
2
|
+
<footer class="py-4 mt-auto text-primary/80 border-t border-primary/20 no-print" :class="class">
|
|
3
3
|
<div class="container mx-auto" v-if="fullWidth == null">
|
|
4
4
|
<slot></slot>
|
|
5
5
|
</div>
|
package/src/layout/kAppMain.vue
CHANGED
package/src/layout/kHero.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template lang="">
|
|
2
|
-
<section class="py-16 text-white border bg-dark
|
|
2
|
+
<section class="py-16 text-white border rounded-xl bg-dark border-primary/30 shadow-[0_0_0_1px_rgb(34_197_94_/_0.12)]">
|
|
3
3
|
<div class="container px-4 mx-auto text-center">
|
|
4
4
|
<slot></slot>
|
|
5
5
|
</div>
|
package/src/ui/kAlert.vue
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<!-- Alert card -->
|
|
8
8
|
<div
|
|
9
|
-
class="relative w-full max-w-sm p-6 space-y-4 text-center bg-white shadow-2xl z-5010 rounded-2xl"
|
|
9
|
+
class="relative w-full max-w-sm p-6 space-y-4 text-center bg-white border shadow-2xl z-5010 rounded-2xl border-primary/20 ring-1 ring-primary/10"
|
|
10
10
|
:class="['border-semantic-' + type + '-border']"
|
|
11
11
|
style="z-index: 5010"
|
|
12
12
|
>
|
package/src/ui/kArrayList.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- kInputList.vue -->
|
|
2
2
|
<template>
|
|
3
3
|
<div class="w-full">
|
|
4
|
-
<label v-if="label" :for="id" class="block mb-1 text-sm font-medium text-
|
|
4
|
+
<label v-if="label" :for="id" class="block mb-1 text-sm font-medium text-primary/90">
|
|
5
5
|
{{ label }}
|
|
6
6
|
</label>
|
|
7
7
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
:disabled="disabled"
|
|
14
14
|
:class="[
|
|
15
15
|
'block w-full p-3 transition border border-gray-300 shadow-sm outline-none rounded-xl',
|
|
16
|
-
disabled ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : 'bg-white focus:border-
|
|
16
|
+
disabled ? 'bg-gray-100 text-gray-400 cursor-not-allowed' : 'bg-white focus:border-primary focus:ring-2 focus:ring-primary/20',
|
|
17
17
|
]"
|
|
18
18
|
@focus="isFocused = true"
|
|
19
19
|
@blur="isFocused = false"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
></textarea>
|
|
23
23
|
|
|
24
24
|
<div class="flex items-center justify-between mt-2 text-xs text-gray-500">
|
|
25
|
-
<span>Items: <span class="font-semibold text-
|
|
25
|
+
<span>Items: <span class="font-semibold text-primary">{{ count }}</span></span>
|
|
26
26
|
<span v-if="hint">{{ hint }}</span>
|
|
27
27
|
</div>
|
|
28
28
|
</div>
|
package/src/ui/kCode.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!-- kCode.vue -->
|
|
2
2
|
<template>
|
|
3
|
-
<div class="p-4 mt-3 overflow-hidden text-white whitespace-pre bg-gray-900 border rounded-lg">
|
|
3
|
+
<div class="p-4 mt-3 overflow-hidden text-white whitespace-pre bg-gray-900 border rounded-lg border-primary/30">
|
|
4
4
|
<div class="overflow-auto">
|
|
5
5
|
<code>{{ normalizedContent }}</code>
|
|
6
6
|
</div>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Teleport to="body">
|
|
3
3
|
<Transition name="fade">
|
|
4
|
-
<div v-if="visible" class="fixed inset-0
|
|
5
|
-
<div class="w-full max-w-md p-6 bg-white rounded-lg shadow-xl">
|
|
6
|
-
<h2 class="mb-2 text-lg font-semibold">{{ title }}</h2>
|
|
4
|
+
<div v-if="visible" class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-40" style="z-index: 1500">
|
|
5
|
+
<div class="w-full max-w-md p-6 bg-white border rounded-lg shadow-xl border-primary/20">
|
|
6
|
+
<h2 class="mb-2 text-lg font-semibold text-primary">{{ title }}</h2>
|
|
7
7
|
<div class="mb-6 text-gray-700"><span v-html="message" /></div>
|
|
8
8
|
<div class="flex justify-end gap-3">
|
|
9
9
|
<kButton :disabled="loading" secondary label="Άκυρο" @click="cancel" />
|
package/src/ui/kDatatable.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="disabled ? 'pointer-events-none opacity-60' : ''">
|
|
2
|
+
<div :class="['rounded-lg border border-primary/15', disabled ? 'pointer-events-none opacity-60' : '']">
|
|
3
3
|
<EasyDataTable
|
|
4
4
|
v-bind="$attrs"
|
|
5
5
|
:headers="headers"
|
|
@@ -120,7 +120,7 @@ export default {
|
|
|
120
120
|
--easy-table-body-row-height: 3.2rem;
|
|
121
121
|
--easy-table-body-row-font-size: 12px;
|
|
122
122
|
--easy-table-body-row-hover-font-color: #1f2937;
|
|
123
|
-
--easy-table-body-row-hover-background-color: #
|
|
123
|
+
--easy-table-body-row-hover-background-color: #ecfdf3;
|
|
124
124
|
--easy-table-body-item-padding: 0.5rem 0.75rem;
|
|
125
125
|
|
|
126
126
|
--easy-table-footer-background-color: transparent;
|
|
@@ -137,7 +137,7 @@ export default {
|
|
|
137
137
|
|
|
138
138
|
--easy-table-scrollbar-track-color: transparent;
|
|
139
139
|
--easy-table-scrollbar-color: transparent;
|
|
140
|
-
--easy-table-scrollbar-thumb-color: #
|
|
140
|
+
--easy-table-scrollbar-thumb-color: #86efac;
|
|
141
141
|
--easy-table-scrollbar-corner-color: transparent;
|
|
142
142
|
|
|
143
143
|
--easy-table-loading-mask-background-color: rgba(255, 255, 255, 0.6);
|
|
@@ -155,7 +155,7 @@ export default {
|
|
|
155
155
|
background-color: #fff; /* white dropdown background */
|
|
156
156
|
color: #1f2937; /* gray-800 text */
|
|
157
157
|
padding: 0.25rem 0.5rem; /* small padding */
|
|
158
|
-
border: 1px solid #
|
|
158
|
+
border: 1px solid #bbf7d0;
|
|
159
159
|
border-radius: 0.25rem;
|
|
160
160
|
}
|
|
161
161
|
|
package/src/ui/kDateSelector.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative w-full">
|
|
3
|
-
<label :for="id" class="inputLabel" :class="hasError || inputInvalid ? 'text-red-500' : 'text-
|
|
3
|
+
<label :for="id" class="inputLabel" :class="hasError || inputInvalid ? 'text-red-500' : 'text-primary/90'">
|
|
4
4
|
{{ label }}
|
|
5
5
|
</label>
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<!-- Right-side calendar icon (opens popup) -->
|
|
23
23
|
<button
|
|
24
24
|
type="button"
|
|
25
|
-
class="absolute p-1 text-
|
|
25
|
+
class="absolute p-1 text-primary/70 -translate-y-1/2 right-2 top-1/2 hover:text-primary disabled:opacity-50"
|
|
26
26
|
:disabled="disabled"
|
|
27
27
|
@click="openCalendar"
|
|
28
28
|
aria-label="Open calendar"
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
<!-- Right-side calendar icon (opens month grid) -->
|
|
46
46
|
<button
|
|
47
47
|
type="button"
|
|
48
|
-
class="absolute p-1 text-
|
|
48
|
+
class="absolute p-1 text-primary/70 -translate-y-1/2 right-2 top-1/2 hover:text-primary disabled:opacity-50"
|
|
49
49
|
:disabled="disabled"
|
|
50
50
|
@click.stop="togglePopup"
|
|
51
51
|
aria-label="Open month selector"
|
|
@@ -67,14 +67,14 @@
|
|
|
67
67
|
|
|
68
68
|
<!-- Month Grid Popover (Teleported) -->
|
|
69
69
|
<teleport to="body">
|
|
70
|
-
<div v-if="showPopup" class="p-4 bg-white border
|
|
70
|
+
<div v-if="showPopup" class="p-4 bg-white border rounded-lg shadow-lg border-primary/20" :style="popupStyles">
|
|
71
71
|
<!-- Year Nav -->
|
|
72
72
|
<div class="flex items-center justify-between pb-3 mb-4 border-b">
|
|
73
|
-
<button @click.stop="currentYear--" class="text-
|
|
73
|
+
<button @click.stop="currentYear--" class="text-primary/80 hover:text-primary" aria-label="Previous year">
|
|
74
74
|
<ChevronLeft />
|
|
75
75
|
</button>
|
|
76
|
-
<span class="font-medium text-
|
|
77
|
-
<button @click.stop="currentYear++" class="text-
|
|
76
|
+
<span class="font-medium text-primary">{{ currentYear }}</span>
|
|
77
|
+
<button @click.stop="currentYear++" class="text-primary/80 hover:text-primary" aria-label="Next year">
|
|
78
78
|
<ChevronRight />
|
|
79
79
|
</button>
|
|
80
80
|
</div>
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
:key="index"
|
|
87
87
|
@click="selectMonth(index + 1)"
|
|
88
88
|
class="px-3 py-2 text-center transition rounded-lg cursor-pointer"
|
|
89
|
-
:class="[isSelected(index + 1) ? 'bg-
|
|
89
|
+
:class="[isSelected(index + 1) ? 'bg-primary text-white' : 'hover:bg-primary/10 text-gray-700']"
|
|
90
90
|
>
|
|
91
91
|
{{ month }}
|
|
92
92
|
</div>
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
<div class="text-sm text-red-500" v-if="inputInvalid && !hasError">Μη έγκυρη ημερομηνία. Χρησιμοποιήστε μορφή dd/mm/yyyy.</div>
|
|
105
105
|
|
|
106
106
|
<!-- Info message -->
|
|
107
|
-
<div class="text-sm text-
|
|
107
|
+
<div class="text-sm text-primary/80" v-if="info != null">
|
|
108
108
|
{{ info }}
|
|
109
109
|
</div>
|
|
110
110
|
</div>
|
|
@@ -148,7 +148,7 @@ export default {
|
|
|
148
148
|
})();
|
|
149
149
|
|
|
150
150
|
return {
|
|
151
|
-
defaultStyle: "w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-
|
|
151
|
+
defaultStyle: "w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-2 focus:ring-primary/20 focus:border-primary bg-white placeholder-gray-400",
|
|
152
152
|
errorStyle: "border-red-500 focus:ring focus:ring-red-300",
|
|
153
153
|
disabledStyle: "!bg-gray-100 !text-gray-400 !cursor-not-allowed",
|
|
154
154
|
|
package/src/ui/kEditor.vue
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="inputLabel" :class="hasError ? 'text-red-500' : 'text-
|
|
2
|
+
<div class="inputLabel" :class="hasError ? 'text-red-500' : 'text-primary/90'">
|
|
3
3
|
{{ label }}
|
|
4
4
|
</div>
|
|
5
5
|
<div class="w-full">
|
|
6
6
|
<!-- Toolbar -->
|
|
7
|
-
<div class="flex items-center gap-2 px-2 py-1 border rounded-t-md bg-
|
|
7
|
+
<div class="flex items-center gap-2 px-2 py-1 border rounded-t-md bg-primary/5 border-primary/20">
|
|
8
8
|
<button
|
|
9
9
|
:disabled="disabled"
|
|
10
10
|
v-for="(cmd, i) in toolbar"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
@click.prevent="exec(cmd.command, cmd.value)"
|
|
13
13
|
:title="cmd.title"
|
|
14
14
|
class="text-gray-600 p-1.5 rounded"
|
|
15
|
-
:class="disabled == false ? 'hover:text-
|
|
15
|
+
:class="disabled == false ? 'hover:text-primary hover:bg-primary/10' : ''"
|
|
16
16
|
>
|
|
17
17
|
<component :is="cmd.icon" class="w-5 h-5" />
|
|
18
18
|
</button>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
</div>
|
|
33
33
|
|
|
34
34
|
<!-- Info message -->
|
|
35
|
-
<div class="text-sm text-
|
|
35
|
+
<div class="text-sm text-primary/80" v-if="info != null">
|
|
36
36
|
{{ info }}
|
|
37
37
|
</div>
|
|
38
38
|
</div>
|
|
@@ -65,7 +65,7 @@ export default {
|
|
|
65
65
|
data() {
|
|
66
66
|
return {
|
|
67
67
|
defaultStyle:
|
|
68
|
-
"w-full px-3 py-2 border rounded-b-lg transition shadow-sm focus:outline-none focus:ring-
|
|
68
|
+
"w-full px-3 py-2 border rounded-b-lg transition shadow-sm focus:outline-none focus:ring-2 focus:ring-primary/20 min-h-[150px] focus:border-primary bg-white placeholder-gray-400 !list-disc !list-inside prose",
|
|
69
69
|
errorStyle: "border-red-500 focus:ring focus:ring-red-300' : 'border-gray-300 focus:ring focus:ring-blue-300",
|
|
70
70
|
disabledStyle: "!bg-gray-100 !text-gray-400 !cursor-not-allowed editor pointer-events-none select-none",
|
|
71
71
|
toolbar: [
|
package/src/ui/kIcon.vue
CHANGED
package/src/ui/kInput.vue
CHANGED
package/src/ui/kMenu.vue
CHANGED
|
@@ -1,51 +1,209 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="relative inline-block text-left">
|
|
3
|
-
<div @click="toggleMenu">
|
|
4
|
-
<slot name="trigger"></slot>
|
|
5
|
-
</div>
|
|
2
|
+
<div ref="menuRef" class="relative inline-block text-left">
|
|
6
3
|
<div
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
ref="triggerRef"
|
|
5
|
+
role="button"
|
|
6
|
+
tabindex="0"
|
|
7
|
+
:aria-expanded="isOpen.toString()"
|
|
8
|
+
:aria-haspopup="'menu'"
|
|
9
|
+
:aria-label="ariaLabel"
|
|
10
|
+
class="rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30"
|
|
11
|
+
@click="toggleMenu"
|
|
12
|
+
@keydown.enter.prevent="toggleMenu"
|
|
13
|
+
@keydown.space.prevent="toggleMenu">
|
|
14
|
+
<slot name="trigger">
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
class="inline-flex items-center justify-center px-3 py-2 text-base font-medium text-center transition border rounded-lg shadow-sm bg-white border-slate-200 text-slate-700 hover:bg-slate-50">
|
|
18
|
+
Menu
|
|
19
|
+
</button>
|
|
20
|
+
</slot>
|
|
11
21
|
</div>
|
|
22
|
+
|
|
23
|
+
<Teleport to="body">
|
|
24
|
+
<div
|
|
25
|
+
v-if="isOpen"
|
|
26
|
+
ref="menuPanelRef"
|
|
27
|
+
class="z-[9999] overflow-visible border rounded-lg shadow-lg bg-white/95 backdrop-blur-sm border-primary/20 ring-1 ring-primary/10"
|
|
28
|
+
:style="panelStyle"
|
|
29
|
+
role="menu">
|
|
30
|
+
<span
|
|
31
|
+
aria-hidden="true"
|
|
32
|
+
class="absolute w-3 h-3 -translate-x-1/2 rotate-45 bg-white"
|
|
33
|
+
:class="[
|
|
34
|
+
placement === 'top'
|
|
35
|
+
? 'bottom-[-7px] border-r border-b border-primary/20'
|
|
36
|
+
: 'top-[-7px] border-l border-t border-primary/20',
|
|
37
|
+
]"
|
|
38
|
+
:style="{ left: `${chevronOffset}px` }"></span>
|
|
39
|
+
<slot name="items">
|
|
40
|
+
<ul class="p-2">
|
|
41
|
+
<li v-for="(link, index) in normalizedLinks" :key="link.key || `${link.label}-${index}`">
|
|
42
|
+
<component
|
|
43
|
+
:is="resolveLinkTag(link)"
|
|
44
|
+
class="flex items-center w-full gap-2 px-3 py-2 min-h-11 text-base rounded-md text-slate-700"
|
|
45
|
+
:class="[
|
|
46
|
+
link.disabled
|
|
47
|
+
? 'cursor-not-allowed opacity-50'
|
|
48
|
+
: 'cursor-pointer hover:bg-primary/10 hover:text-primary active:bg-primary/15',
|
|
49
|
+
]"
|
|
50
|
+
:to="isRouterLink(link) ? link.to : undefined"
|
|
51
|
+
:href="!isRouterLink(link) && link.href ? link.href : undefined"
|
|
52
|
+
:target="!isRouterLink(link) && link.target ? link.target : undefined"
|
|
53
|
+
:rel="!isRouterLink(link) ? resolvedRel(link) : undefined"
|
|
54
|
+
:disabled="resolveLinkTag(link) === 'button' ? !!link.disabled : undefined"
|
|
55
|
+
role="menuitem"
|
|
56
|
+
@click="handleLinkClick(link, $event)">
|
|
57
|
+
<kIcon v-if="link.icon" :name="link.icon" :size="16" class="shrink-0 self-center text-primary/80" />
|
|
58
|
+
<span class="leading-none">{{ link.label }}</span>
|
|
59
|
+
</component>
|
|
60
|
+
</li>
|
|
61
|
+
</ul>
|
|
62
|
+
</slot>
|
|
63
|
+
</div>
|
|
64
|
+
</Teleport>
|
|
12
65
|
</div>
|
|
13
66
|
</template>
|
|
14
67
|
|
|
15
68
|
<script>
|
|
69
|
+
import kIcon from "./kIcon.vue";
|
|
70
|
+
|
|
16
71
|
export default {
|
|
17
|
-
name:
|
|
72
|
+
name: "kMenu",
|
|
73
|
+
components: {
|
|
74
|
+
kIcon,
|
|
75
|
+
},
|
|
76
|
+
props: {
|
|
77
|
+
links: {
|
|
78
|
+
type: Array,
|
|
79
|
+
default: () => [],
|
|
80
|
+
},
|
|
81
|
+
closeOnSelect: {
|
|
82
|
+
type: Boolean,
|
|
83
|
+
default: true,
|
|
84
|
+
},
|
|
85
|
+
ariaLabel: {
|
|
86
|
+
type: String,
|
|
87
|
+
default: "Toggle menu",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
emits: ["select"],
|
|
18
91
|
data() {
|
|
19
92
|
return {
|
|
20
93
|
isOpen: false,
|
|
21
|
-
|
|
94
|
+
placement: "bottom",
|
|
95
|
+
chevronOffset: 24,
|
|
96
|
+
panelStyle: {
|
|
97
|
+
position: "absolute",
|
|
98
|
+
top: "0px",
|
|
99
|
+
left: "0px",
|
|
100
|
+
width: "224px",
|
|
101
|
+
},
|
|
102
|
+
};
|
|
22
103
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this.
|
|
104
|
+
computed: {
|
|
105
|
+
normalizedLinks() {
|
|
106
|
+
return this.links.filter((link) => link && typeof link === "object" && typeof link.label === "string" && link.label.length > 0);
|
|
26
107
|
},
|
|
27
|
-
|
|
28
|
-
this
|
|
108
|
+
hasRouterLink() {
|
|
109
|
+
return Boolean(this.$?.appContext?.components?.RouterLink || this.$router);
|
|
29
110
|
},
|
|
30
111
|
},
|
|
31
|
-
mounted() {
|
|
32
|
-
document.addEventListener('click', this.handleClickOutside)
|
|
33
|
-
},
|
|
34
|
-
beforeUnmount() {
|
|
35
|
-
document.removeEventListener('click', this.handleClickOutside)
|
|
36
|
-
},
|
|
37
112
|
methods: {
|
|
38
113
|
toggleMenu() {
|
|
39
|
-
this.isOpen = !this.isOpen
|
|
114
|
+
this.isOpen = !this.isOpen;
|
|
115
|
+
if (this.isOpen) this.$nextTick(() => this.updatePanelPosition());
|
|
116
|
+
},
|
|
117
|
+
isRouterLink(link) {
|
|
118
|
+
return this.hasRouterLink && link && link.to !== undefined;
|
|
119
|
+
},
|
|
120
|
+
resolveLinkTag(link) {
|
|
121
|
+
if (this.isRouterLink(link)) return "RouterLink";
|
|
122
|
+
if (link && link.href) return "a";
|
|
123
|
+
return "button";
|
|
124
|
+
},
|
|
125
|
+
resolvedRel(link) {
|
|
126
|
+
if (!link?.target || link.target !== "_blank") return link?.rel || undefined;
|
|
127
|
+
return link?.rel || "noopener noreferrer";
|
|
128
|
+
},
|
|
129
|
+
handleLinkClick(link, event) {
|
|
130
|
+
if (link?.disabled) {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (typeof link?.action === "function") link.action(link, event);
|
|
135
|
+
if (typeof link?.onClick === "function") link.onClick(link, event);
|
|
136
|
+
this.$emit("select", link);
|
|
137
|
+
if (this.closeOnSelect) this.closeMenu();
|
|
40
138
|
},
|
|
41
139
|
handleClickOutside(event) {
|
|
42
|
-
|
|
43
|
-
|
|
140
|
+
const clickedTrigger = this.$refs.menuRef?.contains(event.target);
|
|
141
|
+
const clickedPanel = this.$refs.menuPanelRef?.contains(event.target);
|
|
142
|
+
if (!clickedTrigger && !clickedPanel) {
|
|
143
|
+
this.closeMenu();
|
|
44
144
|
}
|
|
45
145
|
},
|
|
146
|
+
handleEscapeKey(event) {
|
|
147
|
+
if (event.key === "Escape") this.closeMenu();
|
|
148
|
+
},
|
|
149
|
+
updatePanelPosition() {
|
|
150
|
+
const trigger = this.$refs.triggerRef;
|
|
151
|
+
if (!trigger) return;
|
|
152
|
+
|
|
153
|
+
const rect = trigger.getBoundingClientRect();
|
|
154
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
155
|
+
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
|
156
|
+
const panelWidth = this.$refs.menuPanelRef?.offsetWidth || 224;
|
|
157
|
+
const viewportWidth = window.innerWidth;
|
|
158
|
+
const viewportHeight = window.innerHeight;
|
|
159
|
+
const pad = 8;
|
|
160
|
+
const gap = 8;
|
|
161
|
+
const panelHeight = this.$refs.menuPanelRef?.offsetHeight || 0;
|
|
162
|
+
|
|
163
|
+
// bottom-end (default): align panel right edge with trigger right edge, below trigger.
|
|
164
|
+
const preferredLeft = rect.right + scrollLeft - panelWidth;
|
|
165
|
+
const minLeft = scrollLeft + pad;
|
|
166
|
+
const maxLeft = scrollLeft + viewportWidth - panelWidth - pad;
|
|
167
|
+
const left = Math.max(minLeft, Math.min(preferredLeft, maxLeft));
|
|
168
|
+
|
|
169
|
+
const bottomTop = rect.bottom + scrollTop + gap;
|
|
170
|
+
const topTop = rect.top + scrollTop - panelHeight - gap;
|
|
171
|
+
const maxVisibleTop = scrollTop + viewportHeight - panelHeight - pad;
|
|
172
|
+
const minVisibleTop = scrollTop + pad;
|
|
173
|
+
|
|
174
|
+
// Flip to top-end only when bottom placement overflows and top has room.
|
|
175
|
+
const shouldFlipTop = bottomTop > maxVisibleTop && topTop >= minVisibleTop;
|
|
176
|
+
const top = shouldFlipTop
|
|
177
|
+
? topTop
|
|
178
|
+
: Math.max(minVisibleTop, Math.min(bottomTop, maxVisibleTop));
|
|
179
|
+
this.placement = shouldFlipTop ? "top" : "bottom";
|
|
180
|
+
|
|
181
|
+
const triggerCenterX = rect.left + scrollLeft + rect.width / 2;
|
|
182
|
+
const relativeChevronX = triggerCenterX - left;
|
|
183
|
+
this.chevronOffset = Math.max(14, Math.min(relativeChevronX, panelWidth - 14));
|
|
184
|
+
|
|
185
|
+
this.panelStyle = {
|
|
186
|
+
position: "absolute",
|
|
187
|
+
top: `${top}px`,
|
|
188
|
+
left: `${left}px`,
|
|
189
|
+
width: `${panelWidth}px`,
|
|
190
|
+
};
|
|
191
|
+
},
|
|
46
192
|
closeMenu() {
|
|
47
|
-
this.isOpen = false
|
|
193
|
+
this.isOpen = false;
|
|
48
194
|
},
|
|
49
195
|
},
|
|
196
|
+
mounted() {
|
|
197
|
+
document.addEventListener("click", this.handleClickOutside);
|
|
198
|
+
document.addEventListener("keydown", this.handleEscapeKey);
|
|
199
|
+
window.addEventListener("resize", this.updatePanelPosition);
|
|
200
|
+
window.addEventListener("scroll", this.updatePanelPosition, true);
|
|
201
|
+
},
|
|
202
|
+
beforeUnmount() {
|
|
203
|
+
document.removeEventListener("click", this.handleClickOutside);
|
|
204
|
+
document.removeEventListener("keydown", this.handleEscapeKey);
|
|
205
|
+
window.removeEventListener("resize", this.updatePanelPosition);
|
|
206
|
+
window.removeEventListener("scroll", this.updatePanelPosition, true);
|
|
207
|
+
},
|
|
50
208
|
}
|
|
51
209
|
</script>
|
package/src/ui/kMessage.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
|
-
class="flex rounded-lg overflow-hidden min-h-[50px] border-l-8"
|
|
3
|
+
class="flex rounded-lg overflow-hidden min-h-[50px] border-l-8 ring-1 ring-primary/10"
|
|
4
4
|
:class="['border-semantic-' + type + '-border', 'bg-semantic-' + type + '-bg']"
|
|
5
5
|
>
|
|
6
6
|
<!-- Icon Column -->
|
package/src/ui/kSearch.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="relative w-full">
|
|
3
3
|
<input type="text" v-model="localValue" @input="onInput" :class="[defaultStyle, disabled ? disabledStyle : '']" :placeholder="placeholder" :disabled="disabled" />
|
|
4
|
-
<Search class="absolute w-4 h-4 text-
|
|
4
|
+
<Search class="absolute w-4 h-4 text-primary/70 -translate-y-1/2 pointer-events-none right-3 top-1/2" />
|
|
5
5
|
</div>
|
|
6
6
|
</template>
|
|
7
7
|
|
|
@@ -20,7 +20,7 @@ export default {
|
|
|
20
20
|
},
|
|
21
21
|
data() {
|
|
22
22
|
return {
|
|
23
|
-
defaultStyle: "w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-
|
|
23
|
+
defaultStyle: "w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-2 focus:ring-primary/20 focus:border-primary bg-white placeholder-gray-400",
|
|
24
24
|
disabledStyle: "bg-gray-100 text-gray-400 cursor-not-allowed",
|
|
25
25
|
|
|
26
26
|
localValue: this.modelValue,
|
package/src/ui/kSelect.vue
CHANGED
|
@@ -123,7 +123,7 @@ export default {
|
|
|
123
123
|
searchQuery: "",
|
|
124
124
|
dropdownPositionStyle: {},
|
|
125
125
|
generatedId: `select-${Math.random().toString(36).substr(2, 9)}`,
|
|
126
|
-
defaultStyle: "w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-
|
|
126
|
+
defaultStyle: "w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-2 focus:ring-primary/20 focus:border-primary bg-white placeholder-gray-400",
|
|
127
127
|
errorStyle: "border-red-500 focus:ring focus:ring-red-300",
|
|
128
128
|
disabledStyle: "!bg-gray-100 !text-gray-400 !cursor-not-allowed",
|
|
129
129
|
};
|
package/src/ui/kSelectButton.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="inline-flex overflow-hidden border
|
|
2
|
+
<div class="inline-flex overflow-hidden border rounded-md border-primary/25" style="width: fit-content;" :aria-disabled="disabled.toString()">
|
|
3
3
|
|
|
4
4
|
<button
|
|
5
5
|
v-for="(option, index) in options"
|
|
@@ -34,13 +34,13 @@ export default {
|
|
|
34
34
|
emits: ["update:modelValue"],
|
|
35
35
|
computed: {
|
|
36
36
|
baseClasses() {
|
|
37
|
-
return "px-4 py-2 text-sm font-medium border-none focus:outline-none";
|
|
37
|
+
return "px-4 py-2 text-sm font-medium border-none focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-inset";
|
|
38
38
|
},
|
|
39
39
|
activeClasses() {
|
|
40
40
|
return "bg-primary text-white";
|
|
41
41
|
},
|
|
42
42
|
inactiveClasses() {
|
|
43
|
-
return this.disabled ? "bg-white text-gray-500" : "bg-white text-
|
|
43
|
+
return this.disabled ? "bg-white text-gray-500" : "bg-white text-primary/90 hover:bg-primary/10";
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
46
|
methods: {
|
package/src/ui/kSkeleton.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template lang="">
|
|
2
2
|
<template v-if="type === 'text'">
|
|
3
3
|
<div class="space-y-2 animate-pulse">
|
|
4
|
-
<div v-for="n in normalizedRows" :key="n" class="w-full h-4 bg-
|
|
4
|
+
<div v-for="n in normalizedRows" :key="n" class="w-full h-4 rounded bg-primary/20"></div>
|
|
5
5
|
</div>
|
|
6
6
|
</template>
|
|
7
7
|
</template>
|
package/src/ui/kSpinner.vue
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="flex items-center justify-center w-16 space-x-1" v-if="type == 'line'">
|
|
3
|
-
<i class="ml-1 text-
|
|
4
|
-
<div class="w-2 h-2
|
|
5
|
-
<div class="w-2 h-2
|
|
6
|
-
<div class="w-2 h-2
|
|
7
|
-
<div class="w-2 h-2
|
|
3
|
+
<i class="ml-1 text-primary pi pi-wave-pulse" />
|
|
4
|
+
<div class="w-2 h-2 rounded-full bg-primary animate-fade" :style="{ animationDelay: '0s' }"></div>
|
|
5
|
+
<div class="w-2 h-2 rounded-full bg-primary animate-fade" :style="{ animationDelay: '0.15s' }"></div>
|
|
6
|
+
<div class="w-2 h-2 rounded-full bg-primary animate-fade" :style="{ animationDelay: '0.3s' }"></div>
|
|
7
|
+
<div class="w-2 h-2 rounded-full bg-primary animate-fade" :style="{ animationDelay: '0.45s' }"></div>
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
<Loader class="w-6 h-6 mr-2 animate-spin" style="animation-duration: 1.5s" v-else-if="type == 'circle'" />
|
package/src/ui/kTags.vue
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="w-full">
|
|
3
|
-
<div v-if="label != null" class="inputLabel" :class="hasError ? 'text-rose-800' : 'text-
|
|
3
|
+
<div v-if="label != null" class="inputLabel" :class="hasError ? 'text-rose-800' : 'text-primary/90'">
|
|
4
4
|
{{ label }}
|
|
5
5
|
</div>
|
|
6
6
|
<div
|
|
7
7
|
:class="[
|
|
8
8
|
'flex flex-wrap items-center gap-2 p-2 border rounded-xl shadow-sm min-h-[3rem] transition',
|
|
9
|
-
hasError ? 'border-rose-500 bg-rose-50/40 focus-within:border-rose-600 focus-within:ring-2 focus-within:ring-rose-500/20' : 'border-gray-300',
|
|
9
|
+
hasError ? 'border-rose-500 bg-rose-50/40 focus-within:border-rose-600 focus-within:ring-2 focus-within:ring-rose-500/20' : 'border-gray-300 focus-within:border-primary focus-within:ring-2 focus-within:ring-primary/20',
|
|
10
10
|
disabled ? 'bg-gray-100 cursor-not-allowed' : 'bg-white',
|
|
11
11
|
]">
|
|
12
|
-
<span v-for="(tag, index) in internalTags" :key="index" class="flex items-center px-2 py-1 text-
|
|
12
|
+
<span v-for="(tag, index) in internalTags" :key="index" class="flex items-center px-2 py-1 rounded-full text-primary bg-primary/10">
|
|
13
13
|
{{ tag }}
|
|
14
14
|
<button
|
|
15
15
|
@click="removeTag(index)"
|
|
16
16
|
:disabled="disabled"
|
|
17
|
-
:class="['ml-1', disabled ? 'text-
|
|
17
|
+
:class="['ml-1', disabled ? 'text-primary/30 cursor-not-allowed' : 'text-primary/70 hover:text-primary']">
|
|
18
18
|
×
|
|
19
19
|
</button>
|
|
20
20
|
</span>
|
package/src/ui/kTextArea.vue
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
v-if="label != null"
|
|
5
5
|
:for="inputId"
|
|
6
6
|
class="inputLabel"
|
|
7
|
-
:class="hasError ? 'text-red-500' : 'text-
|
|
7
|
+
:class="hasError ? 'text-red-500' : 'text-primary/90'"
|
|
8
8
|
>
|
|
9
9
|
{{ label }}
|
|
10
10
|
</label>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
{{ error }}
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
|
-
<div :id="infoId" class="mt-1 text-
|
|
29
|
+
<div :id="infoId" class="mt-1 text-primary/80" v-if="info != null">
|
|
30
30
|
{{ info }}
|
|
31
31
|
</div>
|
|
32
32
|
</div>
|
|
@@ -74,7 +74,7 @@ export default {
|
|
|
74
74
|
},
|
|
75
75
|
textareaClass() {
|
|
76
76
|
return [
|
|
77
|
-
'w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-
|
|
77
|
+
'w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-gray-700 focus:ring-2 focus:ring-primary/20 focus:border-primary bg-white placeholder-gray-400',
|
|
78
78
|
this.hasError ? 'border-red-500 focus:ring focus:ring-red-300' : '',
|
|
79
79
|
this.disabled ? '!bg-gray-100 !text-gray-400 !cursor-not-allowed' : '',
|
|
80
80
|
]
|
package/src/ui/kToast.vue
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
<div v-if="toast.actionLabel && typeof toast.onAction === 'function'" class="mt-2">
|
|
25
25
|
<button
|
|
26
26
|
type="button"
|
|
27
|
-
class="px-2.5 py-1.5 text-xs font-semibold rounded-md ring-1 ring-
|
|
27
|
+
class="px-2.5 py-1.5 text-xs font-semibold rounded-md ring-1 ring-primary/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary"
|
|
28
28
|
:class="'text-semantic-' + toast.type + '-text'"
|
|
29
29
|
@click="handleAction(toast)">
|
|
30
30
|
{{ toast.actionLabel }}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
v-if="toast.closable !== false"
|
|
39
39
|
type="button"
|
|
40
40
|
@click="remove(toast.id)"
|
|
41
|
-
class="absolute text-xl leading-none text-gray-500 rounded-md top-2 right-2 hover:text-
|
|
41
|
+
class="absolute text-xl leading-none text-gray-500 rounded-md top-2 right-2 hover:text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-primary"
|
|
42
42
|
:aria-label="`Close ${toast.type} toast`">
|
|
43
43
|
<X class="w-5 h-5" />
|
|
44
44
|
</button>
|
package/src/ui/kToggle.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :class="labelStyle === 'inline' ? 'flex items-center' : ''">
|
|
3
3
|
<!-- Block-style label -->
|
|
4
|
-
<div v-if="showLabel && labelStyle !== 'inline'" class="block mb-1 text-sm font-bold text-
|
|
4
|
+
<div v-if="showLabel && labelStyle !== 'inline'" class="block mb-1 text-sm font-bold text-primary/90" for="toggle">
|
|
5
5
|
{{ label }}
|
|
6
6
|
</div>
|
|
7
7
|
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
:disabled="disabled"
|
|
15
15
|
:class="[
|
|
16
16
|
'w-16 h-8 flex items-center rounded-full p-1 transition duration-300',
|
|
17
|
-
modelValue ? 'bg-
|
|
17
|
+
modelValue ? 'bg-primary' : 'bg-gray-400',
|
|
18
18
|
disabled ? 'opacity-50 cursor-not-allowed' : '',
|
|
19
19
|
]">
|
|
20
20
|
<div :class="['w-6 h-6 bg-white rounded-full shadow-md transform transition duration-300', modelValue ? 'translate-x-8' : 'translate-x-0']"></div>
|
|
21
21
|
</button>
|
|
22
22
|
|
|
23
23
|
<!-- Inline-style label -->
|
|
24
|
-
<div v-if="showLabel && labelStyle === 'inline'" class="ml-2 text-sm font-bold
|
|
24
|
+
<div v-if="showLabel && labelStyle === 'inline'" class="ml-2 text-sm font-bold cursor-pointer text-primary/90" :for="computedId" @click="toggle">
|
|
25
25
|
{{ label }}
|
|
26
26
|
</div>
|
|
27
27
|
</div>
|
package/src/ui/kToolbar.vue
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
:class="[
|
|
8
8
|
'k-toolbar relative w-full',
|
|
9
9
|
dense ? 'p-0 md:p-0' : 'px-3 md:px-4 py-2.5',
|
|
10
|
-
variant === 'plain' ? 'bg-transparent border-0 rounded-none shadow-none px-0 md:px-0' : 'border
|
|
10
|
+
variant === 'plain' ? 'bg-transparent border-0 rounded-none shadow-none px-0 md:px-0' : 'border rounded-lg bg-white shadow-sm border-primary/20',
|
|
11
11
|
disabled ? 'pointer-events-none opacity-60' : '',
|
|
12
12
|
]">
|
|
13
13
|
<div class="flex flex-wrap items-center gap-2 md:gap-3">
|
|
14
14
|
<div :class="['flex items-center min-w-0 gap-2 shrink-0', isCompact ? 'w-full' : 'w-auto']">
|
|
15
15
|
<slot name="leading" />
|
|
16
|
-
<h1 v-if="title" class="text-base font-semibold leading-6 text-
|
|
16
|
+
<h1 v-if="title" class="text-base font-semibold leading-6 truncate text-primary">{{ title }}</h1>
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
19
|
<div :class="['flex items-center min-w-0', isCompact ? 'w-full' : 'w-auto flex-1 min-w-[180px]']">
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
ref="menuTriggerRef"
|
|
30
30
|
type="button"
|
|
31
31
|
v-show="isCompact"
|
|
32
|
-
class="inline-flex items-center justify-center p-2 ml-auto border rounded-md border-
|
|
32
|
+
class="inline-flex items-center justify-center p-2 ml-auto border rounded-md border-primary/30 text-slate-700 hover:bg-primary/10"
|
|
33
33
|
:aria-label="mobileMenuOpen ? 'Close toolbar actions menu' : 'Open toolbar actions menu'"
|
|
34
34
|
:aria-expanded="mobileMenuOpen.toString()"
|
|
35
35
|
@click="toggleMobileMenu">
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
:disabled="disabled || !!action.disabled"
|
|
47
47
|
:aria-label="action.ariaLabel || action.label"
|
|
48
48
|
:tooltip="action.tooltip"
|
|
49
|
-
:
|
|
49
|
+
:size="resolveActionButtonSize(action)"
|
|
50
|
+
:small="action.small === true"
|
|
50
51
|
:icon-only="!!action.iconOnly"
|
|
51
52
|
:variant="action.variant || 'outlined'"
|
|
52
53
|
:secondary="!!action.secondary"
|
|
@@ -68,11 +69,11 @@
|
|
|
68
69
|
role="dialog"
|
|
69
70
|
aria-modal="true"
|
|
70
71
|
aria-label="Toolbar actions"
|
|
71
|
-
class="absolute bottom-0 left-0 right-0 p-3 border-t shadow-2xl rounded-t-2xl bg-white/95 backdrop-blur-sm border-
|
|
72
|
+
class="absolute bottom-0 left-0 right-0 p-3 border-t shadow-2xl rounded-t-2xl bg-white/95 backdrop-blur-sm border-primary/20"
|
|
72
73
|
style="padding-bottom: calc(0.75rem + env(safe-area-inset-bottom));">
|
|
73
|
-
<div class="flex items-center justify-between pb-2 mb-2 border-b border-
|
|
74
|
-
<h3 class="text-sm font-semibold text-
|
|
75
|
-
<button type="button" class="p-2 rounded-md hover:bg-
|
|
74
|
+
<div class="flex items-center justify-between pb-2 mb-2 border-b border-primary/20">
|
|
75
|
+
<h3 class="text-sm font-semibold text-primary">Actions</h3>
|
|
76
|
+
<button type="button" class="p-2 rounded-md hover:bg-primary/10" aria-label="Close actions menu" @click="closeMobileMenu()">
|
|
76
77
|
<kIcon name="X" :size="18" />
|
|
77
78
|
</button>
|
|
78
79
|
</div>
|
|
@@ -85,7 +86,7 @@
|
|
|
85
86
|
:disabled="disabled || !!action.disabled || !!action.loading"
|
|
86
87
|
:class="[
|
|
87
88
|
'flex items-center w-full gap-3 px-2 py-3 text-left rounded-lg min-h-11',
|
|
88
|
-
disabled || action.disabled || action.loading ? 'opacity-50 cursor-not-allowed' : 'hover:bg-
|
|
89
|
+
disabled || action.disabled || action.loading ? 'opacity-50 cursor-not-allowed' : 'hover:bg-primary/10 active:bg-primary/15',
|
|
89
90
|
]"
|
|
90
91
|
@click="handleMobileAction(action)">
|
|
91
92
|
<kIcon v-if="action.icon" :name="action.icon" :size="18" class="shrink-0 text-slate-600" />
|
|
@@ -138,6 +139,8 @@ const menuTriggerRef = ref(null);
|
|
|
138
139
|
const isCompact = ref(false);
|
|
139
140
|
let resizeObserver = null;
|
|
140
141
|
|
|
142
|
+
const VALID_BUTTON_SIZES = ["small", "normal", "large"];
|
|
143
|
+
|
|
141
144
|
const handleActionClick = (action) => {
|
|
142
145
|
if (typeof action?.onClick === "function") action.onClick();
|
|
143
146
|
};
|
|
@@ -147,6 +150,13 @@ const handleMobileAction = (action) => {
|
|
|
147
150
|
closeMobileMenu();
|
|
148
151
|
};
|
|
149
152
|
|
|
153
|
+
const resolveActionButtonSize = (action) => {
|
|
154
|
+
if (VALID_BUTTON_SIZES.includes(action?.size)) return action.size;
|
|
155
|
+
// Legacy support: `small: true` maps to the new `size="small"`.
|
|
156
|
+
if (action?.small === true) return "small";
|
|
157
|
+
return "normal";
|
|
158
|
+
};
|
|
159
|
+
|
|
150
160
|
const updateCompactMode = () => {
|
|
151
161
|
if (!toolbarRef.value) return;
|
|
152
162
|
isCompact.value = toolbarRef.value.clientWidth < 768;
|
package/src/ui/kTree.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="k-tree" :class="disabled ? 'k-tree--disabled' : ''">
|
|
2
|
+
<div class="k-tree text-primary/90" :class="disabled ? 'k-tree--disabled' : ''">
|
|
3
3
|
<HETree
|
|
4
4
|
ref="treeRef"
|
|
5
5
|
class="k-tree__root"
|
|
@@ -212,8 +212,8 @@ export default {
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
.k-tree-node-content--selected {
|
|
215
|
-
background: #
|
|
216
|
-
color: #
|
|
215
|
+
background: #ecfdf3;
|
|
216
|
+
color: #15803d;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
.k-tree-node-toggler {
|
package/src/ui/kUploader.vue
CHANGED
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
@drop.prevent="onDrop"
|
|
8
8
|
:class="[
|
|
9
9
|
'border-2 border-dashed rounded-lg p-8 text-center transition-colors mb-8',
|
|
10
|
-
dragover ? 'border-
|
|
10
|
+
dragover ? 'border-primary bg-primary/10' : 'border-gray-300 hover:border-primary/50',
|
|
11
11
|
]"
|
|
12
12
|
>
|
|
13
13
|
<div class="flex flex-col items-center justify-center space-y-4">
|
|
14
|
-
<UploadCloudIcon class="w-12 h-12 text-
|
|
14
|
+
<UploadCloudIcon class="w-12 h-12 text-primary/60" />
|
|
15
15
|
<p class="text-lg font-medium text-gray-700">
|
|
16
16
|
Σύρετε το αρχείο εδώ, ή
|
|
17
17
|
<label
|
|
18
18
|
for="file-input"
|
|
19
|
-
class="underline cursor-pointer text-
|
|
19
|
+
class="underline cursor-pointer text-primary hover:text-primary/80 focus:outline-none"
|
|
20
20
|
>
|
|
21
21
|
αναζητήστε
|
|
22
22
|
</label>
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
class="flex items-center justify-between p-4 bg-white rounded-lg shadow"
|
|
46
46
|
>
|
|
47
47
|
<div class="flex items-center space-x-4">
|
|
48
|
-
<FileIcon class="w-8 h-8 text-
|
|
48
|
+
<FileIcon class="w-8 h-8 text-primary/60" />
|
|
49
49
|
<div>
|
|
50
50
|
<p class="text-sm font-medium text-gray-700">{{ file.fileName }}</p>
|
|
51
51
|
<p class="text-xs text-gray-500">{{ formatFileSize(file.fileSize) }}</p>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export const K_INPUT_THEME = {
|
|
2
|
-
label: "text-
|
|
2
|
+
label: "text-primary/90",
|
|
3
3
|
labelError: "text-rose-800",
|
|
4
4
|
baseInput:
|
|
5
|
-
"w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-slate-900 bg-white placeholder-gray-400 focus:ring-2 focus:ring-
|
|
5
|
+
"w-full px-3 py-2 border rounded-lg transition shadow-sm focus:outline-none text-slate-900 bg-white placeholder-gray-400 focus:ring-2 focus:ring-primary/25 focus:border-primary",
|
|
6
6
|
withRightAdornment: "pr-10",
|
|
7
7
|
withPasswordToggle: "pr-14",
|
|
8
8
|
disabled: "bg-slate-100 text-slate-500 cursor-not-allowed border-slate-300",
|
|
9
9
|
errorInput: "border-rose-500 bg-rose-50/40 focus:border-rose-600 focus:ring-rose-500/20",
|
|
10
10
|
infoText: "text-sm text-slate-600",
|
|
11
11
|
errorText: "text-sm text-rose-700",
|
|
12
|
-
trailingIcon: "absolute w-4 h-4 text-
|
|
12
|
+
trailingIcon: "absolute w-4 h-4 text-primary/70 -translate-y-1/2 pointer-events-none right-3 top-1/2",
|
|
13
13
|
passwordToggle: "absolute inset-y-0 right-0 flex items-center pr-3 text-slate-700",
|
|
14
14
|
passwordToggleButton:
|
|
15
|
-
"text-xs font-medium select-none rounded px-1 py-0.5 hover:bg-
|
|
15
|
+
"text-xs font-medium select-none rounded px-1 py-0.5 hover:bg-primary/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
|
|
16
16
|
};
|