mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-07-06 14:01:30 +08:00
packages/shared was never a real pnpm workspace package (no package.json); it was referenced only through the @shared TypeScript path alias. Relocate it under src/ via git mv (143 files, detected as pure renames).
Repoint the @shared alias and include globs to src/shared across electron.vite.config.ts, tsconfig.{json,node,web}.json and vitest.config.ts; update scripts/check-custom-exts.ts, scripts/update-languages.ts, the eslint.config.mjs generated-file globs, the data-classify generator output targets, .github/CODEOWNERS path rules, and CLAUDE.md/docs/source-comment references.
The @shared alias name is unchanged, so all 1403 @shared/* import sites resolve without modification. Verified with typecheck:node, typecheck:web and the full test suite (700 files, 9739 tests passing).
174 lines
5.4 KiB
Markdown
174 lines
5.4 KiB
Markdown
# Preference Schema Guide
|
|
|
|
This guide explains how to add new preference keys to Cherry Studio.
|
|
|
|
## Key Naming Conventions
|
|
|
|
### Format
|
|
|
|
All preference keys MUST follow the format: `namespace.sub.key_name`
|
|
|
|
**Rules:**
|
|
|
|
- At least 2 segments separated by dots (.)
|
|
- Each segment uses lowercase letters, numbers, and underscores only
|
|
- Pattern: `/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/`
|
|
|
|
### Naming Principles
|
|
|
|
1. **Semantic Grouping**: Group related settings under common namespaces
|
|
|
|
- `app.*` - Application-level settings
|
|
- `chat.*` - Chat/message settings
|
|
- `feature.*` - Feature toggles
|
|
- `ui.*` - UI/theme settings
|
|
- `data.*` - Data/backup settings
|
|
- `shortcut.*` - Keyboard shortcuts
|
|
|
|
**Namespace principles:**
|
|
|
|
- Namespaces represent major features with **global impact** across the application
|
|
- The existing namespaces should already cover most use cases
|
|
- If you believe a new namespace is needed, think from a **global perspective** - it should represent a fundamental category, not just a single feature
|
|
|
|
2. **Hierarchy**: Use dots for hierarchy, underscores for multi-word names
|
|
|
|
- `chat.message.font_size` (not `chat.messageFontSize`)
|
|
- `feature.quick_assistant.enabled` (not `feature.quickAssistant.enabled`)
|
|
|
|
3. **Boolean Naming**: Use positive names with `.enabled` suffix for toggles
|
|
- `feature.quick_assistant.enabled` (not `feature.quick_assistant.disabled`)
|
|
- `app.spell_check.enabled`
|
|
|
|
### Examples
|
|
|
|
| Valid | Invalid | Reason |
|
|
| ------------------------- | ---------------------- | ---------------------- |
|
|
| `app.user.avatar` | `userAvatar` | Missing dot separator |
|
|
| `chat.multi_select_mode` | `chat.multiSelectMode` | camelCase not allowed |
|
|
| `feature.quick_assistant.enabled` | `Feature.quickAssistant` | camelCase not allowed |
|
|
|
|
## Design Principles
|
|
|
|
### Prefer Flat Over Nested
|
|
|
|
Prefer granular, flat preference keys over storing complex objects.
|
|
|
|
**Why:**
|
|
|
|
1. **Visibility**: Individual config items are more explicit and discoverable
|
|
2. **Performance**: Avoids parsing entire objects when reading/writing common items
|
|
|
|
**When to use flat keys:**
|
|
|
|
```typescript
|
|
// Good: Flat keys for independent settings
|
|
'chat.code.collapsible': boolean
|
|
'chat.code.show_line_numbers': boolean
|
|
'chat.code.wrappable': boolean
|
|
```
|
|
|
|
**When to keep as object:**
|
|
|
|
Only use object values when the data is frequently read/written as a whole unit.
|
|
|
|
```typescript
|
|
// Acceptable: Shortcut config is always read/written together
|
|
'shortcut.general.show_main_window': { binding: string[], enabled: boolean }
|
|
```
|
|
|
|
**Rule of thumb:** If you find yourself frequently accessing just one property of an object, split it into separate keys.
|
|
|
|
### Keep Values Atomic
|
|
|
|
Each preference should represent one logical setting. Don't combine unrelated settings.
|
|
|
|
```typescript
|
|
// Good: One setting per key
|
|
'chat.message.font_size': number
|
|
'chat.message.font_family': string
|
|
|
|
// Bad: Multiple settings in one key
|
|
'chat.message.font': { size: number, family: string }
|
|
```
|
|
|
|
### Provide Sensible Defaults
|
|
|
|
All preferences MUST have default values in `DefaultPreferences`.
|
|
|
|
## Adding a New Preference
|
|
|
|
### Step 1: Define Custom Types (if needed)
|
|
|
|
If your preference uses a custom type (enum, union type, etc.), add it first.
|
|
|
|
**File:** `src/shared/data/preference/preferenceTypes.ts`
|
|
|
|
```typescript
|
|
// Example: Adding a new enum type
|
|
export enum MyFeatureMode {
|
|
auto = 'auto',
|
|
manual = 'manual',
|
|
disabled = 'disabled'
|
|
}
|
|
```
|
|
|
|
### Step 2: Add to Schema Interface
|
|
|
|
**File:** `src/shared/data/preference/preferenceSchemas.ts`
|
|
|
|
Add your key to the `PreferenceSchemas` interface:
|
|
|
|
```typescript
|
|
export interface PreferenceSchemas {
|
|
default: {
|
|
// ...existing keys (alphabetically sorted)...
|
|
'feature.my_feature.enabled': boolean
|
|
'feature.my_feature.mode': PreferenceTypes.MyFeatureMode
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 3: Add Default Value
|
|
|
|
In the same file, add default value to `DefaultPreferences`:
|
|
|
|
```typescript
|
|
export const DefaultPreferences: PreferenceSchemas = {
|
|
default: {
|
|
// ...existing defaults (alphabetically sorted)...
|
|
'feature.my_feature.enabled': true,
|
|
'feature.my_feature.mode': PreferenceTypes.MyFeatureMode.auto,
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 4: Use in Code
|
|
|
|
```typescript
|
|
import { usePreference } from '@data/hooks/usePreference'
|
|
|
|
const [enabled, setEnabled] = usePreference('feature.my_feature.enabled')
|
|
const [mode, setMode] = usePreference('feature.my_feature.mode')
|
|
```
|
|
|
|
## File Structure
|
|
|
|
| File | Purpose |
|
|
| ----------------------------------------------------- | ------------------------------------------- |
|
|
| `src/shared/data/preference/preferenceSchemas.ts`| Schema interface and default values |
|
|
| `src/shared/data/preference/preferenceTypes.ts` | Custom type definitions (enums, unions) |
|
|
|
|
## Best Practices Summary
|
|
|
|
1. **Flat over nested**: Split objects into individual keys unless frequently accessed as a whole
|
|
2. **Atomic values**: One preference = one logical setting
|
|
3. **Sensible defaults**: All preferences must have default values
|
|
4. **Consistent naming**: Follow `namespace.category.key_name` pattern
|
|
5. **2-3 levels**: Don't over-nest; 2-3 dot-separated segments is usually sufficient
|
|
|
|
## Related Documentation
|
|
|
|
- [Preference Overview](./preference-overview.md) - Architecture and sync mechanism
|
|
- [Preference Usage](./preference-usage.md) - Hooks and service API
|