diff --git a/eslint.config.mjs b/eslint.config.mjs index ef610da5fb..2ff7fd9f41 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -143,19 +143,31 @@ export default defineConfig([ files: ['**/*.{ts,tsx,js,jsx}'], ignores: [], rules: { - // 'no-restricted-imports': [ - // 'error', - // { - // paths: [ - // { - // name: 'antd', - // importNames: ['Flex', 'Switch', 'message', 'Button', 'Tooltip'], - // message: - // '❌ Do not import this component from antd. Use our custom components instead: import { ... } from "@cherrystudio/ui"' - // } - // ] - // } - // ] + 'no-restricted-imports': [ + 'error', + { + paths: [ + // { + // name: 'antd', + // importNames: ['Flex', 'Switch', 'message', 'Button', 'Tooltip'], + // message: + // '❌ Do not import this component from antd. Use our custom components instead: import { ... } from "@cherrystudio/ui"' + // }, + { + name: 'antd', + importNames: ['Switch'], + message: + '❌ Do not import this component from antd. Use our custom components instead: import { ... } from "@cherrystudio/ui"' + }, + { + name: '@heroui/react', + importNames: ['Switch'], + message: + '❌ Do not import the component from heroui directly. It\'s deprecated.' + } + ] + } + ] } }, // Schema key naming convention (cache & preferences) diff --git a/package.json b/package.json index 794e0ab309..4e1ac0061b 100644 --- a/package.json +++ b/package.json @@ -179,6 +179,7 @@ "@opeoginni/github-copilot-openai-compatible": "^0.1.21", "@playwright/test": "^1.55.1", "@radix-ui/react-context-menu": "^2.2.16", + "@radix-ui/react-switch": "^1.2.6", "@reduxjs/toolkit": "^2.2.5", "@shikijs/markdown-it": "^3.12.0", "@swc/plugin-styled-components": "^8.0.4", diff --git a/packages/ui/src/components/primitives/switch.tsx b/packages/ui/src/components/primitives/switch.tsx index 51d9721603..7ce2ac5d3c 100644 --- a/packages/ui/src/components/primitives/switch.tsx +++ b/packages/ui/src/components/primitives/switch.tsx @@ -1,54 +1,178 @@ -import type { SwitchProps } from '@heroui/react' -import { cn, Spinner, Switch } from '@heroui/react' +import { cn } from '@cherrystudio/ui/utils' +import * as SwitchPrimitive from '@radix-ui/react-switch' +import { cva } from 'class-variance-authority' +import * as React from 'react' +import { useId } from 'react' + +const switchRootVariants = cva( + [ + 'cs-switch cs-switch-root', + 'group relative cursor-pointer peer inline-flex shrink-0 items-center rounded-full shadow-xs outline-none transition-all', + 'data-[state=unchecked]:bg-gray-500/20 data-[state=checked]:bg-primary', + 'disabled:cursor-not-allowed disabled:opacity-40', + 'focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50' + ], + { + variants: { + size: { + sm: ['w-9 h-5'], + md: ['w-11 h-5.5'], + lg: ['w-11 h-6'] + }, + loading: { + false: null, + true: ['bg-primary-hover!'] + } + }, + defaultVariants: { + size: 'md', + loading: false + } + } +) + +const switchThumbVariants = cva( + [ + 'cs-switch cs-switch-thumb', + 'pointer-events-none block rounded-full ring-0 transition-all data-[state=unchecked]:translate-x-0' + ], + { + variants: { + size: { + sm: ['size-4.5 ml-[1px] data-[state=checked]:translate-x-4'], + md: ['size-[19px] ml-0.5 data-[state=checked]:translate-x-[21px]'], + lg: ['size-5 ml-[3px] data-[state=checked]:translate-x-4.5'] + }, + loading: { + false: null, + true: ['bg-primary-hover!'] + } + }, + compoundVariants: [ + { + size: 'sm', + loading: true, + className: 'size-3.5 ml-0.5 data-[state=checked]:translate-x-4.5' + }, + { + size: 'md', + loading: true, + className: 'size-4 ml-1 data-[state=checked]:translate-x-5' + }, + { + size: 'lg', + loading: true, + className: 'size-4.5 ml-1 data-[state=checked]:translate-x-4.5' + } + ] + } +) + +const switchThumbSvgVariants = cva(['transition-all'], { + variants: { + loading: { + false: null, + true: ['animate-spin'] + } + }, + defaultVariants: { + loading: false + } +}) // Enhanced Switch component with loading state support -interface CustomSwitchProps extends SwitchProps { - isLoading?: boolean +interface SwitchProps extends Omit, 'children'> { + /** When true, displays a loading animation in the switch thumb. Defaults to false when undefined. */ + loading?: boolean + size?: 'sm' | 'md' | 'lg' + classNames?: { + root?: string + thumb?: string + thumbSvg?: string + } } -/** - * A customized Switch component based on HeroUI Switch - * @see https://www.heroui.com/docs/components/switch#api - * @param isLoading When true, displays a loading spinner in the switch thumb - */ -const CustomizedSwitch = ({ isLoading, children, ref, thumbIcon, ...props }: CustomSwitchProps) => { - const finalThumbIcon = isLoading ? : thumbIcon - +function Switch({ loading = false, size = 'md', className, classNames, ...props }: SwitchProps) { return ( - - {children} - - ) -} - -const DescriptionSwitch = ({ children, ...props }: CustomSwitchProps) => { - return ( - - {children} - + + + + + + ) } -CustomizedSwitch.displayName = 'Switch' +interface DescriptionSwitchProps extends SwitchProps { + /** Text label displayed next to the switch. */ + label: string + /** Optional helper text shown below the label. */ + description?: string + /** Switch position relative to label. Defaults to 'right'. */ + position?: 'left' | 'right' +} -export { DescriptionSwitch, CustomizedSwitch as Switch } -export type { CustomSwitchProps as SwitchProps } +// TODO: It's not finished. We need to use Typography components instead of native html element. +const DescriptionSwitch = ({ + label, + description, + position = 'right', + size = 'md', + ...props +}: DescriptionSwitchProps) => { + const isLeftSide = position === 'left' + const id = useId() + return ( +
+ +
+ +
+
+ ) +} + +Switch.displayName = 'Switch' + +export { DescriptionSwitch, Switch } +export type { SwitchProps } diff --git a/packages/ui/stories/components/primitives/DescriptionSwitch.stories.tsx b/packages/ui/stories/components/primitives/DescriptionSwitch.stories.tsx new file mode 100644 index 0000000000..9587870e27 --- /dev/null +++ b/packages/ui/stories/components/primitives/DescriptionSwitch.stories.tsx @@ -0,0 +1,823 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { Bell, Eye, Lock, Moon, Shield, Wifi, Zap } from 'lucide-react' +import { useState } from 'react' + +import { DescriptionSwitch } from '../../../src/components/primitives/switch' + +const meta: Meta = { + title: 'Components/Primitives/DescriptionSwitch', + component: DescriptionSwitch, + parameters: { + layout: 'centered', + docs: { + description: { + component: + 'An enhanced Switch component with integrated label and optional description text. Perfect for settings panels and preference forms where context is important. Built on top of the Radix UI Switch primitive with support for multiple sizes, loading states, and flexible positioning.' + } + } + }, + tags: ['autodocs'], + argTypes: { + label: { + control: { type: 'text' }, + description: 'Text label displayed next to the switch (required)' + }, + description: { + control: { type: 'text' }, + description: 'Optional helper text shown below the label' + }, + position: { + control: { type: 'select' }, + options: ['left', 'right'], + description: 'Switch position relative to label' + }, + disabled: { + control: { type: 'boolean' }, + description: 'Whether the switch is disabled' + }, + loading: { + control: { type: 'boolean' }, + description: 'When true, displays a loading animation in the switch thumb' + }, + size: { + control: { type: 'select' }, + options: ['sm', 'md', 'lg'], + description: 'The size of the switch' + }, + defaultChecked: { + control: { type: 'boolean' }, + description: 'Default checked state' + }, + checked: { + control: { type: 'boolean' }, + description: 'Checked state in controlled mode' + } + } +} + +export default meta +type Story = StoryObj + +// Default +export const Default: Story = { + render: () => ( +
+ +
+ ) +} + +// Without Description +export const WithoutDescription: Story = { + render: () => ( +
+ + + +
+ ) +} + +// With Description +export const WithDescription: Story = { + render: () => ( +
+ + + +
+ ) +} + +// Positions +export const Positions: Story = { + render: () => ( +
+
+

Switch on Right (Default)

+
+ + + +
+
+ +
+

Switch on Left

+
+ + + +
+
+
+ ) +} + +// Sizes +export const Sizes: Story = { + render: () => ( +
+
+

Small (sm)

+ +
+ +
+

Medium (md) - Default

+ +
+ +
+

Large (lg)

+ +
+
+ ) +} + +// States +export const States: Story = { + render: () => ( +
+
+

Normal (Unchecked)

+ +
+ +
+

Checked

+ +
+ +
+

Disabled (Unchecked)

+ +
+ +
+

Disabled (Checked)

+ +
+ +
+

Loading

+ +
+
+ ) +} + +// Controlled +export const Controlled: Story = { + render: function ControlledExample() { + const [checked, setChecked] = useState(false) + + return ( +
+
+ +
+
+
Current state: {checked ? 'On' : 'Off'}
+ +
+
+ ) + } +} + +// Long Text +export const LongText: Story = { + render: () => ( +
+ + +
+ ) +} + +// Notification Settings Example +export const NotificationSettings: Story = { + render: function NotificationSettingsExample() { + const [notifications, setNotifications] = useState({ + email: true, + push: false, + sms: false, + desktop: true, + mobile: false, + weekly: true + }) + + return ( +
+
+

Notification Preferences

+
+ setNotifications({ ...notifications, email: !!checked })} + /> + setNotifications({ ...notifications, push: !!checked })} + /> + setNotifications({ ...notifications, sms: !!checked })} + /> + setNotifications({ ...notifications, desktop: !!checked })} + /> + setNotifications({ ...notifications, mobile: !!checked })} + /> + setNotifications({ ...notifications, weekly: !!checked })} + /> +
+
+
+ ) + } +} + +// Privacy Settings Example +export const PrivacySettings: Story = { + render: function PrivacySettingsExample() { + const [privacy, setPrivacy] = useState({ + profileVisible: true, + activityTracking: false, + dataSharing: false, + personalization: true, + thirdParty: false + }) + + return ( +
+
+

Privacy & Data

+
+ setPrivacy({ ...privacy, profileVisible: !!checked })} + /> + setPrivacy({ ...privacy, activityTracking: !!checked })} + /> + setPrivacy({ ...privacy, dataSharing: !!checked })} + /> + setPrivacy({ ...privacy, personalization: !!checked })} + /> + setPrivacy({ ...privacy, thirdParty: !!checked })} + /> +
+
+
+ ) + } +} + +// Application Settings Example +export const ApplicationSettings: Story = { + render: function ApplicationSettingsExample() { + const [settings, setSettings] = useState({ + autoSave: true, + spellCheck: true, + darkMode: false, + compactMode: false, + animations: true, + sound: false, + offlineMode: false + }) + + return ( +
+
+

Application Settings

+
+ setSettings({ ...settings, autoSave: !!checked })} + /> + setSettings({ ...settings, spellCheck: !!checked })} + /> + setSettings({ ...settings, darkMode: !!checked })} + /> + setSettings({ ...settings, compactMode: !!checked })} + /> + setSettings({ ...settings, animations: !!checked })} + /> + setSettings({ ...settings, sound: !!checked })} + /> + setSettings({ ...settings, offlineMode: !!checked })} + /> +
+
+
+ ) + } +} + +// With Icons +export const WithIcons: Story = { + render: () => ( +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ ) +} + +// Loading Simulation +export const LoadingSimulation: Story = { + render: function LoadingSimulationExample() { + const [states, setStates] = useState({ + wifi: { enabled: false, loading: false }, + bluetooth: { enabled: false, loading: false }, + location: { enabled: false, loading: false } + }) + + const handleToggle = async (setting: keyof typeof states, checked: boolean) => { + setStates((prev) => ({ + ...prev, + [setting]: { ...prev[setting], loading: true } + })) + + // Simulate API call + await new Promise((resolve) => setTimeout(resolve, 1500)) + + setStates((prev) => ({ + ...prev, + [setting]: { enabled: checked, loading: false } + })) + } + + return ( +
+
+

System Settings

+
+ handleToggle('wifi', !!checked)} + loading={states.wifi.loading} + disabled={states.wifi.loading} + /> + handleToggle('bluetooth', !!checked)} + loading={states.bluetooth.loading} + disabled={states.bluetooth.loading} + /> + handleToggle('location', !!checked)} + loading={states.location.loading} + disabled={states.location.loading} + /> +
+
+

Toggle switches to see a simulated 1.5-second loading state

+
+ ) + } +} + +// Complex Settings Panel +export const ComplexSettingsPanel: Story = { + render: function ComplexSettingsPanelExample() { + const [settings, setSettings] = useState({ + notifications: { + email: true, + push: false, + desktop: true + }, + privacy: { + profile: true, + activity: false, + analytics: true + }, + features: { + autoSave: true, + darkMode: false, + compactView: false + }, + security: { + twoFactor: false, + biometric: true, + sessionTimeout: false + } + }) + + return ( +
+ {/* Notifications Section */} +
+
+ +

Notifications

+
+
+ + setSettings({ + ...settings, + notifications: { ...settings.notifications, email: !!checked } + }) + } + /> + + setSettings({ + ...settings, + notifications: { ...settings.notifications, push: !!checked } + }) + } + /> + + setSettings({ + ...settings, + notifications: { ...settings.notifications, desktop: !!checked } + }) + } + /> +
+
+ + {/* Privacy Section */} +
+
+ +

Privacy

+
+
+ + setSettings({ + ...settings, + privacy: { ...settings.privacy, profile: !!checked } + }) + } + /> + + setSettings({ + ...settings, + privacy: { ...settings.privacy, activity: !!checked } + }) + } + /> + + setSettings({ + ...settings, + privacy: { ...settings.privacy, analytics: !!checked } + }) + } + /> +
+
+ + {/* Features Section */} +
+
+ +

Features

+
+
+ + setSettings({ + ...settings, + features: { ...settings.features, autoSave: !!checked } + }) + } + /> + + setSettings({ + ...settings, + features: { ...settings.features, darkMode: !!checked } + }) + } + /> + + setSettings({ + ...settings, + features: { ...settings.features, compactView: !!checked } + }) + } + /> +
+
+ + {/* Security Section */} +
+
+ +

Security

+
+
+ + setSettings({ + ...settings, + security: { ...settings.security, twoFactor: !!checked } + }) + } + /> + + setSettings({ + ...settings, + security: { ...settings.security, biometric: !!checked } + }) + } + /> + + setSettings({ + ...settings, + security: { ...settings.security, sessionTimeout: !!checked } + }) + } + /> +
+
+
+ ) + } +} + +// Accessibility Features +export const AccessibilityFeatures: Story = { + render: () => ( +
+
+

Keyboard Navigation

+

+ Use Tab to navigate between switches and Space/Enter to toggle them. Each switch has a proper label for screen + readers. +

+
+ + + + +
+
+
+ ) +} + +// Responsive Layout +export const ResponsiveLayout: Story = { + render: () => ( +
+
+

Narrow Layout (300px)

+
+ + +
+
+ +
+

Standard Layout (500px)

+
+ + +
+
+ +
+

Wide Layout (700px)

+
+ + +
+
+
+ ) +} diff --git a/packages/ui/stories/components/primitives/Switch.stories.tsx b/packages/ui/stories/components/primitives/Switch.stories.tsx new file mode 100644 index 0000000000..958701496c --- /dev/null +++ b/packages/ui/stories/components/primitives/Switch.stories.tsx @@ -0,0 +1,666 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { Bell, Moon, Shield, Wifi, Zap } from 'lucide-react' +import { useState } from 'react' + +import { DescriptionSwitch, Switch } from '../../../src/components/primitives/switch' + +const meta: Meta = { + title: 'Components/Primitives/Switch', + component: Switch, + parameters: { + layout: 'centered', + docs: { + description: { + component: + 'A switch component based on Radix UI Switch, allowing users to toggle between on/off states. Supports three sizes (sm, md, lg), loading states, and an enhanced DescriptionSwitch variant with label and description. Built with accessibility in mind.' + } + } + }, + tags: ['autodocs'], + argTypes: { + disabled: { + control: { type: 'boolean' }, + description: 'Whether the switch is disabled' + }, + loading: { + control: { type: 'boolean' }, + description: 'When true, displays a loading animation in the switch thumb' + }, + size: { + control: { type: 'select' }, + options: ['sm', 'md', 'lg'], + description: 'The size of the switch' + }, + defaultChecked: { + control: { type: 'boolean' }, + description: 'Default checked state' + }, + checked: { + control: { type: 'boolean' }, + description: 'Checked state in controlled mode' + } + } +} + +export default meta +type Story = StoryObj + +// Default +export const Default: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ) +} + +// With Default Checked +export const WithDefaultChecked: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ) +} + +// Disabled +export const Disabled: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ ) +} + +// Loading State +export const Loading: Story = { + render: () => ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ) +} + +// Controlled +export const Controlled: Story = { + render: function ControlledExample() { + const [checked, setChecked] = useState(false) + + return ( +
+
+ + +
+
Current state: {checked ? 'On' : 'Off'}
+ +
+ ) + } +} + +// Sizes +export const Sizes: Story = { + render: () => ( +
+
+

Small (sm)

+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+

Medium (md) - Default

+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+

Large (lg)

+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ ) +} + +// Description Switch - Basic +export const DescriptionSwitchBasic: Story = { + render: () => ( +
+ + + +
+ ) +} + +// Description Switch - Positions +export const DescriptionSwitchPositions: Story = { + render: () => ( +
+
+

Switch on Right (Default)

+
+ + +
+
+ +
+

Switch on Left

+
+ + +
+
+
+ ) +} + +// Description Switch - Sizes +export const DescriptionSwitchSizes: Story = { + render: () => ( +
+ + + +
+ ) +} + +// Description Switch - States +export const DescriptionSwitchStates: Story = { + render: () => ( +
+ + + + + +
+ ) +} + +// Size Comparison +export const SizeComparison: Story = { + render: () => ( +
+
+

Off

+
+
+ + sm +
+
+ + md +
+
+ + lg +
+
+
+ +
+

On

+
+
+ + sm +
+
+ + md +
+
+ + lg +
+
+
+ +
+

Loading

+
+
+ + sm +
+
+ + md +
+
+ + lg +
+
+
+
+ ) +} + +// Real World Examples +export const RealWorldExamples: Story = { + render: function RealWorldExample() { + const [settings, setSettings] = useState({ + notifications: true, + autoSave: true, + darkMode: false, + analytics: true + }) + + const [privacy, setPrivacy] = useState({ + shareData: false, + allowCookies: true, + trackLocation: false, + personalizedAds: false + }) + + return ( +
+ {/* General Settings */} +
+

General Settings

+
+
+ setSettings({ ...settings, notifications: !!checked })} + /> + +
+
+ setSettings({ ...settings, autoSave: !!checked })} + /> + +
+
+ setSettings({ ...settings, darkMode: !!checked })} + /> + +
+
+ setSettings({ ...settings, analytics: !!checked })} + /> + +
+
+
+ + {/* Privacy Settings with DescriptionSwitch */} +
+

Privacy Settings

+
+ setPrivacy({ ...privacy, shareData: !!checked })} + /> + setPrivacy({ ...privacy, allowCookies: !!checked })} + /> + setPrivacy({ ...privacy, trackLocation: !!checked })} + /> + setPrivacy({ ...privacy, personalizedAds: !!checked })} + /> +
+
+
+ ) + } +} + +// Interactive Loading Example +export const InteractiveLoading: Story = { + render: function InteractiveLoadingExample() { + const [isLoading, setIsLoading] = useState(false) + const [isEnabled, setIsEnabled] = useState(false) + + const handleToggle = async (checked: boolean) => { + setIsLoading(true) + // Simulate API call + await new Promise((resolve) => setTimeout(resolve, 2000)) + setIsEnabled(checked) + setIsLoading(false) + } + + return ( +
+
+ +
+
+ + Status: + + {isLoading ? 'Connecting...' : isEnabled ? 'Connected' : 'Disconnected'} + +
+
+
+

Click the switch to see a simulated 2-second loading state

+
+ ) + } +} + +// Form Example +export const FormExample: Story = { + render: function FormExample() { + const [formData, setFormData] = useState({ + emailNotifications: true, + pushNotifications: false, + smsNotifications: false, + newsletter: true, + twoFactorAuth: false, + biometricAuth: true + }) + + const [isSaving, setIsSaving] = useState(false) + const [saved, setSaved] = useState(false) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setIsSaving(true) + setSaved(false) + // Simulate API call + await new Promise((resolve) => setTimeout(resolve, 1500)) + setIsSaving(false) + setSaved(true) + setTimeout(() => setSaved(false), 3000) + } + + return ( +
+

Account Preferences

+ +
+
+

Notifications

+
+ setFormData({ ...formData, emailNotifications: !!checked })} + disabled={isSaving} + /> + setFormData({ ...formData, pushNotifications: !!checked })} + disabled={isSaving} + /> + setFormData({ ...formData, smsNotifications: !!checked })} + disabled={isSaving} + /> + setFormData({ ...formData, newsletter: !!checked })} + disabled={isSaving} + /> +
+
+ +
+

Security

+
+ setFormData({ ...formData, twoFactorAuth: !!checked })} + disabled={isSaving} + /> + setFormData({ ...formData, biometricAuth: !!checked })} + disabled={isSaving} + /> +
+
+
+ +
+ + {saved &&

Settings saved successfully!

} +
+
+ ) + } +} + +// Accessibility Example +export const Accessibility: Story = { + render: () => ( +
+
+

Keyboard Navigation

+

+ Use Tab to navigate between switches and Space/Enter to toggle them. +

+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+

ARIA Labels

+

+ Switches include proper ARIA attributes for screen reader support. +

+ +
+
+ ) +} diff --git a/src/renderer/src/components/ObsidianExportDialog.tsx b/src/renderer/src/components/ObsidianExportDialog.tsx index 8d4a2fab3d..1a2ce51174 100644 --- a/src/renderer/src/components/ObsidianExportDialog.tsx +++ b/src/renderer/src/components/ObsidianExportDialog.tsx @@ -415,7 +415,7 @@ const PopupContainer: React.FC = ({ {!rawContent && ( - + )} diff --git a/src/renderer/src/pages/home/Tabs/SettingsTab.tsx b/src/renderer/src/pages/home/Tabs/SettingsTab.tsx index 68a14cca21..b5d3709ec4 100644 --- a/src/renderer/src/pages/home/Tabs/SettingsTab.tsx +++ b/src/renderer/src/pages/home/Tabs/SettingsTab.tsx @@ -115,6 +115,7 @@ const SettingsTab: FC = (props) => { const { theme } = useTheme() const { themeNames } = useCodeStyle() + // FIXME: We should use useMemo to calculate these states instead of using useEffect to sync const [temperature, setTemperature] = useState(assistant?.settings?.temperature ?? DEFAULT_TEMPERATURE) const [enableTemperature, setEnableTemperature] = useState(assistant?.settings?.enableTemperature ?? true) const [contextCount, setContextCount] = useState(assistant?.settings?.contextCount ?? DEFAULT_CONTEXTCOUNT) @@ -270,10 +271,9 @@ const SettingsTab: FC = (props) => { { + checked={enableTemperature} + onCheckedChange={(enabled) => { setEnableTemperature(enabled) onUpdateAssistantSettings({ enableTemperature: enabled }) }} @@ -340,9 +340,8 @@ const SettingsTab: FC = (props) => { {t('models.stream_output')} { + checked={streamOutput} + onCheckedChange={(checked) => { setStreamOutput(checked) onUpdateAssistantSettings({ streamOutput: checked }) }} @@ -357,9 +356,8 @@ const SettingsTab: FC = (props) => { { + checked={enableMaxTokens} + onCheckedChange={async (enabled) => { if (enabled) { const confirmed = await modalConfirm({ title: t('chat.settings.max_tokens.confirm'), @@ -410,38 +408,36 @@ const SettingsTab: FC = (props) => { - - {t('settings.messages.prompt')} - - - - - {/* {t('settings.messages.use_serif_font')} */} setMessageFont(checked ? 'serif' : 'system')}> - {t('settings.messages.use_serif_font')} - + checked={showPrompt} + onCheckedChange={setShowPrompt} + label={t('settings.messages.prompt')} + /> - {/* - {t('chat.settings.thought_auto_collapse.label')} - - */} - - - {t('chat.settings.thought_auto_collapse.label')} - - - + setMessageFont(checked ? 'serif' : 'system')} + label={t('settings.messages.use_serif_font')} + /> - - {t('settings.messages.show_message_outline')} - + + + + + @@ -534,16 +530,12 @@ const SettingsTab: FC = (props) => { - {/* - {t('settings.math.single_dollar.label')} - - */} - - - {t('settings.math.single_dollar.label')} - - - + @@ -567,32 +559,21 @@ const SettingsTab: FC = (props) => { - {/* - {t('chat.settings.code_fancy_block.label')} - - */} - - - {t('chat.settings.code_fancy_block.label')} - - - + - {/* - {t('chat.settings.code_execution.title')} - - */} setCodeExecution({ enabled: checked })}> - - {t('chat.settings.code_execution.title')} - - - + checked={codeExecution.enabled} + onCheckedChange={(checked) => setCodeExecution({ enabled: checked })} + label={t('chat.settings.code_execution.title')} + description={t('chat.settings.code_execution.tip')} + /> {codeExecution.enabled && ( <> @@ -616,90 +597,80 @@ const SettingsTab: FC = (props) => { )} - {/* {t('chat.settings.code_editor.title')} */} setCodeEditor({ enabled: checked })}> - {t('chat.settings.code_editor.title')} - + checked={codeEditor.enabled} + onCheckedChange={(checked) => setCodeEditor({ enabled: checked })} + label={t('chat.settings.code_editor.title')} + /> {codeEditor.enabled && ( <> - {/* - {t('chat.settings.code_editor.highlight_active_line')} - - */} setCodeEditor({ highlightActiveLine: checked })}> - - {t('chat.settings.code_editor.highlight_active_line')} - - - + checked={codeEditor.highlightActiveLine} + onCheckedChange={(checked) => setCodeEditor({ highlightActiveLine: checked })} + label={t('chat.settings.code_editor.highlight_active_line')} + /> - {/* {t('chat.settings.code_editor.fold_gutter')} */} setCodeEditor({ foldGutter: checked })}> - {t('chat.settings.code_editor.fold_gutter')} - + checked={codeEditor.foldGutter} + onCheckedChange={(checked) => setCodeEditor({ foldGutter: checked })} + label={t('chat.settings.code_editor.fold_gutter')} + /> - {/* {t('chat.settings.code_editor.autocompletion')} */} setCodeEditor({ autocompletion: checked })}> - {t('chat.settings.code_editor.autocompletion')} - + checked={codeEditor.autocompletion} + onCheckedChange={(checked) => setCodeEditor({ autocompletion: checked })} + label={t('chat.settings.code_editor.autocompletion')} + /> - {/* {t('chat.settings.code_editor.keymap')} */} setCodeEditor({ keymap: checked })}> - {t('chat.settings.code_editor.keymap')} - + checked={codeEditor.keymap} + onCheckedChange={(checked) => setCodeEditor({ keymap: checked })} + label={t('chat.settings.code_editor.keymap')} + /> )} - - {t('chat.settings.show_line_numbers')} - + - - {t('chat.settings.code_collapsible')} - + - - {t('chat.settings.code_wrappable')} - + - - - {t('chat.settings.code_image_tools.label')} - - - + @@ -708,17 +679,18 @@ const SettingsTab: FC = (props) => { - {t('settings.messages.input.show_estimated_tokens')} - + checked={showInputEstimatedTokens} + onCheckedChange={setShowInputEstimatedTokens} + label={t('settings.messages.input.show_estimated_tokens')} + /> - - {t('settings.messages.input.paste_long_text_as_file')} - + {pasteLongTextAsFile && ( <> @@ -740,54 +712,54 @@ const SettingsTab: FC = (props) => { - {t('settings.messages.markdown_rendering_input_message')} - + checked={renderInputMessageAsMarkdown} + onCheckedChange={setRenderInputMessageAsMarkdown} + label={t('settings.messages.markdown_rendering_input_message')} + /> {!(language || navigator.language).startsWith('en') && ( <> - {t('settings.input.auto_translate_with_space')} - + checked={autoTranslateWithSpace} + onCheckedChange={setAutoTranslateWithSpace} + label={t('settings.input.auto_translate_with_space')} + /> )} - - {t('settings.input.show_translate_confirm')} - + - {t('settings.messages.input.enable_quick_triggers')} - - - - - - {t('settings.messages.input.confirm_delete_message')} - + checked={enableQuickPanelTriggers} + onCheckedChange={setEnableQuickPanelTriggers} + label={t('settings.messages.input.enable_quick_triggers')} + /> - {t('settings.messages.input.confirm_regenerate_message')} - + checked={confirmDeleteMessage} + onCheckedChange={setConfirmDeleteMessage} + label={t('settings.messages.input.confirm_delete_message')} + /> + + + + diff --git a/src/renderer/src/pages/minapps/MiniappSettings/MiniAppSettings.tsx b/src/renderer/src/pages/minapps/MiniappSettings/MiniAppSettings.tsx index d71df5cd93..19c2324983 100644 --- a/src/renderer/src/pages/minapps/MiniappSettings/MiniAppSettings.tsx +++ b/src/renderer/src/pages/minapps/MiniappSettings/MiniAppSettings.tsx @@ -96,7 +96,7 @@ const MiniAppSettings: FC = () => { {t('settings.miniapps.open_link_external.title')} - setMinappsOpenLinkExternal(checked)} /> + setMinappsOpenLinkExternal(checked)} /> {/* 缓存小程序数量设置 */} @@ -134,8 +134,8 @@ const MiniAppSettings: FC = () => { {t('settings.miniapps.sidebar_description')} setShowOpenedMinappsInSidebar(checked)} + checked={showOpenedMinappsInSidebar} + onCheckedChange={(checked) => setShowOpenedMinappsInSidebar(checked)} /> diff --git a/src/renderer/src/pages/paintings/AihubmixPage.tsx b/src/renderer/src/pages/paintings/AihubmixPage.tsx index cbc6881558..294bed47f2 100644 --- a/src/renderer/src/pages/paintings/AihubmixPage.tsx +++ b/src/renderer/src/pages/paintings/AihubmixPage.tsx @@ -800,8 +800,8 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => { return ( updatePaintingState({ [item.key!]: checked })} + checked={(painting[item.key!] || item.initialValue) as boolean} + onCheckedChange={(checked) => updatePaintingState({ [item.key!]: checked })} /> ) diff --git a/src/renderer/src/pages/paintings/DmxapiPage.tsx b/src/renderer/src/pages/paintings/DmxapiPage.tsx index 09cdf1dc2d..7f83183d28 100644 --- a/src/renderer/src/pages/paintings/DmxapiPage.tsx +++ b/src/renderer/src/pages/paintings/DmxapiPage.tsx @@ -938,7 +938,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => { - onChangeAutoCreate(checked)} /> + onChangeAutoCreate(checked)} /> diff --git a/src/renderer/src/pages/paintings/SiliconPage.tsx b/src/renderer/src/pages/paintings/SiliconPage.tsx index 0fc025c22f..16ff35363a 100644 --- a/src/renderer/src/pages/paintings/SiliconPage.tsx +++ b/src/renderer/src/pages/paintings/SiliconPage.tsx @@ -464,8 +464,8 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => { updatePaintingState({ promptEnhancement: checked })} + checked={painting.promptEnhancement} + onCheckedChange={(checked) => updatePaintingState({ promptEnhancement: checked })} /> diff --git a/src/renderer/src/pages/paintings/components/DynamicFormRender.tsx b/src/renderer/src/pages/paintings/components/DynamicFormRender.tsx index ce1dbbe2d1..cf8735c3bd 100644 --- a/src/renderer/src/pages/paintings/components/DynamicFormRender.tsx +++ b/src/renderer/src/pages/paintings/components/DynamicFormRender.tsx @@ -198,8 +198,8 @@ export const DynamicFormRender: React.FC = ({ if (type === 'boolean') { return ( onChange(propertyName, checked)} + checked={value !== undefined ? value : defaultValue} + onCheckedChange={(checked) => onChange(propertyName, checked)} style={{ width: '2px' }} /> ) diff --git a/src/renderer/src/pages/settings/AboutSettings.tsx b/src/renderer/src/pages/settings/AboutSettings.tsx index f55b56775d..571914ac4e 100644 --- a/src/renderer/src/pages/settings/AboutSettings.tsx +++ b/src/renderer/src/pages/settings/AboutSettings.tsx @@ -228,13 +228,13 @@ const AboutSettings: FC = () => { {t('settings.general.auto_check_update.title')} - setAutoCheckUpdate(v)} /> + setAutoCheckUpdate(v)} /> {t('settings.general.test_plan.title')} - handleSetTestPlan(v)} /> + handleSetTestPlan(v)} /> {testPlan && ( diff --git a/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx b/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx index 40dc2249a6..22126c3685 100644 --- a/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx +++ b/src/renderer/src/pages/settings/AgentSettings/ToolingSettings.tsx @@ -1,3 +1,4 @@ +import { Switch } from '@cherrystudio/ui' import { permissionModeCards } from '@renderer/config/agent' import { useMCPServers } from '@renderer/hooks/useMCPServers' import useScrollPosition from '@renderer/hooks/useScrollPosition' @@ -13,7 +14,7 @@ import type { } from '@renderer/types' import { AgentConfigurationSchema } from '@renderer/types' import { Modal, Tag } from 'antd' -import { Alert, Card, Input, Switch } from 'antd' +import { Alert, Card, Input } from 'antd' import { ShieldAlert, Wrench } from 'lucide-react' import type { FC } from 'react' import { useCallback, useMemo, useState } from 'react' @@ -401,8 +402,8 @@ export const ToolingSettings: FC = ({ agentBase, upda })} checked={isApproved} disabled={isAuto || isUpdatingTools} - size="small" - onChange={(checked) => handleToggleTool(tool.id, checked)} + size="sm" + onCheckedChange={(checked) => handleToggleTool(tool.id, checked)} /> } @@ -483,9 +484,9 @@ export const ToolingSettings: FC = ({ agentBase, upda name: server.name })} checked={isSelected} - size="small" + size="sm" disabled={!server.isActive || isUpdatingMcp} - onChange={(checked) => handleToggleMcp(server.id, checked)} + onCheckedChange={(checked) => handleToggleMcp(server.id, checked)} /> } diff --git a/src/renderer/src/pages/settings/AssistantSettings/AssistantMCPSettings.tsx b/src/renderer/src/pages/settings/AssistantSettings/AssistantMCPSettings.tsx index d9bb273d8f..64f66e9cdf 100644 --- a/src/renderer/src/pages/settings/AssistantSettings/AssistantMCPSettings.tsx +++ b/src/renderer/src/pages/settings/AssistantSettings/AssistantMCPSettings.tsx @@ -87,10 +87,9 @@ const AssistantMCPSettings: React.FC = ({ assistant, updateAssistant }) = : undefined }> handleServerToggle(server.id)} - size="sm" + onCheckedChange={() => handleServerToggle(server.id)} /> diff --git a/src/renderer/src/pages/settings/AssistantSettings/AssistantMemorySettings.tsx b/src/renderer/src/pages/settings/AssistantSettings/AssistantMemorySettings.tsx index 60cc2b5b85..b323b6dfcd 100644 --- a/src/renderer/src/pages/settings/AssistantSettings/AssistantMemorySettings.tsx +++ b/src/renderer/src/pages/settings/AssistantSettings/AssistantMemorySettings.tsx @@ -94,8 +94,8 @@ const AssistantMemorySettings: React.FC = ({ assistant, updateAssistant, : '' }> diff --git a/src/renderer/src/pages/settings/AssistantSettings/AssistantModelSettings.tsx b/src/renderer/src/pages/settings/AssistantSettings/AssistantModelSettings.tsx index 120b10103c..1a981251f3 100644 --- a/src/renderer/src/pages/settings/AssistantSettings/AssistantModelSettings.tsx +++ b/src/renderer/src/pages/settings/AssistantSettings/AssistantModelSettings.tsx @@ -246,8 +246,8 @@ const AssistantModelSettings: FC = ({ assistant, updateAssistant, updateA { + checked={enableTemperature} + onCheckedChange={(enabled) => { setEnableTemperature(enabled) updateAssistantSettings({ enableTemperature: enabled }) }} @@ -295,8 +295,8 @@ const AssistantModelSettings: FC = ({ assistant, updateAssistant, updateA /> { + checked={enableTopP} + onCheckedChange={(enabled) => { setEnableTopP(enabled) updateAssistantSettings({ enableTopP: enabled }) }} @@ -387,8 +387,8 @@ const AssistantModelSettings: FC = ({ assistant, updateAssistant, updateA /> { + checked={enableMaxTokens} + onCheckedChange={async (enabled) => { if (enabled) { const confirmed = await modalConfirm({ title: t('chat.settings.max_tokens.confirm'), @@ -430,8 +430,8 @@ const AssistantModelSettings: FC = ({ assistant, updateAssistant, updateA { + checked={streamOutput} + onCheckedChange={(checked) => { setStreamOutput(checked) updateAssistantSettings({ streamOutput: checked }) }} diff --git a/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx b/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx index 0e9bba3ef2..5b98bda4fb 100644 --- a/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/DataSettings.tsx @@ -6,7 +6,7 @@ import { WifiOutlined, YuqueOutlined } from '@ant-design/icons' -import { Button, RowFlex } from '@cherrystudio/ui' +import { Button, RowFlex, Switch } from '@cherrystudio/ui' import { usePreference } from '@data/hooks/usePreference' import DividerWithText from '@renderer/components/DividerWithText' import { NutstoreIcon } from '@renderer/components/Icons/NutstoreIcons' @@ -22,7 +22,7 @@ import { reset } from '@renderer/services/BackupService' import type { AppInfo } from '@renderer/types' import { formatFileSize } from '@renderer/utils' import { occupiedDirs } from '@shared/config/constant' -import { Progress, Switch, Typography } from 'antd' +import { Progress, Typography } from 'antd' import { FileText, FolderCog, FolderInput, FolderOpen, SaveIcon } from 'lucide-react' import type { FC } from 'react' import { useEffect, useState } from 'react' @@ -291,7 +291,7 @@ const DataSettings: FC = () => { (shouldCopyData = checked)} + onCheckedChange={(checked) => (shouldCopyData = checked)} style={{ marginRight: '8px' }} title={t('settings.data.app_data.copy_data_option')} /> @@ -616,7 +616,7 @@ const DataSettings: FC = () => { {t('settings.data.backup.skip_file_data_title')} - + {t('settings.data.backup.skip_file_data_help')} diff --git a/src/renderer/src/pages/settings/DataSettings/ExportMenuSettings.tsx b/src/renderer/src/pages/settings/DataSettings/ExportMenuSettings.tsx index 974f760239..878560d477 100644 --- a/src/renderer/src/pages/settings/DataSettings/ExportMenuSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/ExportMenuSettings.tsx @@ -35,18 +35,15 @@ const ExportMenuOptions: FC = () => { {t('settings.data.export_menu.image')} - handleToggleOption('image', checked)} - /> + handleToggleOption('image', checked)} /> {t('settings.data.export_menu.markdown')} handleToggleOption('markdown', checked)} + checked={exportMenuOptions.markdown} + onCheckedChange={(checked) => handleToggleOption('markdown', checked)} /> @@ -54,8 +51,8 @@ const ExportMenuOptions: FC = () => { {t('settings.data.export_menu.markdown_reason')} handleToggleOption('markdown_reason', checked)} + checked={exportMenuOptions.markdown_reason} + onCheckedChange={(checked) => handleToggleOption('markdown_reason', checked)} /> @@ -63,26 +60,23 @@ const ExportMenuOptions: FC = () => { {t('settings.data.export_menu.notion')} handleToggleOption('notion', checked)} + checked={exportMenuOptions.notion} + onCheckedChange={(checked) => handleToggleOption('notion', checked)} /> {t('settings.data.export_menu.yuque')} - handleToggleOption('yuque', checked)} - /> + handleToggleOption('yuque', checked)} /> {t('settings.data.export_menu.joplin')} handleToggleOption('joplin', checked)} + checked={exportMenuOptions.joplin} + onCheckedChange={(checked) => handleToggleOption('joplin', checked)} /> @@ -90,8 +84,8 @@ const ExportMenuOptions: FC = () => { {t('settings.data.export_menu.obsidian')} handleToggleOption('obsidian', checked)} + checked={exportMenuOptions.obsidian} + onCheckedChange={(checked) => handleToggleOption('obsidian', checked)} /> @@ -99,23 +93,23 @@ const ExportMenuOptions: FC = () => { {t('settings.data.export_menu.siyuan')} handleToggleOption('siyuan', checked)} + checked={exportMenuOptions.siyuan} + onCheckedChange={(checked) => handleToggleOption('siyuan', checked)} /> {t('settings.data.export_menu.docx')} - handleToggleOption('docx', checked)} /> + handleToggleOption('docx', checked)} /> {t('settings.data.export_menu.plain_text')} handleToggleOption('plain_text', checked)} + checked={exportMenuOptions.plain_text} + onCheckedChange={(checked) => handleToggleOption('plain_text', checked)} /> diff --git a/src/renderer/src/pages/settings/DataSettings/JoplinSettings.tsx b/src/renderer/src/pages/settings/DataSettings/JoplinSettings.tsx index b5b72af37c..d34affe07a 100644 --- a/src/renderer/src/pages/settings/DataSettings/JoplinSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/JoplinSettings.tsx @@ -122,7 +122,7 @@ const JoplinSettings: FC = () => { {t('settings.data.joplin.export_reasoning.title')} - + {t('settings.data.joplin.export_reasoning.help')} diff --git a/src/renderer/src/pages/settings/DataSettings/LocalBackupSettings.tsx b/src/renderer/src/pages/settings/DataSettings/LocalBackupSettings.tsx index 5278540af8..f70c3270a5 100644 --- a/src/renderer/src/pages/settings/DataSettings/LocalBackupSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/LocalBackupSettings.tsx @@ -261,7 +261,7 @@ const LocalBackupSettings: React.FC = () => { {t('settings.data.backup.skip_file_data_title')} - + {t('settings.data.backup.skip_file_data_help')} diff --git a/src/renderer/src/pages/settings/DataSettings/MarkdownExportSettings.tsx b/src/renderer/src/pages/settings/DataSettings/MarkdownExportSettings.tsx index 7384660314..c9c8497c74 100644 --- a/src/renderer/src/pages/settings/DataSettings/MarkdownExportSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/MarkdownExportSettings.tsx @@ -98,7 +98,7 @@ const MarkdownExportSettings: FC = () => { {t('settings.data.markdown_export.force_dollar_math.title')} - + {t('settings.data.markdown_export.force_dollar_math.help')} @@ -106,7 +106,7 @@ const MarkdownExportSettings: FC = () => { {t('settings.data.message_title.use_topic_naming.title')} - + {t('settings.data.message_title.use_topic_naming.help')} @@ -114,7 +114,7 @@ const MarkdownExportSettings: FC = () => { {t('settings.data.markdown_export.show_model_name.title')} - + {t('settings.data.markdown_export.show_model_name.help')} @@ -122,7 +122,7 @@ const MarkdownExportSettings: FC = () => { {t('settings.data.markdown_export.show_model_provider.title')} - + {t('settings.data.markdown_export.show_model_provider.help')} @@ -130,7 +130,7 @@ const MarkdownExportSettings: FC = () => { {t('settings.data.markdown_export.exclude_citations.title')} - + {t('settings.data.markdown_export.exclude_citations.help')} @@ -138,7 +138,7 @@ const MarkdownExportSettings: FC = () => { {t('settings.data.markdown_export.standardize_citations.title')} - + {t('settings.data.markdown_export.standardize_citations.help')} diff --git a/src/renderer/src/pages/settings/DataSettings/NotionSettings.tsx b/src/renderer/src/pages/settings/DataSettings/NotionSettings.tsx index 25e0dd1b1e..eb9d116db9 100644 --- a/src/renderer/src/pages/settings/DataSettings/NotionSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/NotionSettings.tsx @@ -128,7 +128,7 @@ const NotionSettings: FC = () => { {t('settings.data.notion.export_reasoning.title')} - + {t('settings.data.notion.export_reasoning.help')} diff --git a/src/renderer/src/pages/settings/DataSettings/NutstoreSettings.tsx b/src/renderer/src/pages/settings/DataSettings/NutstoreSettings.tsx index 4a6ab7c2d1..ec7f81345d 100644 --- a/src/renderer/src/pages/settings/DataSettings/NutstoreSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/NutstoreSettings.tsx @@ -319,7 +319,7 @@ const NutstoreSettings: FC = () => { {t('settings.data.backup.skip_file_data_title')} - + {t('settings.data.backup.skip_file_data_help')} diff --git a/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx b/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx index 2da603ad64..2f1fe25073 100644 --- a/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/S3Settings.tsx @@ -243,7 +243,7 @@ const S3Settings: FC = () => { {t('settings.data.s3.skipBackupFile.label')} - + {t('settings.data.s3.skipBackupFile.help')} diff --git a/src/renderer/src/pages/settings/DataSettings/WebDavSettings.tsx b/src/renderer/src/pages/settings/DataSettings/WebDavSettings.tsx index 2fba0d6243..8def14ee52 100644 --- a/src/renderer/src/pages/settings/DataSettings/WebDavSettings.tsx +++ b/src/renderer/src/pages/settings/DataSettings/WebDavSettings.tsx @@ -201,7 +201,7 @@ const WebDavSettings: FC = () => { {t('settings.data.backup.skip_file_data_title')} - + {t('settings.data.backup.skip_file_data_help')} @@ -209,7 +209,7 @@ const WebDavSettings: FC = () => { {t('settings.data.webdav.disableStream.title')} - + {t('settings.data.webdav.disableStream.help')} diff --git a/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx b/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx index cabbcc7af9..c40ef45631 100644 --- a/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx +++ b/src/renderer/src/pages/settings/DisplaySettings/DisplaySettings.tsx @@ -231,7 +231,7 @@ const DisplaySettings: FC = () => { {t('settings.theme.window.style.transparent')} - + )} @@ -355,8 +355,8 @@ const DisplaySettings: FC = () => { {t('settings.advanced.auto_switch_to_topics')} setClickAssistantToShowTopic(checked)} + checked={clickAssistantToShowTopic} + onCheckedChange={(checked) => setClickAssistantToShowTopic(checked)} /> @@ -364,12 +364,12 @@ const DisplaySettings: FC = () => { )} {t('settings.topic.show.time')} - setShowTopicTime(checked)} /> + setShowTopicTime(checked)} /> {t('settings.topic.pin_to_top')} - setPinTopicsToTop(checked)} /> + setPinTopicsToTop(checked)} /> diff --git a/src/renderer/src/pages/settings/GeneralSettings.tsx b/src/renderer/src/pages/settings/GeneralSettings.tsx index 5cbcc63668..b9c9711c4c 100644 --- a/src/renderer/src/pages/settings/GeneralSettings.tsx +++ b/src/renderer/src/pages/settings/GeneralSettings.tsx @@ -268,12 +268,12 @@ const GeneralSettings: FC = () => { /> )} - + {t('settings.hardware_acceleration.title')} - + @@ -289,24 +289,24 @@ const GeneralSettings: FC = () => { /> handleNotificationChange('assistant', v)} + checked={notificationSettings.assistant} + onCheckedChange={(v) => handleNotificationChange('assistant', v)} /> {t('settings.notification.backup')} handleNotificationChange('backup', v)} + checked={notificationSettings.backup} + onCheckedChange={(v) => handleNotificationChange('backup', v)} /> {t('settings.notification.knowledge_embed')} handleNotificationChange('knowledge', v)} + checked={notificationSettings.knowledge} + onCheckedChange={(v) => handleNotificationChange('knowledge', v)} /> @@ -315,12 +315,12 @@ const GeneralSettings: FC = () => { {t('settings.launch.onboot')} - updateLaunchOnBoot(checked)} /> + updateLaunchOnBoot(checked)} /> {t('settings.launch.totray')} - updateLaunchToTray(checked)} /> + updateLaunchToTray(checked)} /> @@ -328,12 +328,12 @@ const GeneralSettings: FC = () => { {t('settings.tray.show')} - updateTray(checked)} /> + updateTray(checked)} /> {t('settings.tray.onclose')} - updateTrayOnClose(checked)} /> + updateTrayOnClose(checked)} /> @@ -342,8 +342,8 @@ const GeneralSettings: FC = () => { {t('settings.privacy.enable_privacy_mode')} { + checked={enableDataCollection} + onCheckedChange={(v) => { setEnableDataCollection(v) window.api.config.set('enableDataCollection', v) }} @@ -358,7 +358,7 @@ const GeneralSettings: FC = () => { {t('settings.developer.enable_developer_mode')} - + diff --git a/src/renderer/src/pages/settings/MCPSettings/McpServerCard.tsx b/src/renderer/src/pages/settings/MCPSettings/McpServerCard.tsx index 15e65ea6e6..57b013fb3c 100644 --- a/src/renderer/src/pages/settings/MCPSettings/McpServerCard.tsx +++ b/src/renderer/src/pages/settings/MCPSettings/McpServerCard.tsx @@ -116,11 +116,10 @@ const McpServerCard: FC = ({ e.stopPropagation()}> diff --git a/src/renderer/src/pages/settings/ModelSettings/DefaultAssistantSettings.tsx b/src/renderer/src/pages/settings/ModelSettings/DefaultAssistantSettings.tsx index 95e4e5986d..badc5803ee 100644 --- a/src/renderer/src/pages/settings/ModelSettings/DefaultAssistantSettings.tsx +++ b/src/renderer/src/pages/settings/ModelSettings/DefaultAssistantSettings.tsx @@ -173,8 +173,8 @@ const AssistantSettings: FC = () => { { + checked={enableTemperature} + onCheckedChange={(enabled) => { setEnableTemperature(enabled) onUpdateAssistantSettings({ enableTemperature: enabled }) }} @@ -215,8 +215,8 @@ const AssistantSettings: FC = () => { { + checked={enableTopP} + onCheckedChange={(enabled) => { setEnableTopP(enabled) onUpdateAssistantSettings({ enableTopP: enabled }) }} @@ -280,8 +280,8 @@ const AssistantSettings: FC = () => { { + checked={enableMaxTokens} + onCheckedChange={async (enabled) => { if (enabled) { const confirmed = await modalConfirm({ title: t('chat.settings.max_tokens.confirm'), diff --git a/src/renderer/src/pages/settings/ModelSettings/QuickModelPopup.tsx b/src/renderer/src/pages/settings/ModelSettings/QuickModelPopup.tsx index 504c9ece3c..4e6bb6be70 100644 --- a/src/renderer/src/pages/settings/ModelSettings/QuickModelPopup.tsx +++ b/src/renderer/src/pages/settings/ModelSettings/QuickModelPopup.tsx @@ -59,7 +59,7 @@ const PopupContainer: React.FC = ({ resolve }) => {
{t('settings.models.topic_naming.auto')}
- +
diff --git a/src/renderer/src/pages/settings/NotesSettings.tsx b/src/renderer/src/pages/settings/NotesSettings.tsx index 6f00f81c5f..70d8f92a69 100644 --- a/src/renderer/src/pages/settings/NotesSettings.tsx +++ b/src/renderer/src/pages/settings/NotesSettings.tsx @@ -164,8 +164,8 @@ const NotesSettings: FC = () => { {t('notes.settings.display.compress_content')} updateSettings({ isFullWidth: !checked })} + checked={!settings.isFullWidth} + onCheckedChange={(checked) => updateSettings({ isFullWidth: !checked })} /> {t('notes.settings.display.compress_content_description')} @@ -188,8 +188,8 @@ const NotesSettings: FC = () => { {t('notes.settings.display.show_table_of_contents')} updateSettings({ showTableOfContents: checked })} + checked={settings.showTableOfContents} + onCheckedChange={(checked) => updateSettings({ showTableOfContents: checked })} /> {t('notes.settings.display.show_table_of_contents_description')} diff --git a/src/renderer/src/pages/settings/ProviderSettings/ApiOptionsSettings/ApiOptionsSettings.tsx b/src/renderer/src/pages/settings/ProviderSettings/ApiOptionsSettings/ApiOptionsSettings.tsx index fab07d55d0..4ea5cdc050 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/ApiOptionsSettings/ApiOptionsSettings.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/ApiOptionsSettings/ApiOptionsSettings.tsx @@ -124,7 +124,7 @@ const ApiOptionsSettings = ({ providerId }: Props) => { - + ))} diff --git a/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx b/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx index d34f9653b8..5439042c86 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx @@ -343,10 +343,9 @@ const ModelEditContent: FC = ({ provider, mo label={t('settings.models.add.supported_text_delta.label')} tooltip={t('settings.models.add.supported_text_delta.tooltip')}> { + onCheckedChange={(checked) => { setSupportedTextDelta(checked) // 直接传递新值给autoSave autoSave({ supported_text_delta: checked }) diff --git a/src/renderer/src/pages/settings/ProviderSettings/ProviderSetting.tsx b/src/renderer/src/pages/settings/ProviderSettings/ProviderSetting.tsx index c6c856a7e4..d06b72e095 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/ProviderSetting.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/ProviderSetting.tsx @@ -410,9 +410,9 @@ const ProviderSetting: FC = ({ providerId }) => { )} { + onCheckedChange={(enabled) => { updateProvider({ apiHost, enabled }) if (enabled) { moveProviderToTop(provider.id) diff --git a/src/renderer/src/pages/settings/QuickAssistantSettings.tsx b/src/renderer/src/pages/settings/QuickAssistantSettings.tsx index 34b495fbc6..6828e01eb9 100644 --- a/src/renderer/src/pages/settings/QuickAssistantSettings.tsx +++ b/src/renderer/src/pages/settings/QuickAssistantSettings.tsx @@ -82,14 +82,14 @@ const QuickAssistantSettings: FC = () => { iconProps={{ className: 'cursor-pointer' }} /> - + {enableQuickAssistant && ( <> {t('settings.quickAssistant.click_tray_to_show')} - + )} @@ -98,7 +98,7 @@ const QuickAssistantSettings: FC = () => { {t('settings.quickAssistant.read_clipboard_at_startup')} - + )} diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx index 81b55a20c5..55bdb2ed0e 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx @@ -101,8 +101,8 @@ const SelectionAssistantSettings: FC = () => { {!isSupportedOS && {t('selection.settings.enable.description')}} @@ -162,7 +162,7 @@ const SelectionAssistantSettings: FC = () => { {t('selection.settings.toolbar.compact_mode.title')} {t('selection.settings.toolbar.compact_mode.description')} - + @@ -174,7 +174,7 @@ const SelectionAssistantSettings: FC = () => { {t('selection.settings.window.follow_toolbar.title')} {t('selection.settings.window.follow_toolbar.description')} - + @@ -182,7 +182,7 @@ const SelectionAssistantSettings: FC = () => { {t('selection.settings.window.remember_size.title')} {t('selection.settings.window.remember_size.description')} - + @@ -190,7 +190,7 @@ const SelectionAssistantSettings: FC = () => { {t('selection.settings.window.auto_close.title')} {t('selection.settings.window.auto_close.description')} - + @@ -198,7 +198,7 @@ const SelectionAssistantSettings: FC = () => { {t('selection.settings.window.auto_pin.title')} {t('selection.settings.window.auto_pin.description')} - + diff --git a/src/renderer/src/pages/settings/ShortcutSettings.tsx b/src/renderer/src/pages/settings/ShortcutSettings.tsx index e42ee98032..f9c661808e 100644 --- a/src/renderer/src/pages/settings/ShortcutSettings.tsx +++ b/src/renderer/src/pages/settings/ShortcutSettings.tsx @@ -392,7 +392,7 @@ const ShortcutSettings: FC = () => { align: 'right', width: '50px', render: (record: Shortcut) => ( - dispatch(toggleShortcut(record.key))} /> + dispatch(toggleShortcut(record.key))} /> ) } ] diff --git a/src/renderer/src/pages/settings/WebSearchSettings/BasicSettings.tsx b/src/renderer/src/pages/settings/WebSearchSettings/BasicSettings.tsx index 5b3827929c..aa4a4f6590 100644 --- a/src/renderer/src/pages/settings/WebSearchSettings/BasicSettings.tsx +++ b/src/renderer/src/pages/settings/WebSearchSettings/BasicSettings.tsx @@ -23,7 +23,7 @@ const BasicSettings: FC = () => { {t('settings.tool.websearch.search_with_time')} - dispatch(setSearchWithTime(checked))} /> + dispatch(setSearchWithTime(checked))} /> diff --git a/src/renderer/src/pages/translate/TranslateSettings.tsx b/src/renderer/src/pages/translate/TranslateSettings.tsx index 1fcb899a9d..e82cc7c903 100644 --- a/src/renderer/src/pages/translate/TranslateSettings.tsx +++ b/src/renderer/src/pages/translate/TranslateSettings.tsx @@ -67,8 +67,8 @@ const TranslateSettings: FC<{
{t('translate.settings.preview')}
{ + checked={enableMarkdown} + onCheckedChange={(checked) => { setEnableMarkdown(checked) db.settings.put({ id: 'translate:markdown:enabled', value: checked }) }} @@ -80,9 +80,9 @@ const TranslateSettings: FC<{
{t('translate.settings.autoCopy')}
{ + onCheckedChange={(isSelected) => { updateSettings({ autoCopy: isSelected }) }} /> @@ -93,9 +93,9 @@ const TranslateSettings: FC<{
{t('translate.settings.scroll_sync')}
{ + onCheckedChange={(isSelected) => { setIsScrollSyncEnabled(isSelected) db.settings.put({ id: 'translate:scroll:sync', value: isSelected }) }} @@ -145,9 +145,9 @@ const TranslateSettings: FC<{
{ + onCheckedChange={(isSelected) => { setIsBidirectional(isSelected) // 双向翻译设置不需要持久化,它只是界面状态 }} diff --git a/yarn.lock b/yarn.lock index e563de008d..988f760cfd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -231,7 +231,7 @@ __metadata: languageName: node linkType: hard -"@ai-sdk/openai-compatible@npm:1.0.27, @ai-sdk/openai-compatible@npm:^1.0.19": +"@ai-sdk/openai-compatible@npm:1.0.27": version: 1.0.27 resolution: "@ai-sdk/openai-compatible@npm:1.0.27" dependencies: @@ -243,6 +243,18 @@ __metadata: languageName: node linkType: hard +"@ai-sdk/openai-compatible@npm:^1.0.19": + version: 1.0.19 + resolution: "@ai-sdk/openai-compatible@npm:1.0.19" + dependencies: + "@ai-sdk/provider": "npm:2.0.0" + "@ai-sdk/provider-utils": "npm:3.0.10" + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + checksum: 10c0/5b7b21fb515e829c3d8a499a5760ffc035d9b8220695996110e361bd79e9928859da4ecf1ea072735bcbe4977c6dd0661f543871921692e86f8b5bfef14fe0e5 + languageName: node + linkType: hard + "@ai-sdk/openai-compatible@patch:@ai-sdk/openai-compatible@npm%3A1.0.27#~/.yarn/patches/@ai-sdk-openai-compatible-npm-1.0.27-06f74278cf.patch": version: 1.0.27 resolution: "@ai-sdk/openai-compatible@patch:@ai-sdk/openai-compatible@npm%3A1.0.27#~/.yarn/patches/@ai-sdk-openai-compatible-npm-1.0.27-06f74278cf.patch::version=1.0.27&hash=c44b76" @@ -291,6 +303,19 @@ __metadata: languageName: node linkType: hard +"@ai-sdk/provider-utils@npm:3.0.10": + version: 3.0.10 + resolution: "@ai-sdk/provider-utils@npm:3.0.10" + dependencies: + "@ai-sdk/provider": "npm:2.0.0" + "@standard-schema/spec": "npm:^1.0.0" + eventsource-parser: "npm:^3.0.5" + peerDependencies: + zod: ^3.25.76 || ^4.1.8 + checksum: 10c0/d2c16abdb84ba4ef48c9f56190b5ffde224b9e6ae5147c5c713d2623627732d34b96aa9aef2a2ea4b0c49e1b863cc963c7d7ff964a1dc95f0f036097aaaaaa98 + languageName: node + linkType: hard + "@ai-sdk/provider-utils@npm:3.0.17, @ai-sdk/provider-utils@npm:^3.0.10, @ai-sdk/provider-utils@npm:^3.0.17": version: 3.0.17 resolution: "@ai-sdk/provider-utils@npm:3.0.17" @@ -7730,6 +7755,31 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-switch@npm:^1.2.6": + version: 1.2.6 + resolution: "@radix-ui/react-switch@npm:1.2.6" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + "@radix-ui/react-use-previous": "npm:1.1.1" + "@radix-ui/react-use-size": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/888303cbeb0e69ebba5676b225f9ea0f00f61453c6b8a6b66384b5c5c4c7fb0ccc53493c1eb14ec6d436e5b867b302aadd6af51a1f2e6c04581c583fd9be65be + languageName: node + linkType: hard + "@radix-ui/react-tabs@npm:^1.1.13": version: 1.1.13 resolution: "@radix-ui/react-tabs@npm:1.1.13" @@ -13822,6 +13872,7 @@ __metadata: "@paymoapp/electron-shutdown-handler": "npm:^1.1.2" "@playwright/test": "npm:^1.55.1" "@radix-ui/react-context-menu": "npm:^2.2.16" + "@radix-ui/react-switch": "npm:^1.2.6" "@reduxjs/toolkit": "npm:^2.2.5" "@shikijs/markdown-it": "npm:^3.12.0" "@strongtz/win32-arm64-msvc": "npm:^0.4.7" @@ -18519,7 +18570,7 @@ __metadata: languageName: node linkType: hard -"eventsource-parser@npm:^3.0.0": +"eventsource-parser@npm:^3.0.0, eventsource-parser@npm:^3.0.5": version: 3.0.5 resolution: "eventsource-parser@npm:3.0.5" checksum: 10c0/5cb75e3f84ff1cfa1cee6199d4fd430c4544855ab03e953ddbe5927e7b31bc2af3933ab8aba6440ba160ed2c48972b6c317f27b8a1d0764c7b12e34e249de631