ketekny-ui-kit 1.0.91 → 1.0.93

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/README.md CHANGED
@@ -46,6 +46,7 @@ import {
46
46
  kDateSelector,
47
47
  kToggle,
48
48
  kCheckbox,
49
+ twoColLayout,
49
50
  toastPlugin,
50
51
  confirmPlugin,
51
52
  alertPlugin,
@@ -61,6 +62,7 @@ app.component("kSelect", kSelect);
61
62
  app.component("kDateSelector", kDateSelector);
62
63
  app.component("kToggle", kToggle);
63
64
  app.component("kCheckbox", kCheckbox);
65
+ app.component("twoColLayout", twoColLayout);
64
66
 
65
67
  app.use(toastPlugin);
66
68
  app.use(confirmPlugin);
@@ -92,6 +94,44 @@ function save() {
92
94
  </script>
93
95
  ```
94
96
 
97
+ Two-column layout usage:
98
+
99
+ ```vue
100
+ <template>
101
+ <twoColLayout
102
+ title="App title"
103
+ :main-menu="menu"
104
+ :account="account"
105
+ @select-menu="handleSelect"
106
+ >
107
+ <kSingleColPage app-title="Demo" page-title="Dashboard">
108
+ <div class="p-6">Page content</div>
109
+ </kSingleColPage>
110
+ </twoColLayout>
111
+ </template>
112
+
113
+ <script setup>
114
+ import { ref } from "vue";
115
+ import { kSingleColPage } from "ketekny-ui-kit";
116
+
117
+ const account = ref({
118
+ loggedIn: true,
119
+ firstName: "Demo",
120
+ lastName: "User",
121
+ email: "demo@ketekny.gr",
122
+ });
123
+
124
+ const menu = [
125
+ { id: "dashboard", label: "Dashboard", icon: "LayoutDashboard" },
126
+ { id: "reports", label: "Reports", icon: "BarChart3" },
127
+ ];
128
+
129
+ function handleSelect(id) {
130
+ console.log("Selected menu item:", id);
131
+ }
132
+ </script>
133
+ ```
134
+
95
135
  ## Tailwind Setup
96
136
 
97
137
  Use the provided preset to include semantic tokens and safelist patterns used by dynamic component classes.
@@ -165,6 +205,7 @@ Components:
165
205
  - `kSelectButton`, `kTags`, `kSearch`, `kArrayList`, `kList`, `kTextArea`
166
206
  - `kDialog`, `kDrawer`
167
207
  - `kAppHeader`, `kAppFooter`, `kAppMain`, `kHero`
208
+ - `kSingleColPage`, `kTwoColPage`, `twoColLayout`, `legacyTwoColLayout`
168
209
 
169
210
  Other exports:
170
211
 
@@ -202,4 +243,3 @@ ISC
202
243
  - Live demo/docs: https://ui.ketekny.gr
203
244
  - npm: https://www.npmjs.com/package/ketekny-ui-kit
204
245
 
205
-
package/index.js CHANGED
@@ -38,7 +38,8 @@ import kAppMain from './src/layout/kAppMain.vue'
38
38
  import kHero from './src/layout/kHero.vue'
39
39
  import kSingleColPage from './src/layout/kSingleColPage.vue'
40
40
  import kTwoColPage from './src/layout/kTwoColPage.vue'
41
- import twoColLayout from './src/layout/twoColLayout.vue'
41
+ import twoColLayout from './src/twoColLayout/components/TwoColLayout.vue'
42
+ import legacyTwoColLayout from './src/layout/twoColLayout.vue'
42
43
 
43
44
  // Toast/Confirm/Alert Plugins
44
45
  import toastPlugin from './src/plugins/toastPlugin.js'
@@ -62,7 +63,7 @@ export {
62
63
  kDialog, kDrawer,
63
64
 
64
65
  // Layout Components
65
- kAppHeader, kAppFooter, kAppMain, kHero, kSingleColPage, kTwoColPage, twoColLayout,
66
+ kAppHeader, kAppFooter, kAppMain, kHero, kSingleColPage, kTwoColPage, twoColLayout, legacyTwoColLayout,
66
67
 
67
68
  // Plugins
68
69
  toastPlugin, confirmPlugin, alertPlugin, tooltipPlugin, inputDialogPlugin,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ketekny-ui-kit",
3
3
  "type": "module",
4
- "version": "1.0.91",
4
+ "version": "1.0.93",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -33,6 +33,10 @@ export default {
33
33
  type: String,
34
34
  default: "",
35
35
  },
36
+ appIcon: {
37
+ type: String,
38
+ default: "",
39
+ },
36
40
  width: {
37
41
  type: String,
38
42
  default: "360px",
@@ -65,7 +69,7 @@ export default {
65
69
  emits: ['select', 'logo-click', 'signin', 'signup', 'signout', 'edit-profile', 'item-click'],
66
70
  data() {
67
71
  return {
68
- activeId: 'dashboard',
72
+ activeId: '',
69
73
  query: '',
70
74
  collapsed: false,
71
75
  openIds: new Set(['projects']),
@@ -115,7 +119,49 @@ export default {
115
119
  return all
116
120
  },
117
121
  },
122
+ watch: {
123
+ mainMenu: {
124
+ handler() {
125
+ this.syncActiveFromMenu()
126
+ },
127
+ deep: true,
128
+ immediate: true,
129
+ },
130
+ $route() {
131
+ this.syncActiveFromMenu()
132
+ },
133
+ },
118
134
  methods: {
135
+ syncActiveFromMenu() {
136
+ const routePath = this.$route?.path
137
+ const findMatch = (items, parentIds = []) => {
138
+ for (const item of items) {
139
+ const itemPath = item?.link?.to ?? item?.to ?? null
140
+ if (routePath && itemPath === routePath) {
141
+ return {
142
+ id: item.id,
143
+ parentIds,
144
+ }
145
+ }
146
+ if (item?.children?.length) {
147
+ const childMatch = findMatch(item.children, [...parentIds, item.id])
148
+ if (childMatch) return childMatch
149
+ }
150
+ }
151
+ return null
152
+ }
153
+
154
+ const matched = findMatch(this.mainMenu)
155
+ if (matched?.id) {
156
+ this.activeId = matched.id
157
+ this.openIds = new Set([...this.openIds, ...matched.parentIds])
158
+ return
159
+ }
160
+
161
+ if (!this.activeId && this.mainMenu[0]?.id) {
162
+ this.activeId = this.mainMenu[0].id
163
+ }
164
+ },
119
165
  toggleCollapsed() {
120
166
  this.collapsed = !this.collapsed
121
167
  },
@@ -225,12 +271,20 @@ export default {
225
271
  </p>
226
272
  </div>
227
273
 
228
- <div v-else-if="title && collapsed" class="px-3 pb-2">
274
+ <div v-else-if="(title || appIcon) && collapsed" class="flex justify-center px-3 pb-2">
229
275
  <div
230
276
  v-tooltip.right="title"
231
277
  class="flex h-10 w-10 items-center justify-center rounded-md border border-sidebar-border/30 bg-sidebar-accent/30 text-[10px] font-bold tracking-[0.18em] text-sidebar-muted"
232
278
  >
233
- {{ collapsedTitle }}
279
+ <img
280
+ v-if="appIcon"
281
+ :src="appIcon"
282
+ alt="App icon"
283
+ class="h-6 w-6 object-contain"
284
+ />
285
+ <template v-else>
286
+ {{ collapsedTitle }}
287
+ </template>
234
288
  </div>
235
289
  </div>
236
290
 
@@ -4,6 +4,7 @@
4
4
 
5
5
  <MultilevelSidebar
6
6
  :title="title"
7
+ :app-icon="appIcon"
7
8
  :width="width"
8
9
  :collapsed-width="collapsedWidth"
9
10
  :main-menu="mainMenu"
@@ -50,6 +51,10 @@ export default {
50
51
  type: String,
51
52
  default: "",
52
53
  },
54
+ appIcon: {
55
+ type: String,
56
+ default: "",
57
+ },
53
58
  width: {
54
59
  type: String,
55
60
  default: "360px",
@@ -1,14 +1,14 @@
1
1
  <template>
2
- <div class="overflow-hidden border rounded-lg shadow-sm component-card cp-card cp-border">
2
+ <div class="overflow-hidden border rounded-lg shadow-sm component-card cp-card cp-border text-[14px]">
3
3
  <div class="flex items-center justify-between px-4 py-3 border-b cp-border cp-muted-50">
4
- <h2 class="text-lg font-semibold cp-text">{{ componentName }} Description</h2>
4
+ <h2 class="text-[15px] font-semibold cp-text">{{ componentName }} Description</h2>
5
5
 
6
6
  <div class="flex items-center gap-1">
7
7
  <button
8
8
  v-for="tab in tabs"
9
9
  :key="tab.id"
10
10
  @click="activeTab = tab.id"
11
- :class="['px-3 py-1.5 text-sm font-medium rounded-md transition-colors', activeTab === tab.id ? 'cp-tab-active' : 'cp-tab']">
11
+ :class="['px-3 py-1.5 text-[13px] font-medium rounded-md transition-colors', activeTab === tab.id ? 'cp-tab-active' : 'cp-tab']">
12
12
  {{ tab.label }}
13
13
  </button>
14
14
  </div>
@@ -17,7 +17,7 @@
17
17
  <div class="p-4">
18
18
  <div v-show="activeTab === 'props'">
19
19
  <div v-if="props.length > 0" class="overflow-x-auto">
20
- <table class="w-full text-sm">
20
+ <table class="w-full text-[13px]">
21
21
  <thead>
22
22
  <tr class="border-b cp-border">
23
23
  <th class="px-4 py-3 font-semibold text-left cp-text">Name</th>
@@ -30,11 +30,11 @@
30
30
  <tbody>
31
31
  <tr v-for="(prop, index) in props" :key="prop.name" :class="index % 2 === 0 ? 'cp-muted-30' : ''">
32
32
  <td class="px-4 py-3">
33
- <code class="text-sm font-mono px-1.5 py-0.5 rounded cp-chip cp-chip-text">{{ prop.name }}</code>
33
+ <code class="text-[13px] font-mono px-1.5 py-0.5 rounded cp-chip cp-chip-text">{{ prop.name }}</code>
34
34
  </td>
35
- <td class="px-4 py-3"><span class="font-mono text-sm text-blue-600">{{ prop.type }}</span></td>
35
+ <td class="px-4 py-3"><span class="font-mono text-[13px] text-blue-600">{{ prop.type }}</span></td>
36
36
  <td class="px-4 py-3">
37
- <code v-if="prop.default !== undefined" class="font-mono text-sm text-slate-700">{{ prop.default }}</code>
37
+ <code v-if="prop.default !== undefined" class="font-mono text-[13px] text-slate-700">{{ prop.default }}</code>
38
38
  <span v-else class="cp-text-muted">-</span>
39
39
  </td>
40
40
  <td class="px-4 py-3 cp-text-muted">{{ prop.description }}</td>
@@ -50,7 +50,7 @@
50
50
 
51
51
  <div v-show="activeTab === 'slots'">
52
52
  <div v-if="slots.length > 0" class="overflow-x-auto">
53
- <table class="w-full text-sm">
53
+ <table class="w-full text-[13px]">
54
54
  <thead>
55
55
  <tr class="border-b cp-border">
56
56
  <th class="px-4 py-3 font-semibold text-left cp-text">Name</th>
@@ -62,10 +62,10 @@
62
62
  <tbody>
63
63
  <tr v-for="(slot, index) in slots" :key="slot.name" :class="index % 2 === 0 ? 'cp-muted-30' : ''">
64
64
  <td class="px-4 py-3">
65
- <code class="text-sm font-mono px-1.5 py-0.5 rounded cp-chip cp-chip-text">{{ slot.name }}</code>
65
+ <code class="text-[13px] font-mono px-1.5 py-0.5 rounded cp-chip cp-chip-text">{{ slot.name }}</code>
66
66
  </td>
67
67
  <td class="px-4 py-3">
68
- <span :class="['inline-flex items-center px-2 py-0.5 rounded-full text-sm font-medium', slot.scoped ? 'bg-emerald-100 text-emerald-700' : 'cp-badge-muted']">
68
+ <span :class="['inline-flex items-center px-2 py-0.5 rounded-full text-[13px] font-medium', slot.scoped ? 'bg-emerald-100 text-emerald-700' : 'cp-badge-muted']">
69
69
  {{ slot.scoped ? "Yes" : "No" }}
70
70
  </span>
71
71
  </td>
@@ -1,14 +1,14 @@
1
1
  <template>
2
- <div class="overflow-hidden border rounded-lg shadow-sm component-card cp-card cp-border">
2
+ <div class="overflow-hidden border rounded-lg shadow-sm component-card cp-card cp-border text-[14px]">
3
3
  <div class="flex items-center justify-between px-4 py-3 border-b cp-border cp-muted-50">
4
- <h2 class="text-lg font-semibold cp-text">{{ componentName }} Preview</h2>
4
+ <h2 class="text-[15px] font-semibold cp-text">{{ componentName }} Preview</h2>
5
5
 
6
6
  <div class="flex items-center gap-1">
7
7
  <button
8
8
  v-for="tab in tabs"
9
9
  :key="tab.id"
10
10
  @click="activeTab = tab.id"
11
- :class="['px-3 py-1.5 text-sm font-medium rounded-md transition-colors', activeTab === tab.id ? 'cp-tab-active' : 'cp-tab']">
11
+ :class="['px-3 py-1.5 text-[13px] font-medium rounded-md transition-colors', activeTab === tab.id ? 'cp-tab-active' : 'cp-tab']">
12
12
  {{ tab.label }}
13
13
  </button>
14
14
  </div>
@@ -22,7 +22,7 @@
22
22
  v-for="vp in previewViewports"
23
23
  :key="vp.id"
24
24
  @click="activeViewport = vp.id"
25
- :class="['px-3 py-1.5 text-sm font-semibold rounded-md transition-colors', activeViewport === vp.id ? 'cp-tab-active' : 'cp-tab']">
25
+ :class="['px-3 py-1.5 text-[13px] font-semibold rounded-md transition-colors', activeViewport === vp.id ? 'cp-tab-active' : 'cp-tab']">
26
26
  {{ vp.label }}
27
27
  </button>
28
28
  </div>
@@ -37,7 +37,7 @@
37
37
 
38
38
  <div v-show="activeTab === 'code'" class="relative">
39
39
  <div class="absolute z-10 top-3 right-3">
40
- <button @click="copyCode" class="flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors cp-chip cp-chip-hover cp-chip-text">
40
+ <button @click="copyCode" class="flex items-center gap-1.5 px-3 py-1.5 text-[13px] font-medium rounded-md transition-colors cp-chip cp-chip-hover cp-chip-text">
41
41
  <svg
42
42
  v-if="!copied"
43
43
  xmlns="http://www.w3.org/2000/svg"
@@ -72,8 +72,8 @@
72
72
  </button>
73
73
  </div>
74
74
 
75
- <pre class="p-4 overflow-x-auto rounded-lg cp-pre">
76
- <code class="font-mono text-sm" v-html="highlightedCode"></code>
75
+ <pre class="p-4 overflow-x-auto rounded-lg text-[11px] leading-5 cp-pre">
76
+ <code class="font-mono text-[11px]" v-html="highlightedCode"></code>
77
77
  </pre>
78
78
  </div>
79
79
  </div>
package/src/ui/kCode.vue CHANGED
@@ -1,8 +1,8 @@
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 border-primary/30">
3
+ <div class="p-4 mt-3 overflow-hidden text-[11px] leading-5 text-white whitespace-pre bg-gray-900 border rounded-lg border-primary/30">
4
4
  <div class="overflow-auto">
5
- <code>{{ normalizedContent }}</code>
5
+ <code class="font-mono text-[11px]">{{ normalizedContent }}</code>
6
6
  </div>
7
7
  </div>
8
8
  </template>
@@ -5,7 +5,7 @@ export const K_BUTTON_BASE = "inline-flex flex-row items-center justify-center f
5
5
 
6
6
  export const K_BUTTON_SIZE_STYLES = {
7
7
  normal: {
8
- regular: "h-10 px-4 text-base",
8
+ regular: "h-9 px-4 text-sm",
9
9
  iconOnly: "h-10 w-10 p-0",
10
10
  icon: "w-5 h-5",
11
11
  loader: "w-5 h-5",
@@ -27,7 +27,7 @@ export const K_BUTTON_SIZE_STYLES = {
27
27
  },
28
28
  // Backward compatibility aliases
29
29
  default: {
30
- regular: "h-10 px-4 text-base",
30
+ regular: "h-9 px-4 text-sm",
31
31
  iconOnly: "h-10 w-10 p-0",
32
32
  icon: "w-5 h-5",
33
33
  loader: "w-5 h-5",