app.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import "@/index.css"
  2. import { ErrorBoundary, Show, lazy, type ParentProps } from "solid-js"
  3. import { Router, Route, Navigate } from "@solidjs/router"
  4. import { MetaProvider } from "@solidjs/meta"
  5. import { Font } from "@opencode-ai/ui/font"
  6. import { MarkedProvider } from "@opencode-ai/ui/context/marked"
  7. import { DiffComponentProvider } from "@opencode-ai/ui/context/diff"
  8. import { CodeComponentProvider } from "@opencode-ai/ui/context/code"
  9. import { I18nProvider } from "@opencode-ai/ui/context"
  10. import { Diff } from "@opencode-ai/ui/diff"
  11. import { Code } from "@opencode-ai/ui/code"
  12. import { ThemeProvider } from "@opencode-ai/ui/theme"
  13. import { GlobalSyncProvider } from "@/context/global-sync"
  14. import { PermissionProvider } from "@/context/permission"
  15. import { LayoutProvider } from "@/context/layout"
  16. import { GlobalSDKProvider } from "@/context/global-sdk"
  17. import { normalizeServerUrl, ServerProvider, useServer } from "@/context/server"
  18. import { SettingsProvider } from "@/context/settings"
  19. import { TerminalProvider } from "@/context/terminal"
  20. import { PromptProvider } from "@/context/prompt"
  21. import { FileProvider } from "@/context/file"
  22. import { CommentsProvider } from "@/context/comments"
  23. import { NotificationProvider } from "@/context/notification"
  24. import { ModelsProvider } from "@/context/models"
  25. import { DialogProvider } from "@opencode-ai/ui/context/dialog"
  26. import { CommandProvider } from "@/context/command"
  27. import { LanguageProvider, useLanguage } from "@/context/language"
  28. import { usePlatform } from "@/context/platform"
  29. import { HighlightsProvider } from "@/context/highlights"
  30. import Layout from "@/pages/layout"
  31. import DirectoryLayout from "@/pages/directory-layout"
  32. import { ErrorPage } from "./pages/error"
  33. import { Suspense, JSX } from "solid-js"
  34. const Home = lazy(() => import("@/pages/home"))
  35. const Session = lazy(() => import("@/pages/session"))
  36. const Loading = () => <div class="size-full" />
  37. function UiI18nBridge(props: ParentProps) {
  38. const language = useLanguage()
  39. return <I18nProvider value={{ locale: language.locale, t: language.t }}>{props.children}</I18nProvider>
  40. }
  41. declare global {
  42. interface Window {
  43. __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string; deepLinks?: string[] }
  44. }
  45. }
  46. function MarkedProviderWithNativeParser(props: ParentProps) {
  47. const platform = usePlatform()
  48. return <MarkedProvider nativeParser={platform.parseMarkdown}>{props.children}</MarkedProvider>
  49. }
  50. export function AppBaseProviders(props: ParentProps) {
  51. return (
  52. <MetaProvider>
  53. <Font />
  54. <ThemeProvider>
  55. <LanguageProvider>
  56. <UiI18nBridge>
  57. <ErrorBoundary fallback={(error) => <ErrorPage error={error} />}>
  58. <DialogProvider>
  59. <MarkedProviderWithNativeParser>
  60. <DiffComponentProvider component={Diff}>
  61. <CodeComponentProvider component={Code}>{props.children}</CodeComponentProvider>
  62. </DiffComponentProvider>
  63. </MarkedProviderWithNativeParser>
  64. </DialogProvider>
  65. </ErrorBoundary>
  66. </UiI18nBridge>
  67. </LanguageProvider>
  68. </ThemeProvider>
  69. </MetaProvider>
  70. )
  71. }
  72. function ServerKey(props: ParentProps) {
  73. const server = useServer()
  74. return (
  75. <Show when={server.url} keyed>
  76. {props.children}
  77. </Show>
  78. )
  79. }
  80. export function AppInterface(props: { defaultUrl?: string; children?: JSX.Element; isSidecar?: boolean }) {
  81. const platform = usePlatform()
  82. const stored = (() => {
  83. if (platform.platform !== "web") return
  84. const result = platform.getDefaultServerUrl?.()
  85. if (result instanceof Promise) return
  86. if (!result) return
  87. return normalizeServerUrl(result)
  88. })()
  89. const defaultServerUrl = () => {
  90. if (props.defaultUrl) return props.defaultUrl
  91. if (stored) return stored
  92. if (location.hostname.includes("opencode.ai")) return "http://localhost:4096"
  93. if (import.meta.env.DEV)
  94. return `http://${import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "localhost"}:${import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"}`
  95. return window.location.origin
  96. }
  97. return (
  98. <ServerProvider defaultUrl={defaultServerUrl()} isSidecar={props.isSidecar}>
  99. <ServerKey>
  100. <GlobalSDKProvider>
  101. <GlobalSyncProvider>
  102. <Router
  103. root={(routerProps) => (
  104. <SettingsProvider>
  105. <PermissionProvider>
  106. <LayoutProvider>
  107. <NotificationProvider>
  108. <ModelsProvider>
  109. <CommandProvider>
  110. <HighlightsProvider>
  111. <Layout>
  112. {props.children}
  113. {routerProps.children}
  114. </Layout>
  115. </HighlightsProvider>
  116. </CommandProvider>
  117. </ModelsProvider>
  118. </NotificationProvider>
  119. </LayoutProvider>
  120. </PermissionProvider>
  121. </SettingsProvider>
  122. )}
  123. >
  124. <Route
  125. path="/"
  126. component={() => (
  127. <Suspense fallback={<Loading />}>
  128. <Home />
  129. </Suspense>
  130. )}
  131. />
  132. <Route path="/:dir" component={DirectoryLayout}>
  133. <Route path="/" component={() => <Navigate href="session" />} />
  134. <Route
  135. path="/session/:id?"
  136. component={(p) => (
  137. <Show when={p.params.id ?? "new"}>
  138. <TerminalProvider>
  139. <FileProvider>
  140. <PromptProvider>
  141. <CommentsProvider>
  142. <Suspense fallback={<Loading />}>
  143. <Session />
  144. </Suspense>
  145. </CommentsProvider>
  146. </PromptProvider>
  147. </FileProvider>
  148. </TerminalProvider>
  149. </Show>
  150. )}
  151. />
  152. </Route>
  153. </Router>
  154. </GlobalSyncProvider>
  155. </GlobalSDKProvider>
  156. </ServerKey>
  157. </ServerProvider>
  158. )
  159. }