feat: support pin topic to the top

Signed-off-by: jtsang4 <info@jtsang.me>
This commit is contained in:
jtsang4 2025-05-20 07:36:50 +08:00 committed by 亢奋猫
parent ee042e11f1
commit 631fa3a42a
9 changed files with 36 additions and 2 deletions

View File

@ -12,6 +12,7 @@ import {
setTheme, setTheme,
SettingsState, SettingsState,
setTopicPosition, setTopicPosition,
setPinTopicsToTop,
setTray as _setTray, setTray as _setTray,
setTrayOnClose, setTrayOnClose,
setWindowStyle setWindowStyle
@ -68,6 +69,9 @@ export function useSettings() {
setTopicPosition(topicPosition: 'left' | 'right') { setTopicPosition(topicPosition: 'left' | 'right') {
dispatch(setTopicPosition(topicPosition)) dispatch(setTopicPosition(topicPosition))
}, },
setPinTopicsToTop(pinTopicsToTop: boolean) {
dispatch(setPinTopicsToTop(pinTopicsToTop))
},
updateSidebarIcons(icons: { visible: SidebarIcon[]; disabled: SidebarIcon[] }) { updateSidebarIcons(icons: { visible: SidebarIcon[]; disabled: SidebarIcon[] }) {
dispatch(setSidebarIcons(icons)) dispatch(setSidebarIcons(icons))
}, },

View File

@ -1635,6 +1635,7 @@
"topic.position.left": "Left", "topic.position.left": "Left",
"topic.position.right": "Right", "topic.position.right": "Right",
"topic.show.time": "Show topic time", "topic.show.time": "Show topic time",
"topic.pin_to_top": "Pin Topics to Top",
"tray.onclose": "Minimize to Tray on Close", "tray.onclose": "Minimize to Tray on Close",
"tray.show": "Show Tray Icon", "tray.show": "Show Tray Icon",
"tray.title": "Tray", "tray.title": "Tray",

View File

@ -1626,6 +1626,7 @@
"topic.position.left": "左", "topic.position.left": "左",
"topic.position.right": "右", "topic.position.right": "右",
"topic.show.time": "トピックの時間を表示", "topic.show.time": "トピックの時間を表示",
"topic.pin_to_top": "固定トピックを上部に表示",
"tray.onclose": "閉じるときにトレイに最小化", "tray.onclose": "閉じるときにトレイに最小化",
"tray.show": "トレイアイコンを表示", "tray.show": "トレイアイコンを表示",
"tray.title": "トレイ", "tray.title": "トレイ",

View File

@ -1626,6 +1626,7 @@
"topic.position.left": "Слева", "topic.position.left": "Слева",
"topic.position.right": "Справа", "topic.position.right": "Справа",
"topic.show.time": "Показывать время топика", "topic.show.time": "Показывать время топика",
"topic.pin_to_top": "Закрепленные топики сверху",
"tray.onclose": "Свернуть в трей при закрытии", "tray.onclose": "Свернуть в трей при закрытии",
"tray.show": "Показать значок в трее", "tray.show": "Показать значок в трее",
"tray.title": "Трей", "tray.title": "Трей",

View File

@ -1635,6 +1635,7 @@
"topic.position.left": "左侧", "topic.position.left": "左侧",
"topic.position.right": "右侧", "topic.position.right": "右侧",
"topic.show.time": "显示话题时间", "topic.show.time": "显示话题时间",
"topic.pin_to_top": "固定话题置顶",
"tray.onclose": "关闭时最小化到托盘", "tray.onclose": "关闭时最小化到托盘",
"tray.show": "显示托盘图标", "tray.show": "显示托盘图标",
"tray.title": "托盘", "tray.title": "托盘",

View File

@ -1629,6 +1629,7 @@
"topic.position.left": "左側", "topic.position.left": "左側",
"topic.position.right": "右側", "topic.position.right": "右側",
"topic.show.time": "顯示話題時間", "topic.show.time": "顯示話題時間",
"topic.pin_to_top": "固定話題置頂",
"tray.onclose": "關閉時最小化到系统匣", "tray.onclose": "關閉時最小化到系统匣",
"tray.show": "顯示系统匣圖示", "tray.show": "顯示系统匣圖示",
"tray.title": "系统匣", "tray.title": "系统匣",

View File

@ -54,7 +54,7 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
const { assistants } = useAssistants() const { assistants } = useAssistants()
const { assistant, removeTopic, moveTopic, updateTopic, updateTopics } = useAssistant(_assistant.id) const { assistant, removeTopic, moveTopic, updateTopic, updateTopics } = useAssistant(_assistant.id)
const { t } = useTranslation() const { t } = useTranslation()
const { showTopicTime, topicPosition } = useSettings() const { showTopicTime, topicPosition, pinTopicsToTop } = useSettings()
const borderRadius = showTopicTime ? 12 : 'var(--list-item-border-radius)' const borderRadius = showTopicTime ? 12 : 'var(--list-item-border-radius)'
@ -380,10 +380,22 @@ const Topics: FC<Props> = ({ assistant: _assistant, activeTopic, setActiveTopic
targetTopic targetTopic
]) ])
// Sort topics based on pinned status if pinTopicsToTop is enabled
const sortedTopics = useMemo(() => {
if (pinTopicsToTop) {
return [...assistant.topics].sort((a, b) => {
if (a.pinned && !b.pinned) return -1
if (!a.pinned && b.pinned) return 1
return 0
})
}
return assistant.topics
}, [assistant.topics, pinTopicsToTop])
return ( return (
<Dropdown menu={{ items: getTopicMenuItems }} trigger={['contextMenu']}> <Dropdown menu={{ items: getTopicMenuItems }} trigger={['contextMenu']}>
<Container right={topicPosition === 'right'} className="topics-tab"> <Container right={topicPosition === 'right'} className="topics-tab">
<DragableList list={assistant.topics} onUpdate={updateTopics}> <DragableList list={sortedTopics} onUpdate={updateTopics}>
{(topic) => { {(topic) => {
const isActive = topic.id === activeTopic?.id const isActive = topic.id === activeTopic?.id
const topicName = topic.name.replace('`', '') const topicName = topic.name.replace('`', '')

View File

@ -9,6 +9,7 @@ import {
setAssistantIconType, setAssistantIconType,
setClickAssistantToShowTopic, setClickAssistantToShowTopic,
setCustomCss, setCustomCss,
setPinTopicsToTop,
setShowTopicTime, setShowTopicTime,
setSidebarIcons setSidebarIcons
} from '@renderer/store/settings' } from '@renderer/store/settings'
@ -32,6 +33,7 @@ const DisplaySettings: FC = () => {
setTopicPosition, setTopicPosition,
clickAssistantToShowTopic, clickAssistantToShowTopic,
showTopicTime, showTopicTime,
pinTopicsToTop,
customCss, customCss,
sidebarIcons, sidebarIcons,
assistantIconType assistantIconType
@ -189,6 +191,11 @@ const DisplaySettings: FC = () => {
<SettingRowTitle>{t('settings.topic.show.time')}</SettingRowTitle> <SettingRowTitle>{t('settings.topic.show.time')}</SettingRowTitle>
<Switch checked={showTopicTime} onChange={(checked) => dispatch(setShowTopicTime(checked))} /> <Switch checked={showTopicTime} onChange={(checked) => dispatch(setShowTopicTime(checked))} />
</SettingRow> </SettingRow>
<SettingDivider />
<SettingRow>
<SettingRowTitle>{t('settings.topic.pin_to_top')}</SettingRowTitle>
<Switch checked={pinTopicsToTop} onChange={(checked) => dispatch(setPinTopicsToTop(checked))} />
</SettingRow>
</SettingGroup> </SettingGroup>
<SettingGroup theme={theme}> <SettingGroup theme={theme}>
<SettingTitle>{t('settings.display.assistant.title')}</SettingTitle> <SettingTitle>{t('settings.display.assistant.title')}</SettingTitle>

View File

@ -52,6 +52,7 @@ export interface SettingsState {
fontSize: number fontSize: number
topicPosition: 'left' | 'right' topicPosition: 'left' | 'right'
showTopicTime: boolean showTopicTime: boolean
pinTopicsToTop: boolean
assistantIconType: AssistantIconType assistantIconType: AssistantIconType
pasteLongTextAsFile: boolean pasteLongTextAsFile: boolean
pasteLongTextThreshold: number pasteLongTextThreshold: number
@ -192,6 +193,7 @@ export const initialState: SettingsState = {
fontSize: 14, fontSize: 14,
topicPosition: 'left', topicPosition: 'left',
showTopicTime: false, showTopicTime: false,
pinTopicsToTop: false,
assistantIconType: 'emoji', assistantIconType: 'emoji',
pasteLongTextAsFile: false, pasteLongTextAsFile: false,
pasteLongTextThreshold: 1500, pasteLongTextThreshold: 1500,
@ -375,6 +377,9 @@ const settingsSlice = createSlice({
setShowTopicTime: (state, action: PayloadAction<boolean>) => { setShowTopicTime: (state, action: PayloadAction<boolean>) => {
state.showTopicTime = action.payload state.showTopicTime = action.payload
}, },
setPinTopicsToTop: (state, action: PayloadAction<boolean>) => {
state.pinTopicsToTop = action.payload
},
setAssistantIconType: (state, action: PayloadAction<AssistantIconType>) => { setAssistantIconType: (state, action: PayloadAction<AssistantIconType>) => {
state.assistantIconType = action.payload state.assistantIconType = action.payload
}, },
@ -655,6 +660,7 @@ export const {
setWindowStyle, setWindowStyle,
setTopicPosition, setTopicPosition,
setShowTopicTime, setShowTopicTime,
setPinTopicsToTop,
setAssistantIconType, setAssistantIconType,
setPasteLongTextAsFile, setPasteLongTextAsFile,
setAutoCheckUpdate, setAutoCheckUpdate,