diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index b31cfb6cc79..370aacad2d2 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -1,4 +1,4 @@ -import { Component, createMemo, type JSX } from "solid-js" +import { Component, createMemo, Show, type JSX } from "solid-js" import { createStore } from "solid-js/store" import { Button } from "@opencode-ai/ui/button" import { Select } from "@opencode-ai/ui/select" @@ -410,6 +410,27 @@ export const SettingsGeneral: Component = () => { + + {/* Desktop Section - Desktop only */} + +
+

{language.t("settings.general.section.desktop")}

+ +
+ +
+ settings.browser.setOpenLinksExternally(checked)} + /> +
+
+
+
+
) @@ -423,8 +444,8 @@ interface SettingsRowProps { const SettingsRow: Component = (props) => { return ( -
-
+
+
{props.title} {props.description}
diff --git a/packages/app/src/context/settings.tsx b/packages/app/src/context/settings.tsx index 19b3846f84e..35cbf29d620 100644 --- a/packages/app/src/context/settings.tsx +++ b/packages/app/src/context/settings.tsx @@ -15,6 +15,10 @@ export interface SoundSettings { errors: string } +export interface BrowserSettings { + openLinksExternally: boolean +} + export interface Settings { general: { autoSave: boolean @@ -33,6 +37,7 @@ export interface Settings { } notifications: NotificationSettings sounds: SoundSettings + browser: BrowserSettings } const defaultSettings: Settings = { @@ -61,6 +66,9 @@ const defaultSettings: Settings = { permissions: "staplebops-02", errors: "nope-03", }, + browser: { + openLinksExternally: true, + }, } const monoFallback = @@ -172,6 +180,14 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont setStore("sounds", "errors", value) }, }, + browser: { + openLinksExternally: createMemo( + () => store.browser?.openLinksExternally ?? defaultSettings.browser.openLinksExternally, + ), + setOpenLinksExternally(value: boolean) { + setStore("browser", "openLinksExternally", value) + }, + }, } }, }) diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index f816c9aca0e..231293ce009 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -526,6 +526,10 @@ export const dict = { "settings.general.section.notifications": "إشعارات النظام", "settings.general.section.updates": "التحديثات", "settings.general.section.sounds": "المؤثرات الصوتية", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "فتح الروابط في متصفح خارجي", + "settings.general.desktop.openLinksExternally.description": + "عند التفعيل، سيتم فتح الروابط في متصفح النظام الافتراضي بدلاً من داخل التطبيق", "settings.general.row.language.title": "اللغة", "settings.general.row.language.description": "تغيير لغة العرض لـ OpenCode", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 4bb66e11c91..e8bdf7e6086 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -530,6 +530,10 @@ export const dict = { "settings.general.section.notifications": "Notificações do sistema", "settings.general.section.updates": "Atualizações", "settings.general.section.sounds": "Efeitos sonoros", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Abrir links no navegador externo", + "settings.general.desktop.openLinksExternally.description": + "Quando ativado, clicar em links os abrirá no navegador padrão do sistema em vez de dentro do app", "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Alterar o idioma de exibição do OpenCode", diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index 95d9f4a0fc2..0581ce15381 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -530,6 +530,10 @@ export const dict = { "settings.general.section.notifications": "Systemmeddelelser", "settings.general.section.updates": "Opdateringer", "settings.general.section.sounds": "Lydeffekter", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Åbn links i ekstern browser", + "settings.general.desktop.openLinksExternally.description": + "Når aktiveret, åbnes links i din standard systembrowser i stedet for i appen", "settings.general.row.language.title": "Sprog", "settings.general.row.language.description": "Ændr visningssproget for OpenCode", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index 3ead99427d1..e147558c91b 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -535,6 +535,10 @@ export const dict = { "settings.general.section.notifications": "Systembenachrichtigungen", "settings.general.section.updates": "Updates", "settings.general.section.sounds": "Soundeffekte", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Links im externen Browser öffnen", + "settings.general.desktop.openLinksExternally.description": + "Wenn aktiviert, werden Links in Ihrem Standard-Systembrowser geöffnet anstatt innerhalb der App", "settings.general.row.language.title": "Sprache", "settings.general.row.language.description": "Die Anzeigesprache für OpenCode ändern", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 780c19e21c0..6a8778a0143 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -542,6 +542,10 @@ export const dict = { "settings.general.section.notifications": "System notifications", "settings.general.section.updates": "Updates", "settings.general.section.sounds": "Sound effects", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Open links in external browser", + "settings.general.desktop.openLinksExternally.description": + "When enabled, clicking links will open them in your default system browser instead of within the app", "settings.general.row.language.title": "Language", "settings.general.row.language.description": "Change the display language for OpenCode", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index 4c5fe30040f..e6e89857d7b 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -533,6 +533,10 @@ export const dict = { "settings.general.section.notifications": "Notificaciones del sistema", "settings.general.section.updates": "Actualizaciones", "settings.general.section.sounds": "Efectos de sonido", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Abrir enlaces en navegador externo", + "settings.general.desktop.openLinksExternally.description": + "Al activarse, los enlaces se abrirán en el navegador predeterminado del sistema en lugar de dentro de la app", "settings.general.row.language.title": "Idioma", "settings.general.row.language.description": "Cambiar el idioma de visualización para OpenCode", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 41c8b45547e..bea5437965c 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -540,6 +540,10 @@ export const dict = { "settings.general.section.notifications": "Notifications système", "settings.general.section.updates": "Mises à jour", "settings.general.section.sounds": "Effets sonores", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Ouvrir les liens dans un navigateur externe", + "settings.general.desktop.openLinksExternally.description": + "Lorsqu'activé, les liens s'ouvriront dans votre navigateur système par défaut au lieu de l'application", "settings.general.row.language.title": "Langue", "settings.general.row.language.description": "Changer la langue d'affichage pour OpenCode", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index d2530f5e517..b575e6a0142 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -525,6 +525,10 @@ export const dict = { "settings.general.section.notifications": "システム通知", "settings.general.section.updates": "アップデート", "settings.general.section.sounds": "効果音", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "外部ブラウザでリンクを開く", + "settings.general.desktop.openLinksExternally.description": + "有効にすると、リンクをクリックするとアプリ内ではなくシステムの既定ブラウザで開きます", "settings.general.row.language.title": "言語", "settings.general.row.language.description": "OpenCodeの表示言語を変更します", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index f81164ce3b5..def5a02c9d3 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -531,6 +531,10 @@ export const dict = { "settings.general.section.notifications": "시스템 알림", "settings.general.section.updates": "업데이트", "settings.general.section.sounds": "효과음", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "외부 브라우저에서 링크 열기", + "settings.general.desktop.openLinksExternally.description": + "활성화하면 링크를 클릭할 때 앱 내부가 아닌 기본 시스템 브라우저에서 열립니다", "settings.general.row.language.title": "언어", "settings.general.row.language.description": "OpenCode 표시 언어 변경", diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index d1f2bc7fdc5..ce76bfbfeab 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -533,6 +533,10 @@ export const dict = { "settings.general.section.notifications": "Systemvarsler", "settings.general.section.updates": "Oppdateringer", "settings.general.section.sounds": "Lydeffekter", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Åpne lenker i ekstern nettleser", + "settings.general.desktop.openLinksExternally.description": + "Når aktivert, åpnes lenker i standard systemnettleseren i stedet for i appen", "settings.general.row.language.title": "Språk", "settings.general.row.language.description": "Endre visningsspråket for OpenCode", diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index f1211c45993..70626706e2a 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -532,6 +532,10 @@ export const dict = { "settings.general.section.notifications": "Powiadomienia systemowe", "settings.general.section.updates": "Aktualizacje", "settings.general.section.sounds": "Efekty dźwiękowe", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Otwieraj linki w zewnętrznej przeglądarce", + "settings.general.desktop.openLinksExternally.description": + "Po włączeniu linki będą otwierane w domyślnej przeglądarce systemowej zamiast w aplikacji", "settings.general.row.language.title": "Język", "settings.general.row.language.description": "Zmień język wyświetlania dla OpenCode", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index e0efffa41bc..f7f1a477011 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -535,6 +535,10 @@ export const dict = { "settings.general.section.notifications": "Системные уведомления", "settings.general.section.updates": "Обновления", "settings.general.section.sounds": "Звуковые эффекты", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "Открывать ссылки во внешнем браузере", + "settings.general.desktop.openLinksExternally.description": + "При включении ссылки будут открываться в системном браузере по умолчанию, а не внутри приложения", "settings.general.row.language.title": "Язык", "settings.general.row.language.description": "Изменить язык отображения OpenCode", diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index cfe439d510c..cfe2f217d66 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -534,6 +534,10 @@ export const dict = { "settings.general.section.notifications": "การแจ้งเตือนระบบ", "settings.general.section.updates": "การอัปเดต", "settings.general.section.sounds": "เสียงเอฟเฟกต์", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "เปิดลิงก์ในเบราว์เซอร์ภายนอก", + "settings.general.desktop.openLinksExternally.description": + "เมื่อเปิดใช้งาน การคลิกลิงก์จะเปิดในเบราว์เซอร์เริ่มต้นของระบบแทนที่จะเปิดในแอป", "settings.general.row.language.title": "ภาษา", "settings.general.row.language.description": "เปลี่ยนภาษาที่แสดงสำหรับ OpenCode", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index 81bb23db9d8..ea8d99ee3fe 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -528,6 +528,10 @@ export const dict = { "settings.general.section.notifications": "系统通知", "settings.general.section.updates": "更新", "settings.general.section.sounds": "音效", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "在外部浏览器中打开链接", + "settings.general.desktop.openLinksExternally.description": + "启用后,点击链接将在系统默认浏览器中打开,而不是在应用内打开", "settings.general.row.language.title": "语言", "settings.general.row.language.description": "更改 OpenCode 的显示语言", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index f01c1ce0b14..80fd71e236d 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -525,6 +525,10 @@ export const dict = { "settings.general.section.notifications": "系統通知", "settings.general.section.updates": "更新", "settings.general.section.sounds": "音效", + "settings.general.section.desktop": "Desktop", + "settings.general.desktop.openLinksExternally.title": "在外部瀏覽器中開啟連結", + "settings.general.desktop.openLinksExternally.description": + "啟用後,點擊連結將在系統預設瀏覽器中開啟,而非在應用程式內開啟", "settings.general.row.language.title": "語言", "settings.general.row.language.description": "變更 OpenCode 的顯示語言", diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx index 9ef680ed869..aa6c913e565 100644 --- a/packages/desktop/src/index.tsx +++ b/packages/desktop/src/index.tsx @@ -59,6 +59,24 @@ const listenForDeepLinks = async () => { await onOpenUrl((urls) => emitDeepLinks(urls)).catch(() => undefined) } +// Settings key for reading browser preferences +const SETTINGS_KEY = "settings.v3" + +// Read browser settings from store to check if links should open externally +async function shouldOpenLinksExternally(): Promise { + try { + const store = await Store.load("opencode.global.dat") + const settings = await store.get(SETTINGS_KEY) + if (settings && typeof settings === "object" && "browser" in (settings as object)) { + const browser = (settings as { browser?: { openLinksExternally?: boolean } }).browser + return browser?.openLinksExternally !== false // Default to true + } + } catch { + // Ignore errors, default to true + } + return true // Default: open links externally +} + const createPlatform = (password: Accessor): Platform => ({ platform: "desktop", os: (() => { @@ -356,11 +374,26 @@ render(() => { const platform = createPlatform(() => serverPassword()) function handleClick(e: MouseEvent) { - const link = (e.target as HTMLElement).closest("a.external-link") as HTMLAnchorElement | null - if (link?.href) { - e.preventDefault() - platform.openLink(link.href) - } + const link = (e.target as HTMLElement).closest("a") as HTMLAnchorElement | null + if (!link?.href) return + + // Check if it's an external link (http/https) + const isExternal = link.href.startsWith("http://") || link.href.startsWith("https://") + if (!isExternal) return + + // MUST preventDefault immediately (before any async), otherwise browser handles it + e.preventDefault() + const url = link.href + + // Check user preference and handle accordingly + shouldOpenLinksExternally().then((openExternally) => { + if (openExternally) { + platform.openLink(url) + } else { + // Open in app by navigating + window.location.href = url + } + }) } onMount(() => {