From d05ed5ca83e03904c7c3dda23a6dcccfd607bdce Mon Sep 17 00:00:00 2001 From: adamelmore <2363879+adamdottv@users.noreply.github.com> Date: Mon, 26 Jan 2026 10:04:59 -0600 Subject: chore(app): createStore over signals --- .../app/src/components/dialog-edit-project.tsx | 31 +++++++------ .../session/session-sortable-terminal-tab.tsx | 51 ++++++++++++---------- packages/app/src/components/settings-keybinds.tsx | 45 ++++++++++--------- packages/app/src/components/status-popover.tsx | 23 +++++----- 4 files changed, 79 insertions(+), 71 deletions(-) (limited to 'packages/app/src/components') diff --git a/packages/app/src/components/dialog-edit-project.tsx b/packages/app/src/components/dialog-edit-project.tsx index 9e2bddc6b..2ab25ceeb 100644 --- a/packages/app/src/components/dialog-edit-project.tsx +++ b/packages/app/src/components/dialog-edit-project.tsx @@ -3,7 +3,7 @@ import { useDialog } from "@opencode-ai/ui/context/dialog" import { Dialog } from "@opencode-ai/ui/dialog" import { TextField } from "@opencode-ai/ui/text-field" import { Icon } from "@opencode-ai/ui/icon" -import { createMemo, createSignal, For, Show } from "solid-js" +import { createMemo, For, Show } from "solid-js" import { createStore } from "solid-js/store" import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSync } from "@/context/global-sync" @@ -29,35 +29,34 @@ export function DialogEditProject(props: { project: LocalProject }) { iconUrl: props.project.icon?.override || "", startup: props.project.commands?.start ?? "", saving: false, + dragOver: false, + iconHover: false, }) - const [dragOver, setDragOver] = createSignal(false) - const [iconHover, setIconHover] = createSignal(false) - function handleFileSelect(file: File) { if (!file.type.startsWith("image/")) return const reader = new FileReader() reader.onload = (e) => { setStore("iconUrl", e.target?.result as string) - setIconHover(false) + setStore("iconHover", false) } reader.readAsDataURL(file) } function handleDrop(e: DragEvent) { e.preventDefault() - setDragOver(false) + setStore("dragOver", false) const file = e.dataTransfer?.files[0] if (file) handleFileSelect(file) } function handleDragOver(e: DragEvent) { e.preventDefault() - setDragOver(true) + setStore("dragOver", true) } function handleDragLeave() { - setDragOver(false) + setStore("dragOver", false) } function handleInputChange(e: Event) { @@ -116,19 +115,23 @@ export function DialogEditProject(props: { project: LocalProject }) {
-
setIconHover(true)} onMouseLeave={() => setIconHover(false)}> +
setStore("iconHover", true)} + onMouseLeave={() => setStore("iconHover", false)} + >
{ - if (store.iconUrl && iconHover()) { + if (store.iconUrl && store.iconHover) { clearIcon() } else { document.getElementById("icon-upload")?.click() @@ -166,7 +169,7 @@ export function DialogEditProject(props: { project: LocalProject }) { "border-radius": "6px", "z-index": 10, "pointer-events": "none", - opacity: iconHover() && !store.iconUrl ? 1 : 0, + opacity: store.iconHover && !store.iconUrl ? 1 : 0, display: "flex", "align-items": "center", "justify-content": "center", @@ -185,7 +188,7 @@ export function DialogEditProject(props: { project: LocalProject }) { "border-radius": "6px", "z-index": 10, "pointer-events": "none", - opacity: iconHover() && store.iconUrl ? 1 : 0, + opacity: store.iconHover && store.iconUrl ? 1 : 0, display: "flex", "align-items": "center", "justify-content": "center", diff --git a/packages/app/src/components/session/session-sortable-terminal-tab.tsx b/packages/app/src/components/session/session-sortable-terminal-tab.tsx index d16379e80..75e9b22f9 100644 --- a/packages/app/src/components/session/session-sortable-terminal-tab.tsx +++ b/packages/app/src/components/session/session-sortable-terminal-tab.tsx @@ -1,5 +1,6 @@ import type { JSX } from "solid-js" -import { createSignal, Show } from "solid-js" +import { Show } from "solid-js" +import { createStore } from "solid-js/store" import { createSortable } from "@thisbeyond/solid-dnd" import { IconButton } from "@opencode-ai/ui/icon-button" import { Tabs } from "@opencode-ai/ui/tabs" @@ -12,11 +13,13 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => const terminal = useTerminal() const language = useLanguage() const sortable = createSortable(props.terminal.id) - const [editing, setEditing] = createSignal(false) - const [title, setTitle] = createSignal(props.terminal.title) - const [menuOpen, setMenuOpen] = createSignal(false) - const [menuPosition, setMenuPosition] = createSignal({ x: 0, y: 0 }) - const [blurEnabled, setBlurEnabled] = createSignal(false) + const [store, setStore] = createStore({ + editing: false, + title: props.terminal.title, + menuOpen: false, + menuPosition: { x: 0, y: 0 }, + blurEnabled: false, + }) const isDefaultTitle = () => { const number = props.terminal.titleNumber @@ -47,7 +50,7 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => } const focus = () => { - if (editing()) return + if (store.editing) return if (document.activeElement instanceof HTMLElement) { document.activeElement.blur() @@ -71,26 +74,26 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => e.preventDefault() } - setBlurEnabled(false) - setTitle(props.terminal.title) - setEditing(true) + setStore("blurEnabled", false) + setStore("title", props.terminal.title) + setStore("editing", true) setTimeout(() => { const input = document.getElementById(`terminal-title-input-${props.terminal.id}`) as HTMLInputElement if (!input) return input.focus() input.select() - setTimeout(() => setBlurEnabled(true), 100) + setTimeout(() => setStore("blurEnabled", true), 100) }, 10) } const save = () => { - if (!blurEnabled()) return + if (!store.blurEnabled) return - const value = title().trim() + const value = store.title.trim() if (value && value !== props.terminal.title) { terminal.update({ id: props.terminal.id, title: value }) } - setEditing(false) + setStore("editing", false) } const keydown = (e: KeyboardEvent) => { @@ -101,14 +104,14 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => } if (e.key === "Escape") { e.preventDefault() - setEditing(false) + setStore("editing", false) } } const menu = (e: MouseEvent) => { e.preventDefault() - setMenuPosition({ x: e.clientX, y: e.clientY }) - setMenuOpen(true) + setStore("menuPosition", { x: e.clientX, y: e.clientY }) + setStore("menuOpen", true) } return ( @@ -143,17 +146,17 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => /> } > - + {label()} - +
setTitle(e.currentTarget.value)} + value={store.title} + onInput={(e) => setStore("title", e.currentTarget.value)} onBlur={save} onKeyDown={keydown} onMouseDown={(e) => e.stopPropagation()} @@ -161,13 +164,13 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => />
- + setStore("menuOpen", open)}> diff --git a/packages/app/src/components/settings-keybinds.tsx b/packages/app/src/components/settings-keybinds.tsx index 4dc397149..7ff3425ab 100644 --- a/packages/app/src/components/settings-keybinds.tsx +++ b/packages/app/src/components/settings-keybinds.tsx @@ -1,4 +1,5 @@ -import { Component, For, Show, createMemo, createSignal, onCleanup, onMount } from "solid-js" +import { Component, For, Show, createMemo, onCleanup, onMount } from "solid-js" +import { createStore } from "solid-js/store" import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" import { IconButton } from "@opencode-ai/ui/icon-button" @@ -111,24 +112,26 @@ export const SettingsKeybinds: Component = () => { const language = useLanguage() const settings = useSettings() - const [active, setActive] = createSignal(null) - const [filter, setFilter] = createSignal("") + const [store, setStore] = createStore({ + active: null as string | null, + filter: "", + }) const stop = () => { - if (!active()) return - setActive(null) + if (!store.active) return + setStore("active", null) command.keybinds(true) } const start = (id: string) => { - if (active() === id) { + if (store.active === id) { stop() return } - if (active()) stop() + if (store.active) stop() - setActive(id) + setStore("active", id) command.keybinds(false) } @@ -203,7 +206,7 @@ export const SettingsKeybinds: Component = () => { }) const filtered = createMemo(() => { - const query = filter().toLowerCase().trim() + const query = store.filter.toLowerCase().trim() if (!query) return grouped() const map = list() @@ -285,7 +288,7 @@ export const SettingsKeybinds: Component = () => { onMount(() => { const handle = (event: KeyboardEvent) => { - const id = active() + const id = store.active if (!id) return event.preventDefault() @@ -345,7 +348,7 @@ export const SettingsKeybinds: Component = () => { }) onCleanup(() => { - if (active()) command.keybinds(true) + if (store.active) command.keybinds(true) }) return ( @@ -370,8 +373,8 @@ export const SettingsKeybinds: Component = () => { setStore("filter", v)} placeholder={language.t("settings.shortcuts.search.placeholder")} spellcheck={false} autocorrect="off" @@ -379,8 +382,8 @@ export const SettingsKeybinds: Component = () => { autocapitalize="off" class="flex-1" /> - - setFilter("")} /> + + setStore("filter", "")} />
@@ -402,13 +405,13 @@ export const SettingsKeybinds: Component = () => { classList={{ "h-8 px-3 rounded-md text-12-regular": true, "bg-surface-base text-text-subtle hover:bg-surface-raised-base-hover active:bg-surface-raised-base-active": - active() !== id, - "border border-border-weak-base bg-surface-inset-base text-text-weak": active() === id, + store.active !== id, + "border border-border-weak-base bg-surface-inset-base text-text-weak": store.active === id, }} onClick={() => start(id)} > {language.t("settings.shortcuts.pressKeys")} @@ -423,11 +426,11 @@ export const SettingsKeybinds: Component = () => { )} - +
{language.t("settings.shortcuts.search.empty")} - - "{filter()}" + + "{store.filter}"
diff --git a/packages/app/src/components/status-popover.tsx b/packages/app/src/components/status-popover.tsx index cb45c3689..c2c4d268a 100644 --- a/packages/app/src/components/status-popover.tsx +++ b/packages/app/src/components/status-popover.tsx @@ -39,9 +39,10 @@ export function StatusPopover() { const language = useLanguage() const navigate = useNavigate() - const [loading, setLoading] = createSignal(null) const [store, setStore] = createStore({ status: {} as Record, + loading: null as string | null, + defaultServerUrl: undefined as string | undefined, }) const servers = createMemo(() => { @@ -97,8 +98,8 @@ export function StatusPopover() { const mcpConnected = createMemo(() => mcpItems().filter((i) => i.status === "connected").length) const toggleMcp = async (name: string) => { - if (loading()) return - setLoading(name) + if (store.loading) return + setStore("loading", name) const status = sync.data.mcp[name] if (status?.status === "connected") { await sdk.client.mcp.disconnect({ name }) @@ -107,7 +108,7 @@ export function StatusPopover() { } const result = await sdk.client.mcp.status() if (result.data) sync.set("mcp", result.data) - setLoading(null) + setStore("loading", null) } const lspItems = createMemo(() => sync.data.lsp ?? []) @@ -123,19 +124,17 @@ export function StatusPopover() { const serverCount = createMemo(() => sortedServers().length) - const [defaultServerUrl, setDefaultServerUrl] = createSignal() - const refreshDefaultServerUrl = () => { const result = platform.getDefaultServerUrl?.() if (!result) { - setDefaultServerUrl(undefined) + setStore("defaultServerUrl", undefined) return } if (result instanceof Promise) { - result.then((url) => setDefaultServerUrl(url ? normalizeServerUrl(url) : undefined)) + result.then((url) => setStore("defaultServerUrl", url ? normalizeServerUrl(url) : undefined)) return } - setDefaultServerUrl(normalizeServerUrl(result)) + setStore("defaultServerUrl", normalizeServerUrl(result)) } createEffect(() => { @@ -220,7 +219,7 @@ export function StatusPopover() { {(url) => { const isActive = () => url === server.url - const isDefault = () => url === defaultServerUrl() + const isDefault = () => url === store.defaultServerUrl const status = () => store.status[url] const isBlocked = () => status()?.healthy === false const [truncated, setTruncated] = createSignal(false) @@ -329,7 +328,7 @@ export function StatusPopover() { type="button" class="flex items-center gap-2 w-full h-8 pl-3 pr-2 py-1 rounded-md hover:bg-surface-raised-base-hover transition-colors text-left" onClick={() => toggleMcp(item.name)} - disabled={loading() === item.name} + disabled={store.loading === item.name} >
event.stopPropagation()}> toggleMcp(item.name)} />
-- cgit v1.2.3