@meistrari/chat-nuxt 3.2.0 → 3.3.0

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
@@ -196,7 +196,7 @@ import type {
196
196
  | Prop | Type | Default | Description |
197
197
  |------|------|---------|-------------|
198
198
  | `hideSidebar` | `boolean` | `false` | Hide conversation list sidebar |
199
- | `sidebar` | `ChatSidebarConfig` | `undefined` | Sidebar layout: `{ position?: 'left' \| 'right', width?: number, bottomHeight?: number }`. `position` picks the edge (default `'left'`); `width` is the sidebar width in pixels (default `240`); `bottomHeight` is the `sidebar-bottom` pane height as a percentage 0–100 of the conversation area (default `50`) |
199
+ | `sidebar` | `ChatSidebarConfig` | `undefined` | Sidebar layout: `{ position?, width?, bottomHeight?, collapsible?, defaultCollapsed? }`. `position` (`'left'`\|`'right'`, default `'left'`) picks the edge; `width` is the sidebar width in pixels (default `240`); `bottomHeight` is the `sidebar-bottom` pane height as a percentage 0–100 of the conversation area (default `50`); `collapsible` (default `false`) renders a native collapse handle and animates the sidebar open/closed; `defaultCollapsed` (default `false`) starts it collapsed |
200
200
  | `hideSettings` | `boolean` | `false` | Hide workspace settings actions while keeping the chat header and content unchanged |
201
201
  | `conversationId` | `string \| null` | `null` | Controlled conversation (supports v-model) |
202
202
  | `initialConversationId` | `string \| null` | `null` | Open this conversation on mount |
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
3
  "configKey": "chatNuxt",
4
- "version": "3.2.0",
4
+ "version": "3.3.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -36,6 +36,16 @@ const emit = defineEmits(["update:conversationId"]);
36
36
  const sidebarPosition = computed(() => props.sidebar?.position ?? "left");
37
37
  const sidebarWidth = computed(() => props.sidebar?.width ?? 240);
38
38
  const sidebarBottomHeight = computed(() => Math.min(100, Math.max(0, props.sidebar?.bottomHeight ?? 50)));
39
+ const sidebarCollapsible = computed(() => props.sidebar?.collapsible ?? false);
40
+ const isSidebarCollapsed = ref(props.sidebar?.defaultCollapsed ?? false);
41
+ const sidebarCollapsed = computed(() => sidebarCollapsible.value && isSidebarCollapsed.value);
42
+ const sidebarToggleIcon = computed(() => {
43
+ const pointsRight = sidebarPosition.value === "right" ? !sidebarCollapsed.value : sidebarCollapsed.value;
44
+ return pointsRight ? "i-ph-caret-right" : "i-ph-caret-left";
45
+ });
46
+ function toggleSidebarCollapsed() {
47
+ isSidebarCollapsed.value = !isSidebarCollapsed.value;
48
+ }
39
49
  const chatApi = useChatApi();
40
50
  const embedConfig = useEmbedConfig();
41
51
  const chatAction = useChatAction();
@@ -429,51 +439,77 @@ async function handleDelete() {
429
439
  <!-- Sidebar -->
430
440
  <div
431
441
  v-if="!hideSidebar && !isMobile"
432
- h-full flex="~ col" flex-shrink-0
433
- bg-neutral-50
434
- :style="{ width: `${sidebarWidth}px` }"
435
- :class="sidebarPosition === 'right' ? 'order-last border-l-0.5px border-l-neutral-200' : 'border-r-0.5px border-r-neutral-200'"
442
+ class="chat-sidebar"
443
+ :class="[
444
+ sidebarPosition === 'right' ? 'chat-sidebar--right order-last' : 'chat-sidebar--left',
445
+ sidebarCollapsible ? 'chat-sidebar--collapsible' : '',
446
+ sidebarCollapsed ? 'chat-sidebar--collapsed' : ''
447
+ ]"
448
+ :style="{ '--chat-sidebar-width': `${sidebarWidth}px` }"
449
+ h-full flex-shrink-0 relative
436
450
  >
437
- <div px-12px pt-16px pb-8px flex gap-8px>
438
- <button
439
- flex items-center justify-center gap-6px
440
- h-32px px-12px flex-1 min-w-0
441
- bg-white b=".5px neutral-300" rounded-10px
442
- hover:bg-neutral-50 transition-colors cursor-pointer
443
- @click="() => handleNewConversation()"
451
+ <div class="chat-sidebar__clip">
452
+ <div
453
+ class="chat-sidebar__panel"
454
+ :inert="sidebarCollapsed || void 0"
455
+ h-full flex="~ col"
456
+ bg-neutral-50
457
+ :style="{ width: `${sidebarWidth}px` }"
458
+ :class="sidebarPosition === 'right' ? 'border-l-0.5px border-l-neutral-200' : 'border-r-0.5px border-r-neutral-200'"
444
459
  >
445
- <span i-ph-chat-circle text-12px text-gray-900 />
446
- <span text-14px font-semibold text-neutral-900 tracking="-.15px" leading-18px>
447
- Nova conversa
448
- </span>
449
- </button>
450
- <ChatConversationNewGroupButton />
451
- </div>
460
+ <div px-12px pt-16px pb-8px flex gap-8px>
461
+ <button
462
+ flex items-center justify-center gap-6px
463
+ h-32px px-12px flex-1 min-w-0
464
+ bg-white b=".5px neutral-300" rounded-10px
465
+ hover:bg-neutral-50 transition-colors cursor-pointer
466
+ @click="() => handleNewConversation()"
467
+ >
468
+ <span i-ph-chat-circle text-12px text-gray-900 />
469
+ <span text-14px font-semibold text-neutral-900 tracking="-.15px" leading-18px>
470
+ Nova conversa
471
+ </span>
472
+ </button>
473
+ <ChatConversationNewGroupButton />
474
+ </div>
452
475
 
453
- <div
454
- min-h-0 overflow-y-auto px-4px
455
- :class="$slots['sidebar-bottom'] ? '' : 'flex-1'"
456
- :style="$slots['sidebar-bottom'] ? { flexGrow: 100 - sidebarBottomHeight, flexBasis: 0 } : void 0"
457
- >
458
- <ChatConversationList
459
- :conversations="visibleConversations"
460
- :current-id="activeConversationId ?? void 0"
461
- :get-member-image="getMemberImage"
462
- :select-conversation="openConversation"
463
- :reset-conversation="handleNewConversation"
464
- :start-conversation="handleNewConversation"
465
- :loading="conversationsLoading"
466
- />
476
+ <div
477
+ min-h-0 overflow-y-auto px-4px
478
+ :class="$slots['sidebar-bottom'] ? '' : 'flex-1'"
479
+ :style="$slots['sidebar-bottom'] ? { flexGrow: 100 - sidebarBottomHeight, flexBasis: 0 } : void 0"
480
+ >
481
+ <ChatConversationList
482
+ :conversations="visibleConversations"
483
+ :current-id="activeConversationId ?? void 0"
484
+ :get-member-image="getMemberImage"
485
+ :select-conversation="openConversation"
486
+ :reset-conversation="handleNewConversation"
487
+ :start-conversation="handleNewConversation"
488
+ :loading="conversationsLoading"
489
+ />
490
+ </div>
491
+
492
+ <div
493
+ v-if="$slots['sidebar-bottom']"
494
+ min-h-0 overflow-y-auto
495
+ b-t=".5px neutral-200"
496
+ :style="{ flexGrow: sidebarBottomHeight, flexBasis: 0 }"
497
+ >
498
+ <slot name="sidebar-bottom" />
499
+ </div>
500
+ </div>
467
501
  </div>
468
502
 
469
- <div
470
- v-if="$slots['sidebar-bottom']"
471
- min-h-0 overflow-y-auto
472
- b-t=".5px neutral-200"
473
- :style="{ flexGrow: sidebarBottomHeight, flexBasis: 0 }"
503
+ <button
504
+ v-if="sidebarCollapsible"
505
+ type="button"
506
+ class="chat-sidebar__toggle"
507
+ :aria-label="sidebarCollapsed ? 'Expandir conversas' : 'Recolher conversas'"
508
+ :aria-expanded="!sidebarCollapsed"
509
+ @click="toggleSidebarCollapsed"
474
510
  >
475
- <slot name="sidebar-bottom" />
476
- </div>
511
+ <span :class="sidebarToggleIcon" text-14px text-neutral-500 />
512
+ </button>
477
513
  </div>
478
514
 
479
515
  <!-- Main content -->
@@ -851,5 +887,5 @@ async function handleDelete() {
851
887
  </template>
852
888
 
853
889
  <style scoped>
854
- .loading-bar{animation:loading-pulse 1.5s ease-in-out infinite;background:linear-gradient(90deg,transparent,#ea580b,#fb923c,#fdba74,transparent);background-size:200% 100%;height:4px;left:0;position:absolute;right:0;top:0;z-index:100}@keyframes loading-pulse{0%{background-position:200% 0}to{background-position:-200% 0}}.fade-enter-active,.fade-leave-active{transition:opacity .2s ease}.fade-enter-from,.fade-leave-to{opacity:0}
890
+ .loading-bar{animation:loading-pulse 1.5s ease-in-out infinite;background:linear-gradient(90deg,transparent,#ea580b,#fb923c,#fdba74,transparent);background-size:200% 100%;height:4px;left:0;position:absolute;right:0;top:0;z-index:100}@keyframes loading-pulse{0%{background-position:200% 0}to{background-position:-200% 0}}.fade-enter-active,.fade-leave-active{transition:opacity .2s ease}.fade-enter-from,.fade-leave-to{opacity:0}.chat-sidebar{width:var(--chat-sidebar-width)}.chat-sidebar__clip{display:flex;height:100%;width:100%}.chat-sidebar__panel{flex:none}.chat-sidebar--collapsible{min-width:0;transition:width .26s cubic-bezier(.2,.8,.2,1)}.chat-sidebar--collapsible .chat-sidebar__clip{overflow:hidden}.chat-sidebar--collapsible.chat-sidebar--right .chat-sidebar__clip{justify-content:flex-end}.chat-sidebar--collapsible .chat-sidebar__panel{transition:opacity .2s ease}.chat-sidebar--collapsed{width:0}.chat-sidebar--collapsed .chat-sidebar__panel{opacity:0}.chat-sidebar__toggle{align-items:center;background:#fff;border:.5px solid #e5e5e5;border-radius:8px;box-shadow:0 1px 2px rgba(16,24,40,.06);cursor:pointer;display:flex;height:44px;justify-content:center;padding:0;position:absolute;top:50%;transition:transform .26s cubic-bezier(.2,.8,.2,1),background-color .12s ease;width:20px;z-index:20}.chat-sidebar__toggle:hover{background:#fafafa}.chat-sidebar--right .chat-sidebar__toggle{left:0;transform:translate(-50%,-50%)}.chat-sidebar--right.chat-sidebar--collapsed .chat-sidebar__toggle{transform:translate(-100%,-50%)}.chat-sidebar--left .chat-sidebar__toggle{right:0;transform:translate(50%,-50%)}.chat-sidebar--left.chat-sidebar--collapsed .chat-sidebar__toggle{transform:translate(100%,-50%)}@media (prefers-reduced-motion:reduce){.chat-sidebar__clip,.chat-sidebar__panel,.chat-sidebar__toggle{transition:none}}
855
891
  </style>
@@ -21,6 +21,13 @@ export type ChatSidebarConfig = {
21
21
  * Defaults to 50.
22
22
  */
23
23
  bottomHeight?: number;
24
+ /**
25
+ * Render a native collapse handle and animate the sidebar open/closed, so
26
+ * the host doesn't have to build its own toggle. Defaults to false.
27
+ */
28
+ collapsible?: boolean;
29
+ /** Start collapsed on first render when `collapsible` is set. Defaults to false. */
30
+ defaultCollapsed?: boolean;
24
31
  };
25
32
  export type ChatEmbedSharedProps = {
26
33
  /** Controlled conversation id. Use with `v-model:conversation-id` when the host owns active conversation state. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {