mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-08 22:39:36 +08:00
refactor(select): replace Selector component with new Select implementation in SettingsTab
- Updated SettingsTab to utilize the new Select component instead of the deprecated Selector. - Enhanced Select integration with SelectTrigger, SelectContent, SelectItem, and SelectValue for improved functionality. - Removed Selector imports and related code to streamline the component structure. - Adjusted styles and layout for better user experience in the settings interface.
This commit is contained in:
parent
0b3cefb125
commit
30947c6bc1
@ -9,8 +9,10 @@ const selectTriggerVariants = cva(
|
|||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
state: {
|
state: {
|
||||||
default: 'bg-zinc-50 dark:bg-zinc-900 border-border aria-expanded:border-primary aria-expanded:ring-3 aria-expanded:ring-primary/20',
|
default:
|
||||||
error: 'bg-zinc-50 dark:bg-zinc-900 border border-destructive! aria-expanded:ring-3 aria-expanded:ring-red-600/20',
|
'bg-zinc-50 dark:bg-zinc-900 border-border aria-expanded:border-primary aria-expanded:ring-3 aria-expanded:ring-primary/20',
|
||||||
|
error:
|
||||||
|
'bg-zinc-50 dark:bg-zinc-900 border border-destructive! aria-expanded:ring-3 aria-expanded:ring-red-600/20',
|
||||||
disabled: 'opacity-50 cursor-not-allowed pointer-events-none bg-zinc-50 dark:bg-zinc-900'
|
disabled: 'opacity-50 cursor-not-allowed pointer-events-none bg-zinc-50 dark:bg-zinc-900'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
|
|||||||
@ -1,209 +0,0 @@
|
|||||||
import type { Meta } from '@storybook/react'
|
|
||||||
import { useState } from 'react'
|
|
||||||
|
|
||||||
import { Selector } from '../../../src/components'
|
|
||||||
|
|
||||||
const meta: Meta<typeof Selector> = {
|
|
||||||
title: 'Components/Composites/Selector',
|
|
||||||
component: Selector,
|
|
||||||
parameters: {
|
|
||||||
layout: 'padded'
|
|
||||||
},
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
items: {
|
|
||||||
control: false,
|
|
||||||
description: '选项数组'
|
|
||||||
},
|
|
||||||
selectedKeys: {
|
|
||||||
control: false,
|
|
||||||
description: '选中的键值集合'
|
|
||||||
},
|
|
||||||
onSelectionChange: {
|
|
||||||
control: false,
|
|
||||||
description: '选择变化回调函数'
|
|
||||||
},
|
|
||||||
selectionMode: {
|
|
||||||
control: 'select',
|
|
||||||
options: ['single', 'multiple'],
|
|
||||||
description: '选择模式'
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
control: 'text',
|
|
||||||
description: '占位符文本'
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
control: 'select',
|
|
||||||
options: ['sm', 'md', 'lg'],
|
|
||||||
description: 'HeroUI 大小变体'
|
|
||||||
},
|
|
||||||
isDisabled: {
|
|
||||||
control: 'boolean',
|
|
||||||
description: '是否禁用'
|
|
||||||
},
|
|
||||||
className: {
|
|
||||||
control: 'text',
|
|
||||||
description: '自定义类名'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default meta
|
|
||||||
|
|
||||||
// 基础用法 - 单选
|
|
||||||
export const Default = {
|
|
||||||
render: function Render() {
|
|
||||||
const [selectedValue, setSelectedValue] = useState<string>('react')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Selector
|
|
||||||
selectionMode="single"
|
|
||||||
selectedKeys={selectedValue}
|
|
||||||
onSelectionChange={(value) => setSelectedValue(value)}
|
|
||||||
placeholder="选择框架"
|
|
||||||
items={[
|
|
||||||
{ value: 'react', label: 'React' },
|
|
||||||
{ value: 'vue', label: 'Vue' },
|
|
||||||
{ value: 'angular', label: 'Angular' },
|
|
||||||
{ value: 'svelte', label: 'Svelte' }
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<div className="text-sm text-gray-600">
|
|
||||||
当前选择: <code>{selectedValue}</code>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 多选模式
|
|
||||||
export const Multiple = {
|
|
||||||
render: function Render() {
|
|
||||||
const [selectedValues, setSelectedValues] = useState<string[]>(['react', 'vue'])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Selector
|
|
||||||
selectionMode="multiple"
|
|
||||||
selectedKeys={selectedValues}
|
|
||||||
onSelectionChange={(values) => setSelectedValues(values)}
|
|
||||||
placeholder="选择多个框架"
|
|
||||||
items={[
|
|
||||||
{ value: 'react', label: 'React' },
|
|
||||||
{ value: 'vue', label: 'Vue' },
|
|
||||||
{ value: 'angular', label: 'Angular' },
|
|
||||||
{ value: 'svelte', label: 'Svelte' },
|
|
||||||
{ value: 'solid', label: 'Solid' }
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<div className="text-sm text-gray-600">
|
|
||||||
已选择 ({selectedValues.length}): {selectedValues.join(', ')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数字值类型
|
|
||||||
export const NumberValues = {
|
|
||||||
render: function Render() {
|
|
||||||
const [selectedValue, setSelectedValue] = useState<number>(2)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Selector
|
|
||||||
selectionMode="single"
|
|
||||||
selectedKeys={selectedValue}
|
|
||||||
onSelectionChange={(value) => setSelectedValue(value)}
|
|
||||||
placeholder="选择优先级"
|
|
||||||
items={[
|
|
||||||
{ value: 1, label: '🔴 紧急' },
|
|
||||||
{ value: 2, label: '🟠 高' },
|
|
||||||
{ value: 3, label: '🟡 中' },
|
|
||||||
{ value: 4, label: '🟢 低' }
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<div className="text-sm text-gray-600">
|
|
||||||
优先级值: <code>{selectedValue}</code> (类型: {typeof selectedValue})
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不同大小
|
|
||||||
export const Sizes = {
|
|
||||||
render: function Render() {
|
|
||||||
const items = [
|
|
||||||
{ value: 'option1', label: '选项 1' },
|
|
||||||
{ value: 'option2', label: '选项 2' },
|
|
||||||
{ value: 'option3', label: '选项 3' }
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2">小尺寸 (sm)</label>
|
|
||||||
<Selector size="sm" placeholder="选择一个选项" items={items} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2">中等尺寸 (md)</label>
|
|
||||||
<Selector size="md" placeholder="选择一个选项" items={items} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2">大尺寸 (lg)</label>
|
|
||||||
<Selector size="lg" placeholder="选择一个选项" items={items} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 禁用状态
|
|
||||||
export const Disabled = {
|
|
||||||
render: function Render() {
|
|
||||||
return (
|
|
||||||
<Selector
|
|
||||||
isDisabled
|
|
||||||
selectedKeys="react"
|
|
||||||
placeholder="禁用的选择器"
|
|
||||||
items={[
|
|
||||||
{ value: 'react', label: 'React' },
|
|
||||||
{ value: 'vue', label: 'Vue' }
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 实际应用场景:语言选择
|
|
||||||
export const LanguageSelector = {
|
|
||||||
render: function Render() {
|
|
||||||
const [selectedValue, setSelectedValue] = useState<string>('zh')
|
|
||||||
|
|
||||||
const languages = [
|
|
||||||
{ value: 'zh', label: '🇨🇳 简体中文' },
|
|
||||||
{ value: 'en', label: '🇺🇸 English' },
|
|
||||||
{ value: 'ja', label: '🇯🇵 日本語' },
|
|
||||||
{ value: 'ko', label: '🇰🇷 한국어' },
|
|
||||||
{ value: 'fr', label: '🇫🇷 Français' },
|
|
||||||
{ value: 'de', label: '🇩🇪 Deutsch' }
|
|
||||||
]
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<Selector
|
|
||||||
selectionMode="single"
|
|
||||||
selectedKeys={selectedValue}
|
|
||||||
onSelectionChange={(value) => setSelectedValue(value)}
|
|
||||||
placeholder="选择语言"
|
|
||||||
items={languages}
|
|
||||||
/>
|
|
||||||
<div className="p-4 bg-gray-100 dark:bg-gray-800 rounded">
|
|
||||||
当前语言: <strong>{languages.find((l) => l.value === selectedValue)?.label}</strong>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -20,7 +20,8 @@ const meta: Meta<typeof Select> = {
|
|||||||
layout: 'centered',
|
layout: 'centered',
|
||||||
docs: {
|
docs: {
|
||||||
description: {
|
description: {
|
||||||
component: 'A dropdown select component based on Radix UI, with support for groups, separators, and custom content.'
|
component:
|
||||||
|
'A dropdown select component based on Radix UI, with support for groups, separators, and custom content.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,15 @@
|
|||||||
import { Button, DescriptionSwitch, HelpTooltip, RowFlex, Selector, type SelectorItem, Switch } from '@cherrystudio/ui'
|
import {
|
||||||
|
Button,
|
||||||
|
DescriptionSwitch,
|
||||||
|
HelpTooltip,
|
||||||
|
RowFlex,
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
Switch
|
||||||
|
} from '@cherrystudio/ui'
|
||||||
import { useMultiplePreferences, usePreference } from '@data/hooks/usePreference'
|
import { useMultiplePreferences, usePreference } from '@data/hooks/usePreference'
|
||||||
import EditableNumber from '@renderer/components/EditableNumber'
|
import EditableNumber from '@renderer/components/EditableNumber'
|
||||||
import Scrollbar from '@renderer/components/Scrollbar'
|
import Scrollbar from '@renderer/components/Scrollbar'
|
||||||
@ -32,6 +43,13 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import OpenAISettingsGroup from './components/OpenAISettingsGroup'
|
import OpenAISettingsGroup from './components/OpenAISettingsGroup'
|
||||||
|
|
||||||
|
// Type definition for select items
|
||||||
|
type SelectorItem<T extends string = string> = {
|
||||||
|
value: T
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
assistant: Assistant
|
assistant: Assistant
|
||||||
}
|
}
|
||||||
@ -418,39 +436,51 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
{/* <SettingRowTitleSmall>{t('message.message.style.label')}</SettingRowTitleSmall> */}
|
<SettingRowTitleSmall>{t('message.message.style.label')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Select value={messageStyle} onValueChange={setMessageStyle}>
|
||||||
size="sm"
|
<SelectTrigger size="sm" className="w-[180px]">
|
||||||
label={t('message.message.style.label')}
|
<SelectValue />
|
||||||
selectionMode="single"
|
</SelectTrigger>
|
||||||
selectedKeys={messageStyle}
|
<SelectContent>
|
||||||
onSelectionChange={(value) => setMessageStyle(value)}
|
{messageStyleItems.map((item) => (
|
||||||
items={messageStyleItems}
|
<SelectItem key={item.value} value={item.value}>
|
||||||
/>
|
{item.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
{/* <SettingRowTitleSmall>{t('message.message.multi_model_style.label')}</SettingRowTitleSmall> */}
|
<SettingRowTitleSmall>{t('message.message.multi_model_style.label')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Select value={multiModelMessageStyle} onValueChange={setMultiModelMessageStyle}>
|
||||||
size="sm"
|
<SelectTrigger size="sm" className="w-[180px]">
|
||||||
label={t('message.message.multi_model_style.label')}
|
<SelectValue />
|
||||||
selectionMode="single"
|
</SelectTrigger>
|
||||||
selectedKeys={multiModelMessageStyle}
|
<SelectContent>
|
||||||
onSelectionChange={(value) => setMultiModelMessageStyle(value)}
|
{multiModelMessageStyleItems.map((item) => (
|
||||||
items={multiModelMessageStyleItems}
|
<SelectItem key={item.value} value={item.value}>
|
||||||
/>
|
{item.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
{/* <SettingRowTitleSmall>{t('settings.messages.navigation.label')}</SettingRowTitleSmall> */}
|
<SettingRowTitleSmall>{t('settings.messages.navigation.label')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Select value={messageNavigation} onValueChange={setMessageNavigation}>
|
||||||
size="sm"
|
<SelectTrigger size="sm" className="w-[180px]">
|
||||||
label={t('settings.messages.navigation.label')}
|
<SelectValue />
|
||||||
selectionMode="single"
|
</SelectTrigger>
|
||||||
selectedKeys={messageNavigation}
|
<SelectContent>
|
||||||
onSelectionChange={(value) => setMessageNavigation(value)}
|
{messageNavigationItems.map((item) => (
|
||||||
items={messageNavigationItems}
|
<SelectItem key={item.value} value={item.value}>
|
||||||
/>
|
{item.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
@ -479,15 +509,19 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
<CollapsibleSettingGroup title={t('settings.math.title')} defaultExpanded={false}>
|
<CollapsibleSettingGroup title={t('settings.math.title')} defaultExpanded={false}>
|
||||||
<SettingGroup>
|
<SettingGroup>
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
{/* <SettingRowTitleSmall>{t('settings.math.engine.label')}</SettingRowTitleSmall> */}
|
<SettingRowTitleSmall>{t('settings.math.engine.label')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Select value={mathEngine} onValueChange={setMathEngine}>
|
||||||
size="sm"
|
<SelectTrigger size="sm" className="w-[180px]">
|
||||||
label={t('settings.math.engine.label')}
|
<SelectValue />
|
||||||
selectionMode="single"
|
</SelectTrigger>
|
||||||
selectedKeys={mathEngine}
|
<SelectContent>
|
||||||
onSelectionChange={(value) => setMathEngine(value)}
|
{mathEngineItems.map((item) => (
|
||||||
items={mathEngineItems}
|
<SelectItem key={item.value} value={item.value}>
|
||||||
/>
|
{item.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
@ -508,15 +542,19 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
<CollapsibleSettingGroup title={t('chat.settings.code.title')} defaultExpanded={false}>
|
<CollapsibleSettingGroup title={t('chat.settings.code.title')} defaultExpanded={false}>
|
||||||
<SettingGroup>
|
<SettingGroup>
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
{/* <SettingRowTitleSmall>{t('message.message.code_style')}</SettingRowTitleSmall> */}
|
<SettingRowTitleSmall>{t('message.message.code_style')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Select value={codeStyle} onValueChange={onCodeStyleChange}>
|
||||||
size="sm"
|
<SelectTrigger size="sm" className="w-[180px]">
|
||||||
label={t('message.message.code_style')}
|
<SelectValue />
|
||||||
selectionMode="single"
|
</SelectTrigger>
|
||||||
selectedKeys={codeStyle}
|
<SelectContent>
|
||||||
onSelectionChange={(value) => onCodeStyleChange(value)}
|
{codeStyleItems.map((item) => (
|
||||||
items={codeStyleItems}
|
<SelectItem key={item.value} value={item.value}>
|
||||||
/>
|
{item.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
@ -744,28 +782,35 @@ const SettingsTab: FC<Props> = (props) => {
|
|||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
{/* <SettingRowTitleSmall>{t('settings.input.target_language.label')}</SettingRowTitleSmall> */}
|
<SettingRowTitleSmall>{t('settings.input.target_language.label')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Select value={targetLanguage} onValueChange={setTargetLanguage}>
|
||||||
size="sm"
|
<SelectTrigger size="sm" className="w-[180px]">
|
||||||
label={t('settings.input.target_language.label')}
|
<SelectValue placeholder={UNKNOWN.emoji + ' ' + UNKNOWN.label()} />
|
||||||
selectionMode="single"
|
</SelectTrigger>
|
||||||
selectedKeys={targetLanguage}
|
<SelectContent>
|
||||||
onSelectionChange={(value) => setTargetLanguage(value)}
|
{targetLanguageItems.map((item) => (
|
||||||
placeholder={UNKNOWN.emoji + ' ' + UNKNOWN.label()}
|
<SelectItem key={item.value} value={item.value}>
|
||||||
items={targetLanguageItems}
|
{item.label}
|
||||||
/>
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
<SettingDivider />
|
<SettingDivider />
|
||||||
<SettingRow>
|
<SettingRow>
|
||||||
{/* <SettingRowTitleSmall>{}</SettingRowTitleSmall> */}
|
<SettingRowTitleSmall>{t('settings.messages.input.send_shortcuts')}</SettingRowTitleSmall>
|
||||||
<Selector
|
<Select value={sendMessageShortcut} onValueChange={setSendMessageShortcut}>
|
||||||
size="sm"
|
<SelectTrigger size="sm" className="w-[180px]">
|
||||||
label={t('settings.messages.input.send_shortcuts')}
|
<SelectValue />
|
||||||
selectionMode="single"
|
</SelectTrigger>
|
||||||
selectedKeys={sendMessageShortcut}
|
<SelectContent>
|
||||||
onSelectionChange={(value) => setSendMessageShortcut(value)}
|
{sendMessageShortcutItems.map((item) => (
|
||||||
items={sendMessageShortcutItems}
|
<SelectItem key={item.value} value={item.value}>
|
||||||
/>
|
{item.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
</SettingGroup>
|
</SettingGroup>
|
||||||
</CollapsibleSettingGroup>
|
</CollapsibleSettingGroup>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user