mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-22 18:24:21 +01:00
wip: desktop work
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
|||||||
DiffChanges,
|
DiffChanges,
|
||||||
ProgressCircle,
|
ProgressCircle,
|
||||||
Message,
|
Message,
|
||||||
|
Typewriter,
|
||||||
} from "@opencode-ai/ui"
|
} from "@opencode-ai/ui"
|
||||||
import { FileIcon } from "@/ui"
|
import { FileIcon } from "@/ui"
|
||||||
import FileTree from "@/components/file-tree"
|
import FileTree from "@/components/file-tree"
|
||||||
@@ -544,7 +545,6 @@ export default function Page() {
|
|||||||
<For each={local.session.userMessages()}>
|
<For each={local.session.userMessages()}>
|
||||||
{(message) => {
|
{(message) => {
|
||||||
const diffs = createMemo(() => message.summary?.diffs ?? [])
|
const diffs = createMemo(() => message.summary?.diffs ?? [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
class="group/li flex items-center gap-x-2 py-1 self-stretch cursor-default"
|
class="group/li flex items-center gap-x-2 py-1 self-stretch cursor-default"
|
||||||
@@ -570,9 +570,9 @@ export default function Page() {
|
|||||||
<div class="flex flex-col items-start gap-50 pb-50">
|
<div class="flex flex-col items-start gap-50 pb-50">
|
||||||
<For each={local.session.userMessages()}>
|
<For each={local.session.userMessages()}>
|
||||||
{(message) => {
|
{(message) => {
|
||||||
|
const [initialized, setInitialized] = createSignal(!!message.summary?.title)
|
||||||
const [expanded, setExpanded] = createSignal(false)
|
const [expanded, setExpanded] = createSignal(false)
|
||||||
const parts = createMemo(() => sync.data.part[message.id])
|
const parts = createMemo(() => sync.data.part[message.id])
|
||||||
const prompt = createMemo(() => local.session.getMessageText(message))
|
|
||||||
const title = createMemo(() => message.summary?.title)
|
const title = createMemo(() => message.summary?.title)
|
||||||
const summary = createMemo(() => message.summary?.body)
|
const summary = createMemo(() => message.summary?.body)
|
||||||
const assistantMessages = createMemo(() => {
|
const assistantMessages = createMemo(() => {
|
||||||
@@ -581,6 +581,9 @@ export default function Page() {
|
|||||||
) as AssistantMessageType[]
|
) as AssistantMessageType[]
|
||||||
})
|
})
|
||||||
const working = createMemo(() => !summary())
|
const working = createMemo(() => !summary())
|
||||||
|
createEffect(() => {
|
||||||
|
setTimeout(() => setInitialized(!!title()), 10_000)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -589,9 +592,11 @@ export default function Page() {
|
|||||||
>
|
>
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<div class="py-2 flex flex-col items-start gap-2 self-stretch sticky top-0 bg-background-stronger z-10">
|
<div class="py-2 flex flex-col items-start gap-2 self-stretch sticky top-0 bg-background-stronger z-10">
|
||||||
<h1 class="text-14-medium text-text-strong overflow-hidden text-ellipsis min-w-0">
|
<div class="text-14-medium text-text-strong overflow-hidden text-ellipsis min-w-0">
|
||||||
{title() ?? prompt()}
|
<Show when={initialized()} fallback={<Typewriter as="h1" text={title()} />}>
|
||||||
</h1>
|
<h1>{title()}</h1>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Show when={title}>
|
<Show when={title}>
|
||||||
<div class="-mt-8">
|
<div class="-mt-8">
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export * from "./select-dialog"
|
|||||||
export * from "./tabs"
|
export * from "./tabs"
|
||||||
export * from "./basic-tool"
|
export * from "./basic-tool"
|
||||||
export * from "./tooltip"
|
export * from "./tooltip"
|
||||||
|
export * from "./typewriter"
|
||||||
|
|
||||||
export * from "../context/helper"
|
export * from "../context/helper"
|
||||||
export * from "../context/shiki"
|
export * from "../context/shiki"
|
||||||
|
|||||||
14
packages/ui/src/components/typewriter.css
Normal file
14
packages/ui/src/components/typewriter.css
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@keyframes blink {
|
||||||
|
0%,
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
51%,
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blinking-cursor {
|
||||||
|
animation: blink 1s step-end infinite;
|
||||||
|
}
|
||||||
54
packages/ui/src/components/typewriter.tsx
Normal file
54
packages/ui/src/components/typewriter.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { createEffect, Show, type ValidComponent } from "solid-js"
|
||||||
|
import { createStore } from "solid-js/store"
|
||||||
|
import { Dynamic } from "solid-js/web"
|
||||||
|
|
||||||
|
export const Typewriter = <T extends ValidComponent = "p">(props: {
|
||||||
|
text?: string
|
||||||
|
class?: string
|
||||||
|
as?: T
|
||||||
|
}) => {
|
||||||
|
const [store, setStore] = createStore({
|
||||||
|
typing: false,
|
||||||
|
displayed: "",
|
||||||
|
cursor: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const text = props.text
|
||||||
|
if (!text) return
|
||||||
|
|
||||||
|
let i = 0
|
||||||
|
setStore("typing", true)
|
||||||
|
setStore("displayed", "")
|
||||||
|
setStore("cursor", true)
|
||||||
|
|
||||||
|
const getTypingDelay = () => {
|
||||||
|
const random = Math.random()
|
||||||
|
if (random < 0.05) return 150 + Math.random() * 100
|
||||||
|
if (random < 0.15) return 80 + Math.random() * 60
|
||||||
|
return 30 + Math.random() * 50
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = () => {
|
||||||
|
if (i < text.length) {
|
||||||
|
setStore("displayed", text.slice(0, i + 1))
|
||||||
|
i++
|
||||||
|
setTimeout(type, getTypingDelay())
|
||||||
|
} else {
|
||||||
|
setStore("typing", false)
|
||||||
|
setTimeout(() => setStore("cursor", false), 2000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(type, 200)
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dynamic component={props.as || "p"} class={props.class}>
|
||||||
|
{store.displayed}
|
||||||
|
<Show when={store.cursor}>
|
||||||
|
<span classList={{ "blinking-cursor": !store.typing }}>│</span>
|
||||||
|
</Show>
|
||||||
|
</Dynamic>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -25,5 +25,6 @@
|
|||||||
@import "../components/select-dialog.css" layer(components);
|
@import "../components/select-dialog.css" layer(components);
|
||||||
@import "../components/tabs.css" layer(components);
|
@import "../components/tabs.css" layer(components);
|
||||||
@import "../components/tooltip.css" layer(components);
|
@import "../components/tooltip.css" layer(components);
|
||||||
|
@import "../components/typewriter.css" layer(components);
|
||||||
|
|
||||||
@import "./utilities.css" layer(utilities);
|
@import "./utilities.css" layer(utilities);
|
||||||
|
|||||||
Reference in New Issue
Block a user