1+ import { startTransition } from "react" ;
12import { Switch } from "@heroui/react" ;
3+ import { Select } from "@/renderer/components/common" ;
24import { useSharedSettings } from "@/renderer/state/sharedSettingsStore" ;
5+ import type { BrowserLinkOpenTarget , BrowserLinkPresentationMode } from "@/shared/settings" ;
6+
7+ const linkOpenTargetOptions = [
8+ { id : "internal" , label : "App Browser" } ,
9+ { id : "system" , label : "System Browser" } ,
10+ ] as const ;
11+
12+ const linkPresentationModeOptions = [
13+ { id : "panel" , label : "Right panel" } ,
14+ { id : "overlay" , label : "Fullscreen overlay" } ,
15+ ] as const ;
316
417export function BrowserSettings ( ) {
518 const allowEval = useSharedSettings ( ( s ) => s . browser . allowEval ) ;
619 const allowDataAccess = useSharedSettings ( ( s ) => s . browser . allowDataAccess ) ;
20+ const linkOpenTarget = useSharedSettings ( ( s ) => s . browser . linkOpenTarget ) ;
21+ const linkPresentationMode = useSharedSettings ( ( s ) => s . browser . linkPresentationMode ) ;
722 const setBrowserSetting = useSharedSettings ( ( s ) => s . setBrowserSetting ) ;
823
924 return (
1025 < div className = "h-full min-h-0 overflow-y-auto px-6 pb-8 pt-4" >
1126 < div className = "mx-auto max-w-[720px]" >
12- < h1 className = "mb-2 text-lg font-semibold text-foreground" > Browser</ h1 >
13- < p className = "mb-6 text-xs text-muted" >
14- The in-app browser lives in the right panel. Threads can opt in to the browser MCP via the
15- composer "+" menu; once enabled they can navigate, click, type, query the DOM, and take
16- screenshots inside this panel. The browser keeps running in the background even when the
17- panel is hidden.
18- </ p >
27+ < h1 className = "mb-6 text-lg font-semibold text-foreground" > Browser</ h1 >
1928
2029 < div className = "space-y-4" >
30+ < SettingRow
31+ title = "Open links in"
32+ description = "Choose whether links from Lightcode and browser popups stay in Lightcode or open externally."
33+ >
34+ < Select
35+ aria-label = "Open links in"
36+ className = "w-[180px] shrink-0"
37+ options = { linkOpenTargetOptions }
38+ value = { linkOpenTarget }
39+ onChange = { ( value ) => {
40+ startTransition ( ( ) => {
41+ setBrowserSetting ( "linkOpenTarget" , value as BrowserLinkOpenTarget ) ;
42+ } ) ;
43+ } }
44+ />
45+ </ SettingRow >
46+ < SettingRow
47+ title = "Show opened links in"
48+ description = "When links open in a Lightcode browser tab, choose where the browser is revealed."
49+ >
50+ < Select
51+ aria-label = "Show opened links in"
52+ className = "w-[180px] shrink-0"
53+ options = { linkPresentationModeOptions }
54+ value = { linkPresentationMode }
55+ onChange = { ( value ) => {
56+ startTransition ( ( ) => {
57+ setBrowserSetting ( "linkPresentationMode" , value as BrowserLinkPresentationMode ) ;
58+ } ) ;
59+ } }
60+ />
61+ </ SettingRow >
2162 < SettingRow
2263 title = "Allow eval"
2364 description = {
@@ -26,9 +67,20 @@ export function BrowserSettings() {
2667 page. Off by default — turn on only when you trust the loaded sites and the agent.
2768 </ >
2869 }
29- value = { allowEval }
30- onChange = { ( v ) => setBrowserSetting ( "allowEval" , v ) }
31- />
70+ >
71+ < Switch
72+ isSelected = { allowEval }
73+ onChange = { ( selected ) => {
74+ startTransition ( ( ) => {
75+ setBrowserSetting ( "allowEval" , selected ) ;
76+ } ) ;
77+ } }
78+ >
79+ < Switch . Control >
80+ < Switch . Thumb />
81+ </ Switch . Control >
82+ </ Switch >
83+ </ SettingRow >
3284 < SettingRow
3385 title = "Allow agents to read/write cookies and storage"
3486 description = {
@@ -38,9 +90,20 @@ export function BrowserSettings() {
3890 agent and the sites it visits.
3991 </ >
4092 }
41- value = { allowDataAccess }
42- onChange = { ( v ) => setBrowserSetting ( "allowDataAccess" , v ) }
43- />
93+ >
94+ < Switch
95+ isSelected = { allowDataAccess }
96+ onChange = { ( selected ) => {
97+ startTransition ( ( ) => {
98+ setBrowserSetting ( "allowDataAccess" , selected ) ;
99+ } ) ;
100+ } }
101+ >
102+ < Switch . Control >
103+ < Switch . Thumb />
104+ </ Switch . Control >
105+ </ Switch >
106+ </ SettingRow >
44107 </ div >
45108 </ div >
46109 </ div >
@@ -50,25 +113,15 @@ export function BrowserSettings() {
50113function SettingRow ( props : {
51114 title : string ;
52115 description : React . ReactNode ;
53- value : boolean ;
54- onChange : ( v : boolean ) => void ;
55- disabled ?: boolean ;
116+ children : React . ReactNode ;
56117} ) {
57118 return (
58- < div className = "flex items-start justify-between gap-4 rounded-lg border border-border bg-[var(--surface-background,#0d1117)] px-4 py-3 " >
59- < div className = "min-w-0 flex-1 " >
60- < div className = "text-sm font-medium text-foreground" > { props . title } </ div >
61- < div className = "mt-1 text-xs text-muted" > { props . description } </ div >
119+ < div className = "flex items-center justify-between gap-4" >
120+ < div className = "min-w-0" >
121+ < p className = "text-sm font-medium text-foreground" > { props . title } </ p >
122+ < p className = "text-xs text-muted" > { props . description } </ p >
62123 </ div >
63- < Switch
64- isSelected = { props . value }
65- isDisabled = { props . disabled === true }
66- onChange = { ( selected ) => props . onChange ( selected ) }
67- >
68- < Switch . Control >
69- < Switch . Thumb />
70- </ Switch . Control >
71- </ Switch >
124+ { props . children }
72125 </ div >
73126 ) ;
74127}
0 commit comments