feat: Independent Panel (#63, #120)

This commit is contained in:
josc146
2023-04-02 20:27:07 +08:00
parent 7f34dc81d4
commit 60b479729a
20 changed files with 531 additions and 38 deletions
+54
View File
@@ -0,0 +1,54 @@
import { useTranslation } from 'react-i18next'
import { useEffect, useRef, useState } from 'react'
import PropTypes from 'prop-types'
ConfirmButton.propTypes = {
onConfirm: PropTypes.func.isRequired,
text: PropTypes.string.isRequired,
}
function ConfirmButton({ onConfirm, text }) {
const { t } = useTranslation()
const [waitConfirm, setWaitConfirm] = useState(false)
const confirmRef = useRef(null)
useEffect(() => {
if (waitConfirm) confirmRef.current.focus()
}, [waitConfirm])
return (
<span>
<button
ref={confirmRef}
type="button"
className="normal-button"
style={{
...(waitConfirm ? {} : { display: 'none' }),
}}
onBlur={() => {
setWaitConfirm(false)
}}
onClick={() => {
setWaitConfirm(false)
onConfirm()
}}
>
{t('Confirm')}
</button>
<button
type="button"
className="normal-button"
style={{
...(waitConfirm ? { display: 'none' } : {}),
}}
onClick={() => {
setWaitConfirm(true)
}}
>
{text}
</button>
</span>
)
}
export default ConfirmButton
+11 -4
View File
@@ -65,8 +65,8 @@ function ConversationCard(props) {
const config = useConfig()
useEffect(() => {
if (props.onUpdate) props.onUpdate()
})
if (props.onUpdate) props.onUpdate(port, session, conversationItemData)
}, [session, conversationItemData])
useEffect(() => {
bodyRef.current.scrollTop = bodyRef.current.scrollHeight
@@ -201,6 +201,7 @@ function ConversationCard(props) {
title={t('Close the Window')}
size={16}
onClick={() => {
port.disconnect()
if (props.onClose) props.onClose()
}}
/>
@@ -217,7 +218,7 @@ function ConversationCard(props) {
<img src={logo} style="user-select:none;width:20px;height:20px;" />
)}
<select
style={{ width: windowSize[0] * 0.05 + 'px' }}
style={props.notClampSize ? {} : { width: windowSize[0] * 0.05 + 'px' }}
className="normal-button"
required
onChange={(e) => {
@@ -275,6 +276,7 @@ function ConversationCard(props) {
)}
<DeleteButton
size={16}
text={t('Clear Conversation')}
onConfirm={() => {
port.postMessage({ stop: true })
Browser.runtime.sendMessage({
@@ -309,7 +311,11 @@ function ConversationCard(props) {
<div
ref={bodyRef}
className="markdown-body"
style={{ maxHeight: windowSize[1] * 0.75 + 'px' }}
style={
props.notClampSize
? { flexGrow: 1 }
: { maxHeight: windowSize[1] * 0.75 + 'px', resize: 'vertical' }
}
>
{conversationItemData.map((data, idx) => (
<ConversationItem
@@ -356,6 +362,7 @@ ConversationCard.propTypes = {
onClose: PropTypes.func,
dockable: PropTypes.bool,
onDock: PropTypes.func,
notClampSize: PropTypes.bool,
}
export default memo(ConversationCard)
+12 -12
View File
@@ -80,11 +80,10 @@ function DecisionCard(props) {
return <ConversationCard session={props.session} question={question} />
}
return (
<p
className="gpt-inner manual-btn icon-and-text"
onClick={() => setTriggered(true)}
>
<SearchIcon size="small" /> {t('Ask ChatGPT')}
<p className="gpt-inner manual-btn" onClick={() => setTriggered(true)}>
<span className="icon-and-text">
<SearchIcon size="small" /> {t('Ask ChatGPT')}
</span>
</p>
)
case 'questionMark':
@@ -95,18 +94,19 @@ function DecisionCard(props) {
return <ConversationCard session={props.session} question={question} />
}
return (
<p
className="gpt-inner manual-btn icon-and-text"
onClick={() => setTriggered(true)}
>
<SearchIcon size="small" /> {t('Ask ChatGPT')}
<p className="gpt-inner manual-btn" onClick={() => setTriggered(true)}>
<span className="icon-and-text">
<SearchIcon size="small" /> {t('Ask ChatGPT')}
</span>
</p>
)
}
else
return (
<p className="gpt-inner icon-and-text">
<LightBulbIcon size="small" /> {t('No Input Found')}
<p className="gpt-inner">
<span className="icon-and-text">
<LightBulbIcon size="small" /> {t('No Input Found')}
</span>
</p>
)
})()}
+3 -2
View File
@@ -6,9 +6,10 @@ import { TrashIcon } from '@primer/octicons-react'
DeleteButton.propTypes = {
onConfirm: PropTypes.func.isRequired,
size: PropTypes.number.isRequired,
text: PropTypes.string.isRequired,
}
function DeleteButton({ onConfirm, size }) {
function DeleteButton({ onConfirm, size, text }) {
const { t } = useTranslation()
const [waitConfirm, setWaitConfirm] = useState(false)
const confirmRef = useRef(null)
@@ -38,7 +39,7 @@ function DeleteButton({ onConfirm, size }) {
{t('Confirm')}
</button>
<span
title={t('Clear Conversation')}
title={text}
className="gpt-util-icon"
style={waitConfirm ? { display: 'none' } : {}}
onClick={() => {