|
|
@@ -1,8 +1,12 @@
|
|
|
import { Component, createMemo, type JSX } from "solid-js"
|
|
|
+import { createStore } from "solid-js/store"
|
|
|
+import { Button } from "@opencode-ai/ui/button"
|
|
|
import { Select } from "@opencode-ai/ui/select"
|
|
|
import { Switch } from "@opencode-ai/ui/switch"
|
|
|
import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme"
|
|
|
+import { showToast } from "@opencode-ai/ui/toast"
|
|
|
import { useLanguage } from "@/context/language"
|
|
|
+import { usePlatform } from "@/context/platform"
|
|
|
import { useSettings, monoFontFamily } from "@/context/settings"
|
|
|
import { playSound, SOUND_OPTIONS } from "@/utils/sound"
|
|
|
import { Link } from "./link"
|
|
|
@@ -29,8 +33,67 @@ const playDemoSound = (src: string) => {
|
|
|
export const SettingsGeneral: Component = () => {
|
|
|
const theme = useTheme()
|
|
|
const language = useLanguage()
|
|
|
+ const platform = usePlatform()
|
|
|
const settings = useSettings()
|
|
|
|
|
|
+ const [store, setStore] = createStore({
|
|
|
+ checking: false,
|
|
|
+ })
|
|
|
+
|
|
|
+ const check = () => {
|
|
|
+ if (!platform.checkUpdate) return
|
|
|
+ setStore("checking", true)
|
|
|
+
|
|
|
+ void platform
|
|
|
+ .checkUpdate()
|
|
|
+ .then((result) => {
|
|
|
+ if (!result.updateAvailable) {
|
|
|
+ showToast({
|
|
|
+ variant: "success",
|
|
|
+ icon: "circle-check",
|
|
|
+ title: language.t("settings.updates.toast.latest.title"),
|
|
|
+ description: language.t("settings.updates.toast.latest.description", { version: platform.version ?? "" }),
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const actions =
|
|
|
+ platform.update && platform.restart
|
|
|
+ ? [
|
|
|
+ {
|
|
|
+ label: language.t("toast.update.action.installRestart"),
|
|
|
+ onClick: async () => {
|
|
|
+ await platform.update!()
|
|
|
+ await platform.restart!()
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: language.t("toast.update.action.notYet"),
|
|
|
+ onClick: "dismiss" as const,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ : [
|
|
|
+ {
|
|
|
+ label: language.t("toast.update.action.notYet"),
|
|
|
+ onClick: "dismiss" as const,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+
|
|
|
+ showToast({
|
|
|
+ persistent: true,
|
|
|
+ icon: "download",
|
|
|
+ title: language.t("toast.update.title"),
|
|
|
+ description: language.t("toast.update.description", { version: result.version ?? "" }),
|
|
|
+ actions,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .catch((err: unknown) => {
|
|
|
+ const message = err instanceof Error ? err.message : String(err)
|
|
|
+ showToast({ title: language.t("common.requestFailed"), description: message })
|
|
|
+ })
|
|
|
+ .finally(() => setStore("checking", false))
|
|
|
+ }
|
|
|
+
|
|
|
const themeOptions = createMemo(() =>
|
|
|
Object.entries(theme.themes()).map(([id, def]) => ({ id, name: def.name ?? id })),
|
|
|
)
|
|
|
@@ -208,23 +271,6 @@ export const SettingsGeneral: Component = () => {
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- {/* Updates Section */}
|
|
|
- <div class="flex flex-col gap-1">
|
|
|
- <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.updates")}</h3>
|
|
|
-
|
|
|
- <div class="bg-surface-raised-base px-4 rounded-lg">
|
|
|
- <SettingsRow
|
|
|
- title={language.t("settings.general.row.releaseNotes.title")}
|
|
|
- description={language.t("settings.general.row.releaseNotes.description")}
|
|
|
- >
|
|
|
- <Switch
|
|
|
- checked={settings.general.releaseNotes()}
|
|
|
- onChange={(checked) => settings.general.setReleaseNotes(checked)}
|
|
|
- />
|
|
|
- </SettingsRow>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
{/* Sound effects Section */}
|
|
|
<div class="flex flex-col gap-1">
|
|
|
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.sounds")}</h3>
|
|
|
@@ -303,6 +349,50 @@ export const SettingsGeneral: Component = () => {
|
|
|
</SettingsRow>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
+ {/* Updates Section */}
|
|
|
+ <div class="flex flex-col gap-1">
|
|
|
+ <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.updates")}</h3>
|
|
|
+
|
|
|
+ <div class="bg-surface-raised-base px-4 rounded-lg">
|
|
|
+ <SettingsRow
|
|
|
+ title={language.t("settings.updates.row.startup.title")}
|
|
|
+ description={language.t("settings.updates.row.startup.description")}
|
|
|
+ >
|
|
|
+ <Switch
|
|
|
+ checked={settings.updates.startup()}
|
|
|
+ disabled={!platform.checkUpdate}
|
|
|
+ onChange={(checked) => settings.updates.setStartup(checked)}
|
|
|
+ />
|
|
|
+ </SettingsRow>
|
|
|
+
|
|
|
+ <SettingsRow
|
|
|
+ title={language.t("settings.general.row.releaseNotes.title")}
|
|
|
+ description={language.t("settings.general.row.releaseNotes.description")}
|
|
|
+ >
|
|
|
+ <Switch
|
|
|
+ checked={settings.general.releaseNotes()}
|
|
|
+ onChange={(checked) => settings.general.setReleaseNotes(checked)}
|
|
|
+ />
|
|
|
+ </SettingsRow>
|
|
|
+
|
|
|
+ <SettingsRow
|
|
|
+ title={language.t("settings.updates.row.check.title")}
|
|
|
+ description={language.t("settings.updates.row.check.description")}
|
|
|
+ >
|
|
|
+ <Button
|
|
|
+ size="small"
|
|
|
+ variant="secondary"
|
|
|
+ disabled={store.checking || !platform.checkUpdate}
|
|
|
+ onClick={check}
|
|
|
+ >
|
|
|
+ {store.checking
|
|
|
+ ? language.t("settings.updates.action.checking")
|
|
|
+ : language.t("settings.updates.action.checkNow")}
|
|
|
+ </Button>
|
|
|
+ </SettingsRow>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
)
|