ketekny-ui-kit 1.0.132 → 1.0.134

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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ketekny-ui-kit",
3
3
  "type": "module",
4
- "version": "1.0.132",
4
+ "version": "1.0.134",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
package/src/ui/kCard.vue CHANGED
@@ -1,28 +1,66 @@
1
1
  <template>
2
- <article class="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
2
+ <article class="self-start overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
3
3
  <header
4
4
  v-if="hasHeader"
5
- class="border-b border-slate-200 px-5 py-4"
5
+ class="flex justify-between gap-3 border-slate-200 bg-slate-50/70 px-5 py-4"
6
+ :class="{
7
+ 'border-b': !isCollapsed,
8
+ 'group cursor-pointer select-none transition-colors hover:bg-slate-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand/30': collapsible,
9
+ 'items-start': subtitle,
10
+ 'items-center': !subtitle,
11
+ }"
12
+ :role="collapsible ? 'button' : undefined"
13
+ :tabindex="collapsible ? 0 : undefined"
14
+ :aria-label="collapsible ? (isCollapsed ? 'Expand card body' : 'Collapse card body') : undefined"
15
+ :aria-expanded="collapsible ? !isCollapsed : undefined"
16
+ @click="collapsible && toggleCollapsed()"
17
+ @keydown.enter.prevent="collapsible && toggleCollapsed()"
18
+ @keydown.space.prevent="collapsible && toggleCollapsed()"
6
19
  >
7
- <slot name="header">
8
- <div>
9
- <p v-if="title" class="text-sm font-semibold text-slate-900">
10
- {{ title }}
11
- </p>
12
- <p v-if="subtitle" :class="title ? 'mt-1 text-sm text-slate-500' : 'text-sm text-slate-500'">
13
- {{ subtitle }}
14
- </p>
15
- </div>
16
- </slot>
20
+ <div class="min-w-0 flex-1">
21
+ <slot name="header">
22
+ <div class="flex items-center gap-3">
23
+ <span
24
+ v-if="icon"
25
+ class="inline-flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary"
26
+ >
27
+ <kIcon :name="icon" :size="18" />
28
+ </span>
29
+ <div class="min-w-0">
30
+ <p v-if="title" class="text-sm font-semibold text-slate-900">
31
+ {{ title }}
32
+ </p>
33
+ <p v-if="subtitle" :class="title ? 'mt-1 text-sm text-slate-500' : 'text-sm text-slate-500'">
34
+ {{ subtitle }}
35
+ </p>
36
+ </div>
37
+ </div>
38
+ </slot>
39
+ </div>
40
+
41
+ <span
42
+ v-if="collapsible"
43
+ class="-mr-1 inline-flex size-8 shrink-0 items-center justify-center text-slate-500 transition-colors group-hover:text-slate-700"
44
+ >
45
+ <ChevronDown
46
+ class="size-5 transition-transform duration-200"
47
+ :class="{ 'rotate-180': !isCollapsed }"
48
+ aria-hidden="true"
49
+ />
50
+ </span>
17
51
  </header>
18
52
 
19
- <div class="px-5 py-4">
53
+ <div
54
+ v-show="!isCollapsed"
55
+ class="bg-white"
56
+ :class="dense ? 'p-0' : 'px-5 py-4'"
57
+ >
20
58
  <slot />
21
59
  </div>
22
60
 
23
61
  <footer
24
62
  v-if="$slots.footer"
25
- class="border-t border-slate-200 px-5 py-4"
63
+ class="border-t border-slate-200 bg-slate-50 px-5 py-4"
26
64
  >
27
65
  <slot name="footer" />
28
66
  </footer>
@@ -30,8 +68,13 @@
30
68
  </template>
31
69
 
32
70
  <script>
71
+ import { ChevronDown } from '@lucide/vue'
72
+ import kIcon from './kIcon.vue'
73
+
33
74
  export default {
34
75
  name: 'kCard',
76
+ components: { ChevronDown, kIcon },
77
+ emits: ['update:collapsed', 'toggle'],
35
78
  props: {
36
79
  title: {
37
80
  type: String,
@@ -41,10 +84,46 @@ export default {
41
84
  type: String,
42
85
  default: '',
43
86
  },
87
+ icon: {
88
+ type: String,
89
+ default: '',
90
+ },
91
+ collapsible: {
92
+ type: Boolean,
93
+ default: false,
94
+ },
95
+ collapsed: {
96
+ type: Boolean,
97
+ default: false,
98
+ },
99
+ dense: {
100
+ type: Boolean,
101
+ default: false,
102
+ },
103
+ },
104
+ data() {
105
+ return {
106
+ internalCollapsed: this.collapsed,
107
+ }
44
108
  },
45
109
  computed: {
46
110
  hasHeader() {
47
- return Boolean(this.$slots.header || this.title || this.subtitle)
111
+ return Boolean(this.$slots.header || this.title || this.subtitle || this.icon || this.collapsible)
112
+ },
113
+ isCollapsed() {
114
+ return this.collapsible && this.internalCollapsed
115
+ },
116
+ },
117
+ watch: {
118
+ collapsed(value) {
119
+ this.internalCollapsed = value
120
+ },
121
+ },
122
+ methods: {
123
+ toggleCollapsed() {
124
+ this.internalCollapsed = !this.internalCollapsed
125
+ this.$emit('update:collapsed', this.internalCollapsed)
126
+ this.$emit('toggle', this.internalCollapsed)
48
127
  },
49
128
  },
50
129
  }
package/src/ui/kList.vue CHANGED
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="w-full">
2
+ <div class="w-full" :class="{ 'k-list--dense': dense }">
3
3
  <dl
4
4
  v-if="!isRowFormat"
5
5
  class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3"
@@ -7,8 +7,11 @@
7
7
  <div
8
8
  v-for="(stat, index) in normalizedStats"
9
9
  :key="resolveKey(stat, index)"
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)"
10
+ class="flex items-center gap-3"
11
+ :class="[
12
+ dense ? '' : 'border border-gray-200 rounded-xl bg-white p-3 dark:border-slate-700 dark:bg-slate-800',
13
+ entryClass(stat),
14
+ ]"
12
15
  :role="stat.action ? 'button' : undefined"
13
16
  :tabindex="stat.action ? 0 : undefined"
14
17
  @click="handleAction(stat, index)"
@@ -38,7 +41,11 @@
38
41
  </div>
39
42
  </dl>
40
43
 
41
- <div v-else class="overflow-hidden bg-white border border-gray-200 rounded-xl dark:bg-slate-800 dark:border-slate-700">
44
+ <div
45
+ v-else
46
+ class="overflow-hidden bg-white dark:bg-slate-800"
47
+ :class="{ 'border border-gray-200 rounded-xl dark:border-slate-700': !dense }"
48
+ >
42
49
  <table class="w-full">
43
50
  <tbody>
44
51
  <tr
@@ -52,7 +59,10 @@
52
59
  @keydown.enter.prevent="handleAction(stat, index)"
53
60
  @keydown.space.prevent="handleAction(stat, index)"
54
61
  >
55
- <td class="px-4 py-3 text-sm text-gray-600 dark:text-slate-400">
62
+ <td
63
+ class="py-3 text-sm text-gray-600 dark:text-slate-400"
64
+ :class="dense ? 'px-5' : 'px-4'"
65
+ >
56
66
  <div class="flex items-center gap-2">
57
67
  <div
58
68
  v-if="stat.icon"
@@ -72,7 +82,10 @@
72
82
  <span>{{ stat.label }}</span>
73
83
  </div>
74
84
  </td>
75
- <td class="px-4 py-3 text-base font-semibold text-right text-gray-900 dark:text-slate-100">
85
+ <td
86
+ class="py-3 text-base font-semibold text-right text-gray-900 dark:text-slate-100"
87
+ :class="dense ? 'px-5' : 'px-4'"
88
+ >
76
89
  {{ stat.value }}
77
90
  </td>
78
91
  </tr>
@@ -100,6 +113,10 @@ export default {
100
113
  default: 'col',
101
114
  validator: (value) => ['col', 'row'].includes(value),
102
115
  },
116
+ dense: {
117
+ type: Boolean,
118
+ default: false,
119
+ },
103
120
  },
104
121
  emits: ['action'],
105
122
  computed: {