feat(settings): add a scrollbar minimap switch under Appearance
chatMinimapEnabled defaults to on; turning it off restores the native message scrollbar while keeping continuous history and DOM windowing.
This commit is contained in:
@@ -14,4 +14,4 @@
|
||||
|
||||
- **历史窗口**:允许滚动访问的消息范围。第一阶段扩大为当前已加载会话的全部消息。
|
||||
- **DOM 窗口**:实际挂载消息组件的范围。继续由消息高度估算和最多约 60 条挂载消息控制。
|
||||
- **minimap**:替代消息区原生滚动条的 canvas 全局概览,高度与滚动区一致,悬停时展开为较宽的缩略长图;不等于完整渲染所有消息。
|
||||
- **minimap**:替代消息区原生滚动条的 canvas 全局概览,高度与滚动区一致,悬停时展开为较宽的缩略长图;不等于完整渲染所有消息。设置界面中称为“滚动条缩略图”(设置 › 外观),对应应用设置 `chatMinimapEnabled`,默认开启;关闭后恢复原生滚动条,历史窗口不受影响。
|
||||
|
||||
@@ -73,3 +73,10 @@
|
||||
- 验证:minimap、历史窗口、时间线定向测试 69/69(新增“行测量不��发重画”和“滑块对齐可见行的概览区段”用例);web 类型检查与 lint 通过;`npm run build:bundle` 通过。
|
||||
- `npm run perf:app` 连续两次通过。第二次结果:长会话打开、长会话滚动、`stream-seeded`、`stream-and-type` 均无长任务,帧 p95 8.5 ms;24 次切换后 DOM 2,449、堆 23.2 MB,后半段增长 0.2 MB。第一次运行中长会话滚动帧 p95 为 16.6 ms,`stream-seeded` 有 1 个 62 ms 长任务,第二次未复现,按单次噪声记录。
|
||||
- 未验证:真实桌面端滚动时的视觉稳定性需人工确认。
|
||||
|
||||
### 2026-10-12 外观设置开关
|
||||
|
||||
- 新增应用设置 `chatMinimapEnabled`(`z.boolean().default(true)`),旧设置文件缺省时读为开启,无需升级设置版本;`application.update` 配置工具复用同一更新 schema,自动接受该字段。
|
||||
- 设置 › 外观新增开关“滚动条缩略图”/“Scrollbar minimap”,位于“透明磨砂特效”之后,保存后立即生效。
|
||||
- 关闭时 `ChatHistoryPane` 不挂载 `ChatMinimap`,也不再设置 `data-minimap`,原生滚动条随之恢复;历史窗口(完整已加载消息)和约 60 条 DOM 窗口不变。
|
||||
- 验证:设置存储(缺省默认、两种取值的持久化与重载、非法值拒绝)、外观开关(中英文)、窗格开关切换用例均通过;相关 8 个测试文件 410 项中修正配置快照夹具后全部通过;`App.test.tsx` 342/350,8 个失败与此前相同;web/node 类型检查(除既有 `desktop-storage-electron-fixture.ts`)与改动文件 lint 通过。
|
||||
|
||||
@@ -84,6 +84,20 @@ describe('ApplicationSettingsStore', () => {
|
||||
expect(applicationSettingsSchema.parse({ ...defaultApplicationSettings, transparentFrostedEffectEnabled: undefined }).transparentFrostedEffectEnabled).toBe(true)
|
||||
})
|
||||
|
||||
it('defaults a missing scrollbar minimap setting to on and persists both choices', async () => {
|
||||
const { filePath, store } = await createStore()
|
||||
const legacy: Record<string, unknown> = { ...defaultApplicationSettings, version: 12, lastSeenReleaseNotesVersion: null }
|
||||
delete legacy.chatMinimapEnabled
|
||||
await writeFile(filePath, JSON.stringify(legacy))
|
||||
expect((await store.get()).chatMinimapEnabled).toBe(true)
|
||||
for (const chatMinimapEnabled of [false, true]) {
|
||||
expect((await store.update({ chatMinimapEnabled })).chatMinimapEnabled).toBe(chatMinimapEnabled)
|
||||
await store.update({ checkUpdatesOnStartup: false })
|
||||
expect((await createApplicationSettingsStore(filePath).get()).chatMinimapEnabled).toBe(chatMinimapEnabled)
|
||||
}
|
||||
await expect(store.update({ chatMinimapEnabled: 'false' })).rejects.toThrow()
|
||||
})
|
||||
|
||||
it('persists and publishes both frosted glass choices across unrelated updates and reloads', async () => {
|
||||
const { filePath, store } = await createStore()
|
||||
expect((await store.get()).transparentFrostedEffectEnabled).toBe(true)
|
||||
|
||||
@@ -252,6 +252,7 @@ export const defaultApplicationSettings: ApplicationSettings = {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: true,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: 'github',
|
||||
modelDownloadSource: 'modelscope',
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -295,6 +296,7 @@ export class ApplicationSettingsStore {
|
||||
| 'conversationHtmlRenderingEnabled'
|
||||
| 'desktopNotificationsEnabled'
|
||||
| 'transparentFrostedEffectEnabled'
|
||||
| 'chatMinimapEnabled'
|
||||
| 'localToolEnvironment'
|
||||
| 'version'
|
||||
| 'applicationNavigation'
|
||||
@@ -532,6 +534,7 @@ export class ApplicationSettingsStore {
|
||||
checkUpdatesOnStartup: stored.checkUpdatesOnStartup,
|
||||
desktopNotificationsEnabled: stored.desktopNotificationsEnabled,
|
||||
transparentFrostedEffectEnabled: stored.transparentFrostedEffectEnabled,
|
||||
chatMinimapEnabled: stored.chatMinimapEnabled,
|
||||
updateSource: stored.updateSource,
|
||||
modelDownloadSource: stored.modelDownloadSource,
|
||||
localToolEnvironment: stored.localToolEnvironment,
|
||||
@@ -581,6 +584,7 @@ export class ApplicationSettingsStore {
|
||||
checkUpdatesOnStartup: next.checkUpdatesOnStartup,
|
||||
desktopNotificationsEnabled: next.desktopNotificationsEnabled,
|
||||
transparentFrostedEffectEnabled: next.transparentFrostedEffectEnabled,
|
||||
chatMinimapEnabled: next.chatMinimapEnabled,
|
||||
updateSource: next.updateSource,
|
||||
modelDownloadSource: next.modelDownloadSource,
|
||||
localToolEnvironment: next.localToolEnvironment,
|
||||
|
||||
@@ -1256,6 +1256,7 @@ function installRemoteProjectsSetting(enabled: boolean): {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github",
|
||||
modelDownloadSource: "modelscope",
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -3486,6 +3487,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -3591,6 +3593,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -3608,6 +3611,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -3711,6 +3715,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -3728,6 +3733,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -6430,6 +6436,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github",
|
||||
modelDownloadSource: "modelscope",
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14663,6 +14670,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14680,6 +14688,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14734,6 +14743,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14795,6 +14805,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14833,6 +14844,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14850,6 +14862,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github" as const,
|
||||
modelDownloadSource: "modelscope" as const,
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14913,6 +14926,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github",
|
||||
modelDownloadSource: "modelscope",
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -14973,6 +14987,7 @@ describe("App", () => {
|
||||
checkUpdatesOnStartup: false,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: "github",
|
||||
modelDownloadSource: "modelscope",
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
|
||||
@@ -6511,6 +6511,8 @@ function App(): React.JSX.Element {
|
||||
const settingsPanelActions = useStableHandlers({
|
||||
onTransparentFrostedEffectEnabledChange: (enabled: boolean) =>
|
||||
updateApplicationSettings({ transparentFrostedEffectEnabled: enabled }),
|
||||
onChatMinimapEnabledChange: (enabled: boolean) =>
|
||||
updateApplicationSettings({ chatMinimapEnabled: enabled }),
|
||||
onRetryApplicationSettings: () => void reloadApplicationSettings(),
|
||||
onBrandingPreferencesChange: (preferences: Parameters<typeof saveBrandingPreferences>[0]) => {
|
||||
if (!saveBrandingPreferences(preferences)) {
|
||||
@@ -7069,6 +7071,7 @@ function App(): React.JSX.Element {
|
||||
conversationHtmlRenderingEnabled={
|
||||
conversationHtmlRenderingEnabled
|
||||
}
|
||||
chatMinimapEnabled={applicationSettings?.chatMinimapEnabled ?? true}
|
||||
conversationId={conversationId}
|
||||
key={conversationId}
|
||||
loadHistory={ensureConversationHistory}
|
||||
@@ -7394,6 +7397,7 @@ function App(): React.JSX.Element {
|
||||
{...settingsPanelActions}
|
||||
appearanceTheme={appearanceTheme}
|
||||
transparentFrostedEffectEnabled={applicationSettings?.transparentFrostedEffectEnabled ?? true}
|
||||
chatMinimapEnabled={applicationSettings?.chatMinimapEnabled ?? true}
|
||||
applicationSettingsPending={applicationSettingsPending}
|
||||
applicationSettingsLocked={applicationSettingsUnconfirmed || !applicationSettings}
|
||||
applicationSettingsError={applicationSettingsError}
|
||||
|
||||
@@ -181,6 +181,19 @@ afterEach(() => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
describe('ChatHistoryPane scrollbar minimap setting', () => {
|
||||
it('replaces the native scrollbar only while the minimap is enabled', () => {
|
||||
const messages = makeMessages(5)
|
||||
const { container, rerender, props } = setup(messages)
|
||||
const pane = container.querySelector<HTMLElement>('.chat-history-pane')!
|
||||
expect(pane).toHaveAttribute('data-minimap', 'true')
|
||||
expect(container.querySelector('.chat-minimap')).not.toBeNull()
|
||||
rerender(<ChatHistoryPane {...props} chatMinimapEnabled={false} />)
|
||||
expect(pane).not.toHaveAttribute('data-minimap')
|
||||
expect(container.querySelector('.chat-minimap')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ChatHistoryPane windowing', () => {
|
||||
it('restores disclosures after eviction by more than eight row interactions with bounded DOM', async () => {
|
||||
const messages = makeMessages(2_000).map(message => ({ ...message, role: 'assistant' as const, reasoning: 'Reasoning' }))
|
||||
|
||||
@@ -152,6 +152,7 @@ export const ChatHistoryPane = memo(function ChatHistoryPane({
|
||||
active,
|
||||
artifactById,
|
||||
conversationHtmlRenderingEnabled,
|
||||
chatMinimapEnabled = true,
|
||||
conversation,
|
||||
locale,
|
||||
onCopyMessage,
|
||||
@@ -177,6 +178,8 @@ export const ChatHistoryPane = memo(function ChatHistoryPane({
|
||||
active: boolean;
|
||||
artifactById: ReadonlyMap<string, AssistantArtifact>;
|
||||
conversationHtmlRenderingEnabled: boolean;
|
||||
/** Replaces the native scrollbar with the minimap; off restores the scrollbar. */
|
||||
chatMinimapEnabled?: boolean;
|
||||
conversation: Conversation;
|
||||
locale: TimeFormatLocale;
|
||||
onCopyMessage: (content: string, kind?: 'tool') => Promise<boolean>;
|
||||
@@ -1071,6 +1074,7 @@ export const ChatHistoryPane = memo(function ChatHistoryPane({
|
||||
className="chat-history-pane"
|
||||
data-active={active ? "true" : "false"}
|
||||
data-conversation-id={conversation.id}
|
||||
data-minimap={chatMinimapEnabled ? "true" : undefined}
|
||||
hidden={!active}
|
||||
inert={!active}
|
||||
>
|
||||
@@ -1142,7 +1146,7 @@ export const ChatHistoryPane = memo(function ChatHistoryPane({
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
{active && (
|
||||
{active && chatMinimapEnabled && (
|
||||
<ChatMinimap
|
||||
messages={messages}
|
||||
rowHeights={heights}
|
||||
|
||||
@@ -79,6 +79,7 @@ const otherTodo: MagicTodoItem = { ...todo, id: '00000000-0000-4000-8000-0000000
|
||||
const settings: ApplicationSettings = {
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
checkUpdatesOnStartup: false, updateSource: 'github', modelDownloadSource: 'modelscope',
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings, applicationNavigation: defaultApplicationNavigation,
|
||||
localInferenceEnabled: true, deviceSharingEnabled: false, conversationHtmlRenderingEnabled: true, remoteProjectsEnabled: false,
|
||||
|
||||
@@ -520,6 +520,7 @@ let applicationSettings: ApplicationSettings = {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: 'github',
|
||||
modelDownloadSource: 'modelscope',
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -815,6 +816,7 @@ describe('SettingsPanel runtime files', () => {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: 'github',
|
||||
modelDownloadSource: 'modelscope',
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
@@ -1594,6 +1596,32 @@ describe('SettingsPanel runtime files', () => {
|
||||
expect(onChange).toHaveBeenLastCalledWith(true)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['zh-CN', '外观', '滚动条缩略图'],
|
||||
['en-US', 'Appearance', 'Scrollbar minimap']
|
||||
] as const)('exposes the scrollbar minimap Switch under Appearance in %s', async (locale, category, label) => {
|
||||
await changeUiLocale(locale)
|
||||
const onChange = vi.fn(async () => true)
|
||||
const props = {
|
||||
...heartbeatSettingsProps,
|
||||
open: true,
|
||||
onClearLocalData: vi.fn(async () => {}),
|
||||
onClose: vi.fn(),
|
||||
onSaved: vi.fn(),
|
||||
onChatMinimapEnabledChange: onChange
|
||||
}
|
||||
const { rerender } = render(<SettingsPanel {...props} />)
|
||||
fireEvent.click(screen.getByRole('tab', { name: category }))
|
||||
const toggle = screen.getByRole('switch', { name: label })
|
||||
expect(toggle).toBeChecked()
|
||||
fireEvent.click(toggle)
|
||||
expect(onChange).toHaveBeenCalledExactlyOnceWith(false)
|
||||
rerender(<SettingsPanel {...props} chatMinimapEnabled={false} />)
|
||||
expect(toggle).not.toBeChecked()
|
||||
fireEvent.click(toggle)
|
||||
expect(onChange).toHaveBeenLastCalledWith(true)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['zh-CN', '平台功能', '桌面通知'],
|
||||
['en-US', 'Platform features', 'Desktop notifications']
|
||||
|
||||
@@ -243,6 +243,8 @@ type SettingsPanelProps = {
|
||||
applicationSettingsLocked?: boolean
|
||||
applicationSettingsError?: string
|
||||
onTransparentFrostedEffectEnabledChange?: (enabled: boolean) => Promise<boolean>
|
||||
chatMinimapEnabled?: boolean
|
||||
onChatMinimapEnabledChange?: (enabled: boolean) => Promise<boolean>
|
||||
onRetryApplicationSettings?: () => void
|
||||
onAppearanceThemeChange?: (theme: AppearanceTheme) => void
|
||||
brandingPreferences?: BrandingPreferences
|
||||
@@ -658,6 +660,8 @@ function SettingsPanelView({
|
||||
applicationSettingsLocked = false,
|
||||
applicationSettingsError,
|
||||
onTransparentFrostedEffectEnabledChange,
|
||||
chatMinimapEnabled = true,
|
||||
onChatMinimapEnabledChange,
|
||||
onRetryApplicationSettings,
|
||||
onAppearanceThemeChange = () => {},
|
||||
brandingPreferences = defaultBrandingPreferences,
|
||||
@@ -2380,6 +2384,22 @@ function SettingsPanelView({
|
||||
<p id="frosted-glass-description" className="settings-panel__description">
|
||||
{t('appearance.frostedGlass.description')}
|
||||
</p>
|
||||
<label className="toggle-row">
|
||||
<span>{t('appearance.chatMinimap.label')}</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
checked={chatMinimapEnabled}
|
||||
disabled={applicationSettingsPending || applicationSettingsLocked || !onChatMinimapEnabledChange}
|
||||
aria-describedby="chat-minimap-description"
|
||||
onChange={(event) => {
|
||||
void onChatMinimapEnabledChange?.(event.target.checked)
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
<p id="chat-minimap-description" className="settings-panel__description">
|
||||
{t('appearance.chatMinimap.description')}
|
||||
</p>
|
||||
{applicationSettingsError && (
|
||||
<div role="alert">
|
||||
<p>{applicationSettingsError}</p>
|
||||
|
||||
@@ -25,6 +25,7 @@ describe('UpdateSettingsSection', () => {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: 'github',
|
||||
modelDownloadSource: 'modelscope',
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
|
||||
@@ -876,6 +876,10 @@ export const settings = {
|
||||
description: 'Applies to the top bar and expanded runtime checklist. Takes effect as soon as it is saved.',
|
||||
retry: 'Retry'
|
||||
},
|
||||
chatMinimap: {
|
||||
label: 'Scrollbar minimap',
|
||||
description: 'Replaces the message scrollbar with an overview of the conversation that expands on hover; click or drag to jump. Takes effect as soon as it is saved.'
|
||||
},
|
||||
theme: {
|
||||
title: 'Interface theme',
|
||||
description: 'Applies immediately and is saved on this device',
|
||||
|
||||
@@ -811,6 +811,10 @@ export const settings = {
|
||||
description: '应用于顶栏和展开的运行待办卡片,保存后立即生效。',
|
||||
retry: '重试'
|
||||
},
|
||||
chatMinimap: {
|
||||
label: '滚动条缩略图',
|
||||
description: '在消息区右侧用缩略图代替滚动条,悬停时展开,可点击或拖动定位。保存后立即生效。'
|
||||
},
|
||||
theme: {
|
||||
title: '界面主题',
|
||||
description: '选择后立即应用,并保存在此设备',
|
||||
|
||||
@@ -7343,12 +7343,12 @@ button > svg {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
/* The minimap replaces the native scrollbar of the message scroller. */
|
||||
.chat-history-pane > .chat {
|
||||
/* When enabled, the minimap replaces the native scrollbar of the message scroller. */
|
||||
.chat-history-pane[data-minimap='true'] > .chat {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.chat-history-pane > .chat::-webkit-scrollbar {
|
||||
.chat-history-pane[data-minimap='true'] > .chat::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ const applicationPreferencesSchema = z
|
||||
checkUpdatesOnStartup: z.boolean(),
|
||||
desktopNotificationsEnabled: z.boolean().default(true),
|
||||
transparentFrostedEffectEnabled: z.boolean().default(true),
|
||||
chatMinimapEnabled: z.boolean().default(true),
|
||||
updateSource: updateSourceSchema,
|
||||
modelDownloadSource: modelDownloadSourceSchema,
|
||||
localToolEnvironment: localToolEnvironmentSettingsSchema,
|
||||
@@ -94,6 +95,7 @@ export const applicationSettingsUpdateSchema = applicationPreferencesSchema
|
||||
applicationNavigation: applicationNavigationSchema.optional(),
|
||||
desktopNotificationsEnabled: z.boolean().optional(),
|
||||
transparentFrostedEffectEnabled: z.boolean().optional(),
|
||||
chatMinimapEnabled: z.boolean().optional(),
|
||||
localInferenceEnabled: z.boolean().optional(),
|
||||
deviceSharingEnabled: z.boolean().optional(),
|
||||
magicNotesEnabled: z.boolean().optional(),
|
||||
|
||||
@@ -154,6 +154,7 @@ describe('GoodBuddy configuration contracts', () => {
|
||||
checkUpdatesOnStartup: true,
|
||||
desktopNotificationsEnabled: true,
|
||||
transparentFrostedEffectEnabled: false,
|
||||
chatMinimapEnabled: true,
|
||||
updateSource: 'github',
|
||||
modelDownloadSource: 'modelscope',
|
||||
localToolEnvironment: defaultLocalToolEnvironmentSettings,
|
||||
|
||||
Reference in New Issue
Block a user