From 47d9e017657c4d265dea53bd86d727097a7ba282 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Thu, 16 Oct 2025 14:53:44 -0500
Subject: wip: css/ui and desktop work
---
packages/desktop/src/components/editor-pane.tsx | 237 ++++++++++-----------
packages/desktop/src/components/file-tree.tsx | 3 +-
packages/desktop/src/components/prompt-form.tsx | 4 +-
.../desktop/src/components/resizeable-pane.tsx | 217 -------------------
packages/desktop/src/components/select-dialog.tsx | 3 +-
packages/desktop/src/components/select.tsx | 108 ----------
packages/desktop/src/components/session-list.tsx | 2 +-
.../desktop/src/components/session-timeline.tsx | 3 +-
packages/desktop/src/components/sidebar-nav.tsx | 48 -----
packages/desktop/src/context/index.ts | 1 -
packages/desktop/src/context/local.tsx | 50 ++---
packages/desktop/src/context/theme.tsx | 92 --------
packages/desktop/src/index.css | 169 +--------------
packages/desktop/src/index.tsx | 53 ++---
packages/desktop/src/pages/index.tsx | 110 +++++-----
packages/desktop/src/pages/layout.tsx | 5 -
packages/desktop/src/ui/button.tsx | 36 ----
packages/desktop/src/ui/collapsible.tsx | 2 +-
packages/desktop/src/ui/icon.tsx | 155 --------------
packages/desktop/src/ui/index.ts | 5 -
packages/desktop/src/ui/link.tsx | 13 --
packages/desktop/src/ui/logo.tsx | 125 -----------
packages/desktop/src/ui/tabs.tsx | 71 ------
packages/desktop/src/ui/tooltip.tsx | 58 -----
24 files changed, 229 insertions(+), 1341 deletions(-)
delete mode 100644 packages/desktop/src/components/resizeable-pane.tsx
delete mode 100644 packages/desktop/src/components/select.tsx
delete mode 100644 packages/desktop/src/components/sidebar-nav.tsx
delete mode 100644 packages/desktop/src/context/theme.tsx
delete mode 100644 packages/desktop/src/pages/layout.tsx
delete mode 100644 packages/desktop/src/ui/button.tsx
delete mode 100644 packages/desktop/src/ui/icon.tsx
delete mode 100644 packages/desktop/src/ui/link.tsx
delete mode 100644 packages/desktop/src/ui/logo.tsx
delete mode 100644 packages/desktop/src/ui/tabs.tsx
delete mode 100644 packages/desktop/src/ui/tooltip.tsx
(limited to 'packages/desktop/src')
diff --git a/packages/desktop/src/components/editor-pane.tsx b/packages/desktop/src/components/editor-pane.tsx
index 2f4c87e25..2741a6208 100644
--- a/packages/desktop/src/components/editor-pane.tsx
+++ b/packages/desktop/src/components/editor-pane.tsx
@@ -1,6 +1,7 @@
import { For, Match, Show, Switch, createSignal, splitProps } from "solid-js"
-import { Tabs } from "@/ui/tabs"
-import { FileIcon, Icon, IconButton, Logo, Tooltip } from "@/ui"
+import { Tabs, Tooltip } from "@opencode-ai/ui"
+import { Icon } from "@opencode-ai/ui"
+import { FileIcon, IconButton } from "@/ui"
import {
DragDropProvider,
DragDropSensors,
@@ -64,127 +65,119 @@ export default function EditorPane(props: EditorPaneProps): JSX.Element {
}
return (
-
-
-
-
-
-
-
- file.path)}>
-
- {(file) => (
-
- )}
-
-
-
-
-
- {(() => {
- const activeFile = local.file.active()!
- const view = local.file.view(activeFile.path)
- return (
-
-
-
-
- navigateChange(-1)}>
-
-
-
-
- navigateChange(1)}>
-
-
-
-
-
-
- local.file.setView(activeFile.path, "raw")}
- >
-
-
-
-
- local.file.setView(activeFile.path, "diff-unified")}
- >
-
-
-
-
- local.file.setView(activeFile.path, "diff-split")}
- >
-
-
-
-
- )
- })()}
-
-
+
+
+
+
+
+
+ file.path)}>
+
+ {(file) => }
+
+
+
+
+
+ {(() => {
+ const activeFile = local.file.active()!
+ const view = local.file.view(activeFile.path)
+ return (
+
+
+
+
+ navigateChange(-1)}>
+
+
+
+
+ navigateChange(1)}>
+
+
+
+
+
+
+ local.file.setView(activeFile.path, "raw")}
+ >
+
+
+
+
+ local.file.setView(activeFile.path, "diff-unified")}
+ >
+
+
+
+
+ local.file.setView(activeFile.path, "diff-split")}
+ >
+
+
+
+
+ )
+ })()}
+
-
- {(file) => (
-
- {(() => {
- const view = local.file.view(file.path)
- const showRaw = view === "raw" || !file.content?.diff
- const code = showRaw ? (file.content?.content ?? "") : (file.content?.diff ?? "")
- return
- })()}
-
- )}
-
-
-
- {(() => {
- const id = activeItem()
- if (!id) return null
- const draggedFile = local.file.node(id)
- if (!draggedFile) return null
- return (
-
-
-
- )
- })()}
-
-
-
+
+
+ {(file) => (
+
+ {(() => {
+ const view = local.file.view(file.path)
+ const showRaw = view === "raw" || !file.content?.diff
+ const code = showRaw ? (file.content?.content ?? "") : (file.content?.diff ?? "")
+ return
+ })()}
+
+ )}
+
+
+
+ {(() => {
+ const id = activeItem()
+ if (!id) return null
+ const draggedFile = local.file.node(id)
+ if (!draggedFile) return null
+ return (
+
+
+
+ )
+ })()}
+
+
)
}
diff --git a/packages/desktop/src/components/file-tree.tsx b/packages/desktop/src/components/file-tree.tsx
index d31255ced..348e25ad7 100644
--- a/packages/desktop/src/components/file-tree.tsx
+++ b/packages/desktop/src/components/file-tree.tsx
@@ -1,6 +1,7 @@
import { useLocal } from "@/context"
import type { LocalFile } from "@/context/local"
-import { Collapsible, FileIcon, Tooltip } from "@/ui"
+import { Tooltip } from "@opencode-ai/ui"
+import { Collapsible, FileIcon } from "@/ui"
import { For, Match, Switch, Show, type ComponentProps, type ParentProps } from "solid-js"
import { Dynamic } from "solid-js/web"
diff --git a/packages/desktop/src/components/prompt-form.tsx b/packages/desktop/src/components/prompt-form.tsx
index 5e6441596..06fbfbb03 100644
--- a/packages/desktop/src/components/prompt-form.tsx
+++ b/packages/desktop/src/components/prompt-form.tsx
@@ -1,8 +1,8 @@
import { For, Show, createMemo, onCleanup, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { Popover } from "@kobalte/core/popover"
-import { Button, FileIcon, Icon, IconButton, Tooltip } from "@/ui"
-import { Select } from "@/components/select"
+import { Tooltip, Button, Icon, Select } from "@opencode-ai/ui"
+import { FileIcon, IconButton } from "@/ui"
import { useLocal } from "@/context"
import type { FileContext, LocalFile } from "@/context/local"
import { getDirectory, getFilename } from "@/utils"
diff --git a/packages/desktop/src/components/resizeable-pane.tsx b/packages/desktop/src/components/resizeable-pane.tsx
deleted file mode 100644
index 49ccc4e70..000000000
--- a/packages/desktop/src/components/resizeable-pane.tsx
+++ /dev/null
@@ -1,217 +0,0 @@
-import { batch, createContext, createMemo, createSignal, onCleanup, Show, useContext } from "solid-js"
-import type { ComponentProps, JSX } from "solid-js"
-import { createStore } from "solid-js/store"
-import { useLocal } from "@/context"
-
-type PaneDefault = number | { size: number; visible?: boolean }
-
-type LayoutContextValue = {
- id: string
- register: (pane: string, options: { min?: number | string; max?: number | string }) => void
- size: (pane: string) => number
- visible: (pane: string) => boolean
- percent: (pane: string) => number
- next: (pane: string) => string | undefined
- startDrag: (left: string, right: string | undefined, event: MouseEvent) => void
- dragging: () => string | undefined
-}
-
-const LayoutContext = createContext
(undefined)
-
-export interface ResizeableLayoutProps {
- id: string
- defaults: Record
- class?: ComponentProps<"div">["class"]
- classList?: ComponentProps<"div">["classList"]
- children: JSX.Element
-}
-
-export interface ResizeablePaneProps {
- id: string
- minSize?: number | string
- maxSize?: number | string
- class?: ComponentProps<"div">["class"]
- classList?: ComponentProps<"div">["classList"]
- children: JSX.Element
-}
-
-export function ResizeableLayout(props: ResizeableLayoutProps) {
- const local = useLocal()
- const [meta, setMeta] = createStore>({})
- const [dragging, setDragging] = createSignal()
- let container: HTMLDivElement | undefined
-
- local.layout.ensure(props.id, props.defaults)
-
- const order = createMemo(() => local.layout.order(props.id))
- const visibleOrder = createMemo(() => order().filter((pane) => local.layout.visible(props.id, pane)))
- const totalVisible = createMemo(() => {
- const panes = visibleOrder()
- if (!panes.length) return 0
- return panes.reduce((total, pane) => total + local.layout.size(props.id, pane), 0)
- })
-
- const percent = (pane: string) => {
- const panes = visibleOrder()
- if (!panes.length) return 0
- const total = totalVisible()
- if (!total) return 100 / panes.length
- return (local.layout.size(props.id, pane) / total) * 100
- }
-
- const nextPane = (pane: string) => {
- const panes = visibleOrder()
- const index = panes.indexOf(pane)
- if (index === -1) return undefined
- return panes[index + 1]
- }
-
- const minMax = (pane: string) => meta[pane] ?? { min: 5, max: 95 }
-
- const pxToPercent = (px: number, total: number) => (px / total) * 100
-
- const boundsForPair = (left: string, right: string, total: number) => {
- const leftMeta = minMax(left)
- const rightMeta = minMax(right)
- const containerWidth = container?.getBoundingClientRect().width ?? 0
-
- let minLeft = leftMeta.min
- let maxLeft = leftMeta.max
- let minRight = rightMeta.min
- let maxRight = rightMeta.max
-
- if (containerWidth && leftMeta.minPx !== undefined) minLeft = pxToPercent(leftMeta.minPx, containerWidth)
- if (containerWidth && leftMeta.maxPx !== undefined) maxLeft = pxToPercent(leftMeta.maxPx, containerWidth)
- if (containerWidth && rightMeta.minPx !== undefined) minRight = pxToPercent(rightMeta.minPx, containerWidth)
- if (containerWidth && rightMeta.maxPx !== undefined) maxRight = pxToPercent(rightMeta.maxPx, containerWidth)
-
- const finalMinLeft = Math.max(minLeft, total - maxRight)
- const finalMaxLeft = Math.min(maxLeft, total - minRight)
- return {
- min: Math.min(finalMinLeft, finalMaxLeft),
- max: Math.max(finalMinLeft, finalMaxLeft),
- }
- }
-
- const setPair = (left: string, right: string, leftSize: number, rightSize: number) => {
- batch(() => {
- local.layout.setSize(props.id, left, leftSize)
- local.layout.setSize(props.id, right, rightSize)
- })
- }
-
- const startDrag = (left: string, right: string | undefined, event: MouseEvent) => {
- if (!right) return
- if (!container) return
- const rect = container.getBoundingClientRect()
- if (!rect.width) return
- event.preventDefault()
- const startX = event.clientX
- const startLeft = local.layout.size(props.id, left)
- const startRight = local.layout.size(props.id, right)
- const total = startLeft + startRight
- const bounds = boundsForPair(left, right, total)
- const move = (moveEvent: MouseEvent) => {
- const delta = ((moveEvent.clientX - startX) / rect.width) * 100
- const nextLeft = Math.max(bounds.min, Math.min(bounds.max, startLeft + delta))
- const nextRight = total - nextLeft
- setPair(left, right, nextLeft, nextRight)
- }
- const stop = () => {
- setDragging()
- document.removeEventListener("mousemove", move)
- document.removeEventListener("mouseup", stop)
- }
- setDragging(left)
- document.addEventListener("mousemove", move)
- document.addEventListener("mouseup", stop)
- onCleanup(() => stop())
- }
-
- const register = (pane: string, options: { min?: number | string; max?: number | string }) => {
- let min = 5
- let max = 95
- let minPx: number | undefined
- let maxPx: number | undefined
-
- if (typeof options.min === "string" && options.min.endsWith("px")) {
- minPx = parseInt(options.min)
- min = 0
- } else if (typeof options.min === "number") {
- min = options.min
- }
-
- if (typeof options.max === "string" && options.max.endsWith("px")) {
- maxPx = parseInt(options.max)
- max = 100
- } else if (typeof options.max === "number") {
- max = options.max
- }
-
- setMeta(pane, () => ({ min, max, minPx, maxPx }))
- const fallback = props.defaults[pane]
- local.layout.ensurePane(props.id, pane, fallback ?? { size: min, visible: true })
- }
-
- const contextValue: LayoutContextValue = {
- id: props.id,
- register,
- size: (pane) => local.layout.size(props.id, pane),
- visible: (pane) => local.layout.visible(props.id, pane),
- percent,
- next: nextPane,
- startDrag,
- dragging,
- }
-
- return (
-
- {
- container = node ?? undefined
- }}
- class={props.class ? `relative flex h-full w-full ${props.class}` : "relative flex h-full w-full"}
- classList={props.classList}
- >
- {props.children}
-
-
- )
-}
-
-export function ResizeablePane(props: ResizeablePaneProps) {
- const context = useContext(LayoutContext)!
- context.register(props.id, { min: props.minSize, max: props.maxSize })
- const visible = () => context.visible(props.id)
- const width = () => context.percent(props.id)
- const next = () => context.next(props.id)
- const dragging = () => context.dragging() === props.id
-
- return (
-
-
- {props.children}
-
- context.startDrag(props.id, next(), event)}
- >
-
-
-
-
-
- )
-}
diff --git a/packages/desktop/src/components/select-dialog.tsx b/packages/desktop/src/components/select-dialog.tsx
index 315fe14e5..bf9aa0dbd 100644
--- a/packages/desktop/src/components/select-dialog.tsx
+++ b/packages/desktop/src/components/select-dialog.tsx
@@ -1,6 +1,7 @@
import { createEffect, Show, For, createMemo, type JSX, createResource } from "solid-js"
import { Dialog } from "@kobalte/core/dialog"
-import { Icon, IconButton } from "@/ui"
+import { Icon } from "@opencode-ai/ui"
+import { IconButton } from "@/ui"
import { createStore } from "solid-js/store"
import { entries, flatMap, groupBy, map, pipe } from "remeda"
import { createList } from "solid-list"
diff --git a/packages/desktop/src/components/select.tsx b/packages/desktop/src/components/select.tsx
deleted file mode 100644
index 6ab3f4012..000000000
--- a/packages/desktop/src/components/select.tsx
+++ /dev/null
@@ -1,108 +0,0 @@
-import { Select as KobalteSelect } from "@kobalte/core/select"
-import { createMemo } from "solid-js"
-import type { ComponentProps } from "solid-js"
-import { Icon } from "@/ui/icon"
-import { pipe, groupBy, entries, map } from "remeda"
-import { Button, type ButtonProps } from "@/ui"
-
-export interface SelectProps {
- placeholder?: string
- options: T[]
- current?: T
- value?: (x: T) => string
- label?: (x: T) => string
- groupBy?: (x: T) => string
- onSelect?: (value: T | undefined) => void
- class?: ComponentProps<"div">["class"]
- classList?: ComponentProps<"div">["classList"]
-}
-
-export function Select(props: SelectProps & ButtonProps) {
- const grouped = createMemo(() => {
- const result = pipe(
- props.options,
- groupBy((x) => (props.groupBy ? props.groupBy(x) : "")),
- // mapValues((x) => x.sort((a, b) => a.title.localeCompare(b.title))),
- entries(),
- map(([k, v]) => ({ category: k, options: v })),
- )
- return result
- })
-
- return (
-
- value={props.current}
- options={grouped()}
- optionValue={(x) => (props.value ? props.value(x) : (x as string))}
- optionTextValue={(x) => (props.label ? props.label(x) : (x as string))}
- optionGroupChildren="options"
- placeholder={props.placeholder}
- sectionComponent={(props) => (
-
- {props.section.rawValue.category}
-
- )}
- itemComponent={(itemProps) => (
-
-
- {props.label ? props.label(itemProps.item.rawValue) : (itemProps.item.rawValue as string)}
-
-
-
-
-
- )}
- onChange={(v) => {
- props.onSelect?.(v ?? undefined)
- }}
- >
-
- class="truncate">
- {(state) => {
- const selected = state.selectedOption() ?? props.current
- if (!selected) return props.placeholder || ""
- if (props.label) return props.label(selected)
- return selected as string
- }}
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
diff --git a/packages/desktop/src/components/session-list.tsx b/packages/desktop/src/components/session-list.tsx
index a339fc6b4..f26d39af8 100644
--- a/packages/desktop/src/components/session-list.tsx
+++ b/packages/desktop/src/components/session-list.tsx
@@ -1,5 +1,5 @@
import { useSync, useLocal } from "@/context"
-import { Tooltip } from "@/ui"
+import { Tooltip } from "@opencode-ai/ui"
import { DateTime } from "luxon"
import { VList } from "virtua/solid"
diff --git a/packages/desktop/src/components/session-timeline.tsx b/packages/desktop/src/components/session-timeline.tsx
index 07d93031e..d4adf2e4a 100644
--- a/packages/desktop/src/components/session-timeline.tsx
+++ b/packages/desktop/src/components/session-timeline.tsx
@@ -1,5 +1,6 @@
import { useLocal, useSync } from "@/context"
-import { Collapsible, Icon } from "@/ui"
+import { Icon } from "@opencode-ai/ui"
+import { Collapsible } from "@/ui"
import type { Part, ToolPart } from "@opencode-ai/sdk"
import { DateTime } from "luxon"
import {
diff --git a/packages/desktop/src/components/sidebar-nav.tsx b/packages/desktop/src/components/sidebar-nav.tsx
deleted file mode 100644
index 24750bdba..000000000
--- a/packages/desktop/src/components/sidebar-nav.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { For } from "solid-js"
-import { Icon, Link, Logo, Tooltip } from "@/ui"
-import { useLocation } from "@solidjs/router"
-
-const navigation = [
- { name: "Sessions", href: "/sessions", icon: "dashboard" as const },
- { name: "Commands", href: "/commands", icon: "slash" as const },
- { name: "Agents", href: "/agents", icon: "bolt" as const },
- { name: "Providers", href: "/providers", icon: "cloud" as const },
- { name: "Tools (MCP)", href: "/tools", icon: "hammer" as const },
- { name: "LSP", href: "/lsp", icon: "code" as const },
- { name: "Settings", href: "/settings", icon: "settings" as const },
-]
-
-export default function SidebarNav() {
- const location = useLocation()
- return (
-
-
-
-
-
-
- )
-}
diff --git a/packages/desktop/src/context/index.ts b/packages/desktop/src/context/index.ts
index bc4bf3b1d..6ca3bbf97 100644
--- a/packages/desktop/src/context/index.ts
+++ b/packages/desktop/src/context/index.ts
@@ -4,4 +4,3 @@ export { MarkedProvider, useMarked } from "./marked"
export { SDKProvider, useSDK } from "./sdk"
export { ShikiProvider, useShiki } from "./shiki"
export { SyncProvider, useSync } from "./sync"
-export { ThemeProvider, useTheme } from "./theme"
diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx
index e9fe8ee5c..c60e4520e 100644
--- a/packages/desktop/src/context/local.tsx
+++ b/packages/desktop/src/context/local.tsx
@@ -131,31 +131,31 @@ function init() {
const changeset = createMemo(() => new Set(sync.data.changes.map((f) => f.path)))
const changes = createMemo(() => Array.from(changeset()).sort((a, b) => a.localeCompare(b)))
- createEffect((prev: FileStatus[]) => {
- const removed = prev.filter((p) => !sync.data.changes.find((c) => c.path === p.path))
- for (const p of removed) {
- setStore(
- "node",
- p.path,
- produce((draft) => {
- draft.status = undefined
- draft.view = "raw"
- }),
- )
- load(p.path)
- }
- for (const p of sync.data.changes) {
- if (store.node[p.path] === undefined) {
- fetch(p.path).then(() => {
- if (store.node[p.path] === undefined) return
- setStore("node", p.path, "status", p)
- })
- } else {
- setStore("node", p.path, "status", p)
- }
- }
- return sync.data.changes
- }, sync.data.changes)
+ // createEffect((prev: FileStatus[]) => {
+ // const removed = prev.filter((p) => !sync.data.changes.find((c) => c.path === p.path))
+ // for (const p of removed) {
+ // setStore(
+ // "node",
+ // p.path,
+ // produce((draft) => {
+ // draft.status = undefined
+ // draft.view = "raw"
+ // }),
+ // )
+ // load(p.path)
+ // }
+ // for (const p of sync.data.changes) {
+ // if (store.node[p.path] === undefined) {
+ // fetch(p.path).then(() => {
+ // if (store.node[p.path] === undefined) return
+ // setStore("node", p.path, "status", p)
+ // })
+ // } else {
+ // setStore("node", p.path, "status", p)
+ // }
+ // }
+ // return sync.data.changes
+ // }, sync.data.changes)
const changed = (path: string) => {
const node = store.node[path]
diff --git a/packages/desktop/src/context/theme.tsx b/packages/desktop/src/context/theme.tsx
deleted file mode 100644
index 0b344ea97..000000000
--- a/packages/desktop/src/context/theme.tsx
+++ /dev/null
@@ -1,92 +0,0 @@
-import {
- createContext,
- useContext,
- createSignal,
- createEffect,
- onMount,
- type ParentComponent,
- onCleanup,
-} from "solid-js"
-
-export interface ThemeContextValue {
- theme: string | undefined
- isDark: boolean
- setTheme: (themeName: string) => void
- setDarkMode: (isDark: boolean) => void
-}
-
-const ThemeContext = createContext()
-
-export const useTheme = () => {
- const context = useContext(ThemeContext)
- if (!context) {
- throw new Error("useTheme must be used within a ThemeProvider")
- }
- return context
-}
-
-interface ThemeProviderProps {
- defaultTheme?: string
- defaultDarkMode?: boolean
-}
-
-const themes = ["opencode", "tokyonight", "ayu", "nord", "catppuccin"]
-
-export const ThemeProvider: ParentComponent = (props) => {
- const [theme, setThemeSignal] = createSignal()
- const [isDark, setIsDark] = createSignal(props.defaultDarkMode ?? false)
-
- const handleKeyDown = (event: KeyboardEvent) => {
- if (event.key === "t" && event.ctrlKey) {
- event.preventDefault()
- const current = theme()
- if (!current) return
- const index = themes.indexOf(current)
- const next = themes[(index + 1) % themes.length]
- setTheme(next)
- }
- }
-
- onMount(() => {
- window.addEventListener("keydown", handleKeyDown)
- })
-
- onCleanup(() => {
- window.removeEventListener("keydown", handleKeyDown)
- })
-
- onMount(() => {
- const savedTheme = localStorage.getItem("theme") ?? "opencode"
- const savedDarkMode = localStorage.getItem("darkMode") ?? "true"
- setIsDark(savedDarkMode === "true")
- setTheme(savedTheme)
- })
-
- createEffect(() => {
- const currentTheme = theme()
- const darkMode = isDark()
- if (currentTheme) {
- document.documentElement.setAttribute("data-theme", currentTheme)
- document.documentElement.setAttribute("data-dark", darkMode.toString())
- }
- })
-
- const setTheme = async (theme: string) => {
- setThemeSignal(theme)
- localStorage.setItem("theme", theme)
- }
-
- const setDarkMode = (dark: boolean) => {
- setIsDark(dark)
- localStorage.setItem("darkMode", dark.toString())
- }
-
- const contextValue: ThemeContextValue = {
- theme: theme(),
- isDark: isDark(),
- setTheme,
- setDarkMode,
- }
-
- return {props.children}
-}
diff --git a/packages/desktop/src/index.css b/packages/desktop/src/index.css
index cac2e91a6..b4717a4e8 100644
--- a/packages/desktop/src/index.css
+++ b/packages/desktop/src/index.css
@@ -1,168 +1 @@
-@import "tailwindcss";
-
-:root {
- interpolate-size: allow-keywords;
-}
-
-@layer components {
- [data-popper-positioner] {
- pointer-events: none;
- }
-
- body {
- line-height: 1;
- }
-
- ::selection {
- background-color: color-mix(in srgb, var(--color-primary) 33%, transparent);
- /* background-color: var(--color-primary); */
- /* color: var(--color-background); */
- }
-
- ::-webkit-scrollbar-track {
- background: var(--theme-background-panel);
- }
-
- ::-webkit-scrollbar-thumb {
- background-color: var(--theme-border-subtle);
- border-radius: 6px;
- }
-
- * {
- scrollbar-color: var(--theme-border-subtle) var(--theme-background-panel);
- }
-
- .prose h1 {
- color: var(--color-text);
- font-size: var(--text-sm);
- line-height: var(--text-sm--line-height);
- margin-bottom: calc(var(--spacing) * 3);
- }
- .prose h2 {
- color: var(--color-text);
- font-size: var(--text-sm);
- line-height: var(--text-sm--line-height);
- margin-bottom: calc(var(--spacing) * 3);
- }
- .prose h3 {
- color: var(--color-text);
- font-size: var(--text-xs);
- line-height: var(--text-xs--line-height);
- margin-bottom: calc(var(--spacing) * 2);
- }
- .prose h4 {
- color: var(--color-text);
- font-size: var(--text-xs);
- line-height: var(--text-xs--line-height);
- margin-bottom: calc(var(--spacing) * 2);
- }
- .prose h5 {
- color: var(--color-text);
- font-size: var(--text-xs);
- line-height: var(--text-xs--line-height);
- margin-bottom: calc(var(--spacing) * 2);
- }
- .prose h6 {
- color: var(--color-text);
- font-size: var(--text-xs);
- line-height: var(--text-xs--line-height);
- margin-bottom: calc(var(--spacing) * 2);
- }
- .prose p {
- font-size: var(--text-xs);
- line-height: var(--text-xs--line-height);
- margin-bottom: calc(var(--spacing) * 2);
- }
- .prose strong {
- color: var(--color-text);
- }
- .prose ul,
- ol {
- list-style-type: disc;
- list-style-position: inside;
- margin-bottom: calc(var(--spacing) * 2);
- }
- .prose pre {
- background-color: var(--color-background-panel);
- padding: calc(var(--spacing) * 2);
- border-radius: var(--radius-md);
- border: 1px solid var(--color-border-subtle);
- overflow-x: auto;
- white-space: pre;
- margin-bottom: calc(var(--spacing) * 2);
- @apply no-scrollbar;
- }
- .prose code {
- font-family: var(--font-mono);
- font-size: var(--text-xs);
- line-height: var(--text-xs--line-height);
- }
- .prose blockquote {
- margin-bottom: calc(var(--spacing) * 2);
- }
-}
-
-@utility no-scrollbar {
- &::-webkit-scrollbar {
- display: none;
- }
- /* Hide scrollbar for IE, Edge and Firefox */
- & {
- -ms-overflow-style: none; /* IE and Edge */
- scrollbar-width: none; /* Firefox */
- }
-}
-
-@theme {
- --color-*: initial;
- --color-primary: var(--theme-primary);
- --color-secondary: var(--theme-secondary);
- --color-accent: var(--theme-accent);
- --color-error: var(--theme-error);
- --color-warning: var(--theme-warning);
- --color-success: var(--theme-success);
- --color-info: var(--theme-info);
- --color-text: var(--theme-text);
- --color-text-muted: var(--theme-text-muted);
- --color-background: var(--theme-background);
- --color-background-panel: var(--theme-background-panel);
- --color-background-element: var(--theme-background-element);
- --color-border: var(--theme-border);
- --color-border-active: var(--theme-border-active);
- --color-border-subtle: var(--theme-border-subtle);
- --color-diff-added: var(--theme-diff-added);
- --color-diff-removed: var(--theme-diff-removed);
- --color-diff-context: var(--theme-diff-context);
- --color-diff-hunk-header: var(--theme-diff-hunk-header);
- --color-diff-highlight-added: var(--theme-diff-highlight-added);
- --color-diff-highlight-removed: var(--theme-diff-highlight-removed);
- --color-diff-added-bg: var(--theme-diff-added-bg);
- --color-diff-removed-bg: var(--theme-diff-removed-bg);
- --color-diff-context-bg: var(--theme-diff-context-bg);
- --color-diff-line-number: var(--theme-diff-line-number);
- --color-diff-added-line-number-bg: var(--theme-diff-added-line-number-bg);
- --color-diff-removed-line-number-bg: var(--theme-diff-removed-line-number-bg);
- --color-markdown-text: var(--theme-markdown-text);
- --color-markdown-heading: var(--theme-markdown-heading);
- --color-markdown-link: var(--theme-markdown-link);
- --color-markdown-link-text: var(--theme-markdown-link-text);
- --color-markdown-code: var(--theme-markdown-code);
- --color-markdown-block-quote: var(--theme-markdown-block-quote);
- --color-markdown-emph: var(--theme-markdown-emph);
- --color-markdown-strong: var(--theme-markdown-strong);
- --color-markdown-horizontal-rule: var(--theme-markdown-horizontal-rule);
- --color-markdown-list-item: var(--theme-markdown-list-item);
- --color-markdown-list-enumeration: var(--theme-markdown-list-enumeration);
- --color-markdown-image: var(--theme-markdown-image);
- --color-markdown-image-text: var(--theme-markdown-image-text);
- --color-markdown-code-block: var(--theme-markdown-code-block);
- --color-syntax-comment: var(--theme-syntax-comment);
- --color-syntax-keyword: var(--theme-syntax-keyword);
- --color-syntax-function: var(--theme-syntax-function);
- --color-syntax-variable: var(--theme-syntax-variable);
- --color-syntax-string: var(--theme-syntax-string);
- --color-syntax-number: var(--theme-syntax-number);
- --color-syntax-type: var(--theme-syntax-type);
- --color-syntax-operator: var(--theme-syntax-operator);
- --color-syntax-punctuation: var(--theme-syntax-punctuation);
-}
+@import "@opencode-ai/css/tailwind.css";
diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx
index 66ed93d3a..5fa840f0d 100644
--- a/packages/desktop/src/index.tsx
+++ b/packages/desktop/src/index.tsx
@@ -1,21 +1,13 @@
/* @refresh reload */
+import "@/index.css"
import { render } from "solid-js/web"
import { Router, Route } from "@solidjs/router"
-import "@/index.css"
-import Layout from "@/pages/layout"
+import { MetaProvider } from "@solidjs/meta"
+import { EventProvider, SDKProvider, SyncProvider, LocalProvider, ShikiProvider, MarkedProvider } from "@/context"
+import { Fonts } from "@opencode-ai/ui"
import Home from "@/pages"
-import {
- EventProvider,
- SDKProvider,
- SyncProvider,
- LocalProvider,
- ThemeProvider,
- ShikiProvider,
- MarkedProvider,
-} from "@/context"
const root = document.getElementById("root")
-
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
throw new Error(
"Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?",
@@ -24,25 +16,24 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
render(
() => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
),
root!,
)
diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx
index 2e26eb0c2..1174f1e16 100644
--- a/packages/desktop/src/pages/index.tsx
+++ b/packages/desktop/src/pages/index.tsx
@@ -1,5 +1,5 @@
-import { FileIcon, Icon, IconButton, Tooltip } from "@/ui"
-import * as KobalteTabs from "@kobalte/core/tabs"
+import { Icon, Tooltip } from "@opencode-ai/ui"
+import { FileIcon, IconButton } from "@/ui"
import FileTree from "@/components/file-tree"
import EditorPane from "@/components/editor-pane"
import { For, Match, onCleanup, onMount, Show, Switch } from "solid-js"
@@ -11,9 +11,7 @@ import SessionTimeline from "@/components/session-timeline"
import PromptForm, { type PromptContentPart, type PromptSubmitValue } from "@/components/prompt-form"
import { createStore } from "solid-js/store"
import { getDirectory, getFilename } from "@/utils"
-import { Select } from "@/components/select"
-import { Tabs } from "@/ui/tabs"
-import { Code } from "@/components/code"
+import { PromptInput } from "@/components/prompt-input"
export default function Page() {
const local = useLocal()
@@ -52,7 +50,7 @@ export default function Page() {
const focused = document.activeElement === inputRef
if (focused) {
if (event.key === "Escape") {
- inputRef?.blur()
+ // inputRef?.blur()
}
return
}
@@ -79,7 +77,7 @@ export default function Page() {
}
if (event.key.length === 1 && event.key !== "Unidentified") {
- inputRef?.focus()
+ // inputRef?.focus()
}
}
@@ -106,6 +104,8 @@ export default function Page() {
}
}
+ const handlePromptSubmit2 = () => {}
+
const handlePromptSubmit = async (prompt: PromptSubmitValue) => {
const existingSession = local.session.active()
let session = existingSession
@@ -231,51 +231,54 @@ export default function Page() {
-
-
- {(activeSession) => }
-
-
-
-
-
-
- No changes
}
- >
-
-
- {(path) => (
- -
-
-
- )}
-
-
-
-
-
-
-
-
-
setStore("modelSelectOpen", true)}
- onInputRefChange={(element: HTMLTextAreaElement | undefined) => {
- inputRef = element ?? undefined
- }}
- />
+
+
+
+ {(activeSession) => }
+
+
+
+
+
+
+
+ {/*
setStore("modelSelectOpen", true)} */}
+ {/* onInputRefChange={(element: HTMLTextAreaElement | undefined) => { */}
+ {/* inputRef = element ?? undefined */}
+ {/* }} */}
+ {/* /> */}
+
+
+
+
+
+ No changes
}
+ >
+
+
+ {(path) => (
+ -
+
+
+ )}
+
+
+
+
@@ -343,8 +346,7 @@ export default function Page() {
)}
onClose={() => setStore("fileSelectOpen", false)}
- onSelect={(x) => (x ? local.context.openFile(x) : undefined)}
- // onSelect={(x) => (x ? local.file.open(x, { pinned: true }) : undefined)}
+ onSelect={(x) => (x ? local.file.open(x, { pinned: true }) : undefined)}
/>
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx
deleted file mode 100644
index d2e33a2ca..000000000
--- a/packages/desktop/src/pages/layout.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { type ParentProps } from "solid-js"
-
-export default function Layout(props: ParentProps) {
- return {props.children}
-}
diff --git a/packages/desktop/src/ui/button.tsx b/packages/desktop/src/ui/button.tsx
deleted file mode 100644
index 21d89fbee..000000000
--- a/packages/desktop/src/ui/button.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { Button as Kobalte } from "@kobalte/core/button"
-import { type ComponentProps, splitProps } from "solid-js"
-
-export interface ButtonProps {
- variant?: "primary" | "secondary" | "ghost"
- size?: "sm" | "md" | "lg"
-}
-
-export function Button(props: ComponentProps<"button"> & ButtonProps) {
- const [split, rest] = splitProps(props, ["variant", "size", "class", "classList"])
- return (
-
- {props.children}
-
- )
-}
diff --git a/packages/desktop/src/ui/collapsible.tsx b/packages/desktop/src/ui/collapsible.tsx
index e0202f617..d17b3e623 100644
--- a/packages/desktop/src/ui/collapsible.tsx
+++ b/packages/desktop/src/ui/collapsible.tsx
@@ -1,7 +1,7 @@
import { Collapsible as KobalteCollapsible } from "@kobalte/core/collapsible"
import { splitProps } from "solid-js"
import type { ComponentProps, ParentProps } from "solid-js"
-import { Icon, type IconProps } from "./icon"
+import { Icon, type IconProps } from "@opencode-ai/ui"
export interface CollapsibleProps extends ComponentProps {}
export interface CollapsibleTriggerProps extends ComponentProps {}
diff --git a/packages/desktop/src/ui/icon.tsx b/packages/desktop/src/ui/icon.tsx
deleted file mode 100644
index 35c77c078..000000000
--- a/packages/desktop/src/ui/icon.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-import { splitProps, type ComponentProps } from "solid-js"
-
-export interface IconProps extends ComponentProps<"svg"> {
- name: keyof typeof icons
- size?: number
-}
-
-// prettier-ignore
-const icons = {
- close: '',
- menu: ' ',
- "chevron-right": '',
- "chevron-left": '',
- "chevron-down": '',
- "chevron-up": '',
- "chevron-down-square": '',
- "chevron-up-square": '',
- "chevron-right-square": '',
- "chevron-left-square": '',
- settings: '',
- globe: '',
- github: '',
- hammer: '',
- "avatar-square": '',
- slash: '',
- robot: '',
- cloud: '',
- "file-text": '',
- file: '',
- "file-checkmark": '',
- "file-code": '',
- "file-important": '',
- "file-minus": '',
- "file-plus": '',
- files: '',
- "file-zip": '',
- jpg: '',
- pdf: '',
- png: '',
- gif: '',
- archive: '',
- sun: '',
- moon: '',
- monitor: '',
- command: '',
- link: '',
- share: '',
- branch: '',
- logout: '',
- login: '',
- keys: '',
- key: '',
- info: '',
- warning: '',
- checkmark: '',
- "checkmark-square": '',
- plus: '',
- minus: '',
- undo: '',
- merge: '',
- redo: '',
- refresh: '',
- rotate: '',
- "arrow-left": '',
- "arrow-down": '',
- "arrow-right": '',
- "arrow-up": '',
- enter: '',
- trash: '',
- package: '',
- box: '',
- lock: '',
- unlocked: '',
- activity: '',
- asterisk: '',
- bell: '',
- "bell-off": '',
- bolt: '',
- bookmark: '',
- brain: '',
- browser: '',
- "browser-cursor": '',
- bug: '',
- "carat-down": '',
- "carat-left": '',
- "carat-right": '',
- "carat-up": '',
- cards: '',
- chart: '',
- "check-circle": '',
- checklist: '',
- "checklist-cards": '',
- lab: '',
- circle: '',
- "circle-dotted": '',
- clipboard: '',
- clock: '',
- "close-circle": '',
- terminal: '',
- code: '',
- components: '',
- copy: '',
- cpu: '',
- dashboard: '',
- transfer: '',
- devices: '',
- diamond: '',
- dice: '',
- discord: '',
- dots: '',
- expand: '',
- droplet: '',
- "chevron-double-down": '',
- "chevron-double-left": '',
- "chevron-double-right": '',
- "chevron-double-up": '',
- "speech-bubble": '',
- message: '',
- annotation: '',
- square: '',
- "pull-request": '',
- pencil: '',
- sparkles: '',
- photo: '',
- columns: '',
- "open-pane": '',
- "close-pane": '',
- "file-search": '',
- "folder-search": '',
- search: '',
- "web-search": '',
- loading: '',
- mic: '',
- } as const
-
-export function Icon(props: IconProps) {
- const [local, others] = splitProps(props, ["name", "size", "class", "classList"])
- const size = local.size ?? 24
- return (
-
- )
-}
diff --git a/packages/desktop/src/ui/index.ts b/packages/desktop/src/ui/index.ts
index d3f24a192..a6ade6ff3 100644
--- a/packages/desktop/src/ui/index.ts
+++ b/packages/desktop/src/ui/index.ts
@@ -1,4 +1,3 @@
-export { Button, type ButtonProps } from "./button"
export {
Collapsible,
type CollapsibleProps,
@@ -6,8 +5,4 @@ export {
type CollapsibleContentProps,
} from "./collapsible"
export { FileIcon, type FileIconProps } from "./file-icon"
-export { Icon, type IconProps } from "./icon"
export { IconButton, type IconButtonProps } from "./icon-button"
-export { Link, type LinkProps } from "./link"
-export { Logo, type LogoProps } from "./logo"
-export { Tooltip, type TooltipProps } from "./tooltip"
diff --git a/packages/desktop/src/ui/link.tsx b/packages/desktop/src/ui/link.tsx
deleted file mode 100644
index 461206d58..000000000
--- a/packages/desktop/src/ui/link.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import { A } from "@solidjs/router"
-import { splitProps } from "solid-js"
-import type { ComponentProps } from "solid-js"
-
-export interface LinkProps extends ComponentProps {
- variant?: "primary" | "secondary" | "ghost"
- size?: "sm" | "md" | "lg"
-}
-
-export function Link(props: LinkProps) {
- const [, others] = splitProps(props, ["variant", "size", "class"])
- return
-}
diff --git a/packages/desktop/src/ui/logo.tsx b/packages/desktop/src/ui/logo.tsx
deleted file mode 100644
index 0bbaba835..000000000
--- a/packages/desktop/src/ui/logo.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import type { ComponentProps } from "solid-js"
-
-export interface LogoProps extends ComponentProps<"svg"> {
- variant?: "mark" | "full" | "ornate"
- size?: number
-}
-
-export function Logo(props: LogoProps) {
- const { variant = "mark", size = 64, ...others } = props
-
- if (variant === "mark") {
- return (
-
- )
- }
-
- if (variant === "full") {
- return (
-
- )
- }
-
- return (
-
- )
-}
diff --git a/packages/desktop/src/ui/tabs.tsx b/packages/desktop/src/ui/tabs.tsx
deleted file mode 100644
index d82d3327a..000000000
--- a/packages/desktop/src/ui/tabs.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import { Tabs as KobalteTabs } from "@kobalte/core/tabs"
-import { splitProps } from "solid-js"
-import type { ComponentProps, ParentProps } from "solid-js"
-
-export interface TabsProps extends ComponentProps {}
-export interface TabsListProps extends ComponentProps {}
-export interface TabsTriggerProps extends ComponentProps {}
-export interface TabsContentProps extends ComponentProps {}
-
-function TabsRoot(props: TabsProps) {
- return
-}
-
-function TabsList(props: TabsListProps) {
- const [local, others] = splitProps(props, ["class"])
- return (
-
- )
-}
-
-function TabsTrigger(props: ParentProps) {
- const [local, others] = splitProps(props, ["class", "children"])
- return (
-
- {local.children}
-
- )
-}
-
-function TabsContent(props: ParentProps) {
- const [local, others] = splitProps(props, ["class", "children"])
- return (
-
- {local.children}
-
- )
-}
-
-export const Tabs = Object.assign(TabsRoot, {
- List: TabsList,
- Trigger: TabsTrigger,
- Content: TabsContent,
-})
diff --git a/packages/desktop/src/ui/tooltip.tsx b/packages/desktop/src/ui/tooltip.tsx
deleted file mode 100644
index 8bf1dc429..000000000
--- a/packages/desktop/src/ui/tooltip.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { Tooltip as KobalteTooltip } from "@kobalte/core/tooltip"
-import { children, createEffect, createSignal, splitProps } from "solid-js"
-import type { ComponentProps } from "solid-js"
-
-export interface TooltipProps extends ComponentProps {
- value: string | (() => string)
- class?: string
-}
-
-export function Tooltip(props: TooltipProps) {
- const [open, setOpen] = createSignal(false)
- const [local, others] = splitProps(props, ["class", "children"])
-
- const c = children(() => local.children)
-
- createEffect(() => {
- const childElements = c()
- if (childElements instanceof HTMLElement) {
- childElements.addEventListener("focus", () => setOpen(true))
- childElements.addEventListener("blur", () => setOpen(false))
- } else if (Array.isArray(childElements)) {
- for (const child of childElements) {
- if (child instanceof HTMLElement) {
- child.addEventListener("focus", () => setOpen(true))
- child.addEventListener("blur", () => setOpen(false))
- }
- }
- }
- })
-
- return (
-
-
- {c()}
-
-
-
- {typeof others.value === "function" ? others.value() : others.value}
-
-
-
-
- )
-}
--
cgit v1.2.3