@@ -34,7 +34,9 @@ import {
3434 DEFAULT_GIT_TEXT_GENERATION_MODEL ,
3535} from "@okcode/contracts" ;
3636import { getModelOptions , normalizeModelSlug } from "@okcode/shared/model" ;
37+ import { validateHttpPreviewUrl } from "@okcode/shared/preview" ;
3738import {
39+ DEFAULT_BROWSER_PREVIEW_START_PAGE_URL ,
3840 DEFAULT_SIDEBAR_FONT_SIZE ,
3941 DEFAULT_SIDEBAR_PROJECT_ROW_HEIGHT ,
4042 DEFAULT_SIDEBAR_SPACING ,
@@ -46,6 +48,7 @@ import {
4648 MODEL_PROVIDER_SETTINGS ,
4749 patchCustomModels ,
4850 PrReviewRequestChangesTone ,
51+ resolveBrowserPreviewStartPageUrl ,
4952 SIDEBAR_FONT_SIZE_MAX ,
5053 SIDEBAR_FONT_SIZE_MIN ,
5154 SIDEBAR_PROJECT_ROW_HEIGHT_MAX ,
@@ -758,6 +761,14 @@ function SettingsRouteView() {
758761 const { settings, defaults, updateSettings, resetSettings } = useAppSettings ( ) ;
759762 const serverConfigQuery = useQuery ( serverConfigQueryOptions ( ) ) ;
760763 const queryClient = useQueryClient ( ) ;
764+ const trimmedBrowserPreviewStartPageUrl = settings . browserPreviewStartPageUrl . trim ( ) ;
765+ const browserPreviewStartPageValidation =
766+ trimmedBrowserPreviewStartPageUrl . length > 0
767+ ? validateHttpPreviewUrl ( trimmedBrowserPreviewStartPageUrl )
768+ : null ;
769+ const effectiveBrowserPreviewStartPageUrl = resolveBrowserPreviewStartPageUrl (
770+ settings . browserPreviewStartPageUrl ,
771+ ) ;
761772 const projects = useStore ( ( state ) => state . projects ) ;
762773 const threads = useStore ( ( state ) => state . threads ) ;
763774 const [ selectedProjectId , setSelectedProjectId ] = useState < ProjectId | null > (
@@ -2133,6 +2144,64 @@ function SettingsRouteView() {
21332144 }
21342145 />
21352146
2147+ < SettingsRow
2148+ title = "Browser preview start page"
2149+ description = "Used when opening a new browser preview tab without typing a URL first."
2150+ status = {
2151+ trimmedBrowserPreviewStartPageUrl . length === 0 ? (
2152+ < >
2153+ Blank uses the default start page:{ " " }
2154+ < code > { DEFAULT_BROWSER_PREVIEW_START_PAGE_URL } </ code >
2155+ </ >
2156+ ) : browserPreviewStartPageValidation ?. ok ? (
2157+ < >
2158+ New blank preview tabs will open at{ " " }
2159+ < code > { browserPreviewStartPageValidation . url } </ code > .
2160+ </ >
2161+ ) : (
2162+ < >
2163+ < span className = "text-destructive" >
2164+ Invalid URL. Falling back to{ " " }
2165+ < code > { DEFAULT_BROWSER_PREVIEW_START_PAGE_URL } </ code > .
2166+ </ span >
2167+ < span className = "mt-1 block break-all" >
2168+ Effective start page:{ " " }
2169+ < code > { effectiveBrowserPreviewStartPageUrl } </ code >
2170+ </ span >
2171+ </ >
2172+ )
2173+ }
2174+ resetAction = {
2175+ settings . browserPreviewStartPageUrl !==
2176+ defaults . browserPreviewStartPageUrl ? (
2177+ < SettingResetButton
2178+ label = "browser preview start page"
2179+ onClick = { ( ) =>
2180+ updateSettings ( {
2181+ browserPreviewStartPageUrl : defaults . browserPreviewStartPageUrl ,
2182+ } )
2183+ }
2184+ />
2185+ ) : null
2186+ }
2187+ control = {
2188+ < Input
2189+ value = { settings . browserPreviewStartPageUrl }
2190+ onChange = { ( event ) =>
2191+ updateSettings ( {
2192+ browserPreviewStartPageUrl : event . target . value ,
2193+ } )
2194+ }
2195+ placeholder = { DEFAULT_BROWSER_PREVIEW_START_PAGE_URL }
2196+ aria-label = "Browser preview start page"
2197+ autoCapitalize = "off"
2198+ autoCorrect = "off"
2199+ spellCheck = { false }
2200+ className = "w-full sm:w-72"
2201+ />
2202+ }
2203+ />
2204+
21362205 < SettingsRow
21372206 title = "Code Preview Autosave"
21382207 description = "Automatically save edits made in the built-in code preview after a short delay."
0 commit comments