Adam 10 mesiacov pred
rodič
commit
887a819f24
46 zmenil súbory, kde vykonal 513 pridanie a 397 odobranie
  1. 11 6
      bun.lock
  2. 2 0
      package.json
  3. 0 34
      packages/css/.gitignore
  4. 0 18
      packages/css/package.json
  5. 0 14
      packages/css/src/index.css
  6. 0 12
      packages/css/src/tailwind.css
  7. 0 37
      packages/css/src/utilities.css
  8. 2 2
      packages/desktop/package.json
  9. 1 1
      packages/desktop/src/components/prompt-input.tsx
  10. 0 38
      packages/desktop/src/components/session-list.tsx
  11. 4 1
      packages/desktop/src/context/sync.tsx
  12. 1 1
      packages/desktop/src/index.css
  13. 40 8
      packages/desktop/src/pages/index.tsx
  14. 15 6
      packages/ui/package.json
  15. 0 0
      packages/ui/script/colors.txt
  16. 1 9
      packages/ui/script/tailwind.ts
  17. 0 0
      packages/ui/src/assets/fonts/geist-italic.ttf
  18. 0 0
      packages/ui/src/assets/fonts/geist-italic.woff2
  19. 0 0
      packages/ui/src/assets/fonts/geist-mono-italic.ttf
  20. 0 0
      packages/ui/src/assets/fonts/geist-mono-italic.woff2
  21. 0 0
      packages/ui/src/assets/fonts/geist-mono.ttf
  22. 0 0
      packages/ui/src/assets/fonts/geist-mono.woff2
  23. 0 0
      packages/ui/src/assets/fonts/geist.ttf
  24. 0 0
      packages/ui/src/assets/fonts/geist.woff2
  25. 25 13
      packages/ui/src/components/button.css
  26. 6 6
      packages/ui/src/components/fonts.tsx
  27. 0 0
      packages/ui/src/components/icon.css
  28. 1 0
      packages/ui/src/components/index.ts
  29. 30 0
      packages/ui/src/components/list.css
  30. 76 0
      packages/ui/src/components/list.tsx
  31. 2 0
      packages/ui/src/components/select.css
  32. 0 2
      packages/ui/src/components/style.css
  33. 2 2
      packages/ui/src/components/tabs.css
  34. 12 6
      packages/ui/src/components/tooltip.css
  35. 1 1
      packages/ui/src/components/tooltip.tsx
  36. 9 3
      packages/ui/src/demo.tsx
  37. 1 3
      packages/ui/src/index.css
  38. 2 2
      packages/ui/src/index.tsx
  39. 7 7
      packages/ui/src/styles/base.css
  40. 0 0
      packages/ui/src/styles/colors.css
  41. 15 0
      packages/ui/src/styles/index.css
  42. 1 1
      packages/ui/src/styles/tailwind/colors.css
  43. 40 0
      packages/ui/src/styles/tailwind/index.css
  44. 9 0
      packages/ui/src/styles/tailwind/utilities.css
  45. 88 164
      packages/ui/src/styles/theme.css
  46. 109 0
      packages/ui/src/styles/utilities.css

+ 11 - 6
bun.lock

@@ -138,9 +138,9 @@
         "remeda": "catalog:",
         "shiki": "3.9.2",
         "solid-js": "catalog:",
-        "solid-list": "0.3.0",
+        "solid-list": "catalog:",
         "tailwindcss": "catalog:",
-        "virtua": "0.42.3",
+        "virtua": "catalog:",
       },
       "devDependencies": {
         "@tailwindcss/vite": "catalog:",
@@ -281,12 +281,17 @@
       "version": "0.15.7",
       "dependencies": {
         "@kobalte/core": "catalog:",
-        "@opencode-ai/css": "workspace:*",
         "@solidjs/meta": "catalog:",
+        "luxon": "catalog:",
         "remeda": "catalog:",
         "solid-js": "catalog:",
+        "solid-list": "catalog:",
+        "virtua": "catalog:",
       },
       "devDependencies": {
+        "@tailwindcss/vite": "catalog:",
+        "@types/bun": "catalog:",
+        "tailwindcss": "catalog:",
         "typescript": "catalog:",
         "vite": "catalog:",
         "vite-plugin-solid": "catalog:",
@@ -355,8 +360,10 @@
     "luxon": "3.6.1",
     "remeda": "2.26.0",
     "solid-js": "1.9.9",
+    "solid-list": "0.3.0",
     "tailwindcss": "4.1.11",
     "typescript": "5.8.2",
+    "virtua": "0.42.3",
     "vite": "7.1.4",
     "vite-plugin-solid": "2.11.8",
     "zod": "4.1.8",
@@ -3694,7 +3701,7 @@
 
     "named-placeholders/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
 
-    "nitropack/c12": ["c12@3.3.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.2", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.5.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-K9ZkuyeJQeqLEyqldbYLG3wjqwpw4BVaAqvmxq3GYKK0b1A/yYQdIcJxkzAOWcNVWhJpRXAPfZFueekiY/L8Dw=="],
+    "nitropack/c12": ["c12@3.3.1", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-LcWQ01LT9tkoUINHgpIOv3mMs+Abv7oVCrtpMRi1PaapVEpWoMga5WuT7/DqFTu7URP9ftbOmimNw1KNIGh9DQ=="],
 
     "nitropack/globby": ["globby@15.0.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "fast-glob": "^3.3.3", "ignore": "^7.0.5", "path-type": "^6.0.0", "slash": "^5.1.0", "unicorn-magic": "^0.3.0" } }, "sha512-oB4vkQGqlMl682wL1IlWd02tXCbquGWM4voPEI85QmNKCaw8zGTm1f1rubFgkg3Eli2PtKlFgrnmUqasbQWlkw=="],
 
@@ -4102,8 +4109,6 @@
 
     "axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
 
-    "bl/buffer/ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
-
     "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
 
     "c12/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],

+ 2 - 0
package.json

@@ -37,7 +37,9 @@
       "zod": "4.1.8",
       "remeda": "2.26.0",
       "solid-js": "1.9.9",
+      "solid-list": "0.3.0",
       "tailwindcss": "4.1.11",
+      "virtua": "0.42.3",
       "vite": "7.1.4",
       "vite-plugin-solid": "2.11.8"
     }

+ 0 - 34
packages/css/.gitignore

@@ -1,34 +0,0 @@
-# dependencies (bun install)
-node_modules
-
-# output
-out
-dist
-*.tgz
-
-# code coverage
-coverage
-*.lcov
-
-# logs
-logs
-_.log
-report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
-
-# dotenv environment variable files
-.env
-.env.development.local
-.env.test.local
-.env.production.local
-.env.local
-
-# caches
-.eslintcache
-.cache
-*.tsbuildinfo
-
-# IntelliJ based IDEs
-.idea
-
-# Finder (MacOS) folder config
-.DS_Store

+ 0 - 18
packages/css/package.json

@@ -1,18 +0,0 @@
-{
-  "name": "@opencode-ai/css",
-  "version": "0.15.7",
-  "type": "module",
-  "exports": {
-    ".": "./src/index.css",
-    "./*": "./src/*",
-    "./fonts/*": "./src/assets/fonts/*"
-  },
-  "scripts": {
-    "dev": "bun run dev.ts",
-    "generate:tailwind": "bun run script/colors.ts"
-  },
-  "dependencies": {
-    "tailwindcss": "catalog:",
-    "@tailwindcss/vite": "catalog:"
-  }
-}

+ 0 - 14
packages/css/src/index.css

@@ -1,14 +0,0 @@
-@layer theme, base, components, utilities;
-
-@import "./color.css" layer(theme);
-@import "./theme.css" layer(theme);
-
-@import "./base.css" layer(base);
-
-@import "./components/button.css" layer(components);
-@import "./components/icon.css" layer(components);
-@import "./components/select.css" layer(components);
-@import "./components/tabs.css" layer(components);
-@import "./components/tooltip.css" layer(components);
-
-@import "./utilities.css" layer(utilities);

+ 0 - 12
packages/css/src/tailwind.css

@@ -1,12 +0,0 @@
-@layer theme, base, components, utilities;
-@import "tailwindcss/theme.css" layer(theme);
-@import "tailwindcss/utilities.css" layer(utilities);
-
-@import "./index.css";
-
-@theme {
-  --shadow-*: initial;
-  --shadow-xs-border-selected: var(--shadow-xs-border-selected);
-}
-
-@import "./tailwind-colors.css";

+ 0 - 37
packages/css/src/utilities.css

@@ -1,37 +0,0 @@
-:root {
-  interpolate-size: allow-keywords;
-
-  [data-popper-positioner] {
-    pointer-events: none;
-  }
-
-  ::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);
-  }
-}
-
-.no-scrollbar {
-  &::-webkit-scrollbar {
-    display: none;
-  }
-  /* Hide scrollbar for IE, Edge and Firefox */
-  & {
-    -ms-overflow-style: none; /* IE and Edge */
-    scrollbar-width: none; /* Firefox */
-  }
-}

+ 2 - 2
packages/desktop/package.json

@@ -42,9 +42,9 @@
     "remeda": "catalog:",
     "solid-js": "catalog:",
     "shiki": "3.9.2",
-    "solid-list": "0.3.0",
+    "solid-list": "catalog:",
     "tailwindcss": "catalog:",
-    "virtua": "0.42.3"
+    "virtua": "catalog:"
   },
   "prettier": {
     "semi": false,

+ 1 - 1
packages/desktop/src/components/prompt-input.tsx

@@ -187,7 +187,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
   return (
     <div
       classList={{
-        "size-full max-w-xl bg-surface-base border border-border-base": true,
+        "size-full max-w-xl bg-surface-raised-stronger-non-alpha border border-border-strong-base": true,
         "rounded-2xl overflow-clip focus-within:shadow-xs-border-selected": true,
         [props.class ?? ""]: !!props.class,
       }}

+ 0 - 38
packages/desktop/src/components/session-list.tsx

@@ -1,38 +0,0 @@
-import { useSync, useLocal } from "@/context"
-import { Tooltip } from "@opencode-ai/ui"
-import { DateTime } from "luxon"
-import { VList } from "virtua/solid"
-
-export default function SessionList() {
-  const sync = useSync()
-  const local = useLocal()
-  return (
-    <VList data={sync.data.session} class="no-scrollbar p-3">
-      {(session) => (
-        <Tooltip placement="right" value={session.title} class="w-full min-w-0">
-          <button
-            data-active={local.session.active()?.id === session.id}
-            class="group w-full min-w-0 text-left truncate justify-start text-xs my-0.5 cursor-pointer
-                   flex flex-col gap-1 rounded-md p-2 border-[0.5px] border-transparent
-                   hover:not-data-[active=true]:bg-background-panel
-                   data-[active=true]:bg-background-element data-[active=true]:border-border-subtle"
-            onClick={() => local.session.setActive(session.id)}
-          >
-            <div class="flex gap-1 items-center">
-              <div
-                classList={{
-                  "text-text/80 min-w-0 grow truncate": true,
-                  "group-data-[active=true]:text-text!": true,
-                }}
-              >
-                {session.title}
-              </div>
-              <div class="shrink-0 text-text-muted/60">{DateTime.fromMillis(session.time.updated).toRelative()}</div>
-            </div>
-            <span class="text-text-muted truncate">{session.share?.url}</span>
-          </button>
-        </Tooltip>
-      )}
-    </VList>
-  )
-}

+ 4 - 1
packages/desktop/src/context/sync.tsx

@@ -1,4 +1,4 @@
-import type { Message, Agent, Provider, Session, Part, Config, Path, File, FileNode } from "@opencode-ai/sdk"
+import type { Message, Agent, Provider, Session, Part, Config, Path, File, FileNode, Project } from "@opencode-ai/sdk"
 import { createStore, produce, reconcile } from "solid-js/store"
 import { createContext, createMemo, Show, useContext, type ParentProps } from "solid-js"
 import { useSDK, useEvent } from "@/context"
@@ -9,6 +9,7 @@ function init() {
     ready: boolean
     provider: Provider[]
     agent: Agent[]
+    project: Project
     config: Config
     path: Path
     session: Session[]
@@ -21,6 +22,7 @@ function init() {
     node: FileNode[]
     changes: File[]
   }>({
+    project: { id: "", worktree: "", time: { created: 0, initialized: 0 } },
     config: {},
     path: { state: "", config: "", worktree: "", directory: "" },
     ready: false,
@@ -96,6 +98,7 @@ function init() {
   const sdk = useSDK()
 
   const load = {
+    project: () => sdk.project.current().then((x) => setStore("project", x.data!)),
     provider: () => sdk.config.providers().then((x) => setStore("provider", x.data!.providers)),
     path: () => sdk.path.get().then((x) => setStore("path", x.data!)),
     agent: () => sdk.app.agents().then((x) => setStore("agent", x.data ?? [])),

+ 1 - 1
packages/desktop/src/index.css

@@ -1 +1 @@
-@import "@opencode-ai/css/tailwind.css";
+@import "@opencode-ai/ui/styles/tailwind";

+ 40 - 8
packages/desktop/src/pages/index.tsx

@@ -1,4 +1,4 @@
-import { Icon, Tooltip } from "@opencode-ai/ui"
+import { Button, Icon, List, Tooltip } from "@opencode-ai/ui"
 import { FileIcon, IconButton } from "@/ui"
 import FileTree from "@/components/file-tree"
 import EditorPane from "@/components/editor-pane"
@@ -6,12 +6,12 @@ import { For, Match, onCleanup, onMount, Show, Switch } from "solid-js"
 import { SelectDialog } from "@/components/select-dialog"
 import { useSync, useSDK, useLocal } from "@/context"
 import type { LocalFile, TextSelection } from "@/context/local"
-import SessionList from "@/components/session-list"
 import SessionTimeline from "@/components/session-timeline"
-import PromptForm, { type PromptContentPart, type PromptSubmitValue } from "@/components/prompt-form"
+import { type PromptContentPart, type PromptSubmitValue } from "@/components/prompt-form"
 import { createStore } from "solid-js/store"
 import { getDirectory, getFilename } from "@/utils"
 import { PromptInput } from "@/components/prompt-input"
+import { DateTime } from "luxon"
 
 export default function Page() {
   const local = useLocal()
@@ -225,13 +225,45 @@ export default function Page() {
   )
 
   return (
-    <div class="relative h-screen flex flex-col bg-background-weak">
-      <header class="hidden h-12 shrink-0 bg-background-base border-b border-border-weak-base"></header>
+    <div class="relative h-screen flex flex-col">
+      <header class="hidden h-12 shrink-0 bg-background-strong border-b border-border-weak-base"></header>
       <main class="h-[calc(100vh-0rem)] flex">
-        <div class="shrink-0 w-70">
-          <SessionList />
+        <div class="shrink-0 w-70 p-1.5 bg-background-weak border-r border-border-weak-base flex flex-col items-start gap-1.5">
+          <div class="flex flex-col items-start self-stretch px-3 py-1">
+            <span class="text-12-medium overflow-hidden text-ellipsis">{sync.data.path.directory}</span>
+          </div>
+          <div class="flex flex-col items-start gap-4 self-stretch flex-1">
+            <div class="px-3 py-1.5 w-full">
+              <Button class="w-full" size="large">
+                New Session
+              </Button>
+            </div>
+            <List data={sync.data.session} key={(x) => x.id} onSelect={(s) => local.session.setActive(s?.id)}>
+              {(session) => (
+                <Tooltip placement="right" value={session.title}>
+                  <div>
+                    <div class="flex items-center self-stretch gap-6">
+                      <span class="text-14-regular text-text-strong overflow-hidden text-ellipsis truncate">
+                        {session.title}
+                      </span>
+                      <span class="text-12-regular text-text-weak text-right whitespace-nowrap">
+                        {DateTime.fromMillis(session.time.updated).toRelative()}
+                      </span>
+                    </div>
+                    <div class="flex justify-between items-center self-stretch">
+                      <span class="text-12-regular text-text-weak">2 files changed</span>
+                      <div class="flex gap-2 justify-end items-center">
+                        <span class="text-12-mono text-right text-text-diff-add-base">+43</span>
+                        <span class="text-12-mono text-right text-text-diff-delete-base">-2</span>
+                      </div>
+                    </div>
+                  </div>
+                </Tooltip>
+              )}
+            </List>
+          </div>
         </div>
-        <div class="relative grid grid-cols-2">
+        <div class="relative grid grid-cols-2 bg-background-base">
           <div class="min-w-0 overflow-y-auto no-scrollbar flex justify-center">
             <Show when={local.session.active()}>
               {(activeSession) => <SessionTimeline session={activeSession().id} class="w-full" />}

+ 15 - 6
packages/ui/package.json

@@ -4,21 +4,30 @@
   "type": "module",
   "exports": {
     ".": "./src/components/index.ts",
-    "./*": "./src/components/*"
+    "./*": "./src/components/*.tsx",
+    "./styles": "./src/styles/index.css",
+    "./styles/tailwind": "./src/styles/tailwind/index.css",
+    "./fonts/*": "./src/assets/fonts/*"
   },
   "scripts": {
-    "dev": "vite"
+    "dev": "vite",
+    "generate:tailwind": "bun run script/tailwind.ts"
   },
   "devDependencies": {
+    "@types/bun": "catalog:",
     "typescript": "catalog:",
     "vite": "catalog:",
-    "vite-plugin-solid": "catalog:"
+    "vite-plugin-solid": "catalog:",
+    "tailwindcss": "catalog:",
+    "@tailwindcss/vite": "catalog:"
   },
   "dependencies": {
+    "@kobalte/core": "catalog:",
+    "@solidjs/meta": "catalog:",
     "remeda": "catalog:",
+    "luxon": "catalog:",
+    "virtua": "catalog:",
     "solid-js": "catalog:",
-    "@solidjs/meta": "catalog:",
-    "@kobalte/core": "catalog:",
-    "@opencode-ai/css": "workspace:*"
+    "solid-list": "catalog:"
   }
 }

+ 0 - 0
packages/css/script/colors.txt → packages/ui/script/colors.txt


+ 1 - 9
packages/css/script/colors.ts → packages/ui/script/tailwind.ts

@@ -1,10 +1,5 @@
 #!/usr/bin/env bun
 
-// read lines from colors.txt
-// parse each line into a color name and hex value
-// create a css variable for each color
-// NOTE: only use Bun file APIs here
-
 const colors = await Bun.file(import.meta.dir + "/colors.txt").text()
 
 const variables = []
@@ -25,7 +20,4 @@ const output = `
 }
 `
 
-// write to src/tailwind-colors.css
-Bun.file(import.meta.dir + "/../src/tailwind-colors.css").write(output.trim())
-
-// Bun.file(import.meta.dir + "../src/tailwind-colors.css").write(output.trim())
+await Bun.file(import.meta.dir + "/../src/styles/tailwind/colors.css").write(output.trim())

+ 0 - 0
packages/css/src/assets/fonts/geist-italic.ttf → packages/ui/src/assets/fonts/geist-italic.ttf


+ 0 - 0
packages/css/src/assets/fonts/geist-italic.woff2 → packages/ui/src/assets/fonts/geist-italic.woff2


+ 0 - 0
packages/css/src/assets/fonts/geist-mono-italic.ttf → packages/ui/src/assets/fonts/geist-mono-italic.ttf


+ 0 - 0
packages/css/src/assets/fonts/geist-mono-italic.woff2 → packages/ui/src/assets/fonts/geist-mono-italic.woff2


+ 0 - 0
packages/css/src/assets/fonts/geist-mono.ttf → packages/ui/src/assets/fonts/geist-mono.ttf


+ 0 - 0
packages/css/src/assets/fonts/geist-mono.woff2 → packages/ui/src/assets/fonts/geist-mono.woff2


+ 0 - 0
packages/css/src/assets/fonts/geist.ttf → packages/ui/src/assets/fonts/geist.ttf


+ 0 - 0
packages/css/src/assets/fonts/geist.woff2 → packages/ui/src/assets/fonts/geist.woff2


+ 25 - 13
packages/css/src/components/button.css → packages/ui/src/components/button.css

@@ -5,13 +5,9 @@
   justify-content: center;
   border-style: solid;
   border-width: 1px;
-  border-radius: var(--radius-md);
-  font-size: var(--text-base);
-  line-height: var(--text-base--line-height);
-  font-weight: var(--font-weight-normal);
+  border-radius: 6px;
   text-decoration: none;
   user-select: none;
-  gap: calc(var(--spacing) * 0.5);
 
   &[data-variant="primary"] {
     border-color: var(--border-base);
@@ -33,10 +29,16 @@
   }
 
   &[data-variant="secondary"] {
-    border-color: var(--border-base);
-    background-color: var(--surface-base);
+    border-color: var(--border-weak-base);
+    background-color: var(--button-secondary-base);
     color: var(--text-strong);
 
+    /* shadow-xs */
+    box-shadow:
+      0 1px 2px -1px rgba(19, 16, 16, 0.04),
+      0 1px 2px 0 rgba(19, 16, 16, 0.06),
+      0 1px 3px 0 rgba(19, 16, 16, 0.08);
+
     &:hover:not(:disabled) {
       border-color: var(--border-hover);
       background-color: var(--surface-hover);
@@ -70,15 +72,25 @@
   }
 
   &[data-size="normal"] {
-    padding: calc(var(--spacing) * 0.5) calc(var(--spacing) * 3);
-    font-size: var(--text-xs);
-    line-height: var(--text-sm--line-height);
+    padding: 0 6px 0 6px;
+
+    font-size: var(--font-size-small);
+    line-height: var(--line-height-large);
+    gap: calc(var(--spacing) * 0.5);
   }
 
   &[data-size="large"] {
-    padding: calc(var(--spacing) * 1) calc(var(--spacing) * 4);
-    font-size: var(--text-sm);
-    line-height: var(--text-sm--line-height);
+    height: 32px;
+    padding: 0 8px 0 6px;
+    gap: 8px;
+
+    /* text-12-medium */
+    font-family: var(--font-family-sans);
+    font-size: var(--font-size-small);
+    font-style: normal;
+    font-weight: var(--font-weight-medium);
+    line-height: var(--line-height-large); /* 166.667% */
+    letter-spacing: var(--letter-spacing-normal);
   }
 
   &:disabled {

+ 6 - 6
packages/ui/src/components/fonts.tsx

@@ -1,20 +1,20 @@
 import { Style, Link } from "@solidjs/meta"
-import geist from "@opencode-ai/css/fonts/geist.woff2"
-import geistMono from "@opencode-ai/css/fonts/geist-mono.woff2"
+import geist from "../assets/fonts/geist.woff2"
+import geistMono from "../assets/fonts/geist-mono.woff2"
 
 export const Fonts = () => {
   return (
     <>
       <Style>{`
         @font-face {
-          font-family: "geist";
+          font-family: "Geist";
           src: url("${geist}") format("woff2-variations");
           font-display: swap;
           font-style: normal;
           font-weight: 100 900;
         }
         @font-face {
-          font-family: "geist-fallback";
+          font-family: "Geist Fallback";
           src: local("Arial");
           size-adjust: 100%;
           ascent-override: 97%;
@@ -22,14 +22,14 @@ export const Fonts = () => {
           line-gap-override: 1%;
         }
         @font-face {
-          font-family: "geist-mono";
+          font-family: "Geist Mono";
           src: url("${geistMono}") format("woff2-variations");
           font-display: swap;
           font-style: normal;
           font-weight: 100 900;
         }
         @font-face {
-          font-family: "geist-mono-fallback";
+          font-family: "Geist Mono Fallback";
           src: local("Courier New");
           size-adjust: 100%;
           ascent-override: 97%;

+ 0 - 0
packages/css/src/components/icon.css → packages/ui/src/components/icon.css


+ 1 - 0
packages/ui/src/components/index.ts

@@ -1,6 +1,7 @@
 export * from "./button"
 export * from "./icon"
 export * from "./fonts"
+export * from "./list"
 export * from "./select"
 export * from "./tabs"
 export * from "./tooltip"

+ 30 - 0
packages/ui/src/components/list.css

@@ -0,0 +1,30 @@
+[data-component="list"] {
+  overflow-y: auto;
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+
+  /* Hide scrollbar */
+  &::-webkit-scrollbar {
+    display: none;
+  }
+  -ms-overflow-style: none;
+  scrollbar-width: none;
+
+  [data-slot="item"] {
+    cursor: pointer;
+    width: 100%;
+    padding: 4px 12px;
+    text-align: left;
+
+    border-radius: 6px;
+    transition: background-color 0.2s ease-in-out;
+
+    &[data-active="true"] {
+      background-color: var(--surface-raised-base-hover);
+    }
+    &:focus {
+      outline: none;
+    }
+  }
+}

+ 76 - 0
packages/ui/src/components/list.tsx

@@ -0,0 +1,76 @@
+import { ComponentProps, createEffect, createSignal, type JSX } from "solid-js"
+import { VirtualizerHandle, VList } from "virtua/solid"
+import { createList } from "solid-list"
+import { createStore } from "solid-js/store"
+
+export interface ListProps<T> {
+  data: T[]
+  children: (x: T) => JSX.Element
+  key: (x: T) => string
+  current?: T
+  onSelect?: (value: T | undefined) => void
+  class?: ComponentProps<"div">["class"]
+}
+
+export function List<T>(props: ListProps<T>) {
+  const [virtualizer, setVirtualizer] = createSignal<VirtualizerHandle | undefined>(undefined)
+  const [store, setStore] = createStore({
+    mouseActive: false,
+  })
+  const list = createList({
+    items: () => props.data.map(props.key),
+    initialActive: props.current ? props.key(props.current) : undefined,
+    loop: true,
+  })
+  // const resetSelection = () => {
+  //   if (props.data.length === 0) return
+  //   list.setActive(props.key(props.data[0]))
+  // }
+  const handleSelect = (item: T) => {
+    props.onSelect?.(item)
+  }
+
+  const handleKey = (e: KeyboardEvent) => {
+    setStore("mouseActive", false)
+
+    if (e.key === "Enter") {
+      e.preventDefault()
+      const selected = props.data.find((x) => props.key(x) === list.active())
+      if (selected) handleSelect(selected)
+    } else {
+      list.onKeyDown(e)
+    }
+  }
+
+  createEffect(() => {
+    if (store.mouseActive || props.data.length === 0) return
+    const index = props.data.findIndex((x) => props.key(x) === list.active())
+    if (index === 0) {
+      virtualizer()?.scrollTo(0)
+      return
+    }
+    // virtualizer()?.scrollTo(list.active())
+    // const element = virtualizer()?.querySelector(`[data-key="${list.active()}"]`)
+    // element?.scrollIntoView({ block: "nearest", behavior: "smooth" })
+  })
+
+  return (
+    <VList data-component="list" ref={setVirtualizer} data={props.data} onKeyDown={handleKey} class={props.class}>
+      {(item) => (
+        <button
+          data-slot="item"
+          data-key={props.key(item)}
+          data-active={props.key(item) === list.active()}
+          onClick={() => handleSelect(item)}
+          onMouseMove={(e) => {
+            e.currentTarget.focus()
+            setStore("mouseActive", true)
+            list.setActive(props.key(item))
+          }}
+        >
+          {props.children(item)}
+        </button>
+      )}
+    </VList>
+  )
+}

+ 2 - 0
packages/css/src/components/select.css → packages/ui/src/components/select.css

@@ -1,5 +1,7 @@
 [data-component="select"] {
   [data-slot="trigger"] {
+    padding: 0 4px 0 8px;
+
     [data-slot="value"] {
       overflow: hidden;
       text-overflow: ellipsis;

+ 0 - 2
packages/ui/src/components/style.css

@@ -1,2 +0,0 @@
-/* re-exporting for convenience */
-@import "@opencode-ai/css";

+ 2 - 2
packages/css/src/components/tabs.css → packages/ui/src/components/tabs.css

@@ -7,7 +7,7 @@
   border-style: solid;
   border-radius: var(--radius-sm);
   border-color: var(--border-weak-base);
-  background-color: var(--background-weaker);
+  background-color: var(--background-stronger);
   overflow: clip;
 
   & [data-slot="list"] {
@@ -31,7 +31,7 @@
       flex-grow: 1;
       height: 100%;
       border-bottom: 1px solid var(--border-weak-base);
-      background-color: var(--background-weak);
+      background-color: var(--background-base);
       border-top-right-radius: var(--radius-sm);
     }
 

+ 12 - 6
packages/css/src/components/tooltip.css → packages/ui/src/components/tooltip.css

@@ -6,18 +6,24 @@
 [data-component="tooltip"] {
   z-index: 1000;
   max-width: 320px;
-  border-radius: var(--radius-md);
-  background-color: var(--surface-base);
-  padding: calc(var(--spacing) * 0.5) calc(var(--spacing) * 1);
-  font-size: var(--text-xs);
-  font-weight: var(--font-weight-medium);
-  color: var(--text-base);
+  border-radius: 12px;
+  background-color: var(--surface-float-base);
+  color: var(--white);
+  padding: 2px 12px 2px 12px;
   box-shadow: var(--shadow-md);
   pointer-events: none !important;
   transition: all 150ms ease-out;
   transform: translate3d(0, 0, 0);
   transform-origin: var(--kb-tooltip-content-transform-origin);
 
+  /* text-14-regular */
+  font-family: var(--font-family-sans);
+  font-size: var(--font-size-base);
+  font-style: normal;
+  font-weight: var(--font-weight-regular);
+  line-height: var(--line-height-large); /* 171.429% */
+  letter-spacing: var(--letter-spacing-normal);
+
   &[data-expanded] {
     opacity: 1;
     transform: translate3d(0, 0, 0);

+ 1 - 1
packages/ui/src/components/tooltip.tsx

@@ -36,7 +36,7 @@ export function Tooltip(props: TooltipProps) {
       <KobalteTooltip.Portal>
         <KobalteTooltip.Content data-component="tooltip" data-placement={props.placement} class={local.class}>
           {typeof others.value === "function" ? others.value() : others.value}
-          <KobalteTooltip.Arrow data-slot="arrow" size={18} />
+          {/* <KobalteTooltip.Arrow data-slot="arrow" size={18} /> */}
         </KobalteTooltip.Content>
       </KobalteTooltip.Portal>
     </KobalteTooltip>

+ 9 - 3
packages/ui/src/app.tsx → packages/ui/src/demo.tsx

@@ -1,8 +1,8 @@
 import type { Component } from "solid-js"
-import { Button, Select, Tabs, Tooltip, Fonts } from "./components"
+import { Button, Select, Tabs, Tooltip, Fonts, List } from "./components"
 import "./index.css"
 
-const App: Component = () => {
+const Demo: Component = () => {
   const Content = (props: { dark?: boolean }) => (
     <div class={`${props.dark ? "dark" : ""}`}>
       <h3>Buttons</h3>
@@ -111,6 +111,12 @@ const App: Component = () => {
           <Button variant="primary">Dynamic Tooltip</Button>
         </Tooltip>
       </section>
+      <h3>List</h3>
+      <section style={{ height: "300px" }}>
+        <List data={["Item 1", "Item 2", "Item 3"]} key={(x) => x}>
+          {(x) => <div>{x}</div>}
+        </List>
+      </section>
     </div>
   )
 
@@ -125,4 +131,4 @@ const App: Component = () => {
   )
 }
 
-export default App
+export default Demo

+ 1 - 3
packages/ui/src/index.css

@@ -1,4 +1,4 @@
-@import "@opencode-ai/css";
+@import "./styles/index.css";
 
 :root {
   body {
@@ -9,14 +9,12 @@
   main {
     display: flex;
     flex-direction: row;
-    height: 100vh;
     overflow-x: hidden;
   }
   main > div {
     flex: 1;
     padding: 2rem;
     min-width: 0;
-    overflow-y: auto;
     overflow-x: hidden;
     display: flex;
     flex-direction: column;

+ 2 - 2
packages/ui/src/index.tsx

@@ -2,7 +2,7 @@
 import { render } from "solid-js/web"
 import { MetaProvider } from "@solidjs/meta"
 
-import App from "./app"
+import Demo from "./demo"
 
 const root = document.getElementById("root")
 
@@ -15,7 +15,7 @@ if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
 render(
   () => (
     <MetaProvider>
-      <App />
+      <Demo />
     </MetaProvider>
   ),
   root!,

+ 7 - 7
packages/css/src/base.css → packages/ui/src/styles/base.css

@@ -27,12 +27,12 @@
 
 html,
 :host {
-  line-height: 1.5; /* 1 */
+  line-height: var(--line-height-large); /* 1 */
   -webkit-text-size-adjust: 100%; /* 2 */
   tab-size: 4; /* 3 */
-  font-family: var(--font-sans); /* 4 */
-  font-feature-settings: var(--font-sans--font-feature-settings, normal); /* 5 */
-  font-variation-settings: var(--default-font-variation-settings, normal); /* 6 */
+  font-family: var(--font-family-sans); /* 4 */
+  font-feature-settings: var(--font-family-sans--font-feature-settings, normal); /* 5 */
+  font-variation-settings: var(--font-family-sans--font-variation-settings, normal); /* 6 */
   -webkit-tap-highlight-color: transparent; /* 7 */
 }
 
@@ -101,9 +101,9 @@ code,
 kbd,
 samp,
 pre {
-  font-family: var(--font-mono); /* 1 */
-  font-feature-settings: var(--font-mono--font-feature-settings, normal); /* 2 */
-  font-variation-settings: var(--default-mono-font-variation-settings, normal); /* 3 */
+  font-family: var(--font-family-mono); /* 1 */
+  font-feature-settings: var(--font-family-mono--font-feature-settings, normal); /* 2 */
+  font-variation-settings: var(--font-family-mono--font-variation-settings, normal); /* 3 */
   font-size: 1em; /* 4 */
 }
 

+ 0 - 0
packages/css/src/color.css → packages/ui/src/styles/colors.css


+ 15 - 0
packages/ui/src/styles/index.css

@@ -0,0 +1,15 @@
+@layer theme, base, components, utilities;
+
+@import "./colors.css" layer(theme);
+@import "./theme.css" layer(theme);
+
+@import "./base.css" layer(base);
+
+@import "../components/button.css" layer(components);
+@import "../components/icon.css" layer(components);
+@import "../components/list.css" layer(components);
+@import "../components/select.css" layer(components);
+@import "../components/tabs.css" layer(components);
+@import "../components/tooltip.css" layer(components);
+
+@import "./utilities.css" layer(utilities);

+ 1 - 1
packages/css/src/tailwind-colors.css → packages/ui/src/styles/tailwind/colors.css

@@ -217,4 +217,4 @@
   --color-markdown-image-text: var(--markdown-image-text);
   --color-markdown-code-block: var(--markdown-code-block);
   --color-border-color: var(--border-color);
-}
+}

+ 40 - 0
packages/ui/src/styles/tailwind/index.css

@@ -0,0 +1,40 @@
+@layer theme, base, components, utilities;
+@import "tailwindcss/theme.css" layer(theme);
+@import "tailwindcss/utilities.css" layer(utilities);
+@import "./utilities.css";
+
+@import "../index.css";
+
+@theme {
+  --*: initial;
+
+  --spacing: 0.25rem;
+  /* --spacing: var(--spacing); */
+
+  --font-sans: var(--font-family-sans);
+  --font-sans--font-feature-settings: var(--font-family-sans--font-feature-settings);
+  --font-mono: var(--font-family-mono);
+  --font-mono--font-feature-settings: var(--font-family-mono--font-feature-settings);
+
+  --text-sm: var(--font-size-small);
+  --text-base: var(--font-size-base);
+  --text-lg: var(--font-size-large);
+  --text-xl: var(--font-size-x-large);
+
+  --font-weight-regular: var(--font-weight-regular);
+  --font-weight-medium: var(--font-weight-medium);
+
+  --leading-lg: var(--line-height-large);
+  --leading-xl: var(--line-height-x-large);
+  --leading-2xl: var(--line-height-2x-large);
+
+  --tracking-normal: var(--letter-spacing-normal);
+  --tracking-tight: var(--letter-spacing-tight);
+  --tracking-tightest: var(--letter-spacing-tightest);
+
+  --shadow-xs: var(--shadow-xs);
+  --shadow-md: var(--shadow-md);
+  --shadow-xs-border-selected: var(--shadow-xs-border-selected);
+}
+
+@import "./colors.css";

+ 9 - 0
packages/ui/src/styles/tailwind/utilities.css

@@ -0,0 +1,9 @@
+@utility no-scrollbar {
+  &::-webkit-scrollbar {
+    display: none;
+  }
+  & {
+    -ms-overflow-style: none; /* IE and Edge */
+    scrollbar-width: none; /* Firefox */
+  }
+}

+ 88 - 164
packages/css/src/theme.css → packages/ui/src/styles/theme.css

@@ -1,27 +1,22 @@
 :root {
-  --font-sans:
-    geist, geist-fallback, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
-    "Segoe UI Symbol", "Noto Color Emoji";
-  --font-sans--font-feature-settings: "ss02" 1;
-  --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
-  --font-mono:
-    geist-mono, geist-mono-fallback, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
-    "Courier New", monospace;
-  --font-mono--font-feature-settings: "ss02" 1;
+  --font-family-sans: "Geist", "Geist Fallback";
+  --font-family-sans--font-feature-settings: "ss03" 1;
+  --font-family-mono: "Geist Mono", "Geist Mono Fallback";
+  --font-family-mono--font-feature-settings: "ss02" 1;
 
-  --size-12: 12;
-  --size-14: 14;
-  --size-16: 16;
-  --size-20: 20;
-  --weight-regular: 400;
-  --weight-medium: 500;
-  --line-height-lg: 20;
-  --line-height-xl: 24;
-  --line-height-2xl: 30;
+  --font-size-small: 12px;
+  --font-size-base: 14px;
+  --font-size-large: 16px;
+  --font-size-x-large: 20px;
+  --font-weight-regular: 400;
+  --font-weight-medium: 500;
+  --line-height-large: 20px;
+  --line-height-x-large: 24px;
+  --line-height-2x-large: 30px;
   --letter-spacing-normal: 0;
   --letter-spacing-tight: -0.1599999964237213;
   --letter-spacing-tightest: -0.3199999928474426;
-  --paragraph-spacing-0: 0;
+  --paragraph-spacing-base: 0;
 
   --spacing: 0.25rem;
 
@@ -45,56 +40,6 @@
   --container-6xl: 72rem;
   --container-7xl: 80rem;
 
-  /* --text-xs: 0.75rem; */
-  /* --text-xs--line-height: calc(1 / 0.75); */
-  /* --text-sm: 0.875rem; */
-  /* --text-sm--line-height: calc(1.25 / 0.875); */
-  /* --text-base: 1rem; */
-  /* --text-base--line-height: calc(1.5 / 1); */
-  /* --text-lg: 1.125rem; */
-  /* --text-lg--line-height: calc(1.75 / 1.125); */
-  /* --text-xl: 1.25rem; */
-  /* --text-xl--line-height: calc(1.75 / 1.25); */
-  /* --text-2xl: 1.5rem; */
-  /* --text-2xl--line-height: calc(2 / 1.5); */
-  /* --text-3xl: 1.875rem; */
-  /* --text-3xl--line-height: calc(2.25 / 1.875); */
-  /* --text-4xl: 2.25rem; */
-  /* --text-4xl--line-height: calc(2.5 / 2.25); */
-  /* --text-5xl: 3rem; */
-  /* --text-5xl--line-height: 1; */
-  /* --text-6xl: 3.75rem; */
-  /* --text-6xl--line-height: 1; */
-  /* --text-7xl: 4.5rem; */
-  /* --text-7xl--line-height: 1; */
-  /* --text-8xl: 6rem; */
-  /* --text-8xl--line-height: 1; */
-  /* --text-9xl: 8rem; */
-  /* --text-9xl--line-height: 1; */
-
-  --font-weight-thin: 100;
-  --font-weight-extralight: 200;
-  --font-weight-light: 300;
-  --font-weight-normal: 400;
-  --font-weight-medium: 500;
-  --font-weight-semibold: 600;
-  --font-weight-bold: 700;
-  --font-weight-extrabold: 800;
-  --font-weight-black: 900;
-
-  /* --tracking-tighter: -0.05em; */
-  /* --tracking-tight: -0.025em; */
-  /* --tracking-normal: 0em; */
-  /* --tracking-wide: 0.025em; */
-  /* --tracking-wider: 0.05em; */
-  /* --tracking-widest: 0.1em; */
-  /**/
-  /* --leading-tight: 1.25; */
-  /* --leading-snug: 1.375; */
-  /* --leading-normal: 1.5; */
-  /* --leading-relaxed: 1.625; */
-  /* --leading-loose: 2; */
-
   --radius-xs: 0.125rem;
   --radius-sm: 0.25rem;
   --radius-md: 0.375rem;
@@ -104,35 +49,14 @@
   --radius-3xl: 1.5rem;
   --radius-4xl: 2rem;
 
+  --shadow-xs:
+    0 1px 2px -1px rgba(19, 16, 16, 0.04), 0 1px 2px 0 rgba(19, 16, 16, 0.06), 0 1px 3px 0 rgba(19, 16, 16, 0.08);
+  --shadow-md:
+    0 6px 8px -4px rgba(19, 16, 16, 0.12), 0 4px 3px -2px rgba(19, 16, 16, 0.12), 0 1px 2px -1px rgba(19, 16, 16, 0.12);
   --shadow-xs-border-selected:
     0 0 0 3px var(--border-weak-selected, rgba(1, 103, 255, 0.29)),
     0 0 0 1px var(--border-selected, rgba(0, 74, 255, 0.99)), 0 1px 2px -1px rgba(19, 16, 16, 0.25),
     0 1px 2px 0 rgba(19, 16, 16, 0.08), 0 1px 3px 0 rgba(19, 16, 16, 0.12);
-
-  /* --shadow-2xs: 0 1px rgb(0 0 0 / 0.05); */
-  /* --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05); */
-  /* --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); */
-  /* --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); */
-  /* --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); */
-  /* --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); */
-  /* --shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25); */
-
-  /* --inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05); */
-  /* --inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05); */
-  /* --inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05); */
-  /**/
-  /* --drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05); */
-  /* --drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15); */
-  /* --drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12); */
-  /* --drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15); */
-  /* --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1); */
-  /* --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15); */
-  /**/
-  /* --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15); */
-  /* --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2); */
-  /* --text-shadow-sm: 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075); */
-  /* --text-shadow-md: 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1); */
-  /* --text-shadow-lg: 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1); */
 }
 
 :root {
@@ -142,8 +66,8 @@
   --background-weak: var(--smoke-light-3);
   --background-strong: var(--smoke-light-1);
   --background-stronger: #fcfcfc;
-  --base: var(--smoke-light-alpha-2);
   --surface-base: var(--smoke-light-alpha-2);
+  --base: var(--smoke-light-alpha-2);
   --base2: var(--smoke-light-alpha-2);
   --base3: var(--smoke-light-alpha-2);
   --surface-inset-base: var(--smoke-light-alpha-3);
@@ -180,9 +104,9 @@
   --surface-info-base: var(--lilac-light-3);
   --surface-info-weak: var(--lilac-light-2);
   --surface-info-strong: var(--lilac-light-9);
+  --surface-diff-hidden-base: var(--blue-light-3);
   --surface-diff-skip-base: var(--smoke-light-3);
   --surface-diff-unchanged-base: #ffffff00;
-  --surface-diff-hidden-base: var(--blue-light-3);
   --surface-diff-hidden-weak: var(--blue-light-2);
   --surface-diff-hidden-weaker: var(--blue-light-1);
   --surface-diff-hidden-strong: var(--blue-light-5);
@@ -209,6 +133,7 @@
   --text-strong: var(--smoke-light-12);
   --text-on-brand-base: var(--smoke-light-alpha-11);
   --text-on-interactive-base: var(--smoke-light-1);
+  --text-on-interactive-weak: var(--smoke-dark-alpha-11);
   --text-on-success-base: var(--smoke-dark-alpha-11);
   --text-on-warning-base: var(--smoke-dark-alpha-11);
   --text-on-info-base: var(--smoke-dark-alpha-11);
@@ -226,6 +151,7 @@
   --text-on-brand-weaker: var(--smoke-light-alpha-8);
   --text-on-brand-strong: var(--smoke-light-alpha-12);
   --button-secondary-base: #fdfcfc;
+  --button-secondary-base-hover: var(--smoke-light-2);
   --border-base: var(--smoke-light-alpha-7);
   --border-hover: var(--smoke-light-alpha-8);
   --border-active: var(--smoke-light-alpha-9);
@@ -241,7 +167,7 @@
   --border-strong-focus: var(--smoke-light-alpha-7);
   --border-weak-hover: var(--smoke-light-alpha-6);
   --border-weak-active: var(--smoke-light-alpha-7);
-  --border-weak-selected: var(--cobalt-light-alpha-6);
+  --border-weak-selected: var(--cobalt-light-alpha-4);
   --border-weak-disabled: var(--smoke-light-alpha-6);
   --border-weak-focus: var(--smoke-light-alpha-7);
   --border-interactive-base: var(--cobalt-light-7);
@@ -298,9 +224,7 @@
   --icon-on-brand-base: var(--smoke-light-alpha-11);
   --icon-on-brand-hover: var(--smoke-light-alpha-12);
   --icon-on-brand-selected: var(--smoke-light-alpha-12);
-  --icon-on-interactive-base: var(--smoke-light-alpha-9);
-  --icon-on-interactive-hover: var(--smoke-light-alpha-10);
-  --icon-on-interactive-selected: var(--smoke-light-alpha-11);
+  --icon-on-interactive-base: var(--smoke-light-1);
   --icon-agent-plan-base: var(--purple-light-9);
   --icon-agent-docs-base: var(--amber-light-9);
   --icon-agent-ask-base: var(--cyan-light-9);
@@ -323,34 +247,34 @@
   --icon-diff-delete-base: var(--ember-light-9);
   --icon-diff-delete-hover: var(--ember-light-10);
   --icon-diff-delete-active: var(--ember-light-11);
-  --syntax-comment: #ffffff;
-  --syntax-string: #ffffff;
-  --syntax-keyword: #ffffff;
-  --syntax-function: #ffffff;
-  --syntax-number: #ffffff;
-  --syntax-operator: #ffffff;
-  --syntax-variable: #ffffff;
-  --syntax-type: #ffffff;
-  --syntax-constant: #ffffff;
-  --syntax-punctuation: #ffffff;
-  --syntax-success: #ffffff;
-  --syntax-warning: #ffffff;
-  --syntax-critical: #ffffff;
-  --syntax-info: #ffffff;
-  --markdown-heading: #ffffff;
-  --markdown-text: #ffffff;
-  --markdown-link: #ffffff;
-  --markdown-link-text: #ffffff;
-  --markdown-code: #ffffff;
-  --markdown-block-quote: #ffffff;
-  --markdown-emph: #ffffff;
-  --markdown-strong: #ffffff;
-  --markdown-horizontal-rule: #ffffff;
-  --markdown-list-item: #ffffff;
-  --markdown-list-enumeration: #ffffff;
-  --markdown-image: #ffffff;
-  --markdown-image-text: #ffffff;
-  --markdown-code-block: #ffffff;
+  --syntax-comment: #8a8a8a;
+  --syntax-string: #d68c27;
+  --syntax-keyword: #3b7dd8;
+  --syntax-function: #d1383d;
+  --syntax-number: #3d9a57;
+  --syntax-operator: #d68c27;
+  --syntax-variable: #b0851f;
+  --syntax-type: #318795;
+  --syntax-constant: #953170;
+  --syntax-punctuation: #1a1a1a;
+  --syntax-success: var(--apple-dark-10);
+  --syntax-warning: var(--amber-light-10);
+  --syntax-critical: var(--ember-dark-9);
+  --syntax-info: var(--lilac-dark-11);
+  --markdown-heading: #d68c27;
+  --markdown-text: #1a1a1a;
+  --markdown-link: #3b7dd8;
+  --markdown-link-text: #318795;
+  --markdown-code: #3d9a57;
+  --markdown-block-quote: #b0851f;
+  --markdown-emph: #b0851f;
+  --markdown-strong: #d68c27;
+  --markdown-horizontal-rule: #8a8a8a;
+  --markdown-list-item: #3b7dd8;
+  --markdown-list-enumeration: #318795;
+  --markdown-image: #3b7dd8;
+  --markdown-image-text: #318795;
+  --markdown-code-block: #1a1a1a;
   --border-color: #ffffff;
 
   .dark {
@@ -360,8 +284,8 @@
     --background-weak: #201d1d;
     --background-strong: #151313;
     --background-stronger: #201c1c;
-    --base: var(--smoke-dark-alpha-2);
     --surface-base: var(--smoke-dark-alpha-3);
+    --base: var(--smoke-dark-alpha-2);
     --base2: var(--smoke-dark-alpha-2);
     --base3: var(--smoke-dark-alpha-2);
     --surface-inset-base: #0e0b0b7f;
@@ -372,14 +296,14 @@
     --surface-float-base: var(--smoke-dark-1);
     --surface-float-base-hover: var(--smoke-dark-2);
     --surface-raised-base-hover: var(--smoke-dark-alpha-4);
-    --surface-raised-strong: var(--smoke-dark-alpha-5);
+    --surface-raised-strong: var(--smoke-dark-alpha-4);
     --surface-raised-strong-hover: var(--smoke-dark-alpha-6);
     --surface-raised-stronger: var(--smoke-dark-alpha-6);
     --surface-raised-stronger-hover: var(--smoke-dark-alpha-7);
     --surface-weak: var(--smoke-dark-alpha-5);
     --surface-weaker: var(--smoke-dark-alpha-6);
     --surface-strong: var(--smoke-dark-alpha-7);
-    --surface-raised-stronger-non-alpha: var(--smoke-dark-5);
+    --surface-raised-stronger-non-alpha: var(--smoke-dark-4);
     --surface-brand-base: var(--yuzu-light-9);
     --surface-brand-hover: var(--yuzu-light-10);
     --surface-interactive-base: var(--cobalt-light-3);
@@ -398,9 +322,9 @@
     --surface-info-base: var(--lilac-light-3);
     --surface-info-weak: var(--lilac-light-2);
     --surface-info-strong: var(--lilac-light-9);
+    --surface-diff-hidden-base: var(--blue-dark-2);
     --surface-diff-skip-base: var(--smoke-dark-alpha-2);
     --surface-diff-unchanged-base: var(--smoke-dark-1);
-    --surface-diff-hidden-base: var(--blue-dark-2);
     --surface-diff-hidden-weak: var(--blue-dark-1);
     --surface-diff-hidden-weaker: var(--blue-dark-3);
     --surface-diff-hidden-strong: var(--blue-dark-5);
@@ -427,6 +351,7 @@
     --text-strong: var(--smoke-dark-alpha-12);
     --text-on-brand-base: var(--smoke-dark-alpha-11);
     --text-on-interactive-base: var(--smoke-dark-12);
+    --text-on-interactive-weak: var(--smoke-dark-alpha-11);
     --text-on-success-base: var(--smoke-dark-alpha-11);
     --text-on-warning-base: var(--smoke-dark-alpha-11);
     --text-on-info-base: var(--smoke-dark-alpha-11);
@@ -444,6 +369,7 @@
     --text-on-brand-weaker: var(--smoke-dark-alpha-8);
     --text-on-brand-strong: var(--smoke-dark-alpha-12);
     --button-secondary-base: var(--smoke-dark-6);
+    --button-secondary-base-hover: var(--smoke-dark-5);
     --border-base: var(--smoke-dark-alpha-7);
     --border-hover: var(--smoke-dark-alpha-8);
     --border-active: var(--smoke-dark-alpha-9);
@@ -459,7 +385,7 @@
     --border-strong-focus: var(--smoke-dark-alpha-8);
     --border-weak-hover: var(--smoke-dark-alpha-7);
     --border-weak-active: var(--smoke-dark-alpha-8);
-    --border-weak-selected: var(--cobalt-dark-alpha-6);
+    --border-weak-selected: var(--cobalt-dark-alpha-3);
     --border-weak-disabled: var(--smoke-dark-alpha-6);
     --border-weak-focus: var(--smoke-dark-alpha-8);
     --border-interactive-base: var(--cobalt-light-7);
@@ -516,9 +442,7 @@
     --icon-on-brand-base: var(--smoke-light-alpha-11);
     --icon-on-brand-hover: var(--smoke-light-alpha-12);
     --icon-on-brand-selected: var(--smoke-light-alpha-12);
-    --icon-on-interactive-base: var(--smoke-dark-alpha-9);
-    --icon-on-interactive-hover: var(--smoke-dark-alpha-10);
-    --icon-on-interactive-selected: var(--smoke-dark-alpha-11);
+    --icon-on-interactive-base: var(--smoke-dark-12);
     --icon-agent-plan-base: var(--purple-dark-9);
     --icon-agent-docs-base: var(--amber-dark-9);
     --icon-agent-ask-base: var(--cyan-dark-9);
@@ -541,34 +465,34 @@
     --icon-diff-delete-base: var(--ember-dark-9);
     --icon-diff-delete-hover: var(--ember-dark-10);
     --icon-diff-delete-active: var(--ember-dark-11);
-    --syntax-comment: #ffffff;
-    --syntax-string: #ffffff;
-    --syntax-keyword: #ffffff;
-    --syntax-function: #ffffff;
-    --syntax-number: #ffffff;
-    --syntax-operator: #ffffff;
-    --syntax-variable: #ffffff;
-    --syntax-type: #ffffff;
-    --syntax-constant: #ffffff;
-    --syntax-punctuation: #ffffff;
-    --syntax-success: #ffffff;
-    --syntax-warning: #ffffff;
-    --syntax-critical: #ffffff;
-    --syntax-info: #ffffff;
-    --markdown-heading: #ffffff;
-    --markdown-text: #ffffff;
-    --markdown-link: #ffffff;
-    --markdown-link-text: #ffffff;
-    --markdown-code: #ffffff;
-    --markdown-block-quote: #ffffff;
-    --markdown-emph: #ffffff;
-    --markdown-strong: #ffffff;
-    --markdown-horizontal-rule: #ffffff;
-    --markdown-list-item: #ffffff;
-    --markdown-list-enumeration: #ffffff;
-    --markdown-image: #ffffff;
-    --markdown-image-text: #ffffff;
-    --markdown-code-block: #ffffff;
+    --syntax-comment: #808080;
+    --syntax-string: #9d7cd8;
+    --syntax-keyword: #fab283;
+    --syntax-function: #e06c75;
+    --syntax-number: #7fd88f;
+    --syntax-operator: #f5a742;
+    --syntax-variable: #e5c07b;
+    --syntax-type: #56b6c2;
+    --syntax-constant: #c2569a;
+    --syntax-punctuation: #eeeeee;
+    --syntax-success: var(--apple-dark-10);
+    --syntax-warning: var(--amber-dark-10);
+    --syntax-critical: var(--ember-dark-10);
+    --syntax-info: var(--lilac-dark-10);
+    --markdown-heading: #9d7cd8;
+    --markdown-text: #eeeeee;
+    --markdown-link: #fab283;
+    --markdown-link-text: #56b6c2;
+    --markdown-code: #7fd88f;
+    --markdown-block-quote: #e5c07b;
+    --markdown-emph: #e5c07b;
+    --markdown-strong: #f5a742;
+    --markdown-horizontal-rule: #808080;
+    --markdown-list-item: #fab283;
+    --markdown-list-enumeration: #56b6c2;
+    --markdown-image: #fab283;
+    --markdown-image-text: #56b6c2;
+    --markdown-code-block: #eeeeee;
     --border-color: #ffffff;
   }
 }

+ 109 - 0
packages/ui/src/styles/utilities.css

@@ -0,0 +1,109 @@
+:root {
+  interpolate-size: allow-keywords;
+
+  [data-popper-positioner] {
+    pointer-events: none;
+  }
+
+  ::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);
+  }
+}
+
+.no-scrollbar {
+  &::-webkit-scrollbar {
+    display: none;
+  }
+  /* Hide scrollbar for IE, Edge and Firefox */
+  & {
+    -ms-overflow-style: none; /* IE and Edge */
+    scrollbar-width: none; /* Firefox */
+  }
+}
+
+.text-12-regular {
+  font-family: var(--font-family-sans);
+  font-size: var(--font-size-small);
+  font-style: normal;
+  font-weight: var(--font-weight-regular);
+  line-height: var(--line-height-large); /* 166.667% */
+  letter-spacing: var(--letter-spacing-normal);
+}
+
+.text-12-medium {
+  font-family: var(--font-family-sans);
+  font-size: var(--font-size-small);
+  font-style: normal;
+  font-weight: var(--font-weight-medium);
+  line-height: var(--line-height-large); /* 166.667% */
+  letter-spacing: var(--letter-spacing-normal);
+}
+
+.text-12-mono {
+  font-family: var(--font-family-mono);
+  font-size: var(--font-size-small);
+  font-style: normal;
+  font-weight: var(--font-weight-regular);
+  line-height: var(--line-height-large); /* 166.667% */
+  letter-spacing: var(--letter-spacing-normal);
+}
+
+.text-14-regular {
+  font-family: var(--font-family-sans);
+  font-size: var(--font-size-base);
+  font-style: normal;
+  font-weight: var(--font-weight-regular);
+  line-height: var(--line-height-x-large); /* 171.429% */
+  letter-spacing: var(--letter-spacing-normal);
+}
+
+.text-14-medium {
+  font-family: var(--font-family-sans);
+  font-size: var(--font-size-base);
+  font-style: normal;
+  font-weight: var(--font-weight-medium);
+  line-height: var(--line-height-large); /* 171.429% */
+  letter-spacing: var(--letter-spacing-normal);
+}
+
+.text-14-mono {
+  font-family: var(--font-family-mono);
+  font-size: var(--font-size-base);
+  font-style: normal;
+  font-weight: var(--font-weight-regular);
+  line-height: var(--line-height-large); /* 171.429% */
+  letter-spacing: var(--letter-spacing-normal);
+}
+
+.text-16-medium {
+  font-family: var(--font-family-sans);
+  font-size: var(--font-size-large);
+  font-style: normal;
+  font-weight: var(--font-weight-medium);
+  line-height: var(--line-height-x-large); /* 150% */
+  letter-spacing: var(--letter-spacing-tight);
+}
+
+.text-20-medium {
+  font-family: var(--font-family-sans);
+  font-size: var(--font-size-x-large);
+  font-style: normal;
+  font-weight: var(--font-weight-medium);
+  line-height: var(--line-height-x-large); /* 120% */
+  letter-spacing: var(--letter-spacing-tightest);
+}