|
1 | | -import { For, createEffect, createMemo, on, onCleanup, Show, Index, type JSX } from "solid-js" |
| 1 | +import { For, createEffect, createMemo, on, onCleanup, Show, Index, type JSX, createSignal } from "solid-js" |
2 | 2 | import { createStore, produce } from "solid-js/store" |
3 | 3 | import { useNavigate } from "@solidjs/router" |
4 | 4 | import { useMutation } from "@tanstack/solid-query" |
@@ -30,6 +30,7 @@ import { useSDK } from "@/context/sdk" |
30 | 30 | import { useSync } from "@/context/sync" |
31 | 31 | import { messageAgentColor } from "@/utils/agent" |
32 | 32 | import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note" |
| 33 | +import { makeTimer } from "@solid-primitives/timer" |
33 | 34 |
|
34 | 35 | type MessageComment = { |
35 | 36 | path: string |
@@ -250,38 +251,21 @@ export function MessageTimeline(props: { |
250 | 251 | const working = createMemo(() => !!pending() || sessionStatus().type !== "idle") |
251 | 252 | const tint = createMemo(() => messageAgentColor(sessionMessages(), sync.data.agent)) |
252 | 253 |
|
253 | | - const [slot, setSlot] = createStore({ |
254 | | - open: false, |
255 | | - show: false, |
256 | | - fade: false, |
| 254 | + const [timeoutDone, setTimeoutDone] = createSignal(true) |
| 255 | + |
| 256 | + const workingStatus = createMemo<"hidden" | "showing" | "hiding">((prev) => { |
| 257 | + if (working()) return "showing" |
| 258 | + if (prev === "showing" || !timeoutDone()) return "hiding" |
| 259 | + return "hidden" |
257 | 260 | }) |
258 | 261 |
|
259 | | - let f: number | undefined |
260 | | - const clear = () => { |
261 | | - if (f !== undefined) window.clearTimeout(f) |
262 | | - f = undefined |
263 | | - } |
| 262 | + createEffect(() => { |
| 263 | + if (workingStatus() !== "hiding") return |
| 264 | + |
| 265 | + setTimeoutDone(false) |
| 266 | + makeTimer(() => setTimeoutDone(true), 260, setTimeout) |
| 267 | + }) |
264 | 268 |
|
265 | | - onCleanup(clear) |
266 | | - createEffect( |
267 | | - on( |
268 | | - working, |
269 | | - (on, prev) => { |
270 | | - clear() |
271 | | - if (on) { |
272 | | - setSlot({ open: true, show: true, fade: false }) |
273 | | - return |
274 | | - } |
275 | | - if (prev) { |
276 | | - setSlot({ open: false, show: true, fade: true }) |
277 | | - f = window.setTimeout(() => setSlot({ show: false, fade: false }), 260) |
278 | | - return |
279 | | - } |
280 | | - setSlot({ open: false, show: false, fade: false }) |
281 | | - }, |
282 | | - { defer: true }, |
283 | | - ), |
284 | | - ) |
285 | 269 | const activeMessageID = createMemo(() => { |
286 | 270 | const parentID = pending()?.parentID |
287 | 271 | if (parentID) { |
@@ -676,17 +660,15 @@ export function MessageTimeline(props: { |
676 | 660 | <div |
677 | 661 | class="shrink-0 flex items-center justify-center overflow-hidden transition-[width,margin] duration-300 ease-[cubic-bezier(0.22,1,0.36,1)]" |
678 | 662 | style={{ |
679 | | - width: slot.open ? "16px" : "0px", |
680 | | - "margin-right": slot.open ? "8px" : "0px", |
| 663 | + width: working() ? "16px" : "0px", |
| 664 | + "margin-right": working() ? "8px" : "0px", |
681 | 665 | }} |
682 | 666 | aria-hidden="true" |
683 | 667 | > |
684 | | - <Show when={slot.show}> |
| 668 | + <Show when={workingStatus() !== "hidden"}> |
685 | 669 | <div |
686 | 670 | class="transition-opacity duration-200 ease-out" |
687 | | - classList={{ |
688 | | - "opacity-0": slot.fade, |
689 | | - }} |
| 671 | + classList={{ "opacity-0": workingStatus() === "hiding" }} |
690 | 672 | > |
691 | 673 | <Spinner class="size-4" style={{ color: tint() ?? "var(--icon-interactive-base)" }} /> |
692 | 674 | </div> |
@@ -912,7 +894,6 @@ export function MessageTimeline(props: { |
912 | 894 | </div> |
913 | 895 | </div> |
914 | 896 | </Show> |
915 | | - |
916 | 897 | <div |
917 | 898 | role="log" |
918 | 899 | class="flex flex-col gap-12 items-start justify-start pb-16 transition-[margin]" |
|
0 commit comments