mirror of
https://github.com/sst/opencode.git
synced 2025-12-23 10:11:41 +00:00
wip(share): more styling
This commit is contained in:
parent
3fb57044d1
commit
acf1dd8500
30 changed files with 266 additions and 192 deletions
|
|
@ -339,7 +339,7 @@ export default function Page() {
|
|||
<div class="flex items-start justify-start h-full min-h-0">
|
||||
<Show when={session.messages.user().length > 1}>
|
||||
<MessageNav
|
||||
classList={{ "mt-1.5 mr-3": wide(), "mt-3 mr-8": !wide() }}
|
||||
classList={{ "mt-0.5 mr-3 absolute right-full": wide(), "mt-3 mr-8": !wide() }}
|
||||
messages={session.messages.user()}
|
||||
current={session.messages.active()}
|
||||
onMessageSelect={session.messages.setActive}
|
||||
|
|
|
|||
|
|
@ -1,18 +1 @@
|
|||
@import "@opencode-ai/ui/styles/tailwind";
|
||||
|
||||
:root {
|
||||
--background-rgb: 214, 219, 220;
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background-rgb: 0, 0, 0;
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
/* background: rgb(var(--background-rgb)); */
|
||||
/* color: rgb(var(--foreground-rgb)); */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { Router } from "@solidjs/router"
|
||||
import { FileRoutes } from "@solidjs/start/router"
|
||||
import { Suspense } from "solid-js"
|
||||
import { Fonts } from "@opencode-ai/ui/fonts"
|
||||
import { MetaProvider } from "@solidjs/meta"
|
||||
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
|
||||
|
|
@ -10,16 +9,12 @@ export default function App() {
|
|||
return (
|
||||
<Router
|
||||
root={(props) => (
|
||||
<>
|
||||
<Suspense>
|
||||
<MarkedProvider>
|
||||
<MetaProvider>
|
||||
<Fonts />
|
||||
{props.children}
|
||||
</MetaProvider>
|
||||
</MarkedProvider>
|
||||
</Suspense>
|
||||
</>
|
||||
<MarkedProvider>
|
||||
<MetaProvider>
|
||||
<Fonts />
|
||||
{props.children}
|
||||
</MetaProvider>
|
||||
</MarkedProvider>
|
||||
)}
|
||||
>
|
||||
<FileRoutes />
|
||||
|
|
|
|||
|
|
@ -3,15 +3,26 @@ import { SessionTurn } from "@opencode-ai/ui/session-turn"
|
|||
import { SessionReview } from "@opencode-ai/ui/session-review"
|
||||
import { DataProvider } from "@opencode-ai/ui/context"
|
||||
import { createAsync, query, RouteDefinition, useParams } from "@solidjs/router"
|
||||
import { createMemo, Show } from "solid-js"
|
||||
import { createMemo, ErrorBoundary, Show } from "solid-js"
|
||||
import { Share } from "~/core/share"
|
||||
import { Logo, Mark } from "@opencode-ai/ui/logo"
|
||||
import { IconButton } from "@opencode-ai/ui/icon-button"
|
||||
import { iife } from "@opencode-ai/util/iife"
|
||||
import { Binary } from "@opencode-ai/util/binary"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { DateTime } from "luxon"
|
||||
import { MessageNav } from "@opencode-ai/ui/message-nav"
|
||||
import { createStore } from "solid-js/store"
|
||||
import z from "zod"
|
||||
import NotFound from "../[...404]"
|
||||
|
||||
const SessionDataMissingError = NamedError.create(
|
||||
"SessionDataMissingError",
|
||||
z.object({
|
||||
sessionID: z.string(),
|
||||
message: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
|
||||
const getData = query(async (sessionID) => {
|
||||
const data = await Share.data(sessionID)
|
||||
|
|
@ -70,6 +81,8 @@ const getData = query(async (sessionID) => {
|
|||
break
|
||||
}
|
||||
}
|
||||
const match = Binary.search(result.session, sessionID!, (s) => s.id)
|
||||
if (!match.found) throw new SessionDataMissingError({ sessionID })
|
||||
return result
|
||||
}, "getShareData")
|
||||
|
||||
|
|
@ -80,126 +93,172 @@ export const route = {
|
|||
export default function () {
|
||||
const params = useParams()
|
||||
const data = createAsync(async () => {
|
||||
if (!params.sessionID) return
|
||||
if (!params.sessionID) throw new Error("Missing sessionID")
|
||||
return getData(params.sessionID)
|
||||
})
|
||||
|
||||
return (
|
||||
<Show when={data()}>
|
||||
{(data) => (
|
||||
<DataProvider data={data()}>
|
||||
{iife(() => {
|
||||
const [store, setStore] = createStore({
|
||||
messageId: undefined as string | undefined,
|
||||
})
|
||||
const match = createMemo(() => Binary.search(data().session, params.sessionID!, (s) => s.id))
|
||||
if (!match().found) throw new Error(`Session ${params.sessionID} not found`)
|
||||
const info = createMemo(() => data().session[match().index])
|
||||
const messages = createMemo(() =>
|
||||
params.sessionID ? (data().message[params.sessionID]?.filter((m) => m.role === "user") ?? []) : [],
|
||||
)
|
||||
const firstUserMessage = createMemo(() => messages().at(0))
|
||||
const activeMessage = createMemo(
|
||||
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
|
||||
)
|
||||
function setActiveMessage(message: UserMessage | undefined) {
|
||||
if (message) {
|
||||
setStore("messageId", message.id)
|
||||
} else {
|
||||
setStore("messageId", undefined)
|
||||
<ErrorBoundary
|
||||
fallback={(e) => {
|
||||
return (
|
||||
<Show when={e.message === "SessionDataMissingError"}>
|
||||
<NotFound />
|
||||
</Show>
|
||||
)
|
||||
}}
|
||||
>
|
||||
<Show when={data()}>
|
||||
{(data) => (
|
||||
<DataProvider data={data()}>
|
||||
{iife(() => {
|
||||
const [store, setStore] = createStore({
|
||||
messageId: undefined as string | undefined,
|
||||
})
|
||||
const match = createMemo(() => Binary.search(data().session, params.sessionID!, (s) => s.id))
|
||||
if (!match().found) throw new Error(`Session ${params.sessionID} not found`)
|
||||
const info = createMemo(() => data().session[match().index])
|
||||
const messages = createMemo(() =>
|
||||
params.sessionID
|
||||
? (data().message[params.sessionID]?.filter((m) => m.role === "user") ?? []).sort(
|
||||
(a, b) => b.time.created - a.time.created,
|
||||
)
|
||||
: [],
|
||||
)
|
||||
const firstUserMessage = createMemo(() => messages().at(0))
|
||||
const activeMessage = createMemo(
|
||||
() => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(),
|
||||
)
|
||||
function setActiveMessage(message: UserMessage | undefined) {
|
||||
if (message) {
|
||||
setStore("messageId", message.id)
|
||||
} else {
|
||||
setStore("messageId", undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
const provider = createMemo(() => activeMessage()?.model?.providerID)
|
||||
const modelID = createMemo(() => activeMessage()?.model?.modelID)
|
||||
const model = createMemo(() => data().model[params.sessionID!]?.find((m) => m.id === modelID()))
|
||||
const diffs = createMemo(() => data().session_diff[params.sessionID!] ?? [])
|
||||
const provider = createMemo(() => activeMessage()?.model?.providerID)
|
||||
const modelID = createMemo(() => activeMessage()?.model?.modelID)
|
||||
const model = createMemo(() => data().model[params.sessionID!]?.find((m) => m.id === modelID()))
|
||||
const diffs = createMemo(() => data().session_diff[params.sessionID!] ?? [])
|
||||
|
||||
return (
|
||||
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
|
||||
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
|
||||
<div class="">
|
||||
<a href="https://opencode.ai">
|
||||
<Mark />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex gap-3 items-center">
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://github.com/sst/opencode"
|
||||
target="_blank"
|
||||
icon="github"
|
||||
variant="ghost"
|
||||
/>
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://opencode.ai/discord"
|
||||
target="_blank"
|
||||
icon="discord"
|
||||
variant="ghost"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
<div class="select-text flex flex-col flex-1 min-h-0">
|
||||
<div class="w-full flex-1 min-h-0 flex">
|
||||
<div
|
||||
classList={{
|
||||
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full mx-auto": true,
|
||||
"px-21 @4xl:px-6 max-w-2xl": diffs().length > 0,
|
||||
"px-6 max-w-2xl": diffs().length === 0,
|
||||
}}
|
||||
>
|
||||
<div class="flex flex-col gap-4 shrink-0">
|
||||
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
|
||||
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
|
||||
<Mark class="shrink-0 w-3 my-0.5" />
|
||||
<div class="text-12-mono text-text-base">v{info().version}</div>
|
||||
</div>
|
||||
<div class="flex gap-2 items-center">
|
||||
<img
|
||||
src={`https://models.dev/logos/${provider()}.svg`}
|
||||
class="size-4 shrink-0 dark:invert"
|
||||
/>
|
||||
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
|
||||
</div>
|
||||
<div class="text-12-regular text-text-weaker">
|
||||
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
|
||||
</div>
|
||||
<div class="flex items-start justify-start h-full min-h-0">
|
||||
<Show when={messages().length > 1}>
|
||||
<MessageNav
|
||||
classList={{ "mt-2 mr-3": true }}
|
||||
messages={messages()}
|
||||
current={activeMessage()}
|
||||
onMessageSelect={setActiveMessage}
|
||||
size={!diffs().length ? "normal" : "compact"}
|
||||
/>
|
||||
</Show>
|
||||
<SessionTurn
|
||||
sessionID={params.sessionID!}
|
||||
messageID={store.messageId ?? firstUserMessage()!.id!}
|
||||
classes={{ root: "grow", content: "flex flex-col justify-between", container: "pb-20" }}
|
||||
>
|
||||
<div class="flex items-center justify-center pb-8 shrink-0">
|
||||
<Logo class="w-58.5 opacity-12" />
|
||||
</div>
|
||||
</SessionTurn>
|
||||
</div>
|
||||
const title = (
|
||||
<div class="flex flex-col gap-4 shrink-0">
|
||||
<div class="h-8 flex gap-4 items-center justify-start self-stretch">
|
||||
<div class="pl-[2.5px] pr-2 flex items-center gap-1.75 bg-surface-strong shadow-xs-border-base">
|
||||
<Mark class="shrink-0 w-3 my-0.5" />
|
||||
<div class="text-12-mono text-text-base">v{info().version}</div>
|
||||
</div>
|
||||
<Show when={diffs().length}>
|
||||
<div class="relative grow px-6 pt-14 flex-1 min-h-0 border-l border-border-weak-base">
|
||||
<SessionReview diffs={diffs()} class="pb-20" />
|
||||
<div class="flex gap-2 items-center">
|
||||
<img src={`https://models.dev/logos/${provider()}.svg`} class="size-3.5 shrink-0 dark:invert" />
|
||||
<div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
|
||||
</div>
|
||||
<div class="text-12-regular text-text-weaker">
|
||||
{DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-left text-16-medium text-text-strong">{info().title}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div class="relative bg-background-stronger w-screen h-screen overflow-hidden flex flex-col">
|
||||
<header class="h-12 px-6 py-2 flex items-center justify-between self-stretch bg-background-base border-b border-border-weak-base">
|
||||
<div class="">
|
||||
<a href="https://opencode.ai">
|
||||
<Mark />
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex gap-3 items-center">
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://github.com/sst/opencode"
|
||||
target="_blank"
|
||||
icon="github"
|
||||
variant="ghost"
|
||||
/>
|
||||
<IconButton
|
||||
as={"a"}
|
||||
href="https://opencode.ai/discord"
|
||||
target="_blank"
|
||||
icon="discord"
|
||||
variant="ghost"
|
||||
/>
|
||||
</div>
|
||||
</header>
|
||||
<div class="select-text flex flex-col flex-1 min-h-0">
|
||||
<div class="w-full flex-1 min-h-0 flex">
|
||||
<div
|
||||
classList={{
|
||||
"@container relative shrink-0 pt-14 flex flex-col gap-10 min-h-0 w-full mx-auto": true,
|
||||
"px-21 @4xl:px-6 max-w-2xl": diffs().length > 0,
|
||||
"px-6 max-w-2xl": diffs().length === 0,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
<div class="flex items-start justify-start h-full min-h-0">
|
||||
<Show when={messages().length > 1}>
|
||||
<>
|
||||
<div
|
||||
classList={{
|
||||
"xl:hidden": true,
|
||||
"absolute right-[90%]": diffs().length > 0,
|
||||
"absolute right-full": diffs().length === 0,
|
||||
}}
|
||||
>
|
||||
<MessageNav
|
||||
classList={{
|
||||
"mt-0.5 mr-8": diffs().length === 0,
|
||||
"mt-2.5 mr-3": diffs().length > 0,
|
||||
}}
|
||||
messages={messages()}
|
||||
current={activeMessage()}
|
||||
onMessageSelect={setActiveMessage}
|
||||
size={!diffs().length ? "normal" : "compact"}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
classList={{
|
||||
"hidden xl:block": true,
|
||||
"absolute right-[90%]": diffs().length > 0,
|
||||
"absolute right-full": diffs().length === 0,
|
||||
}}
|
||||
>
|
||||
<MessageNav
|
||||
classList={{
|
||||
"mt-0.5 mr-8": diffs().length === 0,
|
||||
"mt-2.5 mr-3": diffs().length > 0,
|
||||
}}
|
||||
messages={messages()}
|
||||
current={activeMessage()}
|
||||
onMessageSelect={setActiveMessage}
|
||||
size={!diffs().length ? "normal" : "compact"}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
</Show>
|
||||
<SessionTurn
|
||||
sessionID={params.sessionID!}
|
||||
messageID={store.messageId ?? firstUserMessage()!.id!}
|
||||
classes={{ root: "grow", content: "flex flex-col justify-between", container: "pb-20" }}
|
||||
>
|
||||
<div class="flex items-center justify-center pb-8 shrink-0">
|
||||
<Logo class="w-58.5 opacity-12" />
|
||||
</div>
|
||||
</SessionTurn>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={diffs().length}>
|
||||
<div class="relative grow px-6 pt-14 flex-1 min-h-0 border-l border-border-weak-base">
|
||||
<SessionReview diffs={diffs()} class="pb-20" />
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</DataProvider>
|
||||
)}
|
||||
</Show>
|
||||
)
|
||||
})}
|
||||
</DataProvider>
|
||||
)}
|
||||
</Show>
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import z from "zod"
|
|||
import { Global } from "../global"
|
||||
import { Log } from "../util/log"
|
||||
import path from "path"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { readableStreamToText } from "bun"
|
||||
import { createRequire } from "module"
|
||||
import { Lock } from "../util/lock"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import z from "zod"
|
||||
import { EOL } from "os"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
|
||||
export namespace UI {
|
||||
const LOGO = [
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { mergeDeep, pipe } from "remeda"
|
|||
import { Global } from "../global"
|
||||
import fs from "fs/promises"
|
||||
import { lazy } from "../util/lazy"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { Flag } from "../flag/flag"
|
||||
import { Auth } from "../auth"
|
||||
import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { NamedError } from "@/util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import matter from "gray-matter"
|
||||
import { z } from "zod"
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import path from "path"
|
|||
import { Global } from "../global"
|
||||
import fs from "fs/promises"
|
||||
import z from "zod"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { lazy } from "../util/lazy"
|
||||
import { Log } from "../util/log"
|
||||
import { ZipReader, BlobReader, BlobWriter } from "@zip.js/zip.js"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import path from "path"
|
|||
import { Global } from "../global"
|
||||
import fs from "fs/promises"
|
||||
import z from "zod"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { lazy } from "../util/lazy"
|
||||
import { $ } from "bun"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { spawn } from "bun"
|
||||
import z from "zod"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { Log } from "../util/log"
|
||||
import { Bus } from "../bus"
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { UpgradeCommand } from "./cli/cmd/upgrade"
|
|||
import { ModelsCommand } from "./cli/cmd/models"
|
||||
import { UI } from "./cli/ui"
|
||||
import { Installation } from "./installation"
|
||||
import { NamedError } from "./util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { FormatError } from "./cli/error"
|
||||
import { ServeCommand } from "./cli/cmd/serve"
|
||||
import { DebugCommand } from "./cli/cmd/debug"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import path from "path"
|
||||
import { $ } from "bun"
|
||||
import z from "zod"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { Bus } from "../bus"
|
||||
import { Log } from "../util/log"
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { LANGUAGE_EXTENSIONS } from "./language"
|
|||
import { Bus } from "../bus"
|
||||
import z from "zod"
|
||||
import type { LSPServer } from "./server"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { withTimeout } from "../util/timeout"
|
||||
import { Instance } from "../project/instance"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
|||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
|
||||
import { Config } from "../config/config"
|
||||
import { Log } from "../util/log"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import z from "zod/v4"
|
||||
import { Instance } from "../project/instance"
|
||||
import { withTimeout } from "@/util/timeout"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { map, filter, pipe, fromEntries, mapValues } from "remeda"
|
|||
import z from "zod"
|
||||
import { fn } from "@/util/fn"
|
||||
import type { AuthOuathResult, Hooks } from "@opencode-ai/plugin"
|
||||
import { NamedError } from "@/util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { Auth } from "@/auth"
|
||||
|
||||
export namespace ProviderAuth {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { Log } from "../util/log"
|
|||
import { BunProc } from "../bun"
|
||||
import { Plugin } from "../plugin"
|
||||
import { ModelsDev } from "./models"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { Auth } from "../auth"
|
||||
import { Instance } from "../project/instance"
|
||||
import { Flag } from "../flag/flag"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Session } from "../session"
|
|||
import z from "zod"
|
||||
import { Provider } from "../provider/provider"
|
||||
import { mapValues } from "remeda"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { ModelsDev } from "../provider/models"
|
||||
import { Ripgrep } from "../file/ripgrep"
|
||||
import { Config } from "../config/config"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import z from "zod"
|
||||
import { Bus } from "../bus"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { Message } from "./message"
|
||||
import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai"
|
||||
import { Identifier } from "../id/id"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import z from "zod"
|
||||
import { NamedError } from "../util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
|
||||
export namespace Message {
|
||||
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ import { Command } from "../command"
|
|||
import { $, fileURLToPath } from "bun"
|
||||
import { ConfigMarkdown } from "../config/markdown"
|
||||
import { SessionSummary } from "./summary"
|
||||
import { NamedError } from "@/util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { fn } from "@/util/fn"
|
||||
import { SessionProcessor } from "./processor"
|
||||
import { TaskTool } from "@/tool/task"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { Global } from "../global"
|
|||
import { lazy } from "../util/lazy"
|
||||
import { Lock } from "../util/lock"
|
||||
import { $ } from "bun"
|
||||
import { NamedError } from "@/util/error"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import z from "zod"
|
||||
|
||||
export namespace Storage {
|
||||
|
|
|
|||
BIN
packages/ui/src/assets/fonts/tx-02.otf
Normal file
BIN
packages/ui/src/assets/fonts/tx-02.otf
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/fonts/tx-02.ttf
Normal file
BIN
packages/ui/src/assets/fonts/tx-02.ttf
Normal file
Binary file not shown.
BIN
packages/ui/src/assets/fonts/tx-02.woff2
Normal file
BIN
packages/ui/src/assets/fonts/tx-02.woff2
Normal file
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
import { Style, Link } from "@solidjs/meta"
|
||||
import geist from "../assets/fonts/geist.woff2"
|
||||
import geistMono from "../assets/fonts/geist-mono.woff2"
|
||||
import tx02 from "../assets/fonts/tx-02.woff2"
|
||||
|
||||
export const Fonts = () => {
|
||||
return (
|
||||
|
|
@ -22,14 +22,14 @@ export const Fonts = () => {
|
|||
line-gap-override: 1%;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Geist Mono";
|
||||
src: url("${geistMono}") format("woff2-variations");
|
||||
font-family: "Berkeley Mono";
|
||||
src: url("${tx02}") format("woff2-variations");
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-weight: 400 700;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Geist Mono Fallback";
|
||||
font-family: "Berkeley Mono Fallback";
|
||||
src: local("Courier New");
|
||||
size-adjust: 100%;
|
||||
ascent-override: 97%;
|
||||
|
|
@ -38,7 +38,7 @@ export const Fonts = () => {
|
|||
}
|
||||
`}</Style>
|
||||
<Link rel="preload" href={geist} as="font" type="font/woff2" crossorigin="anonymous" />
|
||||
<Link rel="preload" href={geistMono} as="font" type="font/woff2" crossorigin="anonymous" />
|
||||
<Link rel="preload" href={tx02} as="font" type="font/woff2" crossorigin="anonymous" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
[data-component="message-nav"] {
|
||||
/* margin-right: 32px; */
|
||||
/* margin-top: 12px; */
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -9,15 +7,8 @@
|
|||
list-style: none;
|
||||
|
||||
&[data-size="normal"] {
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
width: 240px;
|
||||
/* margin-top: 12px; */
|
||||
|
||||
@media (min-width: 80rem) {
|
||||
gap: 8px;
|
||||
/* margin-top: 4px; */
|
||||
}
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,10 +27,8 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
height: 8px;
|
||||
width: 32px;
|
||||
/* margin-right: -12px; */
|
||||
cursor: pointer;
|
||||
height: 12px;
|
||||
width: 24px;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
|
|
@ -52,7 +41,7 @@
|
|||
|
||||
[data-slot="message-nav-tick-line"] {
|
||||
height: 1px;
|
||||
width: 20px;
|
||||
width: 16px;
|
||||
background-color: var(--icon-base);
|
||||
transition:
|
||||
width 0.2s,
|
||||
|
|
@ -69,11 +58,12 @@
|
|||
align-items: center;
|
||||
align-self: stretch;
|
||||
width: 100%;
|
||||
column-gap: 8px;
|
||||
column-gap: 12px;
|
||||
cursor: default;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
padding: 4px 12px;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
[data-slot="message-nav-title-preview"] {
|
||||
|
|
@ -90,6 +80,37 @@
|
|||
}
|
||||
}
|
||||
|
||||
[data-slot="message-nav-item"]:hover [data-slot="message-nav-title-preview"] {
|
||||
[data-slot="message-nav-item"]:hover [data-slot="message-nav-message-button"] {
|
||||
background-color: var(--surface-base);
|
||||
}
|
||||
[data-slot="message-nav-item"]:active [data-slot="message-nav-message-button"] {
|
||||
background-color: var(--surface-base-active);
|
||||
}
|
||||
|
||||
[data-slot="message-nav-item"]:active [data-slot="message-nav-title-preview"] {
|
||||
color: var(--text-base);
|
||||
}
|
||||
|
||||
[data-slot="message-nav-tooltip"] {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
[data-slot="message-nav-tooltip-content"] {
|
||||
display: flex;
|
||||
padding: 4px 4px 6px 4px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface-raised-stronger-non-alpha);
|
||||
|
||||
/* border/shadow-xs/base */
|
||||
box-shadow:
|
||||
0 0 0 1px var(--border-weak-base, rgba(17, 0, 0, 0.12)),
|
||||
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);
|
||||
|
||||
* {
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { UserMessage } from "@opencode-ai/sdk"
|
|||
import { ComponentProps, createMemo, For, Match, Show, splitProps, Switch } from "solid-js"
|
||||
import { DiffChanges } from "./diff-changes"
|
||||
import { Spinner } from "./spinner"
|
||||
import { HoverCard } from "@kobalte/core/hover-card"
|
||||
import { Tooltip } from "@kobalte/core/tooltip"
|
||||
|
||||
export function MessageNav(
|
||||
props: ComponentProps<"ul"> & {
|
||||
|
|
@ -17,7 +19,7 @@ export function MessageNav(
|
|||
return local.messages?.at(0)
|
||||
})
|
||||
|
||||
return (
|
||||
const content = (
|
||||
<ul role="list" data-component="message-nav" data-size={local.size} {...others}>
|
||||
<For each={local.messages}>
|
||||
{(message) => {
|
||||
|
|
@ -28,13 +30,9 @@ export function MessageNav(
|
|||
<li data-slot="message-nav-item">
|
||||
<Switch>
|
||||
<Match when={local.size === "compact"}>
|
||||
<button
|
||||
data-slot="message-nav-tick-button"
|
||||
data-active={message.id === local.current?.id || undefined}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div data-slot="message-nav-tick-button" data-active={message.id === local.current?.id || undefined}>
|
||||
<div data-slot="message-nav-tick-line" />
|
||||
</button>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={local.size === "normal"}>
|
||||
<button data-slot="message-nav-message-button" onClick={handleClick}>
|
||||
|
|
@ -63,4 +61,22 @@ export function MessageNav(
|
|||
</For>
|
||||
</ul>
|
||||
)
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={local.size === "compact"}>
|
||||
<Tooltip openDelay={0} closeDelay={0} placement="top-start" gutter={-65} shift={-16} overlap>
|
||||
<Tooltip.Trigger as="div">{content}</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content data-slot="message-nav-tooltip">
|
||||
<div data-slot="message-nav-tooltip-content">
|
||||
<MessageNav {...props} size="normal" />
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip>
|
||||
</Match>
|
||||
<Match when={local.size === "normal"}>{content}</Match>
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
:root {
|
||||
--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;
|
||||
--font-family-mono: "Berkeley Mono", "Berkeley Mono Fallback";
|
||||
--font-family-mono--font-feature-settings: "ss01" 1;
|
||||
|
||||
--font-size-small: 12px;
|
||||
--font-size-base: 14px;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue