@flamingo-stack/openframe-frontend-core 0.0.219 → 0.0.220-snapshot.20260602171504

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.
Files changed (146) hide show
  1. package/dist/{chunk-EDW2NVRV.js → chunk-4WZOFD46.js} +37 -37
  2. package/dist/{chunk-EDW2NVRV.js.map → chunk-4WZOFD46.js.map} +1 -1
  3. package/dist/{chunk-ZGBXHK26.cjs → chunk-5GN7TXHY.cjs} +12 -12
  4. package/dist/{chunk-ZGBXHK26.cjs.map → chunk-5GN7TXHY.cjs.map} +1 -1
  5. package/dist/{chunk-F3FO2ZZZ.cjs → chunk-BAKZF4GU.cjs} +7 -7
  6. package/dist/{chunk-F3FO2ZZZ.cjs.map → chunk-BAKZF4GU.cjs.map} +1 -1
  7. package/dist/{chunk-MPHDM2VZ.cjs → chunk-BCL24DFU.cjs} +30 -30
  8. package/dist/{chunk-MPHDM2VZ.cjs.map → chunk-BCL24DFU.cjs.map} +1 -1
  9. package/dist/{chunk-65CPJ4SX.cjs → chunk-C6ASEPZL.cjs} +30 -30
  10. package/dist/{chunk-65CPJ4SX.cjs.map → chunk-C6ASEPZL.cjs.map} +1 -1
  11. package/dist/{chunk-SZXKKEUH.cjs → chunk-E6B4B7GM.cjs} +46 -30
  12. package/dist/chunk-E6B4B7GM.cjs.map +1 -0
  13. package/dist/{chunk-SRA2QYK6.js → chunk-HUA4XG4S.js} +4 -4
  14. package/dist/{chunk-A3PL6ZCF.js → chunk-KXF3WCPH.js} +6397 -5128
  15. package/dist/chunk-KXF3WCPH.js.map +1 -0
  16. package/dist/{chunk-SL3RGBPX.cjs → chunk-QNYH3WUU.cjs} +9 -9
  17. package/dist/{chunk-SL3RGBPX.cjs.map → chunk-QNYH3WUU.cjs.map} +1 -1
  18. package/dist/{chunk-24Q2WLIU.js → chunk-QYRV6MKX.js} +2 -2
  19. package/dist/{chunk-XG7DFRJL.js → chunk-RCECOGMI.js} +3 -3
  20. package/dist/{chunk-7UZLRI7W.cjs → chunk-SEECETJY.cjs} +3301 -2032
  21. package/dist/chunk-SEECETJY.cjs.map +1 -0
  22. package/dist/{chunk-ZII7TNVA.js → chunk-T5MEXJD5.js} +3 -3
  23. package/dist/{chunk-YX3YQNC4.cjs → chunk-W23DRJAA.cjs} +13 -13
  24. package/dist/{chunk-YX3YQNC4.cjs.map → chunk-W23DRJAA.cjs.map} +1 -1
  25. package/dist/{chunk-DRPECAXO.js → chunk-WR32ZE63.js} +2 -2
  26. package/dist/{chunk-Y3MXGCOW.js → chunk-YZDUOUMB.js} +46 -30
  27. package/dist/chunk-YZDUOUMB.js.map +1 -0
  28. package/dist/components/chat/chat-archive-page.d.ts +25 -0
  29. package/dist/components/chat/chat-archive-page.d.ts.map +1 -0
  30. package/dist/components/chat/chat-composer.d.ts +29 -0
  31. package/dist/components/chat/chat-composer.d.ts.map +1 -0
  32. package/dist/components/chat/chat-header-icon-button.d.ts +14 -0
  33. package/dist/components/chat/chat-header-icon-button.d.ts.map +1 -0
  34. package/dist/components/chat/chat-panel-header.d.ts +32 -0
  35. package/dist/components/chat/chat-panel-header.d.ts.map +1 -0
  36. package/dist/components/chat/embeddable-chat.d.ts +18 -0
  37. package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
  38. package/dist/components/chat/guide-mode-banner.d.ts +16 -0
  39. package/dist/components/chat/guide-mode-banner.d.ts.map +1 -0
  40. package/dist/components/chat/guide-welcome.d.ts +40 -0
  41. package/dist/components/chat/guide-welcome.d.ts.map +1 -0
  42. package/dist/components/chat/hooks/use-chat-dialog-manager.d.ts +58 -0
  43. package/dist/components/chat/hooks/use-chat-dialog-manager.d.ts.map +1 -0
  44. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +26 -1
  45. package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
  46. package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
  47. package/dist/components/chat/hooks/use-unified-chat.d.ts.map +1 -1
  48. package/dist/components/chat/index.cjs +29 -5
  49. package/dist/components/chat/index.cjs.map +1 -1
  50. package/dist/components/chat/index.d.ts +9 -0
  51. package/dist/components/chat/index.d.ts.map +1 -1
  52. package/dist/components/chat/index.js +28 -4
  53. package/dist/components/chat/mingo-chat-history.d.ts +37 -0
  54. package/dist/components/chat/mingo-chat-history.d.ts.map +1 -0
  55. package/dist/components/chat/mingo-chat-modals.d.ts +50 -0
  56. package/dist/components/chat/mingo-chat-modals.d.ts.map +1 -0
  57. package/dist/components/chat/mingo-onboarding-card.d.ts.map +1 -1
  58. package/dist/components/chat/mingo-welcome.d.ts +78 -0
  59. package/dist/components/chat/mingo-welcome.d.ts.map +1 -0
  60. package/dist/components/chat/types/unified-chat-state.types.d.ts +6 -0
  61. package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
  62. package/dist/components/contact/index.cjs +6 -6
  63. package/dist/components/contact/index.js +5 -5
  64. package/dist/components/features/index.cjs +5 -5
  65. package/dist/components/features/index.js +4 -4
  66. package/dist/components/icons-v2-generated/brand-logos/fleet-mdm-logo-grey-icon.d.ts.map +1 -1
  67. package/dist/components/icons-v2-generated/brand-logos/fleet-mdm-logo-icon.d.ts.map +1 -1
  68. package/dist/components/icons-v2-generated/index.cjs +2 -2
  69. package/dist/components/icons-v2-generated/index.js +1 -1
  70. package/dist/components/index.cjs +128 -104
  71. package/dist/components/index.cjs.map +1 -1
  72. package/dist/components/index.js +31 -7
  73. package/dist/components/index.js.map +1 -1
  74. package/dist/components/layout/page-heading.d.ts +7 -6
  75. package/dist/components/layout/page-heading.d.ts.map +1 -1
  76. package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -1
  77. package/dist/components/navigation/header-mingo-button.d.ts +4 -2
  78. package/dist/components/navigation/header-mingo-button.d.ts.map +1 -1
  79. package/dist/components/navigation/index.cjs +5 -5
  80. package/dist/components/navigation/index.js +4 -4
  81. package/dist/components/onboarding-guides/index.cjs +28 -28
  82. package/dist/components/onboarding-guides/index.js +6 -6
  83. package/dist/components/tickets/index.cjs +88 -88
  84. package/dist/components/tickets/index.js +7 -7
  85. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  86. package/dist/components/ui/file-manager/index.cjs +50 -50
  87. package/dist/components/ui/file-manager/index.js +1 -1
  88. package/dist/components/ui/index.cjs +29 -5
  89. package/dist/components/ui/index.cjs.map +1 -1
  90. package/dist/components/ui/index.js +28 -4
  91. package/dist/components/ui/modal-v2.d.ts.map +1 -1
  92. package/dist/components/ui/more-actions-menu.d.ts +8 -1
  93. package/dist/components/ui/more-actions-menu.d.ts.map +1 -1
  94. package/dist/components/ui/portal-container.d.ts +21 -0
  95. package/dist/components/ui/portal-container.d.ts.map +1 -0
  96. package/dist/components/ui/tooltip.d.ts.map +1 -1
  97. package/dist/hooks/index.cjs +3 -3
  98. package/dist/hooks/index.js +2 -2
  99. package/dist/index.cjs +29 -5
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.js +28 -4
  102. package/package.json +1 -1
  103. package/src/components/chat/chat-archive-page.tsx +93 -0
  104. package/src/components/chat/chat-composer.tsx +99 -0
  105. package/src/components/chat/chat-header-icon-button.tsx +36 -0
  106. package/src/components/chat/chat-panel-header.tsx +114 -0
  107. package/src/components/chat/embeddable-chat.tsx +386 -311
  108. package/src/components/chat/guide-mode-banner.tsx +75 -0
  109. package/src/components/chat/guide-welcome.tsx +207 -0
  110. package/src/components/chat/hooks/use-chat-dialog-manager.ts +227 -0
  111. package/src/components/chat/hooks/use-nats-chat-adapter.ts +85 -0
  112. package/src/components/chat/hooks/use-sse-chat-adapter.ts +8 -0
  113. package/src/components/chat/hooks/use-unified-chat.ts +12 -0
  114. package/src/components/chat/index.ts +9 -0
  115. package/src/components/chat/mingo-chat-history.tsx +308 -0
  116. package/src/components/chat/mingo-chat-modals.tsx +223 -0
  117. package/src/components/chat/mingo-onboarding-card.tsx +5 -8
  118. package/src/components/chat/mingo-welcome.tsx +396 -0
  119. package/src/components/chat/types/unified-chat-state.types.ts +8 -0
  120. package/src/components/icons-v2/brand-logos/fleet-mdm-logo-grey.svg +6 -6
  121. package/src/components/icons-v2/brand-logos/fleet-mdm-logo.svg +6 -6
  122. package/src/components/icons-v2-generated/brand-logos/fleet-mdm-logo-grey-icon.tsx +2 -22
  123. package/src/components/icons-v2-generated/brand-logos/fleet-mdm-logo-icon.tsx +22 -2
  124. package/src/components/layout/page-heading.tsx +13 -7
  125. package/src/components/navigation/app-header.tsx +12 -12
  126. package/src/components/navigation/app-layout-drawer.tsx +25 -15
  127. package/src/components/navigation/header-mingo-button.tsx +22 -7
  128. package/src/components/ui/dropdown-menu.tsx +9 -3
  129. package/src/components/ui/modal-v2.tsx +33 -3
  130. package/src/components/ui/more-actions-menu.tsx +15 -2
  131. package/src/components/ui/portal-container.tsx +28 -0
  132. package/src/components/ui/tooltip.tsx +9 -3
  133. package/src/stories/AppLayoutSidebar.stories.tsx +184 -0
  134. package/src/stories/EmbeddableChat.stories.tsx +114 -0
  135. package/src/stories/GuideWelcome.stories.tsx +102 -0
  136. package/src/stories/MingoChatModals.stories.tsx +82 -0
  137. package/src/stories/MingoWelcome.stories.tsx +119 -0
  138. package/dist/chunk-7UZLRI7W.cjs.map +0 -1
  139. package/dist/chunk-A3PL6ZCF.js.map +0 -1
  140. package/dist/chunk-SZXKKEUH.cjs.map +0 -1
  141. package/dist/chunk-Y3MXGCOW.js.map +0 -1
  142. /package/dist/{chunk-SRA2QYK6.js.map → chunk-HUA4XG4S.js.map} +0 -0
  143. /package/dist/{chunk-24Q2WLIU.js.map → chunk-QYRV6MKX.js.map} +0 -0
  144. /package/dist/{chunk-XG7DFRJL.js.map → chunk-RCECOGMI.js.map} +0 -0
  145. /package/dist/{chunk-ZII7TNVA.js.map → chunk-T5MEXJD5.js.map} +0 -0
  146. /package/dist/{chunk-DRPECAXO.js.map → chunk-WR32ZE63.js.map} +0 -0
@@ -0,0 +1,93 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Chevron02LeftIcon } from '../icons-v2-generated'
5
+ import { XmarkIcon } from '../icons-v2-generated/signs-and-symbols/xmark-icon'
6
+ import { ChatHeaderIconButton } from './chat-header-icon-button'
7
+ import { MingoChatHistory } from './mingo-chat-history'
8
+ import type { DialogItem } from './types/component.types'
9
+
10
+ export interface ChatArchivePageProps {
11
+ /** Archived dialogs, grouped (Today / Yesterday / Older) by the list. */
12
+ dialogs: ReadonlyArray<DialogItem>
13
+ /** Open an archived dialog. */
14
+ onSelectDialog: (id: string) => void
15
+ /** Back chevron — returns to the previous (list) view. */
16
+ onBack: () => void
17
+ /** Close the whole chat panel. */
18
+ onClose: () => void
19
+ /** True while a page is loading (drives the empty/loading copy + spinner). */
20
+ isLoading?: boolean
21
+ /** Whether another page of archived dialogs remains. */
22
+ hasMore?: boolean
23
+ /** Fetch the next page. */
24
+ onLoadMore?: () => void
25
+ }
26
+
27
+ /**
28
+ * Chat Archive page — Figma node `7361:427312`. Back + title + close header
29
+ * over the date-grouped archived-dialog list (reuses `MingoChatHistory`
30
+ * without the row action menus).
31
+ */
32
+ export function ChatArchivePage({
33
+ dialogs,
34
+ onSelectDialog,
35
+ onBack,
36
+ onClose,
37
+ isLoading = false,
38
+ hasMore = false,
39
+ onLoadMore,
40
+ }: ChatArchivePageProps) {
41
+ return (
42
+ <>
43
+ <div className="flex-shrink-0 flex h-14 w-full overflow-hidden border-b border-ods-border bg-ods-card">
44
+ <div className="flex flex-1 min-w-0 items-center gap-2 px-4 py-3">
45
+ <button
46
+ type="button"
47
+ onClick={onBack}
48
+ aria-label="Back"
49
+ className="inline-flex shrink-0 items-center justify-center size-8 -ml-1 rounded-md text-ods-text-secondary transition-colors hover:bg-ods-bg-hover hover:text-ods-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent"
50
+ >
51
+ <Chevron02LeftIcon size={20} />
52
+ </button>
53
+ <span className="truncate text-h3 text-ods-text-primary">
54
+ Chat Archive
55
+ </span>
56
+ </div>
57
+ <ChatHeaderIconButton onClick={onClose} aria-label="Close">
58
+ <XmarkIcon size={24} />
59
+ </ChatHeaderIconButton>
60
+ </div>
61
+ <div className="flex flex-1 min-h-0 flex-col p-[var(--spacing-system-m)]">
62
+ {dialogs.length > 0 ? (
63
+ <MingoChatHistory
64
+ dialogs={dialogs}
65
+ onSelectDialog={onSelectDialog}
66
+ hasMore={hasMore}
67
+ isLoadingMore={isLoading && dialogs.length > 0}
68
+ onLoadMore={onLoadMore}
69
+ />
70
+ ) : isLoading ? (
71
+ // First-load skeleton — `h-12` rows matching the dialog-list layout
72
+ // so results land without a shift (auth → data → empty → content).
73
+ <div className="flex flex-col" aria-hidden>
74
+ {[...Array(6)].map((_, i) => (
75
+ <div
76
+ key={i}
77
+ className="flex h-12 items-center gap-[var(--spacing-system-xsf)] border-b border-ods-border px-[var(--spacing-system-s)] last:border-b-0"
78
+ >
79
+ <div className="h-4 w-full max-w-[60%] animate-pulse rounded bg-ods-bg-secondary" />
80
+ </div>
81
+ ))}
82
+ </div>
83
+ ) : (
84
+ <div className="flex flex-1 items-center justify-center text-center">
85
+ <p className="text-h4 text-ods-text-secondary">
86
+ No archived chats yet.
87
+ </p>
88
+ </div>
89
+ )}
90
+ </div>
91
+ </>
92
+ )
93
+ }
@@ -0,0 +1,99 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { ChatFooter } from './chat-container'
5
+ import { ChatInput } from './chat-input'
6
+ import { ChatAttachmentAddButton } from './chat-attachment-bar'
7
+ import { ModelDisplay } from './model-display'
8
+ import { BoxArchiveIcon } from '../icons-v2-generated'
9
+ import type { ChatInputRef, ModelDisplayProps } from './types/component.types'
10
+
11
+ export interface ChatComposerProps {
12
+ /** Read-only archived chat → render the unarchive placeholder instead of the
13
+ * input (Figma node 7361:426949). */
14
+ archived?: boolean
15
+ inputRef: React.Ref<ChatInputRef>
16
+ onSend: (text: string) => void
17
+ onStop: () => void
18
+ sending: boolean
19
+ placeholder: string
20
+ autoFocus?: boolean
21
+ slashCommands?: React.ComponentProps<typeof ChatInput>['slashCommands']
22
+ /** Show the (Guide-only) attachment add button to the left of the model row. */
23
+ showAttachmentButton?: boolean
24
+ attachmentsCount?: number
25
+ onAddFiles?: (files: FileList | File[]) => void
26
+ attachmentsDisabled?: boolean
27
+ /** Model + usage row props, forwarded to `<ModelDisplay>`. */
28
+ model: ModelDisplayProps
29
+ }
30
+
31
+ /**
32
+ * Chat panel footer (Figma node 7363:205952): the message composer (live
33
+ * `ChatInput` or the read-only archived placeholder) above the model/usage
34
+ * row. No own background — inherits the panel surface so it blends seamlessly.
35
+ */
36
+ export function ChatComposer({
37
+ archived = false,
38
+ inputRef,
39
+ onSend,
40
+ onStop,
41
+ sending,
42
+ placeholder,
43
+ autoFocus,
44
+ slashCommands,
45
+ showAttachmentButton = false,
46
+ attachmentsCount = 0,
47
+ onAddFiles,
48
+ attachmentsDisabled = false,
49
+ model,
50
+ }: ChatComposerProps) {
51
+ return (
52
+ <div
53
+ className="flex-shrink-0 px-[var(--spacing-system-m)] pb-[var(--spacing-system-m)] flex flex-col gap-[var(--spacing-system-xxs)]"
54
+ style={{ paddingBottom: 'max(1rem, env(safe-area-inset-bottom))' }}
55
+ >
56
+ <ChatFooter className="!p-0" fullWidth>
57
+ {archived ? (
58
+ <div className="flex w-full items-center justify-center gap-[var(--spacing-system-xs)] rounded-md border border-ods-border bg-ods-card p-[var(--spacing-system-sf)]">
59
+ <BoxArchiveIcon size={24} className="shrink-0 text-ods-text-secondary" />
60
+ <p className="truncate text-h4 text-ods-text-secondary">
61
+ Unarchive the chat to continue
62
+ </p>
63
+ </div>
64
+ ) : (
65
+ <ChatInput
66
+ ref={inputRef}
67
+ onSend={onSend}
68
+ onStop={onStop}
69
+ sending={sending}
70
+ placeholder={placeholder}
71
+ fullWidth
72
+ className="px-0"
73
+ reserveAvatarOffset={false}
74
+ autoFocus={autoFocus}
75
+ slashCommands={slashCommands}
76
+ />
77
+ )}
78
+ </ChatFooter>
79
+
80
+ <div className="flex items-center gap-2 w-full">
81
+ {showAttachmentButton && onAddFiles && (
82
+ // Attachments are Guide-only: the NATS agent backend doesn't accept
83
+ // them, so the add-button is hidden in Mingo mode. Skipping the
84
+ // render entirely (not just the icon) collapses the otherwise-
85
+ // invisible 28px placeholder slot the component leaves for layout.
86
+ <ChatAttachmentAddButton
87
+ attachmentsEnabled
88
+ attachmentsCount={attachmentsCount}
89
+ onAddFiles={onAddFiles}
90
+ disabled={attachmentsDisabled}
91
+ />
92
+ )}
93
+ <div className="flex-1 min-w-0">
94
+ <ModelDisplay {...model} />
95
+ </div>
96
+ </div>
97
+ </div>
98
+ )
99
+ }
@@ -0,0 +1,36 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { cn } from '../../utils/cn'
5
+
6
+ export interface ChatHeaderIconButtonProps
7
+ extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
8
+
9
+ /**
10
+ * Square 56×56 icon cell used in the chat panel's top-navigation
11
+ * (archive / restore / close, and the `⋯` menu trigger). A left border acts
12
+ * as the 1px divider between cells.
13
+ *
14
+ * On hover only the background changes (`ods-bg-hover`) — the icon keeps its
15
+ * `ods-text-secondary` colour. `forwardRef` + prop spread so it works as a
16
+ * Radix `asChild` trigger.
17
+ */
18
+ export const ChatHeaderIconButton = React.forwardRef<
19
+ HTMLButtonElement,
20
+ ChatHeaderIconButtonProps
21
+ >(({ className, children, type = 'button', ...props }, ref) => (
22
+ <button
23
+ ref={ref}
24
+ type={type}
25
+ className={cn(
26
+ 'flex size-14 shrink-0 items-center justify-center border-l border-ods-border',
27
+ 'text-ods-text-secondary transition-colors hover:bg-ods-bg-hover',
28
+ 'focus:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent',
29
+ className,
30
+ )}
31
+ {...props}
32
+ >
33
+ {children}
34
+ </button>
35
+ ))
36
+ ChatHeaderIconButton.displayName = 'ChatHeaderIconButton'
@@ -0,0 +1,114 @@
1
+ 'use client'
2
+
3
+ import * as React from 'react'
4
+ import { Chevron01LeftIcon } from '../icons-v2-generated/arrows/chevron-01-left-icon'
5
+ import {
6
+ Ellipsis01Icon,
7
+ ClockHistoryIcon,
8
+ Refresh01LeftIcon,
9
+ } from '../icons-v2-generated'
10
+ import { XmarkIcon } from '../icons-v2-generated/signs-and-symbols/xmark-icon'
11
+ import { ChatHeaderIconButton } from './chat-header-icon-button'
12
+ import { MoreActionsMenu } from '../ui/more-actions-menu'
13
+
14
+ export interface ChatPanelHeaderProps {
15
+ /** Show the back-chevron + bold (h3) title. When false, the static list
16
+ * title (h4) is shown with no back affordance. */
17
+ showBack?: boolean
18
+ /** Title text (next to the back chevron, or the static list title). */
19
+ title: string
20
+ /** Accessible label for the back chevron. */
21
+ backAriaLabel?: string
22
+ /** The open conversation is an archived chat (read-only). */
23
+ isArchivedView?: boolean
24
+ /** Back-chevron handler. */
25
+ onBack: () => void
26
+ /** Close the panel. */
27
+ onClose: () => void
28
+ /** Restore/unarchive — renders the refresh button (archived view only). */
29
+ onRestore?: () => void
30
+ /** Rename — adds the "Rename chat" item to the ⋯ menu. */
31
+ onRename?: () => void
32
+ /** Archive — adds the "Archive chat" item to the ⋯ menu. */
33
+ onArchive?: () => void
34
+ /** Open the Chat Archive page — renders the clock button (list view only). */
35
+ onOpenArchive?: () => void
36
+ }
37
+
38
+ /**
39
+ * Chat panel top-navigation (Figma node 7363:205930). One bar across the
40
+ * list / active-conversation / archived-conversation / guide views: a
41
+ * back-chevron + title (or the static list title), then state-dependent
42
+ * right-hand actions (restore, ⋯ rename/archive, archive entry) and close.
43
+ */
44
+ export function ChatPanelHeader({
45
+ showBack = false,
46
+ title,
47
+ backAriaLabel = 'Back',
48
+ isArchivedView = false,
49
+ onBack,
50
+ onClose,
51
+ onRestore,
52
+ onRename,
53
+ onArchive,
54
+ onOpenArchive,
55
+ }: ChatPanelHeaderProps) {
56
+ const menuItems = [
57
+ onRename && { label: 'Rename chat', onClick: onRename },
58
+ onArchive && { label: 'Archive chat', onClick: onArchive },
59
+ ].filter(Boolean) as { label: string; onClick: () => void }[]
60
+
61
+ return (
62
+ <div className="flex-shrink-0 flex h-14 w-full overflow-hidden border-b border-ods-border bg-ods-card">
63
+ <div className="flex flex-1 min-w-0 items-center gap-2 px-4 py-3">
64
+ {showBack ? (
65
+ <>
66
+ <button
67
+ type="button"
68
+ onClick={onBack}
69
+ aria-label={backAriaLabel}
70
+ className="inline-flex shrink-0 items-center justify-center size-8 -ml-1 rounded-md text-ods-text-secondary transition-colors hover:bg-ods-bg-hover hover:text-ods-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-ods-accent"
71
+ >
72
+ <Chevron01LeftIcon size={20} />
73
+ </button>
74
+ <span className="truncate text-h3 text-ods-text-primary">{title}</span>
75
+ </>
76
+ ) : (
77
+ <p className="truncate text-h4 text-ods-text-primary">{title}</p>
78
+ )}
79
+ </div>
80
+
81
+ {/* Restore (refresh) — archived chat header (Figma node 7361:425441). */}
82
+ {isArchivedView && onRestore && (
83
+ <ChatHeaderIconButton onClick={onRestore} aria-label="Unarchive chat">
84
+ <Refresh01LeftIcon size={24} />
85
+ </ChatHeaderIconButton>
86
+ )}
87
+
88
+ {/* Rename / Archive menu — active (non-archived) conversation only. */}
89
+ {showBack && !isArchivedView && menuItems.length > 0 && (
90
+ <MoreActionsMenu
91
+ ariaLabel="Chat actions"
92
+ onCloseAutoFocus={(e) => e.preventDefault()}
93
+ items={menuItems}
94
+ trigger={
95
+ <ChatHeaderIconButton aria-label="Chat actions">
96
+ <Ellipsis01Icon size={24} />
97
+ </ChatHeaderIconButton>
98
+ }
99
+ />
100
+ )}
101
+
102
+ {/* Chat Archive entry (Figma node 7532:225034) — list view only. */}
103
+ {!showBack && onOpenArchive && (
104
+ <ChatHeaderIconButton onClick={onOpenArchive} aria-label="Chat archive">
105
+ <ClockHistoryIcon size={24} />
106
+ </ChatHeaderIconButton>
107
+ )}
108
+
109
+ <ChatHeaderIconButton onClick={onClose} aria-label="Close">
110
+ <XmarkIcon size={24} />
111
+ </ChatHeaderIconButton>
112
+ </div>
113
+ )
114
+ }