選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

header-in-mobile.tsx 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import { useCallback, useState } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import {
  4. RiMenuLine,
  5. } from '@remixicon/react'
  6. import { useChatWithHistoryContext } from './context'
  7. import Operation from './header/operation'
  8. import Sidebar from './sidebar'
  9. import MobileOperationDropdown from './header/mobile-operation-dropdown'
  10. import AppIcon from '@/app/components/base/app-icon'
  11. import ActionButton from '@/app/components/base/action-button'
  12. import { Message3Fill } from '@/app/components/base/icons/src/public/other'
  13. import InputsFormContent from '@/app/components/base/chat/chat-with-history/inputs-form/content'
  14. import Confirm from '@/app/components/base/confirm'
  15. import RenameModal from '@/app/components/base/chat/chat-with-history/sidebar/rename-modal'
  16. import type { ConversationItem } from '@/models/share'
  17. const HeaderInMobile = () => {
  18. const {
  19. appData,
  20. currentConversationId,
  21. currentConversationItem,
  22. pinnedConversationList,
  23. handleNewConversation,
  24. handlePinConversation,
  25. handleUnpinConversation,
  26. handleDeleteConversation,
  27. handleRenameConversation,
  28. conversationRenaming,
  29. inputsForms,
  30. } = useChatWithHistoryContext()
  31. const { t } = useTranslation()
  32. const isPin = pinnedConversationList.some(item => item.id === currentConversationId)
  33. const [showConfirm, setShowConfirm] = useState<ConversationItem | null>(null)
  34. const [showRename, setShowRename] = useState<ConversationItem | null>(null)
  35. const handleOperate = useCallback((type: string) => {
  36. if (type === 'pin')
  37. handlePinConversation(currentConversationId)
  38. if (type === 'unpin')
  39. handleUnpinConversation(currentConversationId)
  40. if (type === 'delete')
  41. setShowConfirm(currentConversationItem as any)
  42. if (type === 'rename')
  43. setShowRename(currentConversationItem as any)
  44. }, [currentConversationId, currentConversationItem, handlePinConversation, handleUnpinConversation])
  45. const handleCancelConfirm = useCallback(() => {
  46. setShowConfirm(null)
  47. }, [])
  48. const handleDelete = useCallback(() => {
  49. if (showConfirm)
  50. handleDeleteConversation(showConfirm.id, { onSuccess: handleCancelConfirm })
  51. }, [showConfirm, handleDeleteConversation, handleCancelConfirm])
  52. const handleCancelRename = useCallback(() => {
  53. setShowRename(null)
  54. }, [])
  55. const handleRename = useCallback((newName: string) => {
  56. if (showRename)
  57. handleRenameConversation(showRename.id, newName, { onSuccess: handleCancelRename })
  58. }, [showRename, handleRenameConversation, handleCancelRename])
  59. const [showSidebar, setShowSidebar] = useState(false)
  60. const [showChatSettings, setShowChatSettings] = useState(false)
  61. return (
  62. <>
  63. <div className='flex shrink-0 items-center gap-1 bg-mask-top2bottom-gray-50-to-transparent px-2 py-3'>
  64. <ActionButton size='l' className='shrink-0' onClick={() => setShowSidebar(true)}>
  65. <RiMenuLine className='h-[18px] w-[18px]' />
  66. </ActionButton>
  67. <div className='flex grow items-center justify-center'>
  68. {!currentConversationId && (
  69. <>
  70. <AppIcon
  71. className='mr-2'
  72. size='tiny'
  73. icon={appData?.site.icon}
  74. iconType={appData?.site.icon_type}
  75. imageUrl={appData?.site.icon_url}
  76. background={appData?.site.icon_background}
  77. />
  78. <div className='system-md-semibold truncate text-text-secondary'>
  79. {appData?.site.title}
  80. </div>
  81. </>
  82. )}
  83. {currentConversationId && (
  84. <Operation
  85. title={currentConversationItem?.name || ''}
  86. isPinned={!!isPin}
  87. togglePin={() => handleOperate(isPin ? 'unpin' : 'pin')}
  88. isShowDelete
  89. isShowRenameConversation
  90. onRenameConversation={() => handleOperate('rename')}
  91. onDelete={() => handleOperate('delete')}
  92. />
  93. )}
  94. </div>
  95. <MobileOperationDropdown
  96. handleResetChat={handleNewConversation}
  97. handleViewChatSettings={() => setShowChatSettings(true)}
  98. hideViewChatSettings={inputsForms.length < 1}
  99. />
  100. </div>
  101. {showSidebar && (
  102. <div className='fixed inset-0 z-50 flex bg-background-overlay p-1'
  103. onClick={() => setShowSidebar(false)}
  104. >
  105. <div className='flex h-full w-[calc(100vw_-_40px)] rounded-xl bg-components-panel-bg shadow-lg backdrop-blur-sm' onClick={e => e.stopPropagation()}>
  106. <Sidebar />
  107. </div>
  108. </div>
  109. )}
  110. {showChatSettings && (
  111. <div className='fixed inset-0 z-50 flex justify-end bg-background-overlay p-1'
  112. onClick={() => setShowChatSettings(false)}
  113. >
  114. <div className='flex h-full w-[calc(100vw_-_40px)] flex-col rounded-xl bg-components-panel-bg shadow-lg backdrop-blur-sm' onClick={e => e.stopPropagation()}>
  115. <div className='flex items-center gap-3 rounded-t-2xl border-b border-divider-subtle px-4 py-3'>
  116. <Message3Fill className='h-6 w-6 shrink-0' />
  117. <div className='system-xl-semibold grow text-text-secondary'>{t('share.chat.chatSettingsTitle')}</div>
  118. </div>
  119. <div className='p-4'>
  120. <InputsFormContent />
  121. </div>
  122. </div>
  123. </div>
  124. )}
  125. {!!showConfirm && (
  126. <Confirm
  127. title={t('share.chat.deleteConversation.title')}
  128. content={t('share.chat.deleteConversation.content') || ''}
  129. isShow
  130. onCancel={handleCancelConfirm}
  131. onConfirm={handleDelete}
  132. />
  133. )}
  134. {showRename && (
  135. <RenameModal
  136. isShow
  137. onClose={handleCancelRename}
  138. saveLoading={conversationRenaming}
  139. name={showRename?.name || ''}
  140. onSave={handleRename}
  141. />
  142. )}
  143. </>
  144. )
  145. }
  146. export default HeaderInMobile