ketekny-ui-kit 1.0.85 → 1.0.87

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.85",
4
+ "version": "1.0.87",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -7,7 +7,7 @@
7
7
  type="button"
8
8
  :aria-label="expandLabel"
9
9
  v-tooltip.right="expandLabel"
10
- class="fixed top-0 z-[70] hidden h-10 w-10 items-center justify-center rounded-r-full border-white/15 bg-[#0b0c0f] text-white shadow-2xl shadow-black/50 transition-all duration-300 hover:bg-[#14161b] lg:left-[42px] lg:translate-x-full lg:flex"
10
+ class="fixed top-0 z-[70] hidden h-10 w-10 items-center justify-center rounded-r-full border-white/15 bg-[#0b0c0f] text-white shadow-lg shadow-black/25 transition-all duration-300 hover:bg-[#14161b] lg:left-[42px] lg:translate-x-full lg:flex"
11
11
  @click="toggleSidebar"
12
12
  >
13
13
  <slot name="collapsed-toggle-icon">
@@ -20,7 +20,7 @@
20
20
  type="button"
21
21
  :aria-label="collapseLabel"
22
22
  v-tooltip.left="collapseLabel"
23
- class="fixed top-0 z-[70] hidden h-10 w-10 items-center justify-center rounded-r-full border-white/15 bg-[#0b0c0f] text-white shadow-2xl shadow-black/50 transition-all duration-300 hover:bg-[#14161b] lg:left-[326px] lg:translate-x-full lg:flex"
23
+ class="fixed top-0 z-[70] hidden h-10 w-10 items-center justify-center rounded-r-full border-white/15 bg-[#0b0c0f] text-white shadow-lg shadow-black/25 transition-all duration-300 hover:bg-[#14161b] lg:left-[326px] lg:translate-x-full lg:flex"
24
24
  @click.stop="toggleSidebar"
25
25
  >
26
26
  <slot name="toggle-icon">
@@ -82,7 +82,7 @@
82
82
  <transition name="mobile-menu-panel">
83
83
  <aside
84
84
  v-if="!isDesktopViewport && mobileMenuOpen"
85
- class="fixed inset-y-0 left-0 z-[90] flex h-[100dvh] w-[min(90vw,420px)] max-w-full overflow-hidden shadow-2xl"
85
+ class="fixed inset-y-0 left-0 z-[90] flex h-[100dvh] w-[min(90vw,420px)] max-w-full overflow-hidden shadow-[10px_0_30px_rgba(0,0,0,0.2)]"
86
86
  role="dialog"
87
87
  aria-modal="true"
88
88
  >
@@ -1,6 +1,10 @@
1
1
  <template>
2
2
  <div class="space-y-1.5">
3
- <div v-for="item in items" :key="item.key" class="space-y-1.5">
3
+ <div
4
+ v-for="item in items"
5
+ :key="item.key"
6
+ class="space-y-1.5"
7
+ >
4
8
  <div
5
9
  class="flex items-stretch"
6
10
  :class="item.hasChildren ? 'gap-2' : 'gap-0'"
@@ -15,16 +19,25 @@
15
19
  <span
16
20
  class="flex h-5 w-5 shrink-0 items-center justify-center text-[#eef2f7] transition-colors duration-150"
17
21
  >
18
- <kIcon :name="item.icon" size="18" color="#eef2f7" />
22
+ <kIcon
23
+ v-if="showFullIcon(item)"
24
+ :name="item.icon"
25
+ size="18"
26
+ color="#eef2f7"
27
+ />
28
+ <span
29
+ v-else
30
+ class="h-1.5 w-1.5 rounded-full bg-current opacity-80"
31
+ />
19
32
  </span>
20
33
  <span class="min-w-0 flex-1">
21
- <span class="block truncate text-[15px] font-medium leading-5">
34
+ <span class="block truncate font-medium" :class="itemLabelClasses">
22
35
  {{ item.label }}
23
36
  </span>
24
37
  <span
25
38
  v-if="item.description"
26
- class="mt-1 block truncate text-[12px] leading-4"
27
- :class="item.active ? 'text-[#9fa6b5]' : 'text-[#6f7786]'"
39
+ class="mt-1 block truncate"
40
+ :class="[itemDescriptionClasses, item.active ? 'text-[#9fa6b5]' : 'text-[#6f7786]']"
28
41
  >
29
42
  {{ item.description }}
30
43
  </span>
@@ -34,28 +47,29 @@
34
47
  <button
35
48
  v-if="item.hasChildren"
36
49
  type="button"
37
- class="flex w-8 shrink-0 appearance-none items-center justify-center border-0 bg-transparent text-[#eef2f7] outline-none transition hover:bg-white/6 hover:text-white"
50
+ class="flex w-8 shrink-0 appearance-none items-center justify-center border-0 bg-transparent text-[#6f7786] outline-none transition hover:bg-white/6 hover:text-[#cbd5e1]"
38
51
  :aria-expanded="isExpanded(item)"
39
52
  :aria-label="`${isExpanded(item) ? 'Collapse' : 'Expand'} ${item.label}`"
40
53
  @click.stop="toggle(item.key)"
41
54
  >
42
55
  <kIcon
43
- name="ChevronDown"
56
+ name="ChevronRight"
44
57
  size="15"
45
- color="#eef2f7"
46
- class="transition-transform duration-200"
47
- :class="isExpanded(item) ? 'rotate-180' : ''"
58
+ color="currentColor"
59
+ class="!text-[#6f7786] transition-transform duration-200"
60
+ :class="isExpanded(item) ? 'rotate-90' : ''"
48
61
  />
49
62
  </button>
50
63
  </div>
51
64
 
52
65
  <div
53
66
  v-if="item.hasChildren && isExpanded(item)"
54
- class="ml-2 border-l border-[#242834] pl-4"
67
+ class="ml-2 pl-4"
55
68
  >
56
69
  <TwoColSidebarMenuList
57
70
  :items="item.children"
58
71
  :expanded-state="expandedState"
72
+ :level="level + 1"
59
73
  @item-click="$emit('item-click', $event)"
60
74
  @toggle-branch="$emit('toggle-branch', $event)"
61
75
  />
@@ -77,8 +91,26 @@ export default {
77
91
  props: {
78
92
  items: { type: Array, default: () => [] },
79
93
  expandedState: { type: Object, required: true },
94
+ level: { type: Number, default: 0 },
80
95
  },
81
96
  emits: ["item-click", "toggle-branch"],
97
+ computed: {
98
+ itemLabelClasses() {
99
+ return this.level === 0
100
+ ? "text-[15px] leading-5"
101
+ : "text-[14px] leading-5";
102
+ },
103
+ itemDescriptionClasses() {
104
+ return this.level === 0
105
+ ? "text-[12px] leading-4"
106
+ : "text-[11px] leading-4";
107
+ },
108
+ activeIndicatorClasses() {
109
+ return this.level === 0
110
+ ? "before:left-0"
111
+ : "before:-left-4";
112
+ },
113
+ },
82
114
  methods: {
83
115
  menuItemComponent(item) {
84
116
  if (item?.isLink) return RouterLink;
@@ -99,9 +131,12 @@ export default {
99
131
  isExpanded(item) {
100
132
  return Boolean(this.expandedState[item.key]);
101
133
  },
134
+ showFullIcon(item) {
135
+ return this.level === 0 && Boolean(item?.icon);
136
+ },
102
137
  itemRowClasses(item) {
103
138
  return item.active
104
- ? "relative rounded-xl bg-[#242424] text-white before:absolute before:bottom-2 before:left-0 before:top-2 before:w-[3px] before:rounded-r-full before:bg-[#2491ff]"
139
+ ? `relative rounded-xl bg-[#1f232b] text-white before:absolute before:bottom-2 before:top-2 before:w-[3px] before:rounded-r-full before:bg-[#2491ff] ${this.activeIndicatorClasses}`
105
140
  : "rounded-xl text-[#e5e7eb] hover:bg-[#242424] hover:text-white";
106
141
  },
107
142
  toggle(key) {
@@ -1,13 +1,17 @@
1
1
  <template>
2
2
  <div
3
- class="flex h-full w-full flex-col overflow-visible border-r border-[#171a21] bg-[#0b0c0f] text-white shadow-[20px_0_50px_rgba(0,0,0,0.35)] transition-all duration-300 ease-out lg:relative lg:z-30 lg:will-change-transform"
3
+ class="flex h-full w-full flex-col overflow-visible border-r border-[#171a21] bg-[#0b0c0f] text-white shadow-[10px_0_28px_rgba(0,0,0,0.18)] transition-all duration-300 ease-out lg:relative lg:z-30 lg:will-change-transform"
4
4
  >
5
5
  <div class="relative">
6
6
  <button
7
7
  v-if="logoSrc"
8
8
  type="button"
9
9
  class="block w-full text-left"
10
- v-tooltip.right.html="collapsed ? collapsedContactTooltip : logoAlt"
10
+ :title="collapsed ? null : logoAlt"
11
+ @mouseenter="handleCollapsedContactEnter($event)"
12
+ @mouseleave="handleCollapsedContactLeave"
13
+ @focus="handleCollapsedContactEnter($event)"
14
+ @blur="handleCollapsedContactLeave"
11
15
  @click="$emit('logo-click')"
12
16
  >
13
17
  <img
@@ -33,7 +37,7 @@
33
37
  v-model="menuSearchTerm"
34
38
  :debounce="0"
35
39
  :placeholder="menuSearchPlaceholder"
36
- input-class="border-[#242834] bg-[#1f1f1f] text-[#eef2f7] placeholder:text-[#8a92a1] shadow-none focus:border-[#3b82f6] focus:ring-[#3b82f6]/20"
40
+ input-class="!border-[#242834] !bg-[#1f1f1f] !text-[#eef2f7] !placeholder:text-[#8a92a1] !shadow-none focus:!border-[#3b82f6] focus:!ring-[#3b82f6]/20 dark:!border-[#242834] dark:!bg-[#1f1f1f] dark:!text-[#eef2f7] dark:!placeholder:text-[#8a92a1]"
37
41
  icon-class="text-[#8a92a1]"
38
42
  />
39
43
  </div>
@@ -77,6 +81,42 @@
77
81
  </div>
78
82
 
79
83
  <Teleport to="body">
84
+ <div
85
+ v-if="collapsedContactFlyoutVisible"
86
+ class="fixed z-[200]"
87
+ :style="collapsedContactFlyoutStyle"
88
+ @mouseenter="handleCollapsedContactEnter()"
89
+ @mouseleave="handleCollapsedContactLeave"
90
+ >
91
+ <div
92
+ class="w-[320px] rounded-2xl border border-[#242834] bg-[#0f1116] p-3 shadow-[0_18px_44px_rgba(0,0,0,0.32)]"
93
+ >
94
+ <div class="mb-2 px-2 text-[11px] font-semibold uppercase tracking-[0.24em] text-[#7f8794]">
95
+ KETEKNY AE
96
+ </div>
97
+ <div class="flex flex-col gap-1 px-2 text-sm leading-6 text-white">
98
+ <div class="text-[#d1d5db]">{{ contactAddressLabel }}</div>
99
+ <a href="tel:2103648337" class="text-[#d1d5db] transition hover:text-white hover:underline">
100
+ 210 3648 337
101
+ </a>
102
+ <a
103
+ :href="`mailto:${contactEmail}`"
104
+ class="text-[#d1d5db] transition hover:text-white hover:underline"
105
+ >
106
+ {{ contactEmail }}
107
+ </a>
108
+ <a
109
+ href="https://ketekny.gr"
110
+ target="_blank"
111
+ rel="noreferrer"
112
+ class="text-[#d1d5db] transition hover:text-white hover:underline"
113
+ >
114
+ https://ketekny.gr
115
+ </a>
116
+ </div>
117
+ </div>
118
+ </div>
119
+
80
120
  <div
81
121
  v-if="collapsedFlyoutItem"
82
122
  class="fixed z-[200]"
@@ -85,7 +125,7 @@
85
125
  @mouseleave="handleCollapsedItemLeave(collapsedFlyoutItem)"
86
126
  >
87
127
  <div
88
- class="w-[320px] rounded-2xl border border-[#242834] bg-[#0f1116] p-3 shadow-[0_24px_60px_rgba(0,0,0,0.45)]"
128
+ class="w-[320px] rounded-2xl border border-[#242834] bg-[#0f1116] p-3 shadow-[0_18px_44px_rgba(0,0,0,0.32)]"
89
129
  >
90
130
  <div class="mb-2 px-2">
91
131
  <div class="text-sm font-semibold text-white">
@@ -344,6 +384,9 @@ export default {
344
384
  collapsedFlyoutKey: null,
345
385
  collapsedFlyoutPosition: null,
346
386
  collapsedFlyoutCloseTimer: null,
387
+ collapsedContactFlyoutPosition: null,
388
+ collapsedContactFlyoutVisible: false,
389
+ collapsedContactFlyoutCloseTimer: null,
347
390
  menuSearchTerm: "",
348
391
  };
349
392
  },
@@ -390,6 +433,14 @@ export default {
390
433
  top: `${this.collapsedFlyoutPosition.top}px`,
391
434
  };
392
435
  },
436
+ collapsedContactFlyoutStyle() {
437
+ if (!this.collapsedContactFlyoutPosition) return {};
438
+
439
+ return {
440
+ left: `${this.collapsedContactFlyoutPosition.left}px`,
441
+ top: `${this.collapsedContactFlyoutPosition.top}px`,
442
+ };
443
+ },
393
444
  accountDisplayName() {
394
445
  if (!this.account) return "";
395
446
 
@@ -418,21 +469,6 @@ export default {
418
469
  contactAddressLabel() {
419
470
  return LABELS.contactAddress;
420
471
  },
421
- collapsedContactTooltip() {
422
- return `
423
- <div style="min-width: 220px;">
424
- <div style="font-weight: 700; text-transform: uppercase; letter-spacing: 0.25em; font-size: 11px; color: rgba(255,255,255,0.65); margin-bottom: 8px;">
425
- KETEKNY AE
426
- </div>
427
- <div style="display: flex; flex-direction: column; gap: 4px; font-size: 13px; line-height: 1.4; color: rgba(255,255,255,0.9);">
428
- <div>${LABELS.contactAddress}</div>
429
- <div>210 3648 337</div>
430
- <div>${this.contactEmail}</div>
431
- <div>https://ketekny.gr</div>
432
- </div>
433
- </div>
434
- `;
435
- },
436
472
  },
437
473
  watch: {
438
474
  menuItems: {
@@ -459,6 +495,7 @@ export default {
459
495
  },
460
496
  beforeUnmount() {
461
497
  this.clearCollapsedFlyoutCloseTimer();
498
+ this.clearCollapsedContactFlyoutCloseTimer();
462
499
  },
463
500
  methods: {
464
501
  menuItemComponent(item) {
@@ -516,12 +553,46 @@ export default {
516
553
  top: Math.max(12, rect.top),
517
554
  };
518
555
  },
556
+ updateCollapsedContactFlyoutPosition(event) {
557
+ const trigger = event?.currentTarget;
558
+ if (!trigger || typeof window === "undefined") return;
559
+
560
+ const rect = trigger.getBoundingClientRect();
561
+ this.collapsedContactFlyoutPosition = {
562
+ left: rect.right + 12,
563
+ top: Math.max(12, rect.top + 8),
564
+ };
565
+ },
519
566
  clearCollapsedFlyoutCloseTimer() {
520
567
  if (this.collapsedFlyoutCloseTimer) {
521
568
  window.clearTimeout(this.collapsedFlyoutCloseTimer);
522
569
  this.collapsedFlyoutCloseTimer = null;
523
570
  }
524
571
  },
572
+ clearCollapsedContactFlyoutCloseTimer() {
573
+ if (this.collapsedContactFlyoutCloseTimer) {
574
+ window.clearTimeout(this.collapsedContactFlyoutCloseTimer);
575
+ this.collapsedContactFlyoutCloseTimer = null;
576
+ }
577
+ },
578
+ handleCollapsedContactEnter(event) {
579
+ if (!this.collapsed || !this.showContactInfo) return;
580
+
581
+ this.clearCollapsedContactFlyoutCloseTimer();
582
+ this.collapsedContactFlyoutVisible = true;
583
+ if (event) {
584
+ this.updateCollapsedContactFlyoutPosition(event);
585
+ }
586
+ },
587
+ handleCollapsedContactLeave() {
588
+ if (!this.collapsedContactFlyoutVisible) return;
589
+
590
+ this.clearCollapsedContactFlyoutCloseTimer();
591
+ this.collapsedContactFlyoutCloseTimer = window.setTimeout(() => {
592
+ this.collapsedContactFlyoutVisible = false;
593
+ this.collapsedContactFlyoutCloseTimer = null;
594
+ }, 180);
595
+ },
525
596
  handleCollapsedItemEnter(item, event) {
526
597
  if (!item?.hasChildren) return;
527
598