mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 11:44:28 +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: {
|
||||
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: {
|
||||
|
||||
@ -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',
|
||||
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.'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user