settings.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { createStore, reconcile } from "solid-js/store"
  2. import { createEffect, createMemo } from "solid-js"
  3. import { createSimpleContext } from "@opencode-ai/ui/context"
  4. import { persisted } from "@/utils/persist"
  5. export interface NotificationSettings {
  6. agent: boolean
  7. permissions: boolean
  8. errors: boolean
  9. }
  10. export interface SoundSettings {
  11. agent: string
  12. permissions: string
  13. errors: string
  14. }
  15. export interface Settings {
  16. general: {
  17. autoSave: boolean
  18. releaseNotes: boolean
  19. }
  20. updates: {
  21. startup: boolean
  22. }
  23. appearance: {
  24. fontSize: number
  25. font: string
  26. }
  27. keybinds: Record<string, string>
  28. permissions: {
  29. autoApprove: boolean
  30. }
  31. notifications: NotificationSettings
  32. sounds: SoundSettings
  33. }
  34. const defaultSettings: Settings = {
  35. general: {
  36. autoSave: true,
  37. releaseNotes: true,
  38. },
  39. updates: {
  40. startup: true,
  41. },
  42. appearance: {
  43. fontSize: 14,
  44. font: "ibm-plex-mono",
  45. },
  46. keybinds: {},
  47. permissions: {
  48. autoApprove: false,
  49. },
  50. notifications: {
  51. agent: true,
  52. permissions: true,
  53. errors: false,
  54. },
  55. sounds: {
  56. agent: "staplebops-01",
  57. permissions: "staplebops-02",
  58. errors: "nope-03",
  59. },
  60. }
  61. const monoFallback =
  62. 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
  63. const monoFonts: Record<string, string> = {
  64. "ibm-plex-mono": `"IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  65. "cascadia-code": `"Cascadia Code Nerd Font", "Cascadia Code NF", "Cascadia Mono NF", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  66. "fira-code": `"Fira Code Nerd Font", "FiraMono Nerd Font", "FiraMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  67. hack: `"Hack Nerd Font", "Hack Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  68. inconsolata: `"Inconsolata Nerd Font", "Inconsolata Nerd Font Mono","IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  69. "intel-one-mono": `"Intel One Mono Nerd Font", "IntoneMono Nerd Font", "IntoneMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  70. iosevka: `"Iosevka Nerd Font", "Iosevka Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  71. "jetbrains-mono": `"JetBrains Mono Nerd Font", "JetBrainsMono Nerd Font Mono", "JetBrainsMonoNL Nerd Font", "JetBrainsMonoNL Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  72. "meslo-lgs": `"Meslo LGS Nerd Font", "MesloLGS Nerd Font", "MesloLGM Nerd Font", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  73. "roboto-mono": `"Roboto Mono Nerd Font", "RobotoMono Nerd Font", "RobotoMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  74. "source-code-pro": `"Source Code Pro Nerd Font", "SauceCodePro Nerd Font", "SauceCodePro Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  75. "ubuntu-mono": `"Ubuntu Mono Nerd Font", "UbuntuMono Nerd Font", "UbuntuMono Nerd Font Mono", "IBM Plex Mono", "IBM Plex Mono Fallback", ${monoFallback}`,
  76. }
  77. export function monoFontFamily(font: string | undefined) {
  78. return monoFonts[font ?? defaultSettings.appearance.font] ?? monoFonts[defaultSettings.appearance.font]
  79. }
  80. export const { use: useSettings, provider: SettingsProvider } = createSimpleContext({
  81. name: "Settings",
  82. init: () => {
  83. const [store, setStore, _, ready] = persisted("settings.v3", createStore<Settings>(defaultSettings))
  84. createEffect(() => {
  85. if (typeof document === "undefined") return
  86. document.documentElement.style.setProperty("--font-family-mono", monoFontFamily(store.appearance?.font))
  87. })
  88. return {
  89. ready,
  90. get current() {
  91. return store
  92. },
  93. general: {
  94. autoSave: createMemo(() => store.general?.autoSave ?? defaultSettings.general.autoSave),
  95. setAutoSave(value: boolean) {
  96. setStore("general", "autoSave", value)
  97. },
  98. releaseNotes: createMemo(() => store.general?.releaseNotes ?? defaultSettings.general.releaseNotes),
  99. setReleaseNotes(value: boolean) {
  100. setStore("general", "releaseNotes", value)
  101. },
  102. },
  103. updates: {
  104. startup: createMemo(() => store.updates?.startup ?? defaultSettings.updates.startup),
  105. setStartup(value: boolean) {
  106. setStore("updates", "startup", value)
  107. },
  108. },
  109. appearance: {
  110. fontSize: createMemo(() => store.appearance?.fontSize ?? defaultSettings.appearance.fontSize),
  111. setFontSize(value: number) {
  112. setStore("appearance", "fontSize", value)
  113. },
  114. font: createMemo(() => store.appearance?.font ?? defaultSettings.appearance.font),
  115. setFont(value: string) {
  116. setStore("appearance", "font", value)
  117. },
  118. },
  119. keybinds: {
  120. get: (action: string) => store.keybinds?.[action],
  121. set(action: string, keybind: string) {
  122. setStore("keybinds", action, keybind)
  123. },
  124. reset(action: string) {
  125. setStore("keybinds", action, undefined!)
  126. },
  127. resetAll() {
  128. setStore("keybinds", reconcile({}))
  129. },
  130. },
  131. permissions: {
  132. autoApprove: createMemo(() => store.permissions?.autoApprove ?? defaultSettings.permissions.autoApprove),
  133. setAutoApprove(value: boolean) {
  134. setStore("permissions", "autoApprove", value)
  135. },
  136. },
  137. notifications: {
  138. agent: createMemo(() => store.notifications?.agent ?? defaultSettings.notifications.agent),
  139. setAgent(value: boolean) {
  140. setStore("notifications", "agent", value)
  141. },
  142. permissions: createMemo(() => store.notifications?.permissions ?? defaultSettings.notifications.permissions),
  143. setPermissions(value: boolean) {
  144. setStore("notifications", "permissions", value)
  145. },
  146. errors: createMemo(() => store.notifications?.errors ?? defaultSettings.notifications.errors),
  147. setErrors(value: boolean) {
  148. setStore("notifications", "errors", value)
  149. },
  150. },
  151. sounds: {
  152. agent: createMemo(() => store.sounds?.agent ?? defaultSettings.sounds.agent),
  153. setAgent(value: string) {
  154. setStore("sounds", "agent", value)
  155. },
  156. permissions: createMemo(() => store.sounds?.permissions ?? defaultSettings.sounds.permissions),
  157. setPermissions(value: string) {
  158. setStore("sounds", "permissions", value)
  159. },
  160. errors: createMemo(() => store.sounds?.errors ?? defaultSettings.sounds.errors),
  161. setErrors(value: string) {
  162. setStore("sounds", "errors", value)
  163. },
  164. },
  165. }
  166. },
  167. })