ketekny-ui-kit 1.0.68 → 1.0.69

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.68",
4
+ "version": "1.0.69",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -16,19 +16,21 @@
16
16
  </button>
17
17
 
18
18
  <aside
19
- class="flex h-screen w-full flex-col overflow-y-auto overflow-x-hidden bg-[radial-gradient(circle_at_0_0,#ffffff0f,#0000_34%),linear-gradient(#101a2d_0%,#0a1120_52%,#070d19_100%)] text-white shadow-2xl transition-all duration-300 ease-out lg:w-[360px] lg:shrink-0 lg:border-r lg:border-white/10 lg:will-change-transform"
19
+ class="flex h-screen w-full flex-col overflow-y-auto overflow-x-hidden bg-[radial-gradient(circle_at_0_0,#ffffff0f,#0000_34%),linear-gradient(#101a2d_0%,#0a1120_52%,#070d19_100%)] text-white shadow-2xl transition-all duration-300 ease-out lg:w-[360px] lg:shrink-0 lg:will-change-transform"
20
20
  :class="
21
21
  isSidebarCollapsed
22
22
  ? 'lg:relative lg:z-30 lg:w-[76px]'
23
23
  : 'lg:relative lg:z-30 lg:translate-x-0'
24
24
  "
25
25
  >
26
- <div class="relative border-b border-white/10">
26
+ <div class="relative ">
27
27
  <button
28
28
  v-if="logoSrc"
29
29
  type="button"
30
30
  class="block w-full text-left"
31
- v-tooltip.right.html="isSidebarCollapsed ? collapsedContactTooltip : logoAlt"
31
+ v-tooltip.right.html="
32
+ isSidebarCollapsed ? collapsedContactTooltip : logoAlt
33
+ "
32
34
  @click="$emit('logo-click')"
33
35
  >
34
36
  <img
@@ -37,27 +39,12 @@
37
39
  class="cursor-pointer px-4 py-4 transition-all duration-300"
38
40
  />
39
41
  </button>
40
- <div v-if="title && !isSidebarCollapsed"
41
- :class="showSponsors ? 'border-b border-white/30 ' : ''"
42
- class="py-3 mt-3 text-xl font-bold text-center bg-[#0f4e8d]">
42
+ <div
43
+ v-if="title && !isSidebarCollapsed"
44
+ class="py-3 text-xl font-bold text-center"
45
+ >
43
46
  {{ title }}
44
47
  </div>
45
- <div v-if="showSponsors && !isSidebarCollapsed" class="flex flex-col gap-3 px-4 py-4 bg-[#0f4e8d]">
46
- <div>
47
- <img
48
- src="https://s3.ketekny.gr/public/web-apps/sponsors/Greece 2.0_NextGeneration_White_gr.png"
49
- alt="Tameio Anakampsis"
50
- class="mx-auto max-h-16 w-auto object-contain"
51
- />
52
- </div>
53
- <div>
54
- <img
55
- src="https://s3.ketekny.gr/public/web-apps/sponsors/yp_ygeias_dark.png"
56
- alt="Ypourgeio Ygeias"
57
- class="mx-auto max-h-16 w-auto object-contain"
58
- />
59
- </div>
60
- </div>
61
48
 
62
49
  <slot name="sidebar-header" />
63
50
 
@@ -70,17 +57,18 @@
70
57
  @click.stop="toggleSidebar"
71
58
  >
72
59
  <slot name="toggle-icon">
73
- <kIcon
74
- :name="collapseIcon"
75
- size="16"
76
- class="text-white"
77
- />
60
+ <kIcon :name="collapseIcon" size="16" class="text-white" />
78
61
  </slot>
79
62
  </button>
80
63
  </div>
81
64
 
65
+
66
+
82
67
  <div class="flex-1 pt-4">
83
- <div v-if="isSidebarCollapsed" class="mx-1 mt-3 flex flex-col items-center gap-2">
68
+ <div
69
+ v-if="isSidebarCollapsed"
70
+ class="mx-1 mt-3 flex flex-col items-center gap-2"
71
+ >
84
72
  <SidebarIconLink
85
73
  v-for="item in normalizedMainMenu"
86
74
  :key="item.key"
@@ -127,23 +115,53 @@
127
115
  </div>
128
116
  </div>
129
117
 
130
- <div v-if="account " class="shrink-0 border-t border-white/10 bg-slate-900/80 px-1 py-4 text-white/80">
118
+ <div
119
+ v-if="account"
120
+ class="shrink-0 border-b border-white/10 bg-slate-900/80 px-1 pb-4 text-white/80"
121
+ >
131
122
  <div v-if="isSidebarCollapsed" class="flex flex-col gap-3">
132
123
  <div v-if="account.loggedIn" class="flex flex-col items-center gap-2">
133
- <SidebarIconLink icon="UserRoundCog" :on-click="() => $emit('edit-profile')" :title="'Επεξεργασία προφίλ'" v-tooltip.right="'Επεξεργασία προφίλ'" />
134
- <SidebarIconLink icon="LogOut" warning :on-click="() => $emit('signout')" :title="'Αποσύνδεση'" v-tooltip.right="'Αποσύνδεση'" />
124
+ <SidebarIconLink
125
+ icon="UserRoundCog"
126
+ :on-click="() => $emit('edit-profile')"
127
+ :title="'Επεξεργασία προφίλ'"
128
+ v-tooltip.right="'Επεξεργασία προφίλ'"
129
+ />
130
+ <SidebarIconLink
131
+ icon="LogOut"
132
+ warning
133
+ :on-click="() => $emit('signout')"
134
+ :title="'Αποσύνδεση'"
135
+ v-tooltip.right="'Αποσύνδεση'"
136
+ />
135
137
  </div>
136
138
  <div v-else class="flex flex-col items-center gap-2">
137
- <SidebarIconLink icon="LogIn" :on-click="() => $emit('signin')" :title="'Sign in'" v-tooltip.right="'Sign in'" />
138
- <SidebarIconLink icon="UserPlus" :on-click="() => $emit('signup')" :title="'Sign up'" v-tooltip.right="'Sign up'" />
139
+ <SidebarIconLink
140
+ icon="LogIn"
141
+ :on-click="() => $emit('signin')"
142
+ :title="'Sign in'"
143
+ v-tooltip.right="'Sign in'"
144
+ />
145
+ <SidebarIconLink
146
+ icon="UserPlus"
147
+ :on-click="() => $emit('signup')"
148
+ :title="'Sign up'"
149
+ v-tooltip.right="'Sign up'"
150
+ />
139
151
  </div>
140
152
  </div>
141
153
  <div v-else class="flex flex-col gap-3 px-3">
142
154
  <div class="min-w-0">
143
- <p v-if="account.loggedIn" class="mt-2 truncate text-lg font-semibold text-white">
155
+ <p
156
+ v-if="account.loggedIn"
157
+ class="mt-2 truncate text-lg font-semibold text-white"
158
+ >
144
159
  {{ accountDisplayName }}
145
160
  </p>
146
- <p v-if="account.loggedIn && displayEmail" class="truncate text-sm text-slate-300">
161
+ <p
162
+ v-if="account.loggedIn && displayEmail"
163
+ class="truncate text-sm text-slate-300"
164
+ >
147
165
  {{ displayEmail }}
148
166
  </p>
149
167
  </div>
@@ -164,7 +182,7 @@
164
182
  />
165
183
  <kButton
166
184
  v-if="account.loggedIn"
167
- variant="soft"
185
+ variant="soft"
168
186
  icon="UserRoundCog"
169
187
  label="Επεξεργασία προφίλ"
170
188
  @click="$emit('edit-profile')"
@@ -179,21 +197,32 @@
179
197
  </div>
180
198
  </div>
181
199
  </div>
200
+
182
201
 
183
202
  <div
184
- v-if="showContactInfo && !isSidebarCollapsed"
185
- class="shrink-0 border-t border-white/10 p-4 text-white/50"
203
+ v-if="!isSidebarCollapsed"
204
+ class="shrink-0 border-t border-white/10 text-white/50"
186
205
  >
187
- <div class="flex flex-col gap-2">
188
- <p v-if="!isSidebarCollapsed" class="text-sm font-semibold uppercase tracking-[0.25em] text-white/60">
206
+ <div class="flex flex-col gap-2 px-4" v-if="showContactInfo">
207
+ <p
208
+ class="text-sm font-semibold uppercase tracking-[0.25em] text-white/60"
209
+ >
189
210
  KETEKNY AE
190
211
  </p>
191
- <div class="flex flex-wrap items-center gap-x-3 text-sm leading-relaxed" :class="isSidebarCollapsed ? 'justify-center' : ''">
192
- <span v-if="isSidebarCollapsed" class="sr-only">KETEKNY AE contact info</span>
212
+ <div
213
+ class="flex flex-wrap items-center gap-x-3 text-sm"
214
+ :class="isSidebarCollapsed ? 'justify-center' : ''"
215
+ >
216
+ <span v-if="isSidebarCollapsed" class="sr-only"
217
+ >KETEKNY AE contact info</span
218
+ >
193
219
  <span class="whitespace-nowrap">Βερανζέρου 13, 10677, Αθήνα</span>
194
220
  <span class="whitespace-nowrap">210 3648 337</span>
195
221
  <span class="whitespace-nowrap">
196
- <a :href="`mailto:${contactEmail}`" class="whitespace-nowrap hover:underline">
222
+ <a
223
+ :href="`mailto:${contactEmail}`"
224
+ class="whitespace-nowrap hover:underline"
225
+ >
197
226
  {{ contactEmail }}
198
227
  </a>
199
228
  </span>
@@ -207,11 +236,32 @@
207
236
  </a>
208
237
  </div>
209
238
  </div>
210
- </div>
211
239
 
240
+ <div
241
+ v-if="showSponsors && !isSidebarCollapsed"
242
+ class="flex flex-col gap-3 px-4 py-1 bg-[#0d4b87] mt-2"
243
+ >
244
+ <div>
245
+ <img
246
+ src="https://s3.ketekny.gr/public/web-apps/sponsors/Greece 2.0_NextGeneration_White_gr.png"
247
+ alt="Tameio Anakampsis"
248
+ class="mx-auto max-h-14 w-auto object-contain"
249
+ />
250
+ </div>
251
+ <div>
252
+ <img
253
+ src="https://s3.ketekny.gr/public/web-apps/sponsors/yp_ygeias_dark.png"
254
+ alt="Ypourgeio Ygeias"
255
+ class="mx-auto max-h-14 w-auto object-contain"
256
+ />
257
+ </div>
258
+ </div>
259
+ </div>
212
260
  </aside>
213
261
 
214
- <main class="min-h-screen min-w-0 flex-1 overflow-y-auto overflow-x-hidden lg:h-full lg:min-h-0">
262
+ <main
263
+ class="min-h-screen min-w-0 flex-1 overflow-y-auto overflow-x-hidden lg:h-full lg:min-h-0"
264
+ >
215
265
  <div class="w-full">
216
266
  <slot />
217
267
  </div>
@@ -220,10 +270,10 @@
220
270
  </template>
221
271
 
222
272
  <script>
223
- import { h } from 'vue'
224
- import kButton from '../ui/kButton.vue'
225
- import kIcon from '../ui/kIcon.vue'
226
- import { RouterLink } from 'vue-router'
273
+ import { h } from "vue";
274
+ import kButton from "../ui/kButton.vue";
275
+ import kIcon from "../ui/kIcon.vue";
276
+ import { RouterLink } from "vue-router";
227
277
 
228
278
  const SidebarIconLink = {
229
279
  props: {
@@ -231,22 +281,22 @@ const SidebarIconLink = {
231
281
  active: { type: Boolean, default: false },
232
282
  to: { type: [String, Object], default: null },
233
283
  href: { type: String, default: null },
234
- title: { type: String, default: '' },
284
+ title: { type: String, default: "" },
235
285
  isExternal: { type: Boolean, default: false },
236
- target: { type: String, default: '_blank' },
237
- rel: { type: String, default: 'noreferrer' },
286
+ target: { type: String, default: "_blank" },
287
+ rel: { type: String, default: "noreferrer" },
238
288
  onClick: { type: Function, default: null },
239
289
  warning: { type: Boolean, default: false },
240
- tooltip: { type: String, default: '' },
290
+ tooltip: { type: String, default: "" },
241
291
  },
242
292
  methods: {
243
293
  handleClick(event) {
244
- if (this.onClick) this.onClick(event)
294
+ if (this.onClick) this.onClick(event);
245
295
  },
246
296
  },
247
297
  render() {
248
- const isLink = Boolean(this.to)
249
- const tag = isLink ? RouterLink : this.isExternal ? 'a' : 'button'
298
+ const isLink = Boolean(this.to);
299
+ const tag = isLink ? RouterLink : this.isExternal ? "a" : "button";
250
300
 
251
301
  return h(
252
302
  tag,
@@ -255,24 +305,24 @@ const SidebarIconLink = {
255
305
  href: this.href,
256
306
  target: this.isExternal ? this.target : null,
257
307
  rel: this.isExternal ? this.rel : null,
258
- type: isLink || this.isExternal ? null : 'button',
308
+ type: isLink || this.isExternal ? null : "button",
259
309
  title: this.title,
260
310
  class: [
261
- 'group relative flex h-14 w-14 items-center justify-center rounded-xl border border-white/15 transition',
311
+ "group relative flex h-14 w-14 items-center justify-center rounded-xl border border-white/15 transition",
262
312
  this.active
263
- ? 'bg-slate-950 text-white'
313
+ ? "bg-slate-950 text-white"
264
314
  : this.warning
265
- ? 'bg-[#d97706] text-white hover:bg-[#b45309]'
266
- : 'bg-white/5 text-white hover:border-cyan-400/40 hover:bg-white/10',
315
+ ? "bg-[#d97706] text-white hover:bg-[#b45309]"
316
+ : "bg-white/5 text-white hover:border-cyan-400/40 hover:bg-white/10",
267
317
  ],
268
318
  onClick: this.handleClick,
269
319
  },
270
- [h(kIcon, { name: this.icon, size: '20', color: '#ffffff' })]
271
- )
320
+ [h(kIcon, { name: this.icon, size: "20", color: "#ffffff" })]
321
+ );
272
322
  },
273
- }
323
+ };
274
324
 
275
- const DEFAULT_STORAGE_KEY = 'two-col-layout-sidebar-collapsed'
325
+ const DEFAULT_STORAGE_KEY = "two-col-layout-sidebar-collapsed";
276
326
 
277
327
  export default {
278
328
  components: {
@@ -281,97 +331,110 @@ export default {
281
331
  RouterLink,
282
332
  SidebarIconLink,
283
333
  },
284
- emits: ['logo-click', 'signin', 'signup', 'signout', 'edit-profile'],
334
+ emits: ["logo-click", "signin", "signup", "signout", "edit-profile"],
285
335
  props: {
286
- title: { type: String, default: '' },
336
+ title: { type: String, default: "" },
287
337
  collapsedLogoSrc: {
288
338
  type: String,
289
- default: 'https://s3.ketekny.gr/public/web-apps/logos/logo-icon-dark.png',
339
+ default: "https://s3.ketekny.gr/public/web-apps/logos/logo-icon-dark.png",
290
340
  },
291
- logoSrc: { type: String, default: '' },
292
- logoAlt: { type: String, default: 'Logo' },
293
- collapseLabel: { type: String, default: 'Collapse sidebar' },
294
- expandLabel: { type: String, default: 'Expand sidebar' },
295
- collapseIcon: { type: String, default: 'ArrowLeftToLine' },
296
- expandIcon: { type: String, default: 'ArrowRightToLine' },
341
+ logoSrc: { type: String, default: "" },
342
+ logoAlt: { type: String, default: "Logo" },
343
+ collapseLabel: { type: String, default: "Collapse sidebar" },
344
+ expandLabel: { type: String, default: "Expand sidebar" },
345
+ collapseIcon: { type: String, default: "ArrowLeftToLine" },
346
+ expandIcon: { type: String, default: "ArrowRightToLine" },
297
347
  showSponsors: { type: Boolean, default: false },
298
348
  storageKey: { type: String, default: DEFAULT_STORAGE_KEY },
299
349
  defaultCollapsed: { type: Boolean, default: false },
300
350
  mainMenu: { type: Array, default: () => [] },
301
351
  showContactInfo: { type: Boolean, default: false },
302
352
  account: { type: Object, default: null },
303
- contactEmail: { type: String, default: 'grammateia@ketekny.gr' },
353
+ contactEmail: { type: String, default: "grammateia@ketekny.gr" },
304
354
  },
305
355
  data() {
306
356
  return {
307
357
  isSidebarCollapsed: false,
308
358
  mdCollapseQuery: null,
309
- }
359
+ };
310
360
  },
311
361
  created() {
312
- this.restoreSidebarState()
362
+ this.restoreSidebarState();
313
363
  },
314
364
  mounted() {
315
- this.mdCollapseQuery = window.matchMedia('(min-width: 768px) and (max-width: 1023px)')
316
- this.syncSidebarForViewport()
317
- this.mdCollapseQuery.addEventListener('change', this.syncSidebarForViewport)
365
+ this.mdCollapseQuery = window.matchMedia(
366
+ "(min-width: 768px) and (max-width: 1023px)"
367
+ );
368
+ this.syncSidebarForViewport();
369
+ this.mdCollapseQuery.addEventListener(
370
+ "change",
371
+ this.syncSidebarForViewport
372
+ );
318
373
  },
319
374
  beforeUnmount() {
320
- this.mdCollapseQuery?.removeEventListener('change', this.syncSidebarForViewport)
375
+ this.mdCollapseQuery?.removeEventListener(
376
+ "change",
377
+ this.syncSidebarForViewport
378
+ );
321
379
  },
322
380
  methods: {
323
381
  restoreSidebarState() {
324
- if (typeof window === 'undefined') {
325
- this.isSidebarCollapsed = this.defaultCollapsed
326
- return
382
+ if (typeof window === "undefined") {
383
+ this.isSidebarCollapsed = this.defaultCollapsed;
384
+ return;
327
385
  }
328
386
 
329
- const stored = window.localStorage.getItem(this.storageKey)
387
+ const stored = window.localStorage.getItem(this.storageKey);
330
388
  if (stored == null) {
331
- this.isSidebarCollapsed = this.defaultCollapsed
332
- return
389
+ this.isSidebarCollapsed = this.defaultCollapsed;
390
+ return;
333
391
  }
334
392
 
335
- this.isSidebarCollapsed = stored === 'true'
393
+ this.isSidebarCollapsed = stored === "true";
336
394
  },
337
395
  syncSidebarForViewport() {
338
- if (typeof window === 'undefined') return
396
+ if (typeof window === "undefined") return;
339
397
 
340
- const isMd = window.matchMedia('(min-width: 768px) and (max-width: 1023px)').matches
398
+ const isMd = window.matchMedia(
399
+ "(min-width: 768px) and (max-width: 1023px)"
400
+ ).matches;
341
401
  if (isMd) {
342
- this.isSidebarCollapsed = true
343
- return
402
+ this.isSidebarCollapsed = true;
403
+ return;
344
404
  }
345
405
 
346
- this.restoreSidebarState()
406
+ this.restoreSidebarState();
347
407
  },
348
408
  persistSidebarState() {
349
- if (typeof window === 'undefined') return
409
+ if (typeof window === "undefined") return;
350
410
 
351
- window.localStorage.setItem(this.storageKey, this.isSidebarCollapsed ? 'true' : 'false')
411
+ window.localStorage.setItem(
412
+ this.storageKey,
413
+ this.isSidebarCollapsed ? "true" : "false"
414
+ );
352
415
  },
353
416
  toggleSidebar() {
354
- this.isSidebarCollapsed = !this.isSidebarCollapsed
355
- this.persistSidebarState()
417
+ this.isSidebarCollapsed = !this.isSidebarCollapsed;
418
+ this.persistSidebarState();
356
419
  },
357
420
  menuItemTag(item) {
358
- if (item?.isLink) return 'RouterLink'
359
- if (item?.isExternal) return 'a'
360
- return 'button'
421
+ if (item?.isLink) return "RouterLink";
422
+ if (item?.isExternal) return "a";
423
+ return "button";
361
424
  },
362
425
  },
363
426
  computed: {
364
427
  normalizedMainMenu() {
365
428
  return this.mainMenu.map((item, index) => {
366
- const isExternal = Boolean(item?.href)
367
- const isLink = Boolean(item?.to)
368
- const active = Boolean(item?.active)
429
+ const isExternal = Boolean(item?.href);
430
+ const isLink = Boolean(item?.to);
431
+ const active = Boolean(item?.active);
369
432
 
370
433
  return {
371
434
  key: item?.key || item?.label || index,
372
- label: item?.label || '',
373
- description: item?.description || '',
374
- icon: item?.icon || 'Dot',
435
+ label: item?.label || "",
436
+ description: item?.description || "",
437
+ icon: item?.icon || "Dot",
375
438
  active,
376
439
  isExternal,
377
440
  isLink,
@@ -379,31 +442,36 @@ export default {
379
442
  ? {
380
443
  to: item.to,
381
444
  title: item.title || item.label,
382
- 'aria-current': active ? 'page' : null,
445
+ "aria-current": active ? "page" : null,
383
446
  }
384
447
  : isExternal
385
- ? {
386
- href: item.href,
387
- target: item.target || '_blank',
388
- rel: item.rel || 'noreferrer',
389
- title: item.title || item.label,
390
- }
391
- : {
392
- type: 'button',
393
- title: item.title || item.label,
394
- },
448
+ ? {
449
+ href: item.href,
450
+ target: item.target || "_blank",
451
+ rel: item.rel || "noreferrer",
452
+ title: item.title || item.label,
453
+ }
454
+ : {
455
+ type: "button",
456
+ title: item.title || item.label,
457
+ },
395
458
  classes: active
396
- ? 'border-white/70 bg-white/90 text-slate-950 shadow-lg shadow-black/20'
397
- : 'border-white/10 bg-white/5 text-white hover:border-cyan-400/40 hover:bg-white/10',
398
- }
399
- })
459
+ ? "border-white/70 bg-white/90 text-slate-950 shadow-lg shadow-black/20"
460
+ : "border-white/10 bg-white/5 text-white hover:border-cyan-400/40 hover:bg-white/10",
461
+ };
462
+ });
400
463
  },
401
464
  accountDisplayName() {
402
- if (!this.account) return ''
403
- return [this.account.firstName, this.account.lastName].filter(Boolean).join(' ').trim() || 'Account'
465
+ if (!this.account) return "";
466
+ return (
467
+ [this.account.firstName, this.account.lastName]
468
+ .filter(Boolean)
469
+ .join(" ")
470
+ .trim() || "Account"
471
+ );
404
472
  },
405
473
  displayEmail() {
406
- return this.account?.email || ''
474
+ return this.account?.email || "";
407
475
  },
408
476
  collapsedContactTooltip() {
409
477
  return `
@@ -418,8 +486,8 @@ export default {
418
486
  <div>https://ketekny.gr</div>
419
487
  </div>
420
488
  </div>
421
- `
489
+ `;
422
490
  },
423
491
  },
424
- }
492
+ };
425
493
  </script>