From dc6e54503cb400ea2533740c9a92d09c8a50d077 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Thu, 30 Oct 2025 13:49:29 -0500 Subject: wip: desktop work --- packages/ui/src/components/basic-tool.css | 76 ++++ packages/ui/src/components/basic-tool.tsx | 95 +++++ packages/ui/src/components/index.ts | 8 +- packages/ui/src/components/markdown.css | 24 ++ packages/ui/src/components/markdown.tsx | 36 ++ packages/ui/src/components/message-part.css | 107 +++++ packages/ui/src/components/message-part.tsx | 365 ++++++++++++++++- packages/ui/src/components/tool-display.css | 76 ---- packages/ui/src/components/tool-display.tsx | 95 ----- packages/ui/src/components/tool-registry.tsx | 33 -- packages/ui/src/context/helper.tsx | 25 ++ packages/ui/src/context/marked.tsx | 30 ++ packages/ui/src/context/shiki.tsx | 577 +++++++++++++++++++++++++++ packages/ui/src/styles/index.css | 3 +- 14 files changed, 1342 insertions(+), 208 deletions(-) create mode 100644 packages/ui/src/components/basic-tool.css create mode 100644 packages/ui/src/components/basic-tool.tsx create mode 100644 packages/ui/src/components/markdown.css create mode 100644 packages/ui/src/components/markdown.tsx delete mode 100644 packages/ui/src/components/tool-display.css delete mode 100644 packages/ui/src/components/tool-display.tsx delete mode 100644 packages/ui/src/components/tool-registry.tsx create mode 100644 packages/ui/src/context/helper.tsx create mode 100644 packages/ui/src/context/marked.tsx create mode 100644 packages/ui/src/context/shiki.tsx (limited to 'packages/ui/src') diff --git a/packages/ui/src/components/basic-tool.css b/packages/ui/src/components/basic-tool.css new file mode 100644 index 000000000..f3d9f865f --- /dev/null +++ b/packages/ui/src/components/basic-tool.css @@ -0,0 +1,76 @@ +[data-component="tool-trigger"] { + width: 100%; + display: flex; + align-items: center; + align-self: stretch; + gap: 20px; + justify-content: space-between; + + [data-slot="tool-trigger-content"] { + width: 100%; + display: flex; + align-items: center; + align-self: stretch; + gap: 20px; + } + + [data-slot="tool-icon"] { + flex-shrink: 0; + } + + [data-slot="tool-info"] { + flex-grow: 1; + min-width: 0; + } + + [data-slot="tool-info-structured"] { + width: 100%; + display: flex; + align-items: center; + gap: 8px; + justify-content: space-between; + } + + [data-slot="tool-info-main"] { + display: flex; + align-items: center; + gap: 8px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + [data-slot="tool-title"] { + 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); + letter-spacing: var(--letter-spacing-normal); + color: var(--text-base); + + &.capitalize { + text-transform: capitalize; + } + } + + [data-slot="tool-subtitle"] { + 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); + letter-spacing: var(--letter-spacing-normal); + color: var(--text-weak); + } + + [data-slot="tool-arg"] { + 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); + letter-spacing: var(--letter-spacing-normal); + color: var(--text-weak); + } +} diff --git a/packages/ui/src/components/basic-tool.tsx b/packages/ui/src/components/basic-tool.tsx new file mode 100644 index 000000000..43574fbb7 --- /dev/null +++ b/packages/ui/src/components/basic-tool.tsx @@ -0,0 +1,95 @@ +import { children, For, Match, Show, Switch, type JSX } from "solid-js" +import { Collapsible } from "./collapsible" +import { Icon, IconProps } from "./icon" + +export type TriggerTitle = { + title: string + titleClass?: string + subtitle?: string + subtitleClass?: string + args?: string[] + argsClass?: string + action?: JSX.Element +} + +const isTriggerTitle = (val: any): val is TriggerTitle => { + return typeof val === "object" && val !== null && "title" in val && !(val instanceof Node) +} + +export interface BasicToolProps { + icon: IconProps["name"] + trigger: TriggerTitle | JSX.Element + children?: JSX.Element + hideDetails?: boolean +} + +export function BasicTool(props: BasicToolProps) { + const resolved = children(() => props.children) + return ( + + + + + + + + + {(trigger) => ( + + + + {trigger().title} + + + + {trigger().subtitle} + + + + + {(arg) => ( + + {arg} + + )} + + + + {trigger().action} + + )} + + {props.trigger as JSX.Element} + + + + + + + + + + {resolved()} + + + ) +} + +export function GenericTool(props: { tool: string; hideDetails?: boolean }) { + return +} diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 29e8cfe3b..8d6ddc89c 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -11,11 +11,15 @@ export * from "./icon-button" export * from "./input" export * from "./fonts" export * from "./list" +export * from "./markdown" export * from "./message-part" export * from "./progress-circle" export * from "./select" export * from "./select-dialog" export * from "./tabs" -export * from "./tool-display" -export * from "./tool-registry" +export * from "./basic-tool" export * from "./tooltip" + +export * from "../context/helper" +export * from "../context/shiki" +export * from "../context/marked" diff --git a/packages/ui/src/components/markdown.css b/packages/ui/src/components/markdown.css new file mode 100644 index 000000000..ddf8b7872 --- /dev/null +++ b/packages/ui/src/components/markdown.css @@ -0,0 +1,24 @@ +[data-component="markdown"] { + min-width: 0; + max-width: 100%; + overflow: auto; + scrollbar-width: none; + color: var(--text-base); + + /* 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); /* 142.857% */ + letter-spacing: var(--letter-spacing-normal); + + &::-webkit-scrollbar { + display: none; + } + + /* p { */ + /* margin-top: 8px; */ + /* margin-bottom: 8px; */ + /* } */ +} diff --git a/packages/ui/src/components/markdown.tsx b/packages/ui/src/components/markdown.tsx new file mode 100644 index 000000000..071132e80 --- /dev/null +++ b/packages/ui/src/components/markdown.tsx @@ -0,0 +1,36 @@ +import { useMarked } from "../context/marked" +import { ComponentProps, createResource, splitProps } from "solid-js" + +function strip(text: string): string { + const wrappedRe = /^\s*<([A-Za-z]\w*)>\s*([\s\S]*?)\s*<\/\1>\s*$/ + const match = text.match(wrappedRe) + return match ? match[2] : text +} + +export function Markdown( + props: ComponentProps<"div"> & { + text: string + class?: string + classList?: Record + }, +) { + const [local, others] = splitProps(props, ["text", "class", "classList"]) + const marked = useMarked() + const [html] = createResource( + () => strip(local.text), + async (markdown) => { + return marked.parse(markdown) + }, + ) + return ( + + ) +} diff --git a/packages/ui/src/components/message-part.css b/packages/ui/src/components/message-part.css index 8931d3bc6..fa251a2b3 100644 --- a/packages/ui/src/components/message-part.css +++ b/packages/ui/src/components/message-part.css @@ -20,3 +20,110 @@ -webkit-box-orient: vertical; overflow: hidden; } + +[data-component="text-part"] { + [data-component="markdown"] { + margin-top: 32px; + } +} + +[data-component="tool-error"] { + display: flex; + align-items: center; + gap: 8px; + + [data-slot="icon"] { + color: var(--icon-critical-active); + } + + [data-slot="content"] { + display: flex; + align-items: center; + gap: 8px; + } + + [data-slot="title"] { + 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); + letter-spacing: var(--letter-spacing-normal); + color: var(--ember-light-11); + text-transform: capitalize; + } +} + +[data-component="tool-output"] { + white-space: pre; +} + +[data-component="edit-trigger"], +[data-component="write-trigger"] { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + + [data-slot="title-area"] { + display: flex; + align-items: center; + gap: 8px; + } + + [data-slot="title"] { + 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); + letter-spacing: var(--letter-spacing-normal); + color: var(--text-base); + text-transform: capitalize; + } + + [data-slot="path"] { + display: flex; + } + + [data-slot="directory"] { + color: var(--text-weak); + } + + [data-slot="filename"] { + color: var(--text-strong); + } + + [data-slot="actions"] { + display: flex; + gap: 16px; + align-items: center; + justify-content: flex-end; + } +} + +[data-component="edit-content"] { + border-top: 1px solid var(--border-weaker-base); +} + +[data-component="tool-action"] { + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; +} + +[data-component="todos"] { + padding: 10px 12px 24px 48px; + display: flex; + flex-direction: column; + gap: 8px; + + [data-slot="todo-content"] { + &[data-completed="completed"] { + text-decoration: line-through; + color: var(--text-weaker); + } + } +} diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx index 06f5046dc..1aaab751a 100644 --- a/packages/ui/src/components/message-part.tsx +++ b/packages/ui/src/components/message-part.tsx @@ -8,6 +8,14 @@ import { ToolPart, UserMessage, } from "@opencode-ai/sdk" +import { BasicTool } from "./basic-tool" +import { GenericTool } from "./basic-tool" +import { Card } from "./card" +import { Icon } from "./icon" +import { Checkbox } from "./checkbox" +import { Diff } from "./diff" +import { DiffChanges } from "./diff-changes" +import { Markdown } from "./markdown" export interface MessageProps { message: MessageType @@ -22,7 +30,20 @@ export interface MessagePartProps { export type PartComponent = Component -const PART_MAPPING: Record = {} +export const PART_MAPPING: Record = {} + +function getFilename(path: string) { + if (!path) return "" + const trimmed = path.replace(/[\/]+$/, "") + const parts = trimmed.split("/") + return parts[parts.length - 1] ?? "" +} + +function getDirectory(path: string) { + const parts = path.split("/") + const dir = parts.slice(0, parts.length - 1).join("/") + return dir ? dir + "/" : "" +} export function registerPartComponent(type: string, component: PartComponent) { PART_MAPPING[type] = component @@ -81,3 +102,345 @@ export function Part(props: MessagePartProps) { ) } + +export interface ToolProps { + input: Record + metadata: Record + tool: string + output?: string + hideDetails?: boolean +} + +export type ToolComponent = Component + +const state: Record< + string, + { + name: string + render?: ToolComponent + } +> = {} + +export function registerTool(input: { name: string; render?: ToolComponent }) { + state[input.name] = input + return input +} + +export function getTool(name: string) { + return state[name]?.render +} + +export const ToolRegistry = { + register: registerTool, + render: getTool, +} + +PART_MAPPING["tool"] = function ToolPartDisplay(props) { + const part = props.part as ToolPart + const component = createMemo(() => { + const render = ToolRegistry.render(part.tool) ?? GenericTool + const metadata = part.state.status === "pending" ? {} : (part.state.metadata ?? {}) + const input = part.state.status === "completed" ? part.state.input : {} + + return ( + + + {(error) => { + const cleaned = error().replace("Error: ", "") + const [title, ...rest] = cleaned.split(": ") + return ( + + + + + + + {title} + {rest.join(": ")} + + + {cleaned} + + + + ) + }} + + + + + + ) + }) + + return {component()} +} + +PART_MAPPING["text"] = function TextPartDisplay(props) { + const part = props.part as TextPart + return ( + + + + + + ) +} + +PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props) { + const part = props.part as any + return ( + + + + + + ) +} + +ToolRegistry.register({ + name: "read", + render(props) { + return ( + + ) + }, +}) + +ToolRegistry.register({ + name: "list", + render(props) { + return ( + + + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "glob", + render(props) { + return ( + + + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "grep", + render(props) { + const args = [] + if (props.input.pattern) args.push("pattern=" + props.input.pattern) + if (props.input.include) args.push("include=" + props.input.include) + return ( + + + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "webfetch", + render(props) { + return ( + + + + ), + }} + > + + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "task", + render(props) { + return ( + + + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "bash", + render(props) { + return ( + + + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "edit", + render(props) { + return ( + + + Edit + + + {getDirectory(props.input.filePath!)} + + {getFilename(props.input.filePath ?? "")} + + + + + + + + + } + > + + + + + + + ) + }, +}) + +ToolRegistry.register({ + name: "write", + render(props) { + return ( + + + Write + + + {getDirectory(props.input.filePath!)} + + {getFilename(props.input.filePath ?? "")} + + + {/* */} + + } + > + + {props.output} + + + ) + }, +}) + +ToolRegistry.register({ + name: "todowrite", + render(props) { + return ( + t.status === "completed").length}/${props.input.todos?.length}`, + }} + > + + + + {(todo: any) => ( + + + {todo.content} + + + )} + + + + + ) + }, +}) diff --git a/packages/ui/src/components/tool-display.css b/packages/ui/src/components/tool-display.css deleted file mode 100644 index f3d9f865f..000000000 --- a/packages/ui/src/components/tool-display.css +++ /dev/null @@ -1,76 +0,0 @@ -[data-component="tool-trigger"] { - width: 100%; - display: flex; - align-items: center; - align-self: stretch; - gap: 20px; - justify-content: space-between; - - [data-slot="tool-trigger-content"] { - width: 100%; - display: flex; - align-items: center; - align-self: stretch; - gap: 20px; - } - - [data-slot="tool-icon"] { - flex-shrink: 0; - } - - [data-slot="tool-info"] { - flex-grow: 1; - min-width: 0; - } - - [data-slot="tool-info-structured"] { - width: 100%; - display: flex; - align-items: center; - gap: 8px; - justify-content: space-between; - } - - [data-slot="tool-info-main"] { - display: flex; - align-items: center; - gap: 8px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - [data-slot="tool-title"] { - 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); - letter-spacing: var(--letter-spacing-normal); - color: var(--text-base); - - &.capitalize { - text-transform: capitalize; - } - } - - [data-slot="tool-subtitle"] { - 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); - letter-spacing: var(--letter-spacing-normal); - color: var(--text-weak); - } - - [data-slot="tool-arg"] { - 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); - letter-spacing: var(--letter-spacing-normal); - color: var(--text-weak); - } -} diff --git a/packages/ui/src/components/tool-display.tsx b/packages/ui/src/components/tool-display.tsx deleted file mode 100644 index 43574fbb7..000000000 --- a/packages/ui/src/components/tool-display.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { children, For, Match, Show, Switch, type JSX } from "solid-js" -import { Collapsible } from "./collapsible" -import { Icon, IconProps } from "./icon" - -export type TriggerTitle = { - title: string - titleClass?: string - subtitle?: string - subtitleClass?: string - args?: string[] - argsClass?: string - action?: JSX.Element -} - -const isTriggerTitle = (val: any): val is TriggerTitle => { - return typeof val === "object" && val !== null && "title" in val && !(val instanceof Node) -} - -export interface BasicToolProps { - icon: IconProps["name"] - trigger: TriggerTitle | JSX.Element - children?: JSX.Element - hideDetails?: boolean -} - -export function BasicTool(props: BasicToolProps) { - const resolved = children(() => props.children) - return ( - - - - - - - - - {(trigger) => ( - - - - {trigger().title} - - - - {trigger().subtitle} - - - - - {(arg) => ( - - {arg} - - )} - - - - {trigger().action} - - )} - - {props.trigger as JSX.Element} - - - - - - - - - - {resolved()} - - - ) -} - -export function GenericTool(props: { tool: string; hideDetails?: boolean }) { - return -} diff --git a/packages/ui/src/components/tool-registry.tsx b/packages/ui/src/components/tool-registry.tsx deleted file mode 100644 index 8ee7d8293..000000000 --- a/packages/ui/src/components/tool-registry.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Component } from "solid-js" - -export interface ToolProps { - input: Record - metadata: Record - tool: string - output?: string - hideDetails?: boolean -} - -export type ToolComponent = Component - -const state: Record< - string, - { - name: string - render?: ToolComponent - } -> = {} - -export function registerTool(input: { name: string; render?: ToolComponent }) { - state[input.name] = input - return input -} - -export function getTool(name: string) { - return state[name]?.render -} - -export const ToolRegistry = { - register: registerTool, - render: getTool, -} diff --git a/packages/ui/src/context/helper.tsx b/packages/ui/src/context/helper.tsx new file mode 100644 index 000000000..6be88e775 --- /dev/null +++ b/packages/ui/src/context/helper.tsx @@ -0,0 +1,25 @@ +import { createContext, Show, useContext, type ParentProps } from "solid-js" + +export function createSimpleContext>(input: { + name: string + init: ((input: Props) => T) | (() => T) +}) { + const ctx = createContext() + + return { + provider: (props: ParentProps) => { + const init = input.init(props) + return ( + // @ts-expect-error + + {props.children} + + ) + }, + use() { + const value = useContext(ctx) + if (!value) throw new Error(`${input.name} context must be used within a context provider`) + return value + }, + } +} diff --git a/packages/ui/src/context/marked.tsx b/packages/ui/src/context/marked.tsx new file mode 100644 index 000000000..18ce4280a --- /dev/null +++ b/packages/ui/src/context/marked.tsx @@ -0,0 +1,30 @@ +import { marked } from "marked" +import markedShiki from "marked-shiki" +import { bundledLanguages, type BundledLanguage } from "shiki" + +import { createSimpleContext } from "./helper" +import { useShiki } from "./shiki" + +export const { use: useMarked, provider: MarkedProvider } = createSimpleContext({ + name: "Marked", + init: () => { + const highlighter = useShiki() + return marked.use( + markedShiki({ + async highlight(code, lang) { + if (!(lang in bundledLanguages)) { + lang = "text" + } + if (!highlighter.getLoadedLanguages().includes(lang)) { + await highlighter.loadLanguage(lang as BundledLanguage) + } + return highlighter.codeToHtml(code, { + lang: lang || "text", + theme: "opencode", + tabindex: false, + }) + }, + }), + ) + }, +}) diff --git a/packages/ui/src/context/shiki.tsx b/packages/ui/src/context/shiki.tsx new file mode 100644 index 000000000..d33b98ab7 --- /dev/null +++ b/packages/ui/src/context/shiki.tsx @@ -0,0 +1,577 @@ +import { createSimpleContext } from "./helper" +import { createHighlighter, type ThemeInput } from "shiki" + +const theme: ThemeInput = { + colors: { + "actionBar.toggledBackground": "var(--surface-raised-base)", + "activityBarBadge.background": "var(--surface-brand-base)", + "checkbox.border": "var(--border-base)", + "editor.background": "transparent", + "editor.foreground": "var(--text-base)", + "editor.inactiveSelectionBackground": "var(--surface-raised-base)", + "editor.selectionHighlightBackground": "var(--border-active)", + "editorIndentGuide.activeBackground1": "var(--border-weak-base)", + "editorIndentGuide.background1": "var(--border-weak-base)", + "input.placeholderForeground": "var(--text-weak)", + "list.activeSelectionIconForeground": "var(--text-base)", + "list.dropBackground": "var(--surface-raised-base)", + "menu.background": "var(--surface-base)", + "menu.border": "var(--border-base)", + "menu.foreground": "var(--text-base)", + "menu.selectionBackground": "var(--surface-interactive-base)", + "menu.separatorBackground": "var(--border-base)", + "ports.iconRunningProcessForeground": "var(--icon-success-base)", + "sideBarSectionHeader.background": "transparent", + "sideBarSectionHeader.border": "var(--border-weak-base)", + "sideBarTitle.foreground": "var(--text-weak)", + "statusBarItem.remoteBackground": "var(--surface-success-base)", + "statusBarItem.remoteForeground": "var(--text-base)", + "tab.lastPinnedBorder": "var(--border-weak-base)", + "tab.selectedBackground": "var(--surface-raised-base)", + "tab.selectedForeground": "var(--text-weak)", + "terminal.inactiveSelectionBackground": "var(--surface-raised-base)", + "widget.border": "var(--border-base)", + }, + displayName: "opencode", + name: "opencode", + semanticHighlighting: true, + semanticTokenColors: { + customLiteral: "var(--syntax-function)", + newOperator: "var(--syntax-operator)", + numberLiteral: "var(--syntax-number)", + stringLiteral: "var(--syntax-string)", + }, + tokenColors: [ + { + scope: [ + "meta.embedded", + "source.groovy.embedded", + "string meta.image.inline.markdown", + "variable.legacy.builtin.python", + ], + settings: { + foreground: "var(--text-base)", + }, + }, + { + scope: "emphasis", + settings: { + fontStyle: "italic", + }, + }, + { + scope: "strong", + settings: { + fontStyle: "bold", + }, + }, + { + scope: "header", + settings: { + foreground: "var(--markdown-heading)", + }, + }, + { + scope: "comment", + settings: { + foreground: "var(--syntax-comment)", + }, + }, + { + scope: "constant.language", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: [ + "constant.numeric", + "variable.other.enummember", + "keyword.operator.plus.exponent", + "keyword.operator.minus.exponent", + ], + settings: { + foreground: "var(--syntax-number)", + }, + }, + { + scope: "constant.regexp", + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: "entity.name.tag", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: ["entity.name.tag.css", "entity.name.tag.less"], + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: "entity.other.attribute-name", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: [ + "entity.other.attribute-name.class.css", + "source.css entity.other.attribute-name.class", + "entity.other.attribute-name.id.css", + "entity.other.attribute-name.parent-selector.css", + "entity.other.attribute-name.parent.less", + "source.css entity.other.attribute-name.pseudo-class", + "entity.other.attribute-name.pseudo-element.css", + "source.css.less entity.other.attribute-name.id", + "entity.other.attribute-name.scss", + ], + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: "invalid", + settings: { + foreground: "var(--syntax-critical)", + }, + }, + { + scope: "markup.underline", + settings: { + fontStyle: "underline", + }, + }, + { + scope: "markup.bold", + settings: { + fontStyle: "bold", + foreground: "var(--markdown-strong)", + }, + }, + { + scope: "markup.heading", + settings: { + fontStyle: "bold", + foreground: "var(--theme-markdown-heading)", + }, + }, + { + scope: "markup.italic", + settings: { + fontStyle: "italic", + }, + }, + { + scope: "markup.strikethrough", + settings: { + fontStyle: "strikethrough", + }, + }, + { + scope: "markup.inserted", + settings: { + foreground: "var(--text-diff-add-base)", + }, + }, + { + scope: "markup.deleted", + settings: { + foreground: "var(--text-diff-delete-base)", + }, + }, + { + scope: "markup.changed", + settings: { + foreground: "var(--text-base)", + }, + }, + { + scope: "punctuation.definition.quote.begin.markdown", + settings: { + foreground: "var(--markdown-block-quote)", + }, + }, + { + scope: "punctuation.definition.list.begin.markdown", + settings: { + foreground: "var(--markdown-list-enumeration)", + }, + }, + { + scope: "markup.inline.raw", + settings: { + foreground: "var(--markdown-code)", + }, + }, + { + scope: "punctuation.definition.tag", + settings: { + foreground: "var(--syntax-punctuation)", + }, + }, + { + scope: ["meta.preprocessor", "entity.name.function.preprocessor"], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "meta.preprocessor.string", + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: "meta.preprocessor.numeric", + settings: { + foreground: "var(--syntax-number)", + }, + }, + { + scope: "meta.structure.dictionary.key.python", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "meta.diff.header", + settings: { + foreground: "var(--text-weak)", + }, + }, + { + scope: "storage", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "storage.type", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: ["storage.modifier", "keyword.operator.noexcept"], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: ["string", "meta.embedded.assembly"], + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: "string.tag", + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: "string.value", + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: "string.regexp", + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: [ + "punctuation.definition.template-expression.begin", + "punctuation.definition.template-expression.end", + "punctuation.section.embedded", + ], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: ["meta.template.expression"], + settings: { + foreground: "var(--text-base)", + }, + }, + { + scope: [ + "support.type.vendored.property-name", + "support.type.property-name", + "source.css variable", + "source.coffee.embedded", + ], + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "keyword", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "keyword.control", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "keyword.operator", + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: [ + "keyword.operator.new", + "keyword.operator.expression", + "keyword.operator.cast", + "keyword.operator.sizeof", + "keyword.operator.alignof", + "keyword.operator.typeid", + "keyword.operator.alignas", + "keyword.operator.instanceof", + "keyword.operator.logical.python", + "keyword.operator.wordlike", + ], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "keyword.other.unit", + settings: { + foreground: "var(--syntax-number)", + }, + }, + { + scope: ["punctuation.section.embedded.begin.php", "punctuation.section.embedded.end.php"], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "support.function.git-rebase", + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: "constant.sha.git-rebase", + settings: { + foreground: "var(--syntax-number)", + }, + }, + { + scope: [ + "storage.modifier.import.java", + "variable.language.wildcard.java", + "storage.modifier.package.java", + ], + settings: { + foreground: "var(--text-base)", + }, + }, + { + scope: "variable.language", + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: [ + "entity.name.function", + "support.function", + "support.constant.handlebars", + "source.powershell variable.other.member", + "entity.name.operator.custom-literal", + ], + settings: { + foreground: "var(--syntax-function)", + }, + }, + { + scope: [ + "support.class", + "support.type", + "entity.name.type", + "entity.name.namespace", + "entity.other.attribute", + "entity.name.scope-resolution", + "entity.name.class", + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.error.go", + "storage.type.rune.go", + "storage.type.cs", + "storage.type.generic.cs", + "storage.type.modifier.cs", + "storage.type.variable.cs", + "storage.type.annotation.java", + "storage.type.generic.java", + "storage.type.java", + "storage.type.object.array.java", + "storage.type.primitive.array.java", + "storage.type.primitive.java", + "storage.type.token.java", + "storage.type.groovy", + "storage.type.annotation.groovy", + "storage.type.parameters.groovy", + "storage.type.generic.groovy", + "storage.type.object.array.groovy", + "storage.type.primitive.array.groovy", + "storage.type.primitive.groovy", + ], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + scope: [ + "meta.type.cast.expr", + "meta.type.new.expr", + "support.constant.math", + "support.constant.dom", + "support.constant.json", + "entity.other.inherited-class", + "punctuation.separator.namespace.ruby", + ], + settings: { + foreground: "var(--syntax-type)", + }, + }, + { + scope: [ + "keyword.control", + "source.cpp keyword.operator.new", + "keyword.operator.delete", + "keyword.other.using", + "keyword.other.directive.using", + "keyword.other.operator", + "entity.name.operator", + ], + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: [ + "variable", + "meta.definition.variable.name", + "support.variable", + "entity.name.variable", + "constant.other.placeholder", + ], + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: ["variable.other.constant", "variable.other.enummember"], + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: ["meta.object-literal.key"], + settings: { + foreground: "var(--syntax-variable)", + }, + }, + { + scope: [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color", + ], + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: [ + "punctuation.definition.group.regexp", + "punctuation.definition.group.assertion.regexp", + "punctuation.definition.character-class.regexp", + "punctuation.character.set.begin.regexp", + "punctuation.character.set.end.regexp", + "keyword.operator.negation.regexp", + "support.other.parenthesis.regexp", + ], + settings: { + foreground: "var(--syntax-string)", + }, + }, + { + scope: [ + "constant.character.character-class.regexp", + "constant.other.character-class.set.regexp", + "constant.other.character-class.regexp", + "constant.character.set.regexp", + ], + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: ["keyword.operator.or.regexp", "keyword.control.anchor.regexp"], + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: "keyword.operator.quantifier.regexp", + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: ["constant.character", "constant.other.option"], + settings: { + foreground: "var(--syntax-keyword)", + }, + }, + { + scope: "constant.character.escape", + settings: { + foreground: "var(--syntax-operator)", + }, + }, + { + scope: "entity.name.label", + settings: { + foreground: "var(--text-weak)", + }, + }, + ], + type: "dark", +} + +const highlighter = await createHighlighter({ + themes: [theme], + langs: [], +}) + +export const { use: useShiki, provider: ShikiProvider } = createSimpleContext({ + name: "Shiki", + init: () => { + return highlighter + }, +}) diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/styles/index.css index 4fe13055a..cea5a082d 100644 --- a/packages/ui/src/styles/index.css +++ b/packages/ui/src/styles/index.css @@ -6,6 +6,7 @@ @import "./base.css" layer(base); @import "../components/accordion.css" layer(components); +@import "../components/basic-tool.css" layer(components); @import "../components/button.css" layer(components); @import "../components/card.css" layer(components); @import "../components/checkbox.css" layer(components); @@ -17,12 +18,12 @@ @import "../components/icon-button.css" layer(components); @import "../components/input.css" layer(components); @import "../components/list.css" layer(components); +@import "../components/markdown.css" layer(components); @import "../components/message-part.css" layer(components); @import "../components/progress-circle.css" layer(components); @import "../components/select.css" layer(components); @import "../components/select-dialog.css" layer(components); @import "../components/tabs.css" layer(components); -@import "../components/tool-display.css" layer(components); @import "../components/tooltip.css" layer(components); @import "./utilities.css" layer(utilities); -- cgit v1.2.3