11import { getChatbotText } from "../data/chatbotTexts" ;
22import { chatbotStyles } from "../styles/styles" ;
3+ import {
4+ exportAsTxt ,
5+ exportAsMd ,
6+ exportAsDocx ,
7+ exportAsPdf ,
8+ } from "../utils/exportchat" ;
9+ import { type Message } from "../model/Message" ;
10+ import { useEffect , useRef , useState } from "react" ;
11+ import {
12+ Upload ,
13+ Trash2 ,
14+ FileText ,
15+ FileCode ,
16+ FileSpreadsheet ,
17+ File ,
18+ } from "lucide-react" ;
319
420/**
521 * Props for the Header component.
@@ -8,6 +24,7 @@ export interface HeaderProps {
824 currentSessionId : string | null ;
925 clearMessages : ( chatSessionId : string ) => void ;
1026 openSideBar : ( ) => void ;
27+ messages : Message [ ] ;
1128}
1229
1330/**
@@ -19,7 +36,29 @@ export const Header = ({
1936 currentSessionId,
2037 clearMessages,
2138 openSideBar,
39+ messages,
2240} : HeaderProps ) => {
41+ const [ showExportMenu , setShowExportMenu ] = useState ( false ) ;
42+ const exportMenuRef = useRef < HTMLDivElement | null > ( null ) ;
43+
44+ useEffect ( ( ) => {
45+ const handleClickOutside = ( event : MouseEvent ) => {
46+ if (
47+ showExportMenu &&
48+ exportMenuRef . current &&
49+ ! exportMenuRef . current . contains ( event . target as Node )
50+ ) {
51+ setShowExportMenu ( false ) ;
52+ }
53+ } ;
54+
55+ document . addEventListener ( "mousedown" , handleClickOutside ) ;
56+
57+ return ( ) => {
58+ document . removeEventListener ( "mousedown" , handleClickOutside ) ;
59+ } ;
60+ } , [ showExportMenu ] ) ;
61+
2362 return (
2463 < div style = { chatbotStyles . chatbotHeader } >
2564 < button
@@ -30,12 +69,74 @@ export const Header = ({
3069 { getChatbotText ( "sidebarLabel" ) }
3170 </ button >
3271 { currentSessionId !== null && (
33- < button
34- onClick = { ( ) => clearMessages ( currentSessionId ) }
35- style = { chatbotStyles . clearButton }
36- >
37- { getChatbotText ( "clearChat" ) }
38- </ button >
72+ < div ref = { exportMenuRef } style = { chatbotStyles . headerActions } >
73+ < div style = { { position : "relative" , display : "inline-block" } } >
74+ { /* Export button */ }
75+ < button
76+ onClick = { ( ) => setShowExportMenu ( ( prev ) => ! prev ) }
77+ style = { chatbotStyles . exportButton }
78+ title = "Export chat"
79+ aria-label = "Export chat"
80+ >
81+ < Upload size = { 16 } />
82+ </ button >
83+
84+ { /* Export menu */ }
85+ { showExportMenu && (
86+ < div style = { chatbotStyles . exportMenu } >
87+ < button
88+ style = { chatbotStyles . exportMenuItem }
89+ onClick = { ( ) => {
90+ exportAsTxt ( messages ) ;
91+ setShowExportMenu ( false ) ;
92+ } }
93+ >
94+ < FileText size = { 20 } />
95+ < span > .txt</ span >
96+ </ button >
97+ < button
98+ style = { chatbotStyles . exportMenuItem }
99+ onClick = { ( ) => {
100+ exportAsMd ( messages ) ;
101+ setShowExportMenu ( false ) ;
102+ } }
103+ >
104+ < FileCode size = { 20 } />
105+ < span > .md</ span >
106+ </ button >
107+ < button
108+ style = { chatbotStyles . exportMenuItem }
109+ onClick = { ( ) => {
110+ exportAsDocx ( messages ) ;
111+ setShowExportMenu ( false ) ;
112+ } }
113+ >
114+ < FileSpreadsheet size = { 20 } />
115+ < span > .docx</ span >
116+ </ button >
117+ < button
118+ style = { chatbotStyles . exportMenuItem }
119+ onClick = { ( ) => {
120+ exportAsPdf ( messages ) ;
121+ setShowExportMenu ( false ) ;
122+ } }
123+ >
124+ < File size = { 20 } />
125+ < span > .pdf</ span >
126+ </ button >
127+ </ div >
128+ ) }
129+ </ div >
130+
131+ < button
132+ onClick = { ( ) => clearMessages ( currentSessionId ) }
133+ style = { chatbotStyles . clearButton }
134+ title = "Clear chat"
135+ aria-label = "Clear chat"
136+ >
137+ < Trash2 size = { 16 } />
138+ </ button >
139+ </ div >
39140 ) }
40141 </ div >
41142 ) ;
0 commit comments