1313 * terminal's hidden textarea, the roles here act on a real page: `copy` and
1414 * `paste` go to the frame that was clicked.
1515 */
16+
17+ import { resolveDesktopZoom } from '@sim/desktop-bridge'
1618import type { ContextMenuParams , MenuItemConstructorOptions , WebContents } from 'electron'
1719import { clipboard , Menu } from 'electron'
1820
@@ -22,9 +24,9 @@ import { clipboard, Menu } from 'electron'
2224 * Chromium refuses to scale past them, and a rung outside the range would come
2325 * back clamped and leave the menu offering a step that never lands.
2426 */
25- const ZOOM_STEP_RATIO = 1.1
2627const MIN_ZOOM_FACTOR = 0.5
2728const MAX_ZOOM_FACTOR = 3
29+ const ZOOM_FACTOR_BOUNDS = { min : MIN_ZOOM_FACTOR , max : MAX_ZOOM_FACTOR } as const
2830
2931/**
3032 * What the panel calls 100%.
@@ -33,14 +35,14 @@ const MAX_ZOOM_FACTOR = 3
3335 * it renders a rung below Chromium's native scale and treats THAT as its
3436 * baseline: the menu reads 100% there, and every other rung is reported
3537 * relative to it. New installs start there; when a user chooses a different
36- * default, Reset Zoom returns to that configured percentage. The initial 100%
38+ * default, Actual Size returns to that configured percentage. The initial 100%
3739 * is genuinely rendering at ~91% of native.
3840 *
3941 * Defined as one rung below native rather than as a round number so the ladder
4042 * still lands exactly on Chromium's 1.0 (the crispest rasterization, one step
4143 * up from the baseline) instead of straddling it.
4244 */
43- export const BASE_ZOOM_FACTOR = 1 / ZOOM_STEP_RATIO
45+ export const BASE_ZOOM_FACTOR = resolveDesktopZoom ( 1 , 'out' , 1 , ZOOM_FACTOR_BOUNDS )
4446
4547/**
4648 * A Chromium zoom factor as a percentage of {@link BASE_ZOOM_FACTOR} — what the
@@ -60,9 +62,12 @@ export function zoomPercentOf(factor: number): number {
6062 * the item rather than offer a step that does nothing.
6163 */
6264export function steppedZoomFactor ( current : number , direction : 1 | - 1 ) : number {
63- const base = Number . isFinite ( current ) && current > 0 ? current : BASE_ZOOM_FACTOR
64- const next = direction === 1 ? base * ZOOM_STEP_RATIO : base / ZOOM_STEP_RATIO
65- return Math . min ( MAX_ZOOM_FACTOR , Math . max ( MIN_ZOOM_FACTOR , next ) )
65+ return resolveDesktopZoom (
66+ current ,
67+ direction === 1 ? 'in' : 'out' ,
68+ BASE_ZOOM_FACTOR ,
69+ ZOOM_FACTOR_BOUNDS
70+ )
6671}
6772
6873/** The parts of a right-click the menu acts on. */
@@ -80,6 +85,7 @@ interface AgentPageContext {
8085}
8186
8287interface AgentContextMenuHandlers {
88+ addToChat ( text : string ) : void
8389 copy ( ) : void
8490 paste ( ) : void
8591 back ( ) : void
@@ -91,6 +97,8 @@ interface AgentContextMenuHandlers {
9197}
9298
9399export interface AgentContextMenuHost {
100+ /** Attaches selected page text to the chat that owns this browser tab. */
101+ addToChat ( text : string ) : void
94102 /** Opens a link from the page in another tab of the same browser. */
95103 openTab ( url : string ) : void
96104 /** Returns the device's current default page zoom factor. */
@@ -112,6 +120,14 @@ export function buildAgentContextMenuTemplate(
112120) : MenuItemConstructorOptions [ ] {
113121 const template : MenuItemConstructorOptions [ ] = [ ]
114122 const linkUrl = / ^ h t t p s ? : \/ \/ / i. test ( params . linkURL ) ? params . linkURL : ''
123+ const selectionText = params . selectionText
124+
125+ if ( selectionText . trim ( ) ) {
126+ template . push (
127+ { label : 'Add to chat' , click : ( ) => handlers . addToChat ( selectionText ) } ,
128+ { type : 'separator' }
129+ )
130+ }
115131
116132 if ( linkUrl ) {
117133 template . push (
@@ -121,7 +137,7 @@ export function buildAgentContextMenuTemplate(
121137 )
122138 }
123139
124- if ( params . selectionText . trim ( ) ) {
140+ if ( selectionText . trim ( ) ) {
125141 template . push ( { label : 'Copy' , click : ( ) => handlers . copy ( ) } )
126142 }
127143 if ( params . isEditable && params . editFlags . canPaste ) {
@@ -153,7 +169,7 @@ export function buildAgentContextMenuTemplate(
153169 click : ( ) => handlers . setZoomFactor ( zoomOut ) ,
154170 } ,
155171 {
156- label : `Reset Zoom (${ zoomPercent } %)` ,
172+ label : `Actual Size (${ zoomPercent } %)` ,
157173 enabled : page . zoomFactor !== page . defaultZoomFactor ,
158174 click : ( ) => handlers . setZoomFactor ( page . defaultZoomFactor ) ,
159175 }
@@ -174,6 +190,7 @@ export function attachAgentContextMenu(contents: WebContents, host: AgentContext
174190 defaultZoomFactor : host . defaultZoomFactor ( ) ,
175191 } ,
176192 {
193+ addToChat : ( text ) => host . addToChat ( text ) ,
177194 copy : ( ) => contents . copy ( ) ,
178195 paste : ( ) => contents . paste ( ) ,
179196 back : ( ) => contents . navigationHistory . goBack ( ) ,
0 commit comments