app.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 { 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 { NotificationProvider } from "@/context/notification"
  23. import { DialogProvider } from "@opencode-ai/ui/context/dialog"
  24. import { CommandProvider } from "@/context/command"
  25. import { LanguageProvider, useLanguage } from "@/context/language"
  26. import { usePlatform } from "@/context/platform"
  27. import { Logo } from "@opencode-ai/ui/logo"
  28. import Layout from "@/pages/layout"
  29. import DirectoryLayout from "@/pages/directory-layout"
  30. import { ErrorPage } from "./pages/error"
  31. import { iife } from "@opencode-ai/util/iife"
  32. import { Suspense } from "solid-js"
  33. const Home = lazy(() => import("@/pages/home"))
  34. const Session = lazy(() => import("@/pages/session"))
  35. const Loading = () => <div class="size-full" />
  36. function UiI18nBridge(props: ParentProps) {
  37. const language = useLanguage()
  38. return <I18nProvider value={{ locale: language.locale, t: language.t }}>{props.children}</I18nProvider>
  39. }
  40. declare global {
  41. interface Window {
  42. __OPENCODE__?: { updaterEnabled?: boolean; serverPassword?: string }
  43. }
  44. }
  45. function MarkedProviderWithNativeParser(props: ParentProps) {
  46. const platform = usePlatform()
  47. return <MarkedProvider nativeParser={platform.parseMarkdown}>{props.children}</MarkedProvider>
  48. }
  49. export function AppBaseProviders(props: ParentProps) {
  50. return (
  51. <MetaProvider>
  52. <Font />
  53. <ThemeProvider>
  54. <LanguageProvider>
  55. <UiI18nBridge>
  56. <ErrorBoundary fallback={(error) => <ErrorPage error={error} />}>
  57. <DialogProvider>
  58. <MarkedProviderWithNativeParser>
  59. <DiffComponentProvider component={Diff}>
  60. <CodeComponentProvider component={Code}>{props.children}</CodeComponentProvider>
  61. </DiffComponentProvider>
  62. </MarkedProviderWithNativeParser>
  63. </DialogProvider>
  64. </ErrorBoundary>
  65. </UiI18nBridge>
  66. </LanguageProvider>
  67. </ThemeProvider>
  68. </MetaProvider>
  69. )
  70. }
  71. function ServerKey(props: ParentProps) {
  72. const server = useServer()
  73. return (
  74. <Show when={server.url} keyed>
  75. {props.children}
  76. </Show>
  77. )
  78. }
  79. export function AppInterface(props: { defaultUrl?: string }) {
  80. const defaultServerUrl = () => {
  81. if (props.defaultUrl) return props.defaultUrl
  82. if (location.hostname.includes("opencode.ai")) return "http://localhost:4096"
  83. if (import.meta.env.DEV)
  84. return `http://${import.meta.env.VITE_OPENCODE_SERVER_HOST ?? "localhost"}:${import.meta.env.VITE_OPENCODE_SERVER_PORT ?? "4096"}`
  85. return window.location.origin
  86. }
  87. return (
  88. <ServerProvider defaultUrl={defaultServerUrl()}>
  89. <ServerKey>
  90. <GlobalSDKProvider>
  91. <GlobalSyncProvider>
  92. <Router
  93. root={(props) => (
  94. <SettingsProvider>
  95. <PermissionProvider>
  96. <LayoutProvider>
  97. <NotificationProvider>
  98. <CommandProvider>
  99. <Layout>{props.children}</Layout>
  100. </CommandProvider>
  101. </NotificationProvider>
  102. </LayoutProvider>
  103. </PermissionProvider>
  104. </SettingsProvider>
  105. )}
  106. >
  107. <Route
  108. path="/"
  109. component={() => (
  110. <Suspense fallback={<Loading />}>
  111. <Home />
  112. </Suspense>
  113. )}
  114. />
  115. <Route path="/:dir" component={DirectoryLayout}>
  116. <Route path="/" component={() => <Navigate href="session" />} />
  117. <Route
  118. path="/session/:id?"
  119. component={(p) => (
  120. <Show when={p.params.id ?? "new"}>
  121. <TerminalProvider>
  122. <FileProvider>
  123. <PromptProvider>
  124. <Suspense fallback={<Loading />}>
  125. <Session />
  126. </Suspense>
  127. </PromptProvider>
  128. </FileProvider>
  129. </TerminalProvider>
  130. </Show>
  131. )}
  132. />
  133. </Route>
  134. </Router>
  135. </GlobalSyncProvider>
  136. </GlobalSDKProvider>
  137. </ServerKey>
  138. </ServerProvider>
  139. )
  140. }