Bring Settings zoom drift fix onto local main

The local main checkout already had a merge in progress for the Settings zoom synchronization fix. The conflict content in globals.css was resolved in the working tree, so this commit records that existing merge before landing the chat scroll fix.

Constraint: main had an existing MERGE_HEAD before the chat scroll landing
Confidence: medium
Scope-risk: narrow
Directive: Do not conflate this merge commit with the chat scroll fix; it only completes the pre-existing Settings zoom merge
Tested: Not run in this step
Not-tested: Settings zoom regression suite after recording the existing merge
This commit is contained in:
程序员阿江(Relakkes) 2026-05-15 19:37:04 +08:00
commit 8e8e596817
3 changed files with 33 additions and 15 deletions

View File

@ -268,7 +268,7 @@ describe('Settings > General tab', () => {
expect((uiZoomHeading.compareDocumentPosition(webFetchHeading) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0).toBe(true)
})
it('previews UI zoom while dragging and applies it only when the user releases the slider', async () => {
it('applies UI zoom while dragging so the slider and app zoom stay synchronized', async () => {
render(<Settings />)
fireEvent.click(screen.getByText('General'))
@ -287,7 +287,9 @@ describe('Settings > General tab', () => {
})
expect(screen.getAllByText('125%')).toHaveLength(2)
expect(useSettingsStore.getState().setUiZoom).not.toHaveBeenCalledWith(1.25)
expect(useSettingsStore.getState().setUiZoom).toHaveBeenCalledWith(1.25)
expect(useSettingsStore.getState().uiZoom).toBe(1.25)
expect(slider).toHaveValue('1.25')
expect(slider).toHaveClass('settings-zoom-range')
expect(slider.closest('.settings-zoom-control')).toHaveClass('is-dragging')
expect(slider.closest('.settings-zoom-control')).toHaveStyle({ '--settings-zoom-range-progress': '50%' })
@ -297,6 +299,7 @@ describe('Settings > General tab', () => {
})
expect(useSettingsStore.getState().setUiZoom).toHaveBeenCalledWith(1.25)
expect(slider.closest('.settings-zoom-control')).not.toHaveClass('is-dragging')
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Reset UI zoom to 100%' }))
@ -305,6 +308,22 @@ describe('Settings > General tab', () => {
expect(useSettingsStore.getState().setUiZoom).toHaveBeenLastCalledWith(1)
})
it('updates the UI zoom slider when shortcut zoom changes the shared setting while Settings is open', async () => {
render(<Settings />)
fireEvent.click(screen.getByText('General'))
const slider = screen.getByLabelText('UI Zoom')
await act(async () => {
useSettingsStore.setState({ uiZoom: 1.1 })
})
expect(slider).toHaveValue('1.1')
expect(screen.getAllByText('110%')).toHaveLength(2)
expect(slider.closest('.settings-zoom-control')).toHaveStyle({ '--settings-zoom-range-progress': '40%' })
})
it('opens the Token usage tab from Settings navigation above Diagnostics', () => {
render(<Settings />)

View File

@ -1396,7 +1396,7 @@ function GeneralSettings() {
const [isUiZoomDragging, setIsUiZoomDragging] = useState(false)
const webSearchDirty = JSON.stringify(webSearchDraft) !== JSON.stringify(webSearch)
const uiZoomPercent = Math.round(uiZoomDraft * 100)
const uiZoomRangeProgress = `${((uiZoomDraft - UI_ZOOM_MIN) / (UI_ZOOM_MAX - UI_ZOOM_MIN)) * 100}%`
const uiZoomRangeProgress = `${Math.round(((uiZoomDraft - UI_ZOOM_MIN) / (UI_ZOOM_MAX - UI_ZOOM_MIN)) * 1000) / 10}%`
useEffect(() => {
setWebSearchDraft(webSearch)
@ -1523,9 +1523,11 @@ function GeneralSettings() {
}
}
const commitUiZoom = (value: number) => {
const commitUiZoom = (value: number, options: { keepDragging?: boolean } = {}) => {
const nextZoom = Number.isFinite(value) ? value : UI_ZOOM_DEFAULT
setIsUiZoomDragging(false)
if (!options.keepDragging) {
setIsUiZoomDragging(false)
}
setUiZoomDraft(nextZoom)
setUiZoom(nextZoom)
}
@ -1599,21 +1601,17 @@ function GeneralSettings() {
max={UI_ZOOM_MAX}
step={UI_ZOOM_STEP}
value={uiZoomDraft}
onPointerDown={(e) => {
onPointerDown={() => {
setIsUiZoomDragging(true)
e.currentTarget.setPointerCapture?.(e.pointerId)
}}
onPointerUp={(e) => commitUiZoom(e.currentTarget.valueAsNumber)}
onPointerCancel={(e) => commitUiZoom(e.currentTarget.valueAsNumber)}
onChange={(e) => setUiZoomDraft(e.currentTarget.valueAsNumber)}
onKeyUp={(e) => {
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown'].includes(e.key)) {
commitUiZoom(e.currentTarget.valueAsNumber)
}
}}
onPointerUp={() => setIsUiZoomDragging(false)}
onPointerCancel={() => setIsUiZoomDragging(false)}
onChange={(e) => commitUiZoom(e.currentTarget.valueAsNumber, { keepDragging: isUiZoomDragging })}
onBlur={(e) => {
if (uiZoomDraft !== uiZoom) {
commitUiZoom(e.currentTarget.valueAsNumber)
} else {
setIsUiZoomDragging(false)
}
}}
className="settings-zoom-range w-full"

View File

@ -199,6 +199,7 @@
cursor: pointer;
background: transparent;
accent-color: var(--color-brand);
touch-action: none;
}
.settings-zoom-range:focus {