ketekny-ui-kit 1.0.3 → 1.0.5

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
@@ -1,22 +1,190 @@
1
- # README #
1
+ # Ketekny UI Kit
2
2
 
3
- Project is based on tailwind 3.x.x
3
+ A comprehensive Vue 3 UI component library built with Tailwind CSS. This library provides a set of reusable, customizable components for modern web applications.
4
4
 
5
- in tailwind.config:
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ npm install ketekny-ui-kit
6
10
  ```
11
+
12
+ ## Tailwind Configuration
13
+
14
+ Add the preset to your `tailwind.config.js`:
15
+
16
+ ```javascript
7
17
  // tailwind.config.js
8
18
  const preset = require('ketekny-ui-kit/tailwind-preset.js')
9
19
 
10
20
  module.exports = {
11
21
  presets: [preset],
12
- content: ['./src/**/*.{vue,js}', './node_modules/ketekny-ui-kit/**/*.{vue,js,ts}'],
22
+ content: [
23
+ './src/**/*.{vue,js,ts}',
24
+ './node_modules/ketekny-ui-kit/**/*.{vue,js,ts}'
25
+ ],
13
26
  safelist: [
14
27
  { pattern: /text-semantic-(success|danger|info|warning)-text/ },
15
28
  { pattern: /border-semantic-(success|danger|info|warning)-border/ },
16
- { pattern: /bg-semantic-(success|warning|error|info)-(bg|disabled|button)/, },
29
+ { pattern: /bg-semantic-(success|warning|error|info)-(bg|disabled|button)/ },
17
30
  ],
18
31
  }
19
32
  ```
20
33
 
34
+ ## Components
35
+
36
+ ### UI Components
37
+ - `kButton` - Versatile button component
38
+ - `kInput` - Input field with validation
39
+ - `kDateSelector` - Date picker with year/month modes
40
+ - `kSelect` - Dropdown select component
41
+ - `kToggle` - Toggle switch
42
+ - `kChip` - Tag/label component
43
+ - `kSpinner` - Loading spinner
44
+ - `kIcon` - Icon component using Lucide icons
45
+ - `kMessage` - Alert/message component
46
+ - `kCode` - Code display component
47
+ - `kSearch` - Search input component
48
+ - `kTags` - Tag input component
49
+ - `kSelectButton` - Button group select
50
+ - `kArrayList` - Array/list management
51
+ - `kToolbar` - Toolbar component
52
+ - `kUploader` - File upload component
53
+ - `kEditor` - Rich text editor
54
+ - `kDialog` - Modal dialog
55
+ - `kDrawer` - Slide-out drawer
56
+ - `kTabs` - Tab navigation
57
+ - `kTable` - Data table
58
+ - `kDatatable` - Advanced data table
59
+
60
+ ### Layout Components
61
+ - `kAppHeader` - Application header
62
+ - `kAppFooter` - Application footer
63
+ - `kAppMain` - Main content area
64
+ - `kHero` - Hero section
65
+
66
+ ### Plugins
67
+ - `toastPlugin` - Toast notifications
68
+ - `confirmPlugin` - Confirmation dialogs
69
+ - `alertPlugin` - Alert dialogs
70
+ - `inputDialogPlugin` - Input dialogs
71
+ - `tooltipPlugin` - Tooltip functionality
72
+
73
+ ## Usage
74
+
75
+ ```javascript
76
+ // main.js
77
+ import { createApp } from 'vue'
78
+ import App from './App.vue'
79
+
80
+ // Import components
81
+ import {
82
+ kButton,
83
+ kInput,
84
+ kDateSelector,
85
+ kSelect,
86
+ kToggle
87
+ } from 'ketekny-ui-kit'
88
+
89
+ // Import plugins
90
+ import toastPlugin from 'ketekny-ui-kit'
91
+ import confirmPlugin from 'ketekny-ui-kit'
92
+
93
+ const app = createApp(App)
94
+
95
+ // Register components globally
96
+ app.component('kButton', kButton)
97
+ app.component('kInput', kInput)
98
+ app.component('kDateSelector', kDateSelector)
99
+ app.component('kSelect', kSelect)
100
+ app.component('kToggle', kToggle)
101
+
102
+ // Use plugins
103
+ app.use(toastPlugin)
104
+ app.use(confirmPlugin)
105
+
106
+ app.mount('#app')
107
+ ```
108
+
109
+ ## Example Component Usage
110
+
111
+ ```vue
112
+ <template>
113
+ <div class="p-4 space-y-4">
114
+ <!-- Button -->
115
+ <k-button @click="handleClick" variant="primary">
116
+ Click me
117
+ </k-button>
118
+
119
+ <!-- Input -->
120
+ <k-input
121
+ v-model="email"
122
+ label="Email"
123
+ placeholder="Enter your email"
124
+ type="email"
125
+ />
126
+
127
+ <!-- Date Selector -->
128
+ <k-date-selector
129
+ v-model="date"
130
+ label="Select Date"
131
+ type="date"
132
+ />
133
+
134
+ <!-- Select -->
135
+ <k-select
136
+ v-model="selectedOption"
137
+ :options="options"
138
+ label="Choose option"
139
+ />
140
+ </div>
141
+ </template>
142
+
143
+ <script>
144
+ import { kButton, kInput, kDateSelector, kSelect } from 'ketekny-ui-kit'
145
+
146
+ export default {
147
+ components: {
148
+ kButton,
149
+ kInput,
150
+ kDateSelector,
151
+ kSelect
152
+ },
153
+ data() {
154
+ return {
155
+ email: '',
156
+ date: null,
157
+ selectedOption: null,
158
+ options: [
159
+ { value: 'option1', label: 'Option 1' },
160
+ { value: 'option2', label: 'Option 2' }
161
+ ]
162
+ }
163
+ },
164
+ methods: {
165
+ handleClick() {
166
+ // Handle button click
167
+ }
168
+ }
169
+ }
170
+ </script>
171
+ ```
172
+
173
+ ## Dependencies
174
+
175
+ This library depends on:
176
+ - Vue 3.x
177
+ - Tailwind CSS 3.x
178
+ - Lucide Vue Next (icons)
179
+ - Vue Datepicker
180
+ - Moment.js
181
+ - PrimeVue
182
+ - Quill (rich text editor)
183
+
184
+ ## License
185
+
186
+ ISC
187
+
188
+ ## Links
21
189
 
22
- npm install git+ssh://git@gitlab.ketekny.gr/support/ui.ketekny.gr.git
190
+ - [npm](https://www.npmjs.com/package/ketekny-ui-kit)
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 kSkeleton from './src/ui/kSkeleton.vue'
25
26
 
26
27
  // Layout Components
27
28
  import kAppHeader from './src/layout/kAppHeader.vue'
@@ -42,7 +43,7 @@ import tailwindPreset from './tailwind-preset.js'
42
43
  // Named exports (tree-shaking friendly)
43
44
  export {
44
45
  // UI Components
45
- kMessage, kCode, kToolbar, kTable, kTabs, kChip, kSpinner, kDatatable, kIcon, kMenu,
46
+ kMessage, kCode, kToolbar, kTable, kTabs, kChip, kSpinner, kDatatable, kIcon, kMenu, kSkeleton,
46
47
 
47
48
  // Form Components
48
49
  kButton, kSelect, kUploader, kToggle, kInput, kDateSelector, kEditor, kSelectButton, kTags, kSearch, kArrayList,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ketekny-ui-kit",
3
3
  "type": "module",
4
- "version": "1.0.3",
4
+ "version": "1.0.5",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -11,7 +11,13 @@
11
11
  "tailwind-preset.js",
12
12
  "tailwind.config.js"
13
13
  ],
14
- "keywords": ["vue", "ui", "components", "tailwind", "library"],
14
+ "keywords": [
15
+ "vue",
16
+ "ui",
17
+ "components",
18
+ "tailwind",
19
+ "library"
20
+ ],
15
21
  "peerDependencies": {
16
22
  "vue": "^3.0.0"
17
23
  },
@@ -40,6 +46,7 @@
40
46
  "primevue": "^4.3.4",
41
47
  "quill": "^2.0.3",
42
48
  "simple-code-editor": "^2.0.9",
49
+ "vue-router": "^4.6.4",
43
50
  "vue3-easy-data-table": "^1.5.47"
44
51
  }
45
52
  }
@@ -0,0 +1,289 @@
1
+ <template>
2
+ <div class="overflow-hidden border rounded-lg shadow-sm component-preview cp-card cp-border">
3
+ <!-- Header -->
4
+ <div class="flex items-center justify-between px-4 py-3 border-b cp-border cp-muted-50">
5
+ <h3 class="text-lg font-semibold cp-text">{{ componentName }}</h3>
6
+
7
+ <div class="flex items-center gap-1">
8
+ <button
9
+ v-for="tab in tabs"
10
+ :key="tab.id"
11
+ @click="activeTab = tab.id"
12
+ :class="['px-3 py-1.5 text-sm font-medium rounded-md transition-colors', activeTab === tab.id ? 'cp-tab-active' : 'cp-tab']">
13
+ {{ tab.label }}
14
+ </button>
15
+ </div>
16
+ </div>
17
+
18
+ <!-- Content -->
19
+ <div class="p-4">
20
+ <!-- Preview Tab -->
21
+ <div v-show="activeTab === 'preview'" class="min-h-[120px] flex items-center justify-center rounded-lg p-6 border cp-muted-30 cp-border-50">
22
+ <slot name="preview"></slot>
23
+ </div>
24
+
25
+ <!-- Props Tab -->
26
+ <div v-show="activeTab === 'props'">
27
+ <div v-if="props.length > 0" class="overflow-x-auto">
28
+ <table class="w-full text-sm">
29
+ <thead>
30
+ <tr class="border-b cp-border">
31
+ <th class="px-4 py-3 font-semibold text-left cp-text">Name</th>
32
+ <th class="px-4 py-3 font-semibold text-left cp-text">Type</th>
33
+ <th class="px-4 py-3 font-semibold text-left cp-text">Default</th>
34
+ <th class="px-4 py-3 font-semibold text-left cp-text">Description</th>
35
+ </tr>
36
+ </thead>
37
+
38
+ <tbody>
39
+ <tr v-for="(prop, index) in props" :key="prop.name" :class="index % 2 === 0 ? 'cp-muted-30' : ''">
40
+ <td class="px-4 py-3">
41
+ <code class="text-sm font-mono px-1.5 py-0.5 rounded cp-chip cp-chip-text">
42
+ {{ prop.name }}
43
+ </code>
44
+ </td>
45
+
46
+ <td class="px-4 py-3">
47
+ <span class="font-mono text-sm text-blue-600">{{ prop.type }}</span>
48
+ </td>
49
+
50
+ <td class="px-4 py-3">
51
+ <code v-if="prop.default !== undefined" class="font-mono text-sm text-emerald-600">
52
+ {{ prop.default }}
53
+ </code>
54
+ <span v-else class="cp-text-muted">—</span>
55
+ </td>
56
+
57
+ <td class="px-4 py-3 cp-text-muted">{{ prop.description }}</td>
58
+ </tr>
59
+ </tbody>
60
+ </table>
61
+ </div>
62
+
63
+ <div v-else class="flex items-center justify-center py-8 cp-text-muted">
64
+ <span>No props defined for this component</span>
65
+ </div>
66
+ </div>
67
+
68
+ <!-- Slots Tab -->
69
+ <div v-show="activeTab === 'slots'">
70
+ <div v-if="slots.length > 0" class="overflow-x-auto">
71
+ <table class="w-full text-sm">
72
+ <thead>
73
+ <tr class="border-b cp-border">
74
+ <th class="px-4 py-3 font-semibold text-left cp-text">Name</th>
75
+ <th class="px-4 py-3 font-semibold text-left cp-text">Scoped</th>
76
+ <th class="px-4 py-3 font-semibold text-left cp-text">Description</th>
77
+ </tr>
78
+ </thead>
79
+
80
+ <tbody>
81
+ <tr v-for="(slot, index) in slots" :key="slot.name" :class="index % 2 === 0 ? 'cp-muted-30' : ''">
82
+ <td class="px-4 py-3">
83
+ <code class="text-sm font-mono px-1.5 py-0.5 rounded cp-chip cp-chip-text">
84
+ {{ slot.name }}
85
+ </code>
86
+ </td>
87
+
88
+ <td class="px-4 py-3">
89
+ <span
90
+ :class="[
91
+ 'inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium',
92
+ slot.scoped ? 'bg-emerald-100 text-emerald-700' : 'cp-badge-muted',
93
+ ]">
94
+ {{ slot.scoped ? "Yes" : "No" }}
95
+ </span>
96
+ </td>
97
+
98
+ <td class="px-4 py-3 cp-text-muted">{{ slot.description }}</td>
99
+ </tr>
100
+ </tbody>
101
+ </table>
102
+ </div>
103
+
104
+ <div v-else class="flex items-center justify-center py-8 cp-text-muted">
105
+ <span>No slots defined for this component</span>
106
+ </div>
107
+ </div>
108
+
109
+ <!-- Code Tab -->
110
+ <div v-show="activeTab === 'code'" class="relative">
111
+ <div class="absolute z-10 top-3 right-3">
112
+ <button
113
+ @click="copyCode"
114
+ 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">
115
+ <svg
116
+ v-if="!copied"
117
+ xmlns="http://www.w3.org/2000/svg"
118
+ width="16"
119
+ height="16"
120
+ viewBox="0 0 24 24"
121
+ fill="none"
122
+ stroke="currentColor"
123
+ stroke-width="2"
124
+ stroke-linecap="round"
125
+ stroke-linejoin="round">
126
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
127
+ <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
128
+ </svg>
129
+
130
+ <svg
131
+ v-else
132
+ xmlns="http://www.w3.org/2000/svg"
133
+ width="16"
134
+ height="16"
135
+ viewBox="0 0 24 24"
136
+ fill="none"
137
+ stroke="currentColor"
138
+ stroke-width="2"
139
+ stroke-linecap="round"
140
+ stroke-linejoin="round"
141
+ class="text-emerald-600">
142
+ <polyline points="20 6 9 17 4 12" />
143
+ </svg>
144
+
145
+ {{ copied ? "Copied!" : "Copy" }}
146
+ </button>
147
+ </div>
148
+
149
+ <pre class="p-4 overflow-x-auto rounded-lg cp-pre">
150
+ <code class="font-mono text-sm" v-html="highlightedCode"></code>
151
+ </pre>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </template>
156
+
157
+ <script>
158
+ import hljs from "highlight.js/lib/core";
159
+ import xml from "highlight.js/lib/languages/xml";
160
+
161
+ hljs.registerLanguage("xml", xml);
162
+
163
+ export default {
164
+ name: "ComponentPreview",
165
+ props: {
166
+ componentName: { type: String, required: true },
167
+ props: { type: Array, default: () => [] },
168
+ slots: { type: Array, default: () => [] },
169
+ code: { type: String, default: "" },
170
+ },
171
+ data() {
172
+ return {
173
+ activeTab: "preview",
174
+ copied: false,
175
+ tabs: [
176
+ { id: "preview", label: "Preview" },
177
+ { id: "props", label: "Props" },
178
+ { id: "slots", label: "Slots" },
179
+ { id: "code", label: "Code" },
180
+ ],
181
+ };
182
+ },
183
+ computed: {
184
+ highlightedCode() {
185
+ if (!this.code) return "";
186
+ try {
187
+ return hljs.highlight(this.code.trim(), { language: "xml" }).value;
188
+ } catch {
189
+ return this.escapeHtml(this.code.trim());
190
+ }
191
+ },
192
+ },
193
+ methods: {
194
+ async copyCode() {
195
+ try {
196
+ await navigator.clipboard.writeText(this.code.trim());
197
+ this.copied = true;
198
+ setTimeout(() => (this.copied = false), 2000);
199
+ } catch (err) {
200
+ console.error("Failed to copy code:", err);
201
+ }
202
+ },
203
+ escapeHtml(text) {
204
+ const div = document.createElement("div");
205
+ div.textContent = text;
206
+ return div.innerHTML;
207
+ },
208
+ },
209
+ };
210
+ </script>
211
+
212
+ <style scoped>
213
+ /* Component-local theme tokens */
214
+ .component-preview {
215
+ --cp-foreground: #0a0a0a;
216
+ --cp-card: #ffffff;
217
+ --cp-border: #e5e5e5;
218
+ --cp-muted: #f5f5f5;
219
+ --cp-muted-foreground: #737373;
220
+ --cp-primary: #0a0a0a;
221
+ --cp-primary-foreground: #fafafa;
222
+ --cp-accent: #f5f5f5;
223
+ --cp-accent-foreground: #0a0a0a;
224
+ }
225
+
226
+ .cp-text {
227
+ color: var(--cp-foreground);
228
+ }
229
+
230
+ .cp-text-muted {
231
+ color: var(--cp-muted-foreground);
232
+ }
233
+
234
+ .cp-card {
235
+ background-color: var(--cp-card);
236
+ }
237
+
238
+ .cp-border {
239
+ border-color: var(--cp-border);
240
+ }
241
+
242
+ .cp-border-50 {
243
+ border-color: color-mix(in srgb, var(--cp-border) 50%, transparent);
244
+ }
245
+
246
+ .cp-muted-50 {
247
+ background-color: color-mix(in srgb, var(--cp-muted) 50%, transparent);
248
+ }
249
+
250
+ .cp-muted-30 {
251
+ background-color: color-mix(in srgb, var(--cp-muted) 30%, transparent);
252
+ }
253
+
254
+ .cp-tab {
255
+ color: var(--cp-muted-foreground);
256
+ }
257
+
258
+ .cp-tab:hover {
259
+ color: var(--cp-foreground);
260
+ background-color: var(--cp-accent);
261
+ }
262
+
263
+ .cp-tab-active {
264
+ background-color: var(--cp-primary);
265
+ color: var(--cp-primary-foreground);
266
+ }
267
+
268
+ .cp-chip {
269
+ background-color: var(--cp-accent);
270
+ }
271
+
272
+ .cp-chip-hover:hover {
273
+ background-color: color-mix(in srgb, var(--cp-accent) 80%, transparent);
274
+ }
275
+
276
+ .cp-chip-text {
277
+ color: var(--cp-accent-foreground);
278
+ }
279
+
280
+ .cp-pre {
281
+ background-color: var(--cp-muted);
282
+ color: var(--cp-foreground);
283
+ }
284
+
285
+ .cp-badge-muted {
286
+ background-color: var(--cp-muted);
287
+ color: var(--cp-muted-foreground);
288
+ }
289
+ </style>
@@ -0,0 +1,21 @@
1
+ <template lang="">
2
+ <template v-if="type === 'text'">
3
+ <div class="space-y-2 animate-pulse">
4
+ <div v-for="n in normalizedRows" :key="n" class="w-full h-4 bg-gray-300 rounded"></div>
5
+ </div>
6
+ </template>
7
+ </template>
8
+ <script>
9
+ export default {
10
+ props: {
11
+ type: { type: String, default: "text" },
12
+ rows: { type: [Number, String], default: 1 },
13
+ },
14
+ computed: {
15
+ normalizedRows() {
16
+ return Number(this.rows) || 1;
17
+ },
18
+ },
19
+ };
20
+ </script>
21
+ <style lang=""></style>