platform.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { createSimpleContext } from "@opencode-ai/ui/context"
  2. import type { AsyncStorage, SyncStorage } from "@solid-primitives/storage"
  3. import type { Accessor } from "solid-js"
  4. import { ServerConnection } from "./server"
  5. type PickerPaths = string | string[] | null
  6. type OpenDirectoryPickerOptions = { title?: string; multiple?: boolean }
  7. type OpenFilePickerOptions = { title?: string; multiple?: boolean; accept?: string[]; extensions?: string[] }
  8. type SaveFilePickerOptions = { title?: string; defaultPath?: string }
  9. type UpdateInfo = { updateAvailable: boolean; version?: string }
  10. export type Platform = {
  11. /** Platform discriminator */
  12. platform: "web" | "desktop"
  13. /** Desktop OS (Tauri only) */
  14. os?: "macos" | "windows" | "linux"
  15. /** App version */
  16. version?: string
  17. /** Open a URL in the default browser */
  18. openLink(url: string): void
  19. /** Open a local path in a local app (desktop only) */
  20. openPath?(path: string, app?: string): Promise<void>
  21. /** Restart the app */
  22. restart(): Promise<void>
  23. /** Navigate back in history */
  24. back(): void
  25. /** Navigate forward in history */
  26. forward(): void
  27. /** Send a system notification (optional deep link) */
  28. notify(title: string, description?: string, href?: string): Promise<void>
  29. /** Open directory picker dialog (native on Tauri, server-backed on web) */
  30. openDirectoryPickerDialog?(opts?: OpenDirectoryPickerOptions): Promise<PickerPaths>
  31. /** Open native file picker dialog (Tauri only) */
  32. openFilePickerDialog?(opts?: OpenFilePickerOptions): Promise<PickerPaths>
  33. /** Save file picker dialog (Tauri only) */
  34. saveFilePickerDialog?(opts?: SaveFilePickerOptions): Promise<string | null>
  35. /** Storage mechanism, defaults to localStorage */
  36. storage?: (name?: string) => SyncStorage | AsyncStorage
  37. /** Check for a downloadable desktop update */
  38. checkUpdate?(): Promise<UpdateInfo>
  39. /** Install the downloaded update using the platform restart flow */
  40. updateAndRestart?(): Promise<void>
  41. /** Fetch override */
  42. fetch?: typeof fetch
  43. /** Get the configured default server URL (platform-specific) */
  44. getDefaultServer?(): Promise<ServerConnection.Key | null>
  45. /** Set the default server URL to use on app startup (platform-specific) */
  46. setDefaultServer?(url: ServerConnection.Key | null): Promise<void> | void
  47. /** Get the configured WSL integration (desktop only) */
  48. getWslEnabled?(): Promise<boolean>
  49. /** Set the configured WSL integration (desktop only) */
  50. setWslEnabled?(config: boolean): Promise<void> | void
  51. /** Get the preferred display backend (desktop only) */
  52. getDisplayBackend?(): Promise<DisplayBackend | null> | DisplayBackend | null
  53. /** Set the preferred display backend (desktop only) */
  54. setDisplayBackend?(backend: DisplayBackend): Promise<void>
  55. /** Parse markdown to HTML using native parser (desktop only, returns unprocessed code blocks) */
  56. parseMarkdown?(markdown: string): Promise<string>
  57. /** Webview zoom level (desktop only) */
  58. webviewZoom?: Accessor<number>
  59. /** Check if an editor app exists (desktop only) */
  60. checkAppExists?(appName: string): Promise<boolean>
  61. /** Read image from clipboard (desktop only) */
  62. readClipboardImage?(): Promise<File | null>
  63. }
  64. export type DisplayBackend = "auto" | "wayland"
  65. export const { use: usePlatform, provider: PlatformProvider } = createSimpleContext({
  66. name: "Platform",
  67. init: (props: { value: Platform }) => {
  68. return props.value
  69. },
  70. })