ketekny-ui-kit 1.0.97 → 1.0.99

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.97",
4
+ "version": "1.0.99",
5
5
  "description": "A Vue 3 UI component library with Tailwind CSS styling",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -196,6 +196,18 @@ export default {
196
196
  visible: false,
197
197
  nodes: null,
198
198
  app: null,
199
+ content,
200
+ }
201
+
202
+ function renderContent(bubble) {
203
+ const content = state.content
204
+ if (content.mode === 'text') bubble.textContent = content.text || ''
205
+ else if (content.mode === 'html') bubble.innerHTML = content.html || ''
206
+ else if (content.mode === 'component') {
207
+ state.app?.unmount?.()
208
+ state.app = createApp({ render: () => h(content.component, content.props || {}) })
209
+ state.app.mount(bubble)
210
+ }
199
211
  }
200
212
 
201
213
  function ensureNodes() {
@@ -204,12 +216,7 @@ export default {
204
216
  const { wrapper, bubble, arrow } = createNodes()
205
217
  document.body.appendChild(wrapper)
206
218
 
207
- if (content.mode === 'text') bubble.textContent = content.text
208
- if (content.mode === 'html') bubble.innerHTML = content.html
209
- if (content.mode === 'component') {
210
- state.app = createApp({ render: () => h(content.component, content.props || {}) })
211
- state.app.mount(bubble)
212
- }
219
+ renderContent(bubble)
213
220
 
214
221
  state.nodes = { wrapper, bubble, arrow }
215
222
  return state.nodes
@@ -297,17 +304,17 @@ export default {
297
304
  t.state.placement = nextPlacement
298
305
  }
299
306
 
300
- const content = normalizeValue(binding)
307
+ t.state.content = normalizeValue(binding)
301
308
  if (!t.state.nodes) return
302
309
 
303
310
  const { bubble } = t.state.nodes
311
+ const content = t.state.content
304
312
  if (content.mode === 'text') bubble.textContent = content.text || ''
305
313
  else if (content.mode === 'html') bubble.innerHTML = content.html || ''
306
314
  else if (content.mode === 'component') {
307
315
  t.state.app?.unmount?.()
308
- const app = createApp({ render: () => h(content.component, content.props || {}) })
309
- app.mount(bubble)
310
- t.state.app = app
316
+ t.state.app = createApp({ render: () => h(content.component, content.props || {}) })
317
+ t.state.app.mount(bubble)
311
318
  }
312
319
  },
313
320
 
@@ -137,10 +137,16 @@ export default {
137
137
  methods: {
138
138
  syncActiveFromMenu() {
139
139
  const routePath = this.$route?.path
140
+ const routeFullPath = this.$route?.fullPath
140
141
  const findMatch = (items, parentIds = []) => {
141
142
  for (const item of items) {
142
143
  const itemPath = item?.link?.to ?? item?.to ?? null
143
- if (routePath && itemPath === routePath) {
144
+ const normalizedItemPath = typeof itemPath === 'string' ? itemPath.split('?')[0] : null
145
+ const matchesPath =
146
+ (routeFullPath && itemPath === routeFullPath) ||
147
+ (routePath && normalizedItemPath === routePath)
148
+
149
+ if (matchesPath) {
144
150
  return {
145
151
  id: item.id,
146
152
  parentIds,
@@ -239,33 +245,38 @@ export default {
239
245
 
240
246
  <template>
241
247
  <aside
242
- class="fixed inset-y-0 left-0 z-40 flex h-full shrink-0 flex-col border-r border-sidebar-border bg-sidebar text-sidebar-foreground transition-[width,transform] duration-200 ease-out lg:static lg:translate-x-0"
248
+ class="group/sidebar fixed inset-y-0 left-0 z-40 flex h-full shrink-0 flex-col border-r border-sidebar-border bg-sidebar text-sidebar-foreground transition-[width,transform] duration-200 ease-out lg:static lg:translate-x-0"
243
249
  :style="sidebarWidthStyle"
244
250
  :class="[
245
251
  mobileOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0',
246
252
  ]"
247
253
  >
248
- <div class="flex items-center px-4 py-4" :class="collapsed ? 'justify-center' : 'gap-2.5'">
254
+ <button
255
+ type="button"
256
+ v-tooltip.right="collapsed ? 'Ανάπτυξη πλαϊνού μενού' : 'Σύμπτυξη πλαϊνού μενού'"
257
+ class="absolute right-0 top-1/2 z-50 hidden h-14 w-6 -translate-y-1/2 translate-x-1/2 items-center justify-center rounded-r-md border border-sidebar-border bg-sidebar-accent text-sidebar-muted opacity-70 shadow-lg shadow-black/30 transition-[color,opacity] hover:opacity-100 hover:text-sidebar-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand lg:inline-flex"
258
+ :aria-label="collapsed ? 'Ανάπτυξη πλαϊνού μενού' : 'Σύμπτυξη πλαϊνού μενού'"
259
+ @click="toggleCollapsed"
260
+ >
261
+ <PanelLeftOpen v-if="collapsed" class="size-4" :stroke-width="2" />
262
+ <PanelLeftClose v-else class="size-4" :stroke-width="2" />
263
+ </button>
264
+
265
+ <div class="relative flex items-center px-4 py-4" :class="collapsed ? 'justify-center' : 'gap-2.5'">
249
266
  <img
250
- :src="
251
- collapsed
252
- ? 'https://s3.ketekny.gr/public/web-apps/logos/logo-icon-dark.png'
253
- : 'https://support.ketekny.gr/logo-dark.png'
254
- "
267
+ v-if="collapsed"
268
+ src="https://s3.ketekny.gr/public/web-apps/logos/logo-icon-dark.png"
255
269
  alt="Ketekny logo"
256
- class="object-contain"
257
- :class="collapsed ? 'size-9 shrink-0 rounded-lg' : 'h-10 min-w-0 flex-1'"
270
+ class="size-9 shrink-0 rounded-lg object-contain cursor-pointer"
271
+ @click="handleLogoClick"
272
+ />
273
+ <img
274
+ v-else
275
+ src="https://support.ketekny.gr/logo-dark.png"
276
+ alt="Ketekny logo"
277
+ class="min-w-0 flex-1 object-contain cursor-pointer"
258
278
  @click="handleLogoClick"
259
279
  />
260
- <button
261
- v-if="!collapsed"
262
- type="button"
263
- class="ml-auto hidden rounded-md p-1.5 text-sidebar-muted hover:bg-sidebar-accent hover:text-sidebar-foreground lg:inline-flex"
264
- aria-label="Collapse sidebar"
265
- @click="toggleCollapsed"
266
- >
267
- <PanelLeftClose class="size-4" :stroke-width="2" />
268
- </button>
269
280
  </div>
270
281
 
271
282
  <div v-if="title && !collapsed" class="px-4 pb-2">
@@ -291,18 +302,6 @@ export default {
291
302
  </div>
292
303
  </div>
293
304
 
294
- <div v-if="collapsed" class="justify-center hidden px-3 pb-1 lg:flex">
295
- <button
296
- type="button"
297
- v-tooltip.right="'Ανάπτυξη πλαϊνού μενού'"
298
- class="flex h-10 w-10 items-center justify-center rounded-md text-sidebar-muted hover:bg-sidebar-accent hover:text-sidebar-foreground"
299
- aria-label="Ανάπτυξη πλαϊνού μενού"
300
- @click="toggleCollapsed"
301
- >
302
- <PanelLeftOpen class="size-4" :stroke-width="2" />
303
- </button>
304
- </div>
305
-
306
305
  <div v-if="!collapsed" class="px-3 pb-2">
307
306
  <div class="relative">
308
307
  <Search
@@ -376,67 +375,69 @@ export default {
376
375
  <Bell class="size-4" :stroke-width="2" />
377
376
  </button>
378
377
  </div>
379
- <button
380
- v-for="link in footerLinks"
381
- :key="link.id"
382
- v-if="collapsed"
383
- type="button"
384
- v-tooltip.right="link.label"
385
- class="flex items-center w-full rounded-md transition-colors duration-150"
386
- :class="[
387
- 'justify-center px-0 py-2',
388
- activeId === link.id
389
- ? 'bg-brand text-brand-foreground font-medium'
390
- : link.id === 'sign-out'
391
- ? 'text-orange-300 hover:bg-orange-500/10 hover:text-orange-200'
392
- : 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-foreground',
393
- ]"
394
- :aria-label="collapsed ? link.label : undefined"
395
- @click="handleFooterSelect(link.id)"
396
- >
397
- <component
398
- :is="link.icon"
399
- class="size-4 shrink-0"
400
- :class="
378
+ <template v-if="collapsed">
379
+ <button
380
+ v-for="link in footerLinks"
381
+ :key="link.id"
382
+ type="button"
383
+ v-tooltip.right="link.label"
384
+ class="flex items-center w-full rounded-md transition-colors duration-150"
385
+ :class="[
386
+ 'justify-center px-0 py-2',
401
387
  activeId === link.id
402
- ? 'text-brand-foreground'
388
+ ? 'bg-brand text-brand-foreground font-medium'
403
389
  : link.id === 'sign-out'
404
- ? 'text-orange-400'
405
- : 'text-sidebar-muted'
406
- "
407
- :stroke-width="2"
408
- />
409
- </button>
410
- <button
411
- v-for="link in expandedFooterLinks"
412
- :key="`${link.id}-expanded`"
413
- v-else
414
- type="button"
415
- class="flex items-center w-full rounded-md transition-colors duration-150"
416
- :class="[
417
- 'gap-2.5 px-2 py-2 text-left',
418
- activeId === link.id
419
- ? 'bg-brand text-brand-foreground font-medium'
420
- : link.id === 'sign-out'
421
- ? 'text-orange-300 hover:bg-orange-500/10 hover:text-orange-200'
422
- : 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-foreground',
423
- ]"
424
- @click="handleFooterSelect(link.id)"
425
- >
426
- <component
427
- :is="link.icon"
428
- class="size-4 shrink-0"
429
- :class="
390
+ ? 'text-orange-300 hover:bg-orange-500/10 hover:text-orange-200'
391
+ : 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-foreground',
392
+ ]"
393
+ :aria-label="link.label"
394
+ @click="handleFooterSelect(link.id)"
395
+ >
396
+ <component
397
+ :is="link.icon"
398
+ class="size-4 shrink-0"
399
+ :class="
400
+ activeId === link.id
401
+ ? 'text-brand-foreground'
402
+ : link.id === 'sign-out'
403
+ ? 'text-orange-400'
404
+ : 'text-sidebar-muted'
405
+ "
406
+ :stroke-width="2"
407
+ />
408
+ </button>
409
+ </template>
410
+ <template v-else>
411
+ <button
412
+ v-for="link in expandedFooterLinks"
413
+ :key="`${link.id}-expanded`"
414
+ type="button"
415
+ class="flex items-center w-full rounded-md transition-colors duration-150"
416
+ :class="[
417
+ 'gap-2.5 px-2 py-2 text-left',
430
418
  activeId === link.id
431
- ? 'text-brand-foreground'
419
+ ? 'bg-brand text-brand-foreground font-medium'
432
420
  : link.id === 'sign-out'
433
- ? 'text-orange-400'
434
- : 'text-sidebar-muted'
435
- "
436
- :stroke-width="2"
437
- />
438
- <span class="truncate">{{ link.label }}</span>
439
- </button>
421
+ ? 'text-orange-300 hover:bg-orange-500/10 hover:text-orange-200'
422
+ : 'text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-foreground',
423
+ ]"
424
+ @click="handleFooterSelect(link.id)"
425
+ >
426
+ <component
427
+ :is="link.icon"
428
+ class="size-4 shrink-0"
429
+ :class="
430
+ activeId === link.id
431
+ ? 'text-brand-foreground'
432
+ : link.id === 'sign-out'
433
+ ? 'text-orange-400'
434
+ : 'text-sidebar-muted'
435
+ "
436
+ :stroke-width="2"
437
+ />
438
+ <span class="truncate">{{ link.label }}</span>
439
+ </button>
440
+ </template>
440
441
  </div>
441
442
 
442
443
  <div
@@ -164,6 +164,7 @@ export default {
164
164
  :level="level + 1"
165
165
  :active-id="activeId"
166
166
  :open-ids="openIds"
167
+ :collapsed="collapsed"
167
168
  @select="$emit('select', $event)"
168
169
  @toggle="$emit('toggle', $event)"
169
170
  />
@@ -207,6 +208,7 @@ export default {
207
208
  :level="0"
208
209
  :active-id="activeId"
209
210
  :open-ids="openIds"
211
+ :collapsed="false"
210
212
  @select="$emit('select', $event)"
211
213
  @toggle="$emit('toggle', $event)"
212
214
  />