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:
MyPrototypeWhat 2025-11-11 11:01:48 +08:00
parent 0b3cefb125
commit 30947c6bc1
4 changed files with 116 additions and 277 deletions

View File

@ -9,8 +9,10 @@ const selectTriggerVariants = cva(
{
variants: {
state: {
default: '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',
default:
'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'
},
size: {

View File

@ -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>
)
}
}

View File

@ -20,7 +20,8 @@ const meta: Meta<typeof Select> = {
layout: 'centered',
docs: {
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.'
}
}
},

View File

@ -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 EditableNumber from '@renderer/components/EditableNumber'
import Scrollbar from '@renderer/components/Scrollbar'
@ -32,6 +43,13 @@ import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import OpenAISettingsGroup from './components/OpenAISettingsGroup'
// Type definition for select items
type SelectorItem<T extends string = string> = {
value: T
label: string
}
interface Props {
assistant: Assistant
}
@ -418,39 +436,51 @@ const SettingsTab: FC<Props> = (props) => {
</SettingRow>
<SettingDivider />
<SettingRow>
{/* <SettingRowTitleSmall>{t('message.message.style.label')}</SettingRowTitleSmall> */}
<Selector
size="sm"
label={t('message.message.style.label')}
selectionMode="single"
selectedKeys={messageStyle}
onSelectionChange={(value) => setMessageStyle(value)}
items={messageStyleItems}
/>
<SettingRowTitleSmall>{t('message.message.style.label')}</SettingRowTitleSmall>
<Select value={messageStyle} onValueChange={setMessageStyle}>
<SelectTrigger size="sm" className="w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{messageStyleItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</SettingRow>
<SettingDivider />
<SettingRow>
{/* <SettingRowTitleSmall>{t('message.message.multi_model_style.label')}</SettingRowTitleSmall> */}
<Selector
size="sm"
label={t('message.message.multi_model_style.label')}
selectionMode="single"
selectedKeys={multiModelMessageStyle}
onSelectionChange={(value) => setMultiModelMessageStyle(value)}
items={multiModelMessageStyleItems}
/>
<SettingRowTitleSmall>{t('message.message.multi_model_style.label')}</SettingRowTitleSmall>
<Select value={multiModelMessageStyle} onValueChange={setMultiModelMessageStyle}>
<SelectTrigger size="sm" className="w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{multiModelMessageStyleItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</SettingRow>
<SettingDivider />
<SettingRow>
{/* <SettingRowTitleSmall>{t('settings.messages.navigation.label')}</SettingRowTitleSmall> */}
<Selector
size="sm"
label={t('settings.messages.navigation.label')}
selectionMode="single"
selectedKeys={messageNavigation}
onSelectionChange={(value) => setMessageNavigation(value)}
items={messageNavigationItems}
/>
<SettingRowTitleSmall>{t('settings.messages.navigation.label')}</SettingRowTitleSmall>
<Select value={messageNavigation} onValueChange={setMessageNavigation}>
<SelectTrigger size="sm" className="w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{messageNavigationItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</SettingRow>
<SettingDivider />
<SettingRow>
@ -479,15 +509,19 @@ const SettingsTab: FC<Props> = (props) => {
<CollapsibleSettingGroup title={t('settings.math.title')} defaultExpanded={false}>
<SettingGroup>
<SettingRow>
{/* <SettingRowTitleSmall>{t('settings.math.engine.label')}</SettingRowTitleSmall> */}
<Selector
size="sm"
label={t('settings.math.engine.label')}
selectionMode="single"
selectedKeys={mathEngine}
onSelectionChange={(value) => setMathEngine(value)}
items={mathEngineItems}
/>
<SettingRowTitleSmall>{t('settings.math.engine.label')}</SettingRowTitleSmall>
<Select value={mathEngine} onValueChange={setMathEngine}>
<SelectTrigger size="sm" className="w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{mathEngineItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</SettingRow>
<SettingDivider />
<SettingRow>
@ -508,15 +542,19 @@ const SettingsTab: FC<Props> = (props) => {
<CollapsibleSettingGroup title={t('chat.settings.code.title')} defaultExpanded={false}>
<SettingGroup>
<SettingRow>
{/* <SettingRowTitleSmall>{t('message.message.code_style')}</SettingRowTitleSmall> */}
<Selector
size="sm"
label={t('message.message.code_style')}
selectionMode="single"
selectedKeys={codeStyle}
onSelectionChange={(value) => onCodeStyleChange(value)}
items={codeStyleItems}
/>
<SettingRowTitleSmall>{t('message.message.code_style')}</SettingRowTitleSmall>
<Select value={codeStyle} onValueChange={onCodeStyleChange}>
<SelectTrigger size="sm" className="w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{codeStyleItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</SettingRow>
<SettingDivider />
<SettingRow>
@ -744,28 +782,35 @@ const SettingsTab: FC<Props> = (props) => {
</SettingRow>
<SettingDivider />
<SettingRow>
{/* <SettingRowTitleSmall>{t('settings.input.target_language.label')}</SettingRowTitleSmall> */}
<Selector
size="sm"
label={t('settings.input.target_language.label')}
selectionMode="single"
selectedKeys={targetLanguage}
onSelectionChange={(value) => setTargetLanguage(value)}
placeholder={UNKNOWN.emoji + ' ' + UNKNOWN.label()}
items={targetLanguageItems}
/>
<SettingRowTitleSmall>{t('settings.input.target_language.label')}</SettingRowTitleSmall>
<Select value={targetLanguage} onValueChange={setTargetLanguage}>
<SelectTrigger size="sm" className="w-[180px]">
<SelectValue placeholder={UNKNOWN.emoji + ' ' + UNKNOWN.label()} />
</SelectTrigger>
<SelectContent>
{targetLanguageItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</SettingRow>
<SettingDivider />
<SettingRow>
{/* <SettingRowTitleSmall>{}</SettingRowTitleSmall> */}
<Selector
size="sm"
label={t('settings.messages.input.send_shortcuts')}
selectionMode="single"
selectedKeys={sendMessageShortcut}
onSelectionChange={(value) => setSendMessageShortcut(value)}
items={sendMessageShortcutItems}
/>
<SettingRowTitleSmall>{t('settings.messages.input.send_shortcuts')}</SettingRowTitleSmall>
<Select value={sendMessageShortcut} onValueChange={setSendMessageShortcut}>
<SelectTrigger size="sm" className="w-[180px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{sendMessageShortcutItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</SettingRow>
</SettingGroup>
</CollapsibleSettingGroup>