ketekny-ui-kit 1.0.20 → 1.0.22

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
@@ -22,6 +22,7 @@ import kMenu from './src/ui/kMenu.vue'
22
22
  import kTags from './src/ui/kTags.vue'
23
23
  import kSearch from './src/ui/kSearch.vue'
24
24
  import kArrayList from './src/ui/kArrayList.vue'
25
+ import kList from './src/ui/kList.vue'
25
26
  import kSkeleton from './src/ui/kSkeleton.vue'
26
27
  import kProgressBar from './src/ui/kProgressBar.vue'
27
28
  import kTextArea from './src/ui/kTextArea.vue'
@@ -49,7 +50,7 @@ export {
49
50
  kMessage, kCode, kToolbar, kTable, kTabs, kChip, kSpinner, kDatatable, kIcon, kMenu, kSkeleton, kProgressBar, kTree,
50
51
 
51
52
  // Form Components
52
- kButton, kSelect, kUploader, kToggle, kInput, kDateSelector, kEditor, kSelectButton, kTags, kSearch, kArrayList, kTextArea,
53
+ kButton, kSelect, kUploader, kToggle, kInput, kDateSelector, kEditor, kSelectButton, kTags, kSearch, kArrayList, kList, kTextArea,
53
54
 
54
55
  // Dialogs
55
56
  kDialog, kDrawer,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ketekny-ui-kit",
3
3
  "type": "module",
4
- "version": "1.0.20",
4
+ "version": "1.0.22",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div class="w-full">
3
+ <dl
4
+ v-if="!isRowFormat"
5
+ class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3"
6
+ >
7
+ <div
8
+ v-for="(stat, index) in normalizedStats"
9
+ :key="resolveKey(stat, index)"
10
+ class="flex items-center gap-3 p-3 border border-gray-200 rounded-xl bg-white"
11
+ >
12
+ <div
13
+ v-if="stat.icon"
14
+ class="flex items-center justify-center w-10 h-10 rounded-lg bg-primary/10 text-primary"
15
+ >
16
+ <kIcon
17
+ v-if="typeof stat.icon === 'string'"
18
+ :name="stat.icon"
19
+ :size="18"
20
+ />
21
+ <component
22
+ :is="stat.icon"
23
+ v-else
24
+ class="w-[18px] h-[18px]"
25
+ />
26
+ </div>
27
+
28
+ <div class="min-w-0">
29
+ <dt class="text-sm text-gray-500 truncate">{{ stat.label }}</dt>
30
+ <dd class="text-xl font-semibold text-gray-900 truncate">{{ stat.value }}</dd>
31
+ </div>
32
+ </div>
33
+ </dl>
34
+
35
+ <div v-else class="overflow-hidden bg-white border border-gray-200 rounded-xl">
36
+ <table class="w-full">
37
+ <tbody>
38
+ <tr
39
+ v-for="(stat, index) in normalizedStats"
40
+ :key="resolveKey(stat, index)"
41
+ class="border-b border-gray-200 last:border-b-0"
42
+ >
43
+ <td class="px-4 py-3 text-sm text-gray-600">
44
+ <div class="flex items-center gap-2">
45
+ <div
46
+ v-if="stat.icon"
47
+ class="flex items-center justify-center w-7 h-7 rounded-md bg-primary/10 text-primary"
48
+ >
49
+ <kIcon
50
+ v-if="typeof stat.icon === 'string'"
51
+ :name="stat.icon"
52
+ :size="14"
53
+ />
54
+ <component
55
+ :is="stat.icon"
56
+ v-else
57
+ class="w-[14px] h-[14px]"
58
+ />
59
+ </div>
60
+ <span>{{ stat.label }}</span>
61
+ </div>
62
+ </td>
63
+ <td class="px-4 py-3 text-base font-semibold text-right text-gray-900">
64
+ {{ stat.value }}
65
+ </td>
66
+ </tr>
67
+ </tbody>
68
+ </table>
69
+ </div>
70
+ </div>
71
+ </template>
72
+
73
+ <script>
74
+ import kIcon from './kIcon.vue'
75
+
76
+ export default {
77
+ name: 'kList',
78
+ components: {
79
+ kIcon,
80
+ },
81
+ props: {
82
+ stats: {
83
+ type: Array,
84
+ default: () => [],
85
+ },
86
+ format: {
87
+ type: String,
88
+ default: 'col',
89
+ validator: (value) => ['col', 'row'].includes(value),
90
+ },
91
+ },
92
+ computed: {
93
+ isRowFormat() {
94
+ return this.format === 'row'
95
+ },
96
+ normalizedStats() {
97
+ return this.stats.map((stat) => ({
98
+ label: stat?.label ?? '',
99
+ value: stat?.value ?? '-',
100
+ icon: stat?.icon ?? null,
101
+ }))
102
+ },
103
+ },
104
+ methods: {
105
+ resolveKey(stat, index) {
106
+ return `${String(stat.label)}-${index}`
107
+ },
108
+ },
109
+ }
110
+ </script>
@@ -37,15 +37,15 @@
37
37
  :side-offset="6"
38
38
  class="select-content z-[9999] bg-white border border-gray-200 rounded-lg shadow-[0_10px_38px_-10px_rgba(22,23,24,0.35),0_10px_20px_-15px_rgba(22,23,24,0.2)] overflow-hidden"
39
39
  >
40
- <div v-if="searchable" class="sticky top-0 z-10 p-1.5 border-b border-gray-100 bg-white">
40
+ <div v-if="searchable" class="sticky top-0 z-10 p-2 border-b border-gray-100 bg-white">
41
41
  <div class="relative">
42
- <Search class="absolute left-2 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-gray-400 pointer-events-none" />
42
+ <Search class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" />
43
43
  <input
44
44
  ref="searchInput"
45
45
  type="text"
46
46
  v-model="searchQuery"
47
47
  placeholder="Αναζήτηση..."
48
- class="w-full pl-7 pr-2.5 py-1.5 text-sm border border-gray-200 rounded-md focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary/30 transition-colors placeholder-gray-400"
48
+ class="w-full pl-9 pr-3 py-2 text-base border border-gray-200 rounded-lg focus:outline-none focus:border-primary focus:ring-2 focus:ring-primary/20 transition-colors placeholder-gray-400"
49
49
  role="searchbox"
50
50
  aria-label="Search options"
51
51
  @keydown="handleSearchKeydown"
@@ -54,13 +54,9 @@
54
54
  </div>
55
55
  </div>
56
56
 
57
- <SelectScrollUpButton class="flex items-center justify-center py-1 text-gray-400 hover:text-gray-600 cursor-default bg-white border-b border-gray-100">
58
- <ChevronUp class="w-4 h-4" />
59
- </SelectScrollUpButton>
60
-
61
57
  <SelectViewport
62
58
  ref="viewportRef"
63
- class="p-1"
59
+ class="select-viewport p-1 overflow-y-scroll"
64
60
  :style="{ maxHeight: dropdownHeight }"
65
61
  @keydown="handleViewportKeydown"
66
62
  >
@@ -68,7 +64,7 @@
68
64
  v-for="(option, index) in filteredOptions"
69
65
  :key="option[optionValue]"
70
66
  :value="option[optionValue]"
71
- class="select-item relative flex items-center gap-1.5 rounded-[4px] py-2.5 pl-7 pr-3 text-sm cursor-pointer outline-none select-none text-slate-700
67
+ class="select-item relative flex items-center gap-1.5 rounded-[4px] py-2.5 pl-8 pr-3 text-base cursor-pointer outline-none select-none text-slate-700
72
68
  data-[highlighted]:bg-primary data-[highlighted]:text-white
73
69
  data-[state=checked]:bg-primary/5 data-[state=checked]:text-primary
74
70
  data-[state=checked]:data-[highlighted]:bg-primary data-[state=checked]:data-[highlighted]:text-white"
@@ -81,15 +77,11 @@
81
77
  <SelectItemText class="truncate">{{ option[optionLabel] }}</SelectItemText>
82
78
  </SelectItem>
83
79
 
84
- <div v-if="filteredOptions.length === 0" class="flex flex-col items-center gap-1.5 px-3 py-4 text-sm text-gray-400 text-center">
80
+ <div v-if="filteredOptions.length === 0" class="flex flex-col items-center gap-1.5 px-3 py-4 text-base text-gray-400 text-center">
85
81
  <SearchX class="w-5 h-5 text-gray-300" />
86
82
  <span>Δεν βρέθηκαν επιλογές</span>
87
83
  </div>
88
84
  </SelectViewport>
89
-
90
- <SelectScrollDownButton class="flex items-center justify-center py-1 text-gray-400 hover:text-gray-600 cursor-default bg-white border-t border-gray-100">
91
- <ChevronDown class="w-4 h-4" />
92
- </SelectScrollDownButton>
93
85
  </SelectContent>
94
86
  </SelectPortal>
95
87
  </SelectRoot>
@@ -113,13 +105,11 @@ import {
113
105
  SelectItemText,
114
106
  SelectPortal,
115
107
  SelectRoot,
116
- SelectScrollDownButton,
117
- SelectScrollUpButton,
118
108
  SelectTrigger,
119
109
  SelectValue,
120
110
  SelectViewport,
121
111
  } from "reka-ui";
122
- import { X, ChevronDown, ChevronUp, Check, Search, SearchX } from "lucide-vue-next";
112
+ import { X, ChevronDown, Check, Search, SearchX } from "lucide-vue-next";
123
113
 
124
114
  const props = defineProps({
125
115
  options: { type: Array, required: true },
@@ -298,5 +288,30 @@ function handleViewportKeydown(event) {
298
288
  transition: background-color 80ms, color 80ms;
299
289
  }
300
290
 
301
- </style>
291
+ :deep([data-reka-select-viewport]) {
292
+ scrollbar-gutter: stable;
293
+ scrollbar-width: auto !important;
294
+ scrollbar-color: #475569 #cbd5e1 !important;
295
+ -ms-overflow-style: auto !important;
296
+ }
302
297
 
298
+ :deep([data-reka-select-viewport]::-webkit-scrollbar) {
299
+ display: block !important;
300
+ width: 12px;
301
+ }
302
+
303
+ :deep([data-reka-select-viewport]::-webkit-scrollbar-track) {
304
+ background: #cbd5e1;
305
+ }
306
+
307
+ :deep([data-reka-select-viewport]::-webkit-scrollbar-thumb) {
308
+ background-color: #475569;
309
+ border-radius: 999px;
310
+ border: 2px solid #cbd5e1;
311
+ }
312
+
313
+ :deep([data-reka-select-viewport]::-webkit-scrollbar-thumb:hover) {
314
+ background-color: #334155;
315
+ }
316
+
317
+ </style>