@topconsultnpm/sdkui-react 6.22.0-dev3.32 → 6.22.0-dev3.33

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 (107) hide show
  1. package/lib/components/NewComponents/ContextMenu/styles.d.ts +43 -45
  2. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +60 -67
  3. package/lib/components/base/Styled.d.ts +77 -93
  4. package/lib/components/base/TMCounterBar.d.ts +2 -2
  5. package/lib/components/base/TMCounterContainer.d.ts +1 -2
  6. package/lib/components/base/TMCustomButton.d.ts +1 -1
  7. package/lib/components/base/TMDataGridExportForm.d.ts +1 -2
  8. package/lib/components/base/TMFileManager.d.ts +1 -2
  9. package/lib/components/base/TMFileManagerDataGridView.d.ts +1 -2
  10. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
  11. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
  12. package/lib/components/base/TMFileManagerUtils.d.ts +6 -4
  13. package/lib/components/base/TMLayout.d.ts +4 -4
  14. package/lib/components/base/TMList.d.ts +1 -2
  15. package/lib/components/base/TMListView.d.ts +1 -1
  16. package/lib/components/base/TMSpinner.d.ts +2 -3
  17. package/lib/components/base/TMTab.d.ts +3 -4
  18. package/lib/components/base/TMTabControl.js +208 -208
  19. package/lib/components/base/TMTooltip.d.ts +1 -1
  20. package/lib/components/base/TMTreeView.d.ts +8 -14
  21. package/lib/components/base/TMUserAvatar.d.ts +1 -2
  22. package/lib/components/base/TMVilViewer.d.ts +1 -2
  23. package/lib/components/base/TMWaitPanel.d.ts +2 -3
  24. package/lib/components/base/waitPanel/TMWaitPanelView.d.ts +1 -2
  25. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
  26. package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +1 -2
  27. package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +1 -2
  28. package/lib/components/choosers/TMQuickSearchInfo.d.ts +1 -2
  29. package/lib/components/choosers/TMRelationChooser.d.ts +3 -3
  30. package/lib/components/choosers/TMUserChooser.d.ts +2 -2
  31. package/lib/components/editors/TMEditorStyled.d.ts +42 -20
  32. package/lib/components/editors/TMFormulaEditor.d.ts +1 -1
  33. package/lib/components/editors/TMHtmlContentDisplay.d.ts +1 -2
  34. package/lib/components/editors/TMHtmlEditor.d.ts +1 -2
  35. package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
  36. package/lib/components/features/assistant/TMHelpOnLineChat.d.ts +1 -0
  37. package/lib/components/features/assistant/TMHelpOnLineChat.js +649 -496
  38. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
  39. package/lib/components/features/assistant/dataset/Designer-Suggested-Questions.json +102 -0
  40. package/lib/components/features/assistant/dataset/Login-Suggested-Questions.json +32 -0
  41. package/lib/components/features/assistant/dataset/Surfer-Suggested-Questions.json +102 -0
  42. package/lib/components/features/blog/TMBlogCommentForm.d.ts +1 -2
  43. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +1 -1
  44. package/lib/components/features/documents/TMDcmtIcon.d.ts +1 -2
  45. package/lib/components/features/documents/TMDcmtPreview.d.ts +6 -8
  46. package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -2
  47. package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
  48. package/lib/components/features/documents/TMFileUploader.js +21 -21
  49. package/lib/components/features/documents/TMMasterInfoFields.d.ts +1 -2
  50. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
  51. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +1 -2
  52. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +4 -4
  53. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +1 -2
  54. package/lib/components/features/search/TMMetadataOutputForm.d.ts +1 -2
  55. package/lib/components/features/search/TMMetadataSorterForm.d.ts +1 -2
  56. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  57. package/lib/components/features/search/TMSearch.d.ts +1 -2
  58. package/lib/components/features/search/TMSearchQueryPanel.d.ts +3 -9
  59. package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
  60. package/lib/components/features/search/TMSignatureInfoContent.d.ts +1 -2
  61. package/lib/components/features/search/TMViewHistoryDcmt.d.ts +1 -2
  62. package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
  63. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
  64. package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
  65. package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
  66. package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
  67. package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
  68. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
  69. package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
  70. package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +2 -3
  71. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +7 -8
  72. package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +1 -3
  73. package/lib/components/forms/Login/ChangePasswordInputs.d.ts +1 -3
  74. package/lib/components/forms/Login/Chooser.d.ts +2 -2
  75. package/lib/components/forms/TMChooserForm.d.ts +1 -2
  76. package/lib/components/forms/TMSaveForm.d.ts +4 -4
  77. package/lib/components/grids/TMBlogAttachments.d.ts +1 -2
  78. package/lib/components/grids/TMBlogHeader.d.ts +1 -1
  79. package/lib/components/grids/TMBlogsPost.d.ts +1 -1
  80. package/lib/components/grids/TMBlogsPostUtils.d.ts +9 -9
  81. package/lib/components/grids/TMValidationItemsList.d.ts +1 -2
  82. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -2
  83. package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +2 -2
  84. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +6 -5
  85. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
  86. package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
  87. package/lib/components/pages/TMPage.d.ts +1 -1
  88. package/lib/components/query/TMQueryEditor.d.ts +10 -14
  89. package/lib/components/settings/SettingsAppearance.d.ts +1 -2
  90. package/lib/components/sidebar/TMAboutApp.d.ts +1 -2
  91. package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
  92. package/lib/components/sidebar/TMHeader.d.ts +3 -3
  93. package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -3
  94. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +2 -3
  95. package/lib/components/viewers/TMMidViewer.d.ts +2 -2
  96. package/lib/components/viewers/TMTidViewer.d.ts +2 -2
  97. package/lib/helper/TMAppUpdatedModal.d.ts +1 -2
  98. package/lib/helper/TMAppUpdatedModal.js +93 -93
  99. package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
  100. package/lib/helper/TMIcons.d.ts +280 -280
  101. package/lib/helper/TMPdfViewer.d.ts +1 -2
  102. package/lib/helper/TMToppyMessage.d.ts +2 -2
  103. package/lib/helper/TMUtils.d.ts +4 -10
  104. package/lib/helper/helpers.d.ts +1 -1
  105. package/lib/hooks/useInputDialog.d.ts +1 -2
  106. package/lib/services/platform_services.d.ts +2 -3
  107. package/package.json +1 -1
@@ -1,11 +1,14 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import styled, { keyframes } from 'styled-components';
4
- import { HolAskDescriptor, SDK_Globals, TopMediaServer } from '@topconsultnpm/sdk-ts';
4
+ import { AppModules, HolAskDescriptor, SDK_Globals, TopMediaServer } from '@topconsultnpm/sdk-ts';
5
5
  import TMTooltip from '../../base/TMTooltip';
6
6
  import { TMColors } from '../../../utils/theme';
7
7
  import { SDKUI_Localizator } from '../../../helper';
8
8
  import ToppyImage from '../../../assets/Toppy-help-center.png';
9
+ import LoginSuggestedQuestions from './dataset/Login-Suggested-Questions.json';
10
+ import SurferSuggestedQuestions from './dataset/Surfer-Suggested-Questions.json';
11
+ import DesignerSuggestedQuestions from './dataset/Designer-Suggested-Questions.json';
9
12
  const generateGUID = () => {
10
13
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replaceAll(/[xy]/g, (c) => {
11
14
  const r = Math.trunc(Math.random() * 16);
@@ -16,6 +19,24 @@ const generateGUID = () => {
16
19
  const PANEL_DEFAULT_WIDTH = 600;
17
20
  const PANEL_MIN_WIDTH = 340;
18
21
  const PANEL_MAX_WIDTH = 900;
22
+ const SUGGESTIONS_COUNT = 4;
23
+ const getDefaultSuggestedQuestions = (isLogged) => {
24
+ if (!isLogged)
25
+ return LoginSuggestedQuestions;
26
+ switch (SDK_Globals.appModule) {
27
+ case AppModules.SURFER: return SurferSuggestedQuestions;
28
+ case AppModules.DESIGNER: return DesignerSuggestedQuestions;
29
+ default: return [];
30
+ }
31
+ };
32
+ const pickRandom = (items, count) => {
33
+ const pool = [...items];
34
+ for (let i = pool.length - 1; i > 0; i--) {
35
+ const j = Math.floor(Math.random() * (i + 1));
36
+ [pool[i], pool[j]] = [pool[j], pool[i]];
37
+ }
38
+ return pool.slice(0, count);
39
+ };
19
40
  const getSafeSession = () => {
20
41
  try {
21
42
  return SDK_Globals.tmSession;
@@ -37,10 +58,11 @@ const getPreLoginSession = (endpointUrl) => {
37
58
  }
38
59
  return preLoginSession;
39
60
  };
40
- const TMHelpOnLineChat = ({ isOpen, showChatButton, isLogged, messages, conversationId, isThinking, endpointUrl, onClose, onToggle, onNewConversation, onAddMessage, onSetThinking, onSetConversationId }) => {
61
+ const TMHelpOnLineChat = ({ isOpen, showChatButton, isLogged, messages, conversationId, isThinking, endpointUrl, onClose, onToggle, onNewConversation, onAddMessage, onSetThinking, onSetConversationId, suggestedQuestions }) => {
41
62
  const [width, setWidth] = useState(PANEL_DEFAULT_WIDTH);
42
63
  const showFab = !isLogged && showChatButton && !isOpen;
43
- return (_jsxs(_Fragment, { children: [isOpen && (_jsxs(_Fragment, { children: [_jsx(Overlay, { onClick: onClose }), _jsx(ChatPanel, { width: width, onWidthChange: setWidth, messages: messages, conversationId: conversationId, isThinking: isThinking, endpointUrl: endpointUrl, onClose: onClose, onNewConversation: onNewConversation, onAddMessage: onAddMessage, onSetThinking: onSetThinking, onSetConversationId: onSetConversationId })] })), showFab && (_jsx(Fab, { onClick: onToggle, title: "Chiedi a Toppy", "aria-label": "Chiedi a Toppy", children: _jsx(FabAvatar, { src: ToppyImage, alt: "Toppy" }) }))] }));
64
+ const questions = suggestedQuestions ?? getDefaultSuggestedQuestions(isLogged);
65
+ return (_jsxs(_Fragment, { children: [isOpen && (_jsxs(_Fragment, { children: [_jsx(Overlay, { onClick: onClose }), _jsx(ChatPanel, { width: width, onWidthChange: setWidth, messages: messages, conversationId: conversationId, isThinking: isThinking, endpointUrl: endpointUrl, onClose: onClose, onNewConversation: onNewConversation, onAddMessage: onAddMessage, onSetThinking: onSetThinking, onSetConversationId: onSetConversationId, suggestedQuestions: questions })] })), showFab && (_jsx(Fab, { onClick: onToggle, title: "Chiedi a Toppy", "aria-label": "Chiedi a Toppy", children: _jsx(FabAvatar, { src: ToppyImage, alt: "Toppy" }) }))] }));
44
66
  };
45
67
  export default TMHelpOnLineChat;
46
68
  //#region Header button
@@ -49,8 +71,11 @@ export const TMToppyHeaderButton = ({ showChatButton, onToggle }) => {
49
71
  return null;
50
72
  return (_jsx(TMTooltip, { content: "Chiedi a Toppy", children: _jsxs(ToppyHeaderButton, { onClick: onToggle, title: "Chiedi a Toppy", children: [_jsx(ToppyHeaderAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(ToppyHeaderText, { children: "Chiedi a Toppy" })] }) }));
51
73
  };
52
- const ChatPanel = ({ width, onWidthChange, messages, conversationId, isThinking, endpointUrl, onClose, onNewConversation, onAddMessage, onSetThinking, onSetConversationId }) => {
74
+ const ChatPanel = ({ width, onWidthChange, messages, conversationId, isThinking, endpointUrl, onClose, onNewConversation, onAddMessage, onSetThinking, onSetConversationId, suggestedQuestions }) => {
53
75
  const [chatInput, setChatInput] = useState('');
76
+ const [suggestions, setSuggestions] = useState(() => pickRandom(suggestedQuestions, SUGGESTIONS_COUNT));
77
+ const [hoveredSuggestion, setHoveredSuggestion] = useState(undefined);
78
+ const prevMessagesCountRef = useRef(messages.length);
54
79
  const inputRef = useRef(null);
55
80
  const messagesEndRef = useRef(null);
56
81
  const onCloseRef = useRef(onClose);
@@ -62,6 +87,12 @@ const ChatPanel = ({ width, onWidthChange, messages, conversationId, isThinking,
62
87
  useEffect(() => {
63
88
  inputRef.current?.focus();
64
89
  }, []);
90
+ useEffect(() => {
91
+ if (messages.length === 0 && prevMessagesCountRef.current > 0) {
92
+ setSuggestions(pickRandom(suggestedQuestions, SUGGESTIONS_COUNT));
93
+ }
94
+ prevMessagesCountRef.current = messages.length;
95
+ }, [messages.length, suggestedQuestions]);
65
96
  useEffect(() => {
66
97
  const onKeyDown = (e) => {
67
98
  if (e.key === 'Escape')
@@ -90,8 +121,8 @@ const ChatPanel = ({ width, onWidthChange, messages, conversationId, isThinking,
90
121
  globalThis.addEventListener('mousemove', onMove);
91
122
  globalThis.addEventListener('mouseup', onUp);
92
123
  }, [width, onWidthChange]);
93
- const askHandler = useCallback(async () => {
94
- const question = chatInput.trim();
124
+ const ask = useCallback(async (text) => {
125
+ const question = text.trim();
95
126
  if (question.length < 2 || isThinking) {
96
127
  return;
97
128
  }
@@ -133,8 +164,14 @@ const ChatPanel = ({ width, onWidthChange, messages, conversationId, isThinking,
133
164
  finally {
134
165
  onSetThinking(false);
135
166
  }
136
- }, [chatInput, conversationId, isThinking, endpointUrl, onAddMessage, onSetThinking, onSetConversationId]);
137
- return (_jsxs(PanelContainer, { $width: width, children: [_jsx(ResizeHandle, { onMouseDown: onResizeStart }), _jsxs(ChatHeader, { children: [_jsxs(HeaderLeft, { children: [_jsx(ToppyAvatar, { src: ToppyImage, alt: "Toppy" }), _jsxs(HeaderText, { children: [_jsxs(HeaderGreeting, { children: ["Ciao ", userName] }), _jsx(HeaderQuestion, { children: "Come posso aiutarti?" })] })] }), _jsxs(HeaderRight, { children: [_jsx(TMTooltip, { content: "Nuova conversazione", children: _jsx(HeaderButton, { onClick: onNewConversation, disabled: !conversationId && messages.length === 0, title: "Nuova conversazione", children: _jsx(IconNewChat, { color: "white", fontSize: 18 }) }) }), _jsx(TMTooltip, { content: "Chiudi", children: _jsx(HeaderButton, { onClick: onClose, title: "Chiudi", children: _jsx(IconClose, { fontSize: 18 }) }) })] })] }), _jsxs(ChatBody, { children: [messages.length === 0 ? (_jsxs(WelcomeMessage, { children: [_jsx(WelcomeIcon, { children: "\uD83D\uDCA1" }), _jsxs(WelcomeText, { children: ["Ciao! Sono ", _jsx("strong", { children: "Toppy" }), ", il tuo assistente.", _jsx("br", {}), "Fai una domanda e ti aiuter\u00F2 a trovare la risposta."] })] })) : (messages.map(msg => (_jsxs(MessageBubble, { $isUser: msg.isUser, children: [!msg.isUser && _jsx(BotAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(MessageContent, { $isUser: msg.isUser, children: msg.isUser ? msg.text : _jsx(MarkdownContent, { children: renderMarkdown(msg.text) }) })] }, msg.id)))), isThinking && (_jsxs(MessageBubble, { $isUser: false, children: [_jsx(BotAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(ThinkingStatus, {}, messages.length)] })), _jsx("div", { ref: messagesEndRef })] }), _jsxs(ChatFooter, { children: [_jsx(TMChatInput, { inputRef: inputRef, value: chatInput, onChange: setChatInput, onSend: askHandler, placeholder: "Scrivi la tua domanda...", tooltip: "Invia", disabled: isThinking }), _jsx(FooterHint, { children: SDKUI_Localizator.HelpOnLineShiftEnterHint })] })] }));
167
+ }, [conversationId, isThinking, endpointUrl, onAddMessage, onSetThinking, onSetConversationId]);
168
+ const askHandler = useCallback(() => ask(chatInput), [ask, chatInput]);
169
+ const onSuggestionClick = (question) => {
170
+ setHoveredSuggestion(undefined);
171
+ ask(question);
172
+ };
173
+ const showSuggestions = messages.length === 0 && !isThinking && suggestions.length > 0;
174
+ return (_jsxs(PanelContainer, { $width: width, children: [_jsx(ResizeHandle, { onMouseDown: onResizeStart }), _jsxs(ChatHeader, { children: [_jsxs(HeaderLeft, { children: [_jsx(ToppyAvatar, { src: ToppyImage, alt: "Toppy" }), _jsxs(HeaderText, { children: [_jsxs(HeaderGreeting, { children: ["Ciao ", userName] }), _jsx(HeaderQuestion, { children: "Come posso aiutarti?" })] })] }), _jsxs(HeaderRight, { children: [_jsx(TMTooltip, { content: "Nuova conversazione", children: _jsx(HeaderButton, { onClick: onNewConversation, disabled: !conversationId && messages.length === 0, title: "Nuova conversazione", children: _jsx(IconNewChat, { color: "white", fontSize: 18 }) }) }), _jsx(TMTooltip, { content: "Chiudi", children: _jsx(HeaderButton, { onClick: onClose, title: "Chiudi", children: _jsx(IconClose, { fontSize: 18 }) }) })] })] }), _jsxs(ChatBody, { children: [messages.length === 0 ? (_jsxs(WelcomeMessage, { children: [_jsx(WelcomeIcon, { children: "\uD83D\uDCA1" }), _jsxs(WelcomeText, { children: ["Ciao! Sono ", _jsx("strong", { children: "Toppy" }), ", il tuo assistente.", _jsx("br", {}), "Fai una domanda e ti aiuter\u00F2 a trovare la risposta."] })] })) : (messages.map(msg => (_jsxs(MessageBubble, { $isUser: msg.isUser, children: [!msg.isUser && _jsx(BotAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(MessageContent, { $isUser: msg.isUser, children: msg.isUser ? msg.text : _jsx(MarkdownContent, { children: renderMarkdown(msg.text) }) })] }, msg.id)))), isThinking && (_jsxs(MessageBubble, { $isUser: false, children: [_jsx(BotAvatar, { src: ToppyImage, alt: "Toppy" }), _jsx(ThinkingStatus, {}, messages.length)] })), _jsx("div", { ref: messagesEndRef })] }), _jsxs(ChatFooter, { children: [showSuggestions && (_jsxs(SuggestionsSection, { children: [_jsxs(SuggestionsTitle, { children: [_jsx(IconSparkle, { fontSize: 14 }), _jsx("span", { children: "Domande suggerite" })] }), _jsx(SuggestionsGrid, { children: suggestions.map((question, index) => (_jsxs(SuggestionCard, { type: "button", $index: index, title: question, onClick: () => onSuggestionClick(question), onMouseEnter: () => setHoveredSuggestion(question), onMouseLeave: () => setHoveredSuggestion(undefined), onFocus: () => setHoveredSuggestion(question), onBlur: () => setHoveredSuggestion(undefined), children: [_jsx(SuggestionIcon, { children: _jsx(IconQuestion, { fontSize: 16 }) }), _jsx(SuggestionText, { children: question }), _jsx(SuggestionArrow, { children: _jsx(IconArrowForward, { fontSize: 16 }) })] }, question))) })] })), _jsx(TMChatInput, { inputRef: inputRef, value: chatInput, onChange: setChatInput, onSend: askHandler, placeholder: hoveredSuggestion ?? 'Scrivi la tua domanda...', tooltip: "Invia", disabled: isThinking }), _jsx(FooterHint, { children: SDKUI_Localizator.HelpOnLineShiftEnterHint })] })] }));
138
175
  };
139
176
  const TMChatInput = ({ value, onChange, onSend, placeholder = 'Scrivi la tua domanda...', disabled = false, inputRef, tooltip = 'Ricerca AI' }) => {
140
177
  const isDisabled = disabled || value.length < 2;
@@ -395,494 +432,610 @@ function IconSendFilled(props) {
395
432
  function IconNewChat(props) {
396
433
  return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: props.color || "currentColor", ...props, children: _jsx("path", { d: "M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z" }) }));
397
434
  }
435
+ function IconSparkle(props) {
436
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor", ...props, children: _jsx("path", { d: "M19 9l1.25-2.75L23 5l-2.75-1.25L19 1l-1.25 2.75L15 5l2.75 1.25L19 9zm-7.5.5L9 4 6.5 9.5 1 12l5.5 2.5L9 20l2.5-5.5L17 12l-5.5-2.5zM19 15l-1.25 2.75L15 19l2.75 1.25L19 23l1.25-2.75L23 19l-2.75-1.25L19 15z" }) }));
437
+ }
438
+ function IconQuestion(props) {
439
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor", ...props, children: _jsx("path", { d: "M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z" }) }));
440
+ }
441
+ function IconArrowForward(props) {
442
+ return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor", ...props, children: _jsx("path", { d: "M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z" }) }));
443
+ }
398
444
  //#endregion
399
445
  //#region Styled Components
400
- const fadeIn = keyframes `
401
- from { opacity: 0; }
402
- to { opacity: 1; }
403
- `;
404
- const slideInRight = keyframes `
405
- from { transform: translateX(100%); }
406
- to { transform: translateX(0); }
407
- `;
408
- const phraseIn = keyframes `
409
- from { opacity: 0; transform: translateY(4px); }
410
- to { opacity: 1; transform: translateY(0); }
411
- `;
412
- const dotCycle = keyframes `
413
- 0% { opacity: 0; }
414
- 25%, 75% { opacity: 1; }
415
- 100% { opacity: 0; }
416
- `;
417
- const ToppyHeaderButton = styled.button `
418
- display: flex;
419
- align-items: center;
420
- gap: 8px;
421
- height: 36px;
422
- padding: 0 14px 0 5px;
423
- border-radius: 18px;
424
- border: 1px solid ${TMColors.primary}35;
425
- background: ${TMColors.primary}0d;
426
- color: ${TMColors.primary};
427
- font-size: 13px;
428
- font-weight: 600;
429
- white-space: nowrap;
430
- cursor: pointer;
431
- flex-shrink: 0;
432
- transition: all 0.2s ease;
433
-
434
- &:hover {
435
- background: ${TMColors.primary}1a;
436
- border-color: ${TMColors.primary}66;
437
- transform: translateY(-1px);
438
- box-shadow: 0 4px 12px ${TMColors.primary}25;
439
- }
440
- &:active { transform: translateY(0); }
441
- `;
442
- const ToppyHeaderAvatar = styled.img `
443
- width: 28px;
444
- height: 28px;
445
- border-radius: 50%;
446
- object-fit: contain;
447
- pointer-events: none;
448
- `;
449
- const ToppyHeaderText = styled.span `
450
- line-height: 1;
451
- `;
452
- const Fab = styled.button `
453
- position: fixed;
454
- bottom: 24px;
455
- right: 24px;
456
- width: 60px;
457
- height: 60px;
458
- border-radius: 50%;
459
- border: none;
460
- padding: 0;
461
- cursor: pointer;
462
- display: flex;
463
- align-items: center;
464
- justify-content: center;
465
- background: white;
466
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
467
- z-index: 100000;
468
- transition: transform 0.2s ease, box-shadow 0.2s ease;
469
- animation: ${fadeIn} 0.3s ease-out;
470
-
471
- &:hover { transform: scale(1.08); box-shadow: 0 8px 26px rgba(0, 0, 0, 0.3); }
472
- &:active { transform: scale(0.96); }
473
- `;
474
- const FabAvatar = styled.img `
475
- width: 52px;
476
- height: 52px;
477
- border-radius: 50%;
478
- object-fit: contain;
479
- pointer-events: none;
480
- `;
481
- const Overlay = styled.div `
482
- position: fixed;
483
- inset: 0;
484
- background: rgba(0, 0, 0, 0.45);
485
- z-index: 100000;
486
- animation: ${fadeIn} 0.2s ease-out;
487
- `;
488
- const PanelContainer = styled.div `
489
- position: fixed;
490
- top: 0;
491
- right: 0;
492
- height: 100vh;
493
- width: ${props => props.$width}px;
494
- max-width: 100vw;
495
- background: white;
496
- display: flex;
497
- flex-direction: column;
498
- box-shadow: -8px 0 32px rgba(0, 0, 0, 0.28);
499
- z-index: 100001;
500
- animation: ${slideInRight} 0.25s ease-out;
501
- `;
502
- const ResizeHandle = styled.div `
503
- position: absolute;
504
- left: 0;
505
- top: 0;
506
- bottom: 0;
507
- width: 6px;
508
- cursor: col-resize;
509
- background: transparent;
510
- z-index: 2;
511
- transition: background 0.2s ease;
512
-
513
- &:hover { background: ${TMColors.primary}55; }
514
- `;
515
- const ChatHeader = styled.div `
516
- display: flex;
517
- align-items: center;
518
- justify-content: space-between;
519
- padding: 16px 20px;
520
- background: linear-gradient(135deg, ${TMColors.primary} 0%, ${TMColors.primary}dd 100%);
521
- color: white;
522
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
523
- `;
524
- const HeaderLeft = styled.div `
525
- display: flex;
526
- align-items: center;
527
- gap: 12px;
528
- flex: 1;
529
- min-width: 0;
530
- `;
531
- const HeaderRight = styled.div `
532
- display: flex;
533
- align-items: center;
534
- gap: 8px;
535
- margin-left: 12px;
536
- flex-shrink: 0;
537
- `;
538
- const ToppyAvatar = styled.img `
539
- width: 44px;
540
- height: 44px;
541
- border-radius: 50%;
542
- background: white;
543
- padding: 4px;
544
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
545
- flex-shrink: 0;
546
- object-fit: contain;
547
- `;
548
- const HeaderText = styled.div `
549
- display: flex;
550
- flex-direction: column;
551
- gap: 2px;
552
- min-width: 0;
553
- `;
554
- const HeaderGreeting = styled.h2 `
555
- margin: 0;
556
- font-size: 17px;
557
- font-weight: 600;
558
- color: white;
559
- white-space: nowrap;
560
- overflow: hidden;
561
- text-overflow: ellipsis;
562
- `;
563
- const HeaderQuestion = styled.p `
564
- margin: 0;
565
- font-size: 13px;
566
- color: rgba(255, 255, 255, 0.9);
567
- `;
568
- const HeaderButton = styled.button `
569
- width: 32px;
570
- height: 32px;
571
- border-radius: 50%;
572
- background: rgba(255, 255, 255, 0.2);
573
- border: 1px solid rgba(255, 255, 255, 0.3);
574
- color: white;
575
- cursor: pointer;
576
- display: flex;
577
- align-items: center;
578
- justify-content: center;
579
- flex-shrink: 0;
580
- transition: all 0.2s ease;
581
-
582
- &:hover:not(:disabled) { background: rgba(255, 255, 255, 0.3); transform: scale(1.05); }
583
- &:active:not(:disabled) { transform: scale(0.95); }
584
- &:disabled { opacity: 0.45; cursor: default; }
585
- `;
586
- const ChatBody = styled.div `
587
- flex: 1;
588
- padding: 20px;
589
- overflow-y: auto;
590
- background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);
591
- `;
592
- const WelcomeMessage = styled.div `
593
- display: flex;
594
- gap: 16px;
595
- padding: 18px;
596
- background: white;
597
- border-radius: 12px;
598
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
599
- border-left: 4px solid ${TMColors.primary};
600
- animation: ${fadeIn} 0.5s ease-out;
601
- `;
602
- const WelcomeIcon = styled.div `
603
- font-size: 30px;
604
- flex-shrink: 0;
605
- `;
606
- const WelcomeText = styled.p `
607
- margin: 0;
608
- font-size: 14px;
609
- line-height: 1.6;
610
- color: #242424;
611
-
612
- strong { color: ${TMColors.primary}; font-weight: 600; }
613
- `;
614
- const MessageBubble = styled.div `
615
- display: flex;
616
- gap: 10px;
617
- margin-bottom: 16px;
618
- align-items: flex-start;
619
- justify-content: ${props => (props.$isUser ? 'flex-end' : 'flex-start')};
620
- animation: ${fadeIn} 0.3s ease-out;
621
- `;
622
- const BotAvatar = styled.img `
623
- width: 32px;
624
- height: 32px;
625
- border-radius: 50%;
626
- background: white;
627
- padding: 2px;
628
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
629
- flex-shrink: 0;
630
- object-fit: contain;
631
- `;
632
- const MessageContent = styled.div `
633
- max-width: 80%;
634
- padding: 10px 14px;
635
- border-radius: 12px;
636
- font-size: 14px;
637
- line-height: 1.5;
638
- background: ${props => (props.$isUser ? TMColors.primary : '#f0f2f5')};
639
- color: ${props => (props.$isUser ? 'white' : '#242424')};
640
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
641
- word-wrap: break-word;
642
- overflow-wrap: anywhere;
643
- white-space: ${props => (props.$isUser ? 'pre-wrap' : 'normal')};
644
- border-bottom-${props => (props.$isUser ? 'right' : 'left')}-radius: 4px;
645
- `;
646
- const MarkdownContent = styled.div `
647
- & > *:first-child { margin-top: 0; }
648
- & > *:last-child { margin-bottom: 0; }
649
-
650
- a { color: ${TMColors.primary}; text-decoration: underline; }
651
- strong { font-weight: 600; }
652
- `;
653
- const MdParagraph = styled.p `
654
- margin: 0 0 8px 0;
655
- line-height: 1.55;
656
- `;
657
- const MdHeading = styled.div `
658
- margin: 12px 0 6px 0;
659
- font-weight: 700;
660
- line-height: 1.3;
661
- font-size: ${props => `${Math.max(14, 20 - (props.$level - 1) * 2)}px`};
662
- `;
663
- const MdUl = styled.ul `
664
- margin: 4px 0 8px 0;
665
- padding-left: 20px;
666
- li { margin: 2px 0; line-height: 1.5; }
667
- `;
668
- const MdOl = styled.ol `
669
- margin: 4px 0 8px 0;
670
- padding-left: 22px;
671
- li { margin: 2px 0; line-height: 1.5; }
672
- `;
673
- const MdCode = styled.code `
674
- background: rgba(0, 0, 0, 0.06);
675
- padding: 1px 5px;
676
- border-radius: 4px;
677
- font-family: 'Consolas', 'Monaco', monospace;
678
- font-size: 0.9em;
679
- `;
680
- const MdPre = styled.pre `
681
- background: rgba(0, 0, 0, 0.06);
682
- padding: 10px 12px;
683
- border-radius: 8px;
684
- overflow-x: auto;
685
- margin: 8px 0;
686
- font-family: 'Consolas', 'Monaco', monospace;
687
- font-size: 0.88em;
688
- white-space: pre;
689
- `;
690
- const MdTableWrapper = styled.div `
691
- margin: 8px 0;
692
- max-width: 100%;
693
- overflow-x: auto;
694
- border: 1px solid #dcdfe3;
695
- border-radius: 8px;
696
-
697
- &::-webkit-scrollbar { height: 6px; }
698
- &::-webkit-scrollbar-track { background: transparent; }
699
- &::-webkit-scrollbar-thumb { background: #ccc; border-radius: 3px; }
700
- &::-webkit-scrollbar-thumb:hover { background: #999; }
701
- `;
702
- const MdTable = styled.table `
703
- border-collapse: collapse;
704
- width: 100%;
705
- font-size: 0.92em;
706
- background: white;
707
- `;
708
- const MdTh = styled.th `
709
- padding: 7px 10px;
710
- background: ${TMColors.primary}14;
711
- color: #242424;
712
- font-weight: 600;
713
- text-align: ${props => props.$align ?? 'left'};
714
- border-bottom: 1px solid #dcdfe3;
715
- white-space: nowrap;
716
-
717
- &:not(:last-child) { border-right: 1px solid #e6e8eb; }
718
- `;
719
- const MdTd = styled.td `
720
- padding: 7px 10px;
721
- text-align: ${props => props.$align ?? 'left'};
722
- vertical-align: top;
723
- border-top: 1px solid #eceef0;
724
-
725
- &:not(:last-child) { border-right: 1px solid #eceef0; }
726
-
727
- tr:nth-child(even) & { background: #fafbfc; }
728
- `;
729
- const MdBlockquote = styled.blockquote `
730
- margin: 8px 0;
731
- padding: 6px 12px;
732
- border-left: 3px solid ${TMColors.primary}66;
733
- background: ${TMColors.primary}0a;
734
- border-radius: 0 6px 6px 0;
735
- color: #444;
736
-
737
- & > *:first-child { margin-top: 0; }
738
- & > *:last-child { margin-bottom: 0; }
739
- `;
740
- const MdHr = styled.hr `
741
- border: none;
742
- border-top: 1px solid #dcdfe3;
743
- margin: 12px 0;
744
- `;
745
- const ThinkingIndicator = styled.div `
746
- display: flex;
747
- align-items: center;
748
- gap: 10px;
749
- max-width: 80%;
750
- padding: 7px 12px;
751
- background: #f0f2f5;
752
- border-radius: 12px;
753
- border-bottom-left-radius: 4px;
754
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
755
- `;
756
- const ThinkingCaption = styled.div `
757
- display: flex;
758
- flex-direction: column;
759
- align-items: flex-start;
760
- gap: 0;
761
- min-width: 0;
762
- `;
763
- const ThinkingPhrase = styled.span `
764
- display: inline-flex;
765
- align-items: center;
766
- min-width: 0;
767
- font-size: 12px;
768
- font-style: italic;
769
- line-height: 1.15;
770
- color: #6b7280;
771
- animation: ${phraseIn} 0.25s ease-out;
772
- `;
773
- const ThinkingDots = styled.span `
774
- display: inline-flex;
775
- width: 12px;
776
- flex-shrink: 0;
777
- `;
778
- const ThinkingDot = styled.span `
779
- animation: ${dotCycle} 1.2s linear infinite;
780
- animation-delay: ${props => props.$delay}s;
781
- will-change: opacity;
782
-
783
- @media (prefers-reduced-motion: reduce) {
784
- animation: none;
785
- opacity: 1;
786
- }
787
- `;
788
- const ThinkingCounter = styled.span `
789
- margin-top: 2px;
790
- font-size: 10px;
791
- font-weight: 600;
792
- line-height: 1.1;
793
- letter-spacing: 0.02em;
794
- color: ${TMColors.primary}b3;
795
- font-variant-numeric: tabular-nums;
796
- font-feature-settings: 'tnum';
797
- opacity: ${props => (props.$visible ? 1 : 0)};
798
- transition: opacity 0.3s ease;
799
- `;
800
- const ChatFooter = styled.div `
801
- padding: 16px 20px;
802
- background: white;
803
- border-top: 1px solid #e1e5e9;
804
- box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
805
- `;
806
- const FooterHint = styled.p `
807
- margin: 6px 0 0 0;
808
- font-size: 11px;
809
- color: #999;
810
- text-align: center;
811
- `;
812
- const ChatInputWrapper = styled.div `
813
- position: relative;
814
- flex: 1;
815
- display: flex;
816
- `;
817
- const ChatInputTextarea = styled.textarea `
818
- width: 100%;
819
- padding: 14px 60px 14px 16px;
820
- border: 2px solid #e1e5e9;
821
- border-radius: 12px;
822
- font-size: 15px;
823
- font-family: inherit;
824
- line-height: 1.5;
825
- transition: all 0.2s ease;
826
- background: #f8f9fa;
827
- resize: none;
828
- min-height: 100px;
829
- max-height: 120px;
830
- overflow-y: hidden;
831
-
832
- &:focus {
833
- outline: none;
834
- border-color: ${TMColors.primary};
835
- background: white;
836
- box-shadow: 0 0 0 4px ${TMColors.primary}15;
837
- }
838
-
839
- &::placeholder {
840
- color: #999;
841
- }
842
-
843
- &::-webkit-scrollbar {
844
- width: 6px;
845
- }
846
-
847
- &::-webkit-scrollbar-track {
848
- background: transparent;
849
- }
850
-
851
- &::-webkit-scrollbar-thumb {
852
- background: #ccc;
853
- border-radius: 3px;
854
- }
855
-
856
- &::-webkit-scrollbar-thumb:hover {
857
- background: #999;
858
- }
859
- `;
860
- const InlineSendButton = styled.button `
861
- position: absolute;
862
- bottom: 8px;
863
- right: 8px;
864
- width: 40px;
865
- height: 40px;
866
- border-radius: 10px;
867
- background: ${props => props.$disabled ? '#ccc' : '#4caf50'};
868
- border: none;
869
- color: white;
870
- cursor: ${props => props.$disabled ? 'default' : 'pointer'};
871
- display: flex;
872
- align-items: center;
873
- justify-content: center;
874
- transition: all 0.2s ease;
875
-
876
- &:hover:not(:disabled) {
877
- background: #45a049;
878
- transform: scale(1.05);
879
- }
880
-
881
- &:active:not(:disabled) {
882
- transform: scale(0.95);
883
- }
884
-
885
- &:disabled {
886
- opacity: 0.6;
887
- }
446
+ const fadeIn = keyframes `
447
+ from { opacity: 0; }
448
+ to { opacity: 1; }
449
+ `;
450
+ const slideInRight = keyframes `
451
+ from { transform: translateX(100%); }
452
+ to { transform: translateX(0); }
453
+ `;
454
+ const phraseIn = keyframes `
455
+ from { opacity: 0; transform: translateY(4px); }
456
+ to { opacity: 1; transform: translateY(0); }
457
+ `;
458
+ const suggestionIn = keyframes `
459
+ from { opacity: 0; transform: translateY(6px); }
460
+ to { opacity: 1; transform: translateY(0); }
461
+ `;
462
+ const dotCycle = keyframes `
463
+ 0% { opacity: 0; }
464
+ 25%, 75% { opacity: 1; }
465
+ 100% { opacity: 0; }
466
+ `;
467
+ const ToppyHeaderButton = styled.button `
468
+ display: flex;
469
+ align-items: center;
470
+ gap: 8px;
471
+ height: 36px;
472
+ padding: 0 14px 0 5px;
473
+ border-radius: 18px;
474
+ border: 1px solid ${TMColors.primary}35;
475
+ background: ${TMColors.primary}0d;
476
+ color: ${TMColors.primary};
477
+ font-size: 13px;
478
+ font-weight: 600;
479
+ white-space: nowrap;
480
+ cursor: pointer;
481
+ flex-shrink: 0;
482
+ transition: all 0.2s ease;
483
+
484
+ &:hover {
485
+ background: ${TMColors.primary}1a;
486
+ border-color: ${TMColors.primary}66;
487
+ transform: translateY(-1px);
488
+ box-shadow: 0 4px 12px ${TMColors.primary}25;
489
+ }
490
+ &:active { transform: translateY(0); }
491
+ `;
492
+ const ToppyHeaderAvatar = styled.img `
493
+ width: 28px;
494
+ height: 28px;
495
+ border-radius: 50%;
496
+ object-fit: contain;
497
+ pointer-events: none;
498
+ `;
499
+ const ToppyHeaderText = styled.span `
500
+ line-height: 1;
501
+ `;
502
+ const Fab = styled.button `
503
+ position: fixed;
504
+ bottom: 24px;
505
+ right: 24px;
506
+ width: 60px;
507
+ height: 60px;
508
+ border-radius: 50%;
509
+ border: none;
510
+ padding: 0;
511
+ cursor: pointer;
512
+ display: flex;
513
+ align-items: center;
514
+ justify-content: center;
515
+ background: white;
516
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
517
+ z-index: 100000;
518
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
519
+ animation: ${fadeIn} 0.3s ease-out;
520
+
521
+ &:hover { transform: scale(1.08); box-shadow: 0 8px 26px rgba(0, 0, 0, 0.3); }
522
+ &:active { transform: scale(0.96); }
523
+ `;
524
+ const FabAvatar = styled.img `
525
+ width: 52px;
526
+ height: 52px;
527
+ border-radius: 50%;
528
+ object-fit: contain;
529
+ pointer-events: none;
530
+ `;
531
+ const Overlay = styled.div `
532
+ position: fixed;
533
+ inset: 0;
534
+ background: rgba(0, 0, 0, 0.45);
535
+ z-index: 100000;
536
+ animation: ${fadeIn} 0.2s ease-out;
537
+ `;
538
+ const PanelContainer = styled.div `
539
+ position: fixed;
540
+ top: 0;
541
+ right: 0;
542
+ height: 100vh;
543
+ width: ${props => props.$width}px;
544
+ max-width: 100vw;
545
+ background: white;
546
+ display: flex;
547
+ flex-direction: column;
548
+ box-shadow: -8px 0 32px rgba(0, 0, 0, 0.28);
549
+ z-index: 100001;
550
+ animation: ${slideInRight} 0.25s ease-out;
551
+ `;
552
+ const ResizeHandle = styled.div `
553
+ position: absolute;
554
+ left: 0;
555
+ top: 0;
556
+ bottom: 0;
557
+ width: 6px;
558
+ cursor: col-resize;
559
+ background: transparent;
560
+ z-index: 2;
561
+ transition: background 0.2s ease;
562
+
563
+ &:hover { background: ${TMColors.primary}55; }
564
+ `;
565
+ const ChatHeader = styled.div `
566
+ display: flex;
567
+ align-items: center;
568
+ justify-content: space-between;
569
+ padding: 16px 20px;
570
+ background: linear-gradient(135deg, ${TMColors.primary} 0%, ${TMColors.primary}dd 100%);
571
+ color: white;
572
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
573
+ `;
574
+ const HeaderLeft = styled.div `
575
+ display: flex;
576
+ align-items: center;
577
+ gap: 12px;
578
+ flex: 1;
579
+ min-width: 0;
580
+ `;
581
+ const HeaderRight = styled.div `
582
+ display: flex;
583
+ align-items: center;
584
+ gap: 8px;
585
+ margin-left: 12px;
586
+ flex-shrink: 0;
587
+ `;
588
+ const ToppyAvatar = styled.img `
589
+ width: 44px;
590
+ height: 44px;
591
+ border-radius: 50%;
592
+ background: white;
593
+ padding: 4px;
594
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
595
+ flex-shrink: 0;
596
+ object-fit: contain;
597
+ `;
598
+ const HeaderText = styled.div `
599
+ display: flex;
600
+ flex-direction: column;
601
+ gap: 2px;
602
+ min-width: 0;
603
+ `;
604
+ const HeaderGreeting = styled.h2 `
605
+ margin: 0;
606
+ font-size: 17px;
607
+ font-weight: 600;
608
+ color: white;
609
+ white-space: nowrap;
610
+ overflow: hidden;
611
+ text-overflow: ellipsis;
612
+ `;
613
+ const HeaderQuestion = styled.p `
614
+ margin: 0;
615
+ font-size: 13px;
616
+ color: rgba(255, 255, 255, 0.9);
617
+ `;
618
+ const HeaderButton = styled.button `
619
+ width: 32px;
620
+ height: 32px;
621
+ border-radius: 50%;
622
+ background: rgba(255, 255, 255, 0.2);
623
+ border: 1px solid rgba(255, 255, 255, 0.3);
624
+ color: white;
625
+ cursor: pointer;
626
+ display: flex;
627
+ align-items: center;
628
+ justify-content: center;
629
+ flex-shrink: 0;
630
+ transition: all 0.2s ease;
631
+
632
+ &:hover:not(:disabled) { background: rgba(255, 255, 255, 0.3); transform: scale(1.05); }
633
+ &:active:not(:disabled) { transform: scale(0.95); }
634
+ &:disabled { opacity: 0.45; cursor: default; }
635
+ `;
636
+ const ChatBody = styled.div `
637
+ flex: 1;
638
+ padding: 20px;
639
+ overflow-y: auto;
640
+ background: linear-gradient(to bottom, #f8f9fa 0%, #ffffff 100%);
641
+ `;
642
+ const WelcomeMessage = styled.div `
643
+ display: flex;
644
+ gap: 16px;
645
+ padding: 18px;
646
+ background: white;
647
+ border-radius: 12px;
648
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
649
+ border-left: 4px solid ${TMColors.primary};
650
+ animation: ${fadeIn} 0.5s ease-out;
651
+ `;
652
+ const WelcomeIcon = styled.div `
653
+ font-size: 30px;
654
+ flex-shrink: 0;
655
+ `;
656
+ const WelcomeText = styled.p `
657
+ margin: 0;
658
+ font-size: 14px;
659
+ line-height: 1.6;
660
+ color: #242424;
661
+
662
+ strong { color: ${TMColors.primary}; font-weight: 600; }
663
+ `;
664
+ const MessageBubble = styled.div `
665
+ display: flex;
666
+ gap: 10px;
667
+ margin-bottom: 16px;
668
+ align-items: flex-start;
669
+ justify-content: ${props => (props.$isUser ? 'flex-end' : 'flex-start')};
670
+ animation: ${fadeIn} 0.3s ease-out;
671
+ `;
672
+ const BotAvatar = styled.img `
673
+ width: 32px;
674
+ height: 32px;
675
+ border-radius: 50%;
676
+ background: white;
677
+ padding: 2px;
678
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
679
+ flex-shrink: 0;
680
+ object-fit: contain;
681
+ `;
682
+ const MessageContent = styled.div `
683
+ max-width: 80%;
684
+ padding: 10px 14px;
685
+ border-radius: 12px;
686
+ font-size: 14px;
687
+ line-height: 1.5;
688
+ background: ${props => (props.$isUser ? TMColors.primary : '#f0f2f5')};
689
+ color: ${props => (props.$isUser ? 'white' : '#242424')};
690
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
691
+ word-wrap: break-word;
692
+ overflow-wrap: anywhere;
693
+ white-space: ${props => (props.$isUser ? 'pre-wrap' : 'normal')};
694
+ border-bottom-${props => (props.$isUser ? 'right' : 'left')}-radius: 4px;
695
+ `;
696
+ const MarkdownContent = styled.div `
697
+ & > *:first-child { margin-top: 0; }
698
+ & > *:last-child { margin-bottom: 0; }
699
+
700
+ a { color: ${TMColors.primary}; text-decoration: underline; }
701
+ strong { font-weight: 600; }
702
+ `;
703
+ const MdParagraph = styled.p `
704
+ margin: 0 0 8px 0;
705
+ line-height: 1.55;
706
+ `;
707
+ const MdHeading = styled.div `
708
+ margin: 12px 0 6px 0;
709
+ font-weight: 700;
710
+ line-height: 1.3;
711
+ font-size: ${props => `${Math.max(14, 20 - (props.$level - 1) * 2)}px`};
712
+ `;
713
+ const MdUl = styled.ul `
714
+ margin: 4px 0 8px 0;
715
+ padding-left: 20px;
716
+ li { margin: 2px 0; line-height: 1.5; }
717
+ `;
718
+ const MdOl = styled.ol `
719
+ margin: 4px 0 8px 0;
720
+ padding-left: 22px;
721
+ li { margin: 2px 0; line-height: 1.5; }
722
+ `;
723
+ const MdCode = styled.code `
724
+ background: rgba(0, 0, 0, 0.06);
725
+ padding: 1px 5px;
726
+ border-radius: 4px;
727
+ font-family: 'Consolas', 'Monaco', monospace;
728
+ font-size: 0.9em;
729
+ `;
730
+ const MdPre = styled.pre `
731
+ background: rgba(0, 0, 0, 0.06);
732
+ padding: 10px 12px;
733
+ border-radius: 8px;
734
+ overflow-x: auto;
735
+ margin: 8px 0;
736
+ font-family: 'Consolas', 'Monaco', monospace;
737
+ font-size: 0.88em;
738
+ white-space: pre;
739
+ `;
740
+ const MdTableWrapper = styled.div `
741
+ margin: 8px 0;
742
+ max-width: 100%;
743
+ overflow-x: auto;
744
+ border: 1px solid #dcdfe3;
745
+ border-radius: 8px;
746
+
747
+ &::-webkit-scrollbar { height: 6px; }
748
+ &::-webkit-scrollbar-track { background: transparent; }
749
+ &::-webkit-scrollbar-thumb { background: #ccc; border-radius: 3px; }
750
+ &::-webkit-scrollbar-thumb:hover { background: #999; }
751
+ `;
752
+ const MdTable = styled.table `
753
+ border-collapse: collapse;
754
+ width: 100%;
755
+ font-size: 0.92em;
756
+ background: white;
757
+ `;
758
+ const MdTh = styled.th `
759
+ padding: 7px 10px;
760
+ background: ${TMColors.primary}14;
761
+ color: #242424;
762
+ font-weight: 600;
763
+ text-align: ${props => props.$align ?? 'left'};
764
+ border-bottom: 1px solid #dcdfe3;
765
+ white-space: nowrap;
766
+
767
+ &:not(:last-child) { border-right: 1px solid #e6e8eb; }
768
+ `;
769
+ const MdTd = styled.td `
770
+ padding: 7px 10px;
771
+ text-align: ${props => props.$align ?? 'left'};
772
+ vertical-align: top;
773
+ border-top: 1px solid #eceef0;
774
+
775
+ &:not(:last-child) { border-right: 1px solid #eceef0; }
776
+
777
+ tr:nth-child(even) & { background: #fafbfc; }
778
+ `;
779
+ const MdBlockquote = styled.blockquote `
780
+ margin: 8px 0;
781
+ padding: 6px 12px;
782
+ border-left: 3px solid ${TMColors.primary}66;
783
+ background: ${TMColors.primary}0a;
784
+ border-radius: 0 6px 6px 0;
785
+ color: #444;
786
+
787
+ & > *:first-child { margin-top: 0; }
788
+ & > *:last-child { margin-bottom: 0; }
789
+ `;
790
+ const MdHr = styled.hr `
791
+ border: none;
792
+ border-top: 1px solid #dcdfe3;
793
+ margin: 12px 0;
794
+ `;
795
+ const ThinkingIndicator = styled.div `
796
+ display: flex;
797
+ align-items: center;
798
+ gap: 10px;
799
+ max-width: 80%;
800
+ padding: 7px 12px;
801
+ background: #f0f2f5;
802
+ border-radius: 12px;
803
+ border-bottom-left-radius: 4px;
804
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
805
+ `;
806
+ const ThinkingCaption = styled.div `
807
+ display: flex;
808
+ flex-direction: column;
809
+ align-items: flex-start;
810
+ gap: 0;
811
+ min-width: 0;
812
+ `;
813
+ const ThinkingPhrase = styled.span `
814
+ display: inline-flex;
815
+ align-items: center;
816
+ min-width: 0;
817
+ font-size: 12px;
818
+ font-style: italic;
819
+ line-height: 1.15;
820
+ color: #6b7280;
821
+ animation: ${phraseIn} 0.25s ease-out;
822
+ `;
823
+ const ThinkingDots = styled.span `
824
+ display: inline-flex;
825
+ width: 12px;
826
+ flex-shrink: 0;
827
+ `;
828
+ const ThinkingDot = styled.span `
829
+ animation: ${dotCycle} 1.2s linear infinite;
830
+ animation-delay: ${props => props.$delay}s;
831
+ will-change: opacity;
832
+
833
+ @media (prefers-reduced-motion: reduce) {
834
+ animation: none;
835
+ opacity: 1;
836
+ }
837
+ `;
838
+ const ThinkingCounter = styled.span `
839
+ margin-top: 2px;
840
+ font-size: 10px;
841
+ font-weight: 600;
842
+ line-height: 1.1;
843
+ letter-spacing: 0.02em;
844
+ color: ${TMColors.primary}b3;
845
+ font-variant-numeric: tabular-nums;
846
+ font-feature-settings: 'tnum';
847
+ opacity: ${props => (props.$visible ? 1 : 0)};
848
+ transition: opacity 0.3s ease;
849
+ `;
850
+ const ChatFooter = styled.div `
851
+ padding: 16px 20px;
852
+ background: white;
853
+ border-top: 1px solid #e1e5e9;
854
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
855
+ `;
856
+ const SuggestionsSection = styled.div `
857
+ margin-bottom: 14px;
858
+ `;
859
+ const SuggestionsTitle = styled.div `
860
+ display: flex;
861
+ align-items: center;
862
+ gap: 6px;
863
+ margin: 0 0 8px 2px;
864
+ font-size: 11px;
865
+ font-weight: 600;
866
+ letter-spacing: 0.06em;
867
+ text-transform: uppercase;
868
+ color: #6b7280;
869
+
870
+ svg { color: ${TMColors.primary}; }
871
+ `;
872
+ const SuggestionsGrid = styled.div `
873
+ display: grid;
874
+ grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
875
+ gap: 8px;
876
+ `;
877
+ const SuggestionIcon = styled.span `
878
+ display: flex;
879
+ align-items: center;
880
+ justify-content: center;
881
+ width: 28px;
882
+ height: 28px;
883
+ border-radius: 8px;
884
+ flex-shrink: 0;
885
+ background: ${TMColors.primary}14;
886
+ color: ${TMColors.primary};
887
+ transition: background 0.2s ease, color 0.2s ease;
888
+ `;
889
+ const SuggestionText = styled.span `
890
+ flex: 1;
891
+ min-width: 0;
892
+ display: -webkit-box;
893
+ -webkit-line-clamp: 2;
894
+ -webkit-box-orient: vertical;
895
+ overflow: hidden;
896
+ `;
897
+ const SuggestionArrow = styled.span `
898
+ display: flex;
899
+ flex-shrink: 0;
900
+ color: ${TMColors.primary};
901
+ opacity: 0;
902
+ transform: translateX(-4px);
903
+ transition: opacity 0.2s ease, transform 0.2s ease;
904
+ `;
905
+ const SuggestionCard = styled.button `
906
+ display: flex;
907
+ align-items: center;
908
+ gap: 10px;
909
+ width: 100%;
910
+ min-height: 52px;
911
+ padding: 9px 12px;
912
+ border: 1px solid ${TMColors.primary}22;
913
+ border-radius: 12px;
914
+ background: linear-gradient(135deg, #ffffff 0%, ${TMColors.primary}08 100%);
915
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
916
+ color: #242424;
917
+ font-family: inherit;
918
+ font-size: 13px;
919
+ line-height: 1.35;
920
+ text-align: left;
921
+ cursor: pointer;
922
+ opacity: 0;
923
+ animation: ${suggestionIn} 0.35s ease-out forwards;
924
+ animation-delay: ${props => props.$index * 70}ms;
925
+ transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
926
+
927
+ &:hover, &:focus-visible {
928
+ border-color: ${TMColors.primary}66;
929
+ background: ${TMColors.primary}0d;
930
+ box-shadow: 0 4px 14px ${TMColors.primary}1f;
931
+ transform: translateY(-1px);
932
+ }
933
+
934
+ &:hover ${SuggestionIcon}, &:focus-visible ${SuggestionIcon} {
935
+ background: ${TMColors.primary};
936
+ color: white;
937
+ }
938
+
939
+ &:hover ${SuggestionArrow}, &:focus-visible ${SuggestionArrow} {
940
+ opacity: 1;
941
+ transform: translateX(0);
942
+ }
943
+
944
+ &:focus-visible {
945
+ outline: 2px solid ${TMColors.primary}55;
946
+ outline-offset: 2px;
947
+ }
948
+
949
+ &:active {
950
+ transform: translateY(0) scale(0.99);
951
+ }
952
+
953
+ @media (prefers-reduced-motion: reduce) {
954
+ animation: none;
955
+ opacity: 1;
956
+ transition: none;
957
+ }
958
+ `;
959
+ const FooterHint = styled.p `
960
+ margin: 6px 0 0 0;
961
+ font-size: 11px;
962
+ color: #999;
963
+ text-align: center;
964
+ `;
965
+ const ChatInputWrapper = styled.div `
966
+ position: relative;
967
+ flex: 1;
968
+ display: flex;
969
+ `;
970
+ const ChatInputTextarea = styled.textarea `
971
+ width: 100%;
972
+ padding: 14px 60px 14px 16px;
973
+ border: 2px solid #e1e5e9;
974
+ border-radius: 12px;
975
+ font-size: 15px;
976
+ font-family: inherit;
977
+ line-height: 1.5;
978
+ transition: all 0.2s ease;
979
+ background: #f8f9fa;
980
+ resize: none;
981
+ min-height: 100px;
982
+ max-height: 120px;
983
+ overflow-y: hidden;
984
+
985
+ &:focus {
986
+ outline: none;
987
+ border-color: ${TMColors.primary};
988
+ background: white;
989
+ box-shadow: 0 0 0 4px ${TMColors.primary}15;
990
+ }
991
+
992
+ &::placeholder {
993
+ color: #999;
994
+ }
995
+
996
+ &::-webkit-scrollbar {
997
+ width: 6px;
998
+ }
999
+
1000
+ &::-webkit-scrollbar-track {
1001
+ background: transparent;
1002
+ }
1003
+
1004
+ &::-webkit-scrollbar-thumb {
1005
+ background: #ccc;
1006
+ border-radius: 3px;
1007
+ }
1008
+
1009
+ &::-webkit-scrollbar-thumb:hover {
1010
+ background: #999;
1011
+ }
1012
+ `;
1013
+ const InlineSendButton = styled.button `
1014
+ position: absolute;
1015
+ bottom: 8px;
1016
+ right: 8px;
1017
+ width: 40px;
1018
+ height: 40px;
1019
+ border-radius: 10px;
1020
+ background: ${props => props.$disabled ? '#ccc' : '#4caf50'};
1021
+ border: none;
1022
+ color: white;
1023
+ cursor: ${props => props.$disabled ? 'default' : 'pointer'};
1024
+ display: flex;
1025
+ align-items: center;
1026
+ justify-content: center;
1027
+ transition: all 0.2s ease;
1028
+
1029
+ &:hover:not(:disabled) {
1030
+ background: #45a049;
1031
+ transform: scale(1.05);
1032
+ }
1033
+
1034
+ &:active:not(:disabled) {
1035
+ transform: scale(0.95);
1036
+ }
1037
+
1038
+ &:disabled {
1039
+ opacity: 0.6;
1040
+ }
888
1041
  `;