diff options
| author | David Hill <[email protected]> | 2026-03-13 15:08:23 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-03-13 10:08:23 -0500 |
| commit | 536abea2e2ed3bee160cf16a12b23558ed6e3fa3 (patch) | |
| tree | 02aadf005ea56f86cf1b4ad42a47c03152a2c650 /packages/app/src/pages | |
| parent | c7a52b6a2d47c39fc2c3c6311355cd7b9286aac2 (diff) | |
| download | opencode-536abea2e2ed3bee160cf16a12b23558ed6e3fa3.tar.gz opencode-536abea2e2ed3bee160cf16a12b23558ed6e3fa3.zip | |
fix(app): restore sidebar dash and sync session spinner colors (#17384)
Diffstat (limited to 'packages/app/src/pages')
| -rw-r--r-- | packages/app/src/pages/layout/sidebar-items.tsx | 147 | ||||
| -rw-r--r-- | packages/app/src/pages/session/message-timeline.tsx | 4 |
2 files changed, 46 insertions, 105 deletions
diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index 04d898134..5ce526103 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -9,14 +9,13 @@ import { Tooltip } from "@opencode-ai/ui/tooltip" import { base64Encode } from "@opencode-ai/util/encode" import { getFilename } from "@opencode-ai/util/path" import { A, useNavigate, useParams } from "@solidjs/router" -import { type Accessor, createEffect, createMemo, For, type JSX, on, onCleanup, Show } from "solid-js" -import { createStore } from "solid-js/store" +import { type Accessor, createMemo, For, type JSX, Match, onCleanup, Show, Switch } from "solid-js" import { useGlobalSync } from "@/context/global-sync" import { useLanguage } from "@/context/language" import { getAvatarColors, type LocalProject, useLayout } from "@/context/layout" import { useNotification } from "@/context/notification" import { usePermission } from "@/context/permission" -import { agentColor } from "@/utils/agent" +import { messageAgentColor } from "@/utils/agent" import { sessionPermissionRequest } from "../session/composer/session-request-tree" import { hasProjectPermissions } from "./helpers" @@ -102,94 +101,46 @@ const SessionRow = (props: { warmPress: () => void warmFocus: () => void cancelHoverPrefetch: () => void -}): JSX.Element => { - const [slot, setSlot] = createStore({ - open: false, - show: false, - fade: false, - }) - - let f: number | undefined - const clear = () => { - if (f !== undefined) window.clearTimeout(f) - f = undefined - } - - onCleanup(clear) - createEffect( - on( - () => props.isWorking(), - (on, prev) => { - clear() - if (on) { - setSlot({ open: true, show: true, fade: false }) - return - } - if (prev) { - setSlot({ open: false, show: true, fade: true }) - f = window.setTimeout(() => setSlot({ show: false, fade: false }), 260) - return - } - setSlot({ open: false, show: false, fade: false }) - }, - { defer: true }, - ), - ) - - return ( - <A - href={`/${props.slug}/session/${props.session.id}`} - class={`relative flex items-center min-w-0 text-left w-full focus:outline-none transition-[padding] ${props.mobile ? "pr-7" : ""} group-hover/session:pr-7 group-focus-within/session:pr-7 group-active/session:pr-7 ${props.dense ? "py-0.5" : "py-1"}`} - onPointerDown={props.warmPress} - onPointerEnter={props.warmHover} - onPointerLeave={props.cancelHoverPrefetch} - onFocus={props.warmFocus} - onClick={() => { - props.setHoverSession(undefined) - if (props.sidebarOpened()) return - props.clearHoverProjectSoon() - }} - > - <Show when={!props.isWorking() && (props.hasPermissions() || props.hasError() || props.unseenCount() > 0)}> - <div - classList={{ - "absolute left-0 top-1/2 -translate-y-1/2 size-1.5 rounded-full": true, - "bg-surface-warning-strong": props.hasPermissions(), - "bg-text-diff-delete-base": !props.hasPermissions() && props.hasError(), - "bg-text-interactive-base": !props.hasPermissions() && !props.hasError() && props.unseenCount() > 0, - }} - aria-hidden="true" - /> - </Show> - - <div class="flex items-center min-w-0 grow-1"> - <div - class="shrink-0 flex items-center justify-center overflow-hidden transition-[width,margin] duration-300 ease-[cubic-bezier(0.22,1,0.36,1)]" - style={{ - width: slot.open ? "16px" : "0px", - "margin-right": slot.open ? "8px" : "0px", - }} - aria-hidden="true" - > - <Show when={slot.show}> - <div - class="transition-opacity duration-200 ease-out" - classList={{ - "opacity-0": slot.fade, - }} - > - <Spinner class="size-4" style={{ color: props.tint() ?? "var(--icon-interactive-base)" }} /> - </div> - </Show> - </div> - - <span class="text-14-regular text-text-strong grow-1 min-w-0 overflow-hidden text-ellipsis truncate"> - {props.session.title} - </span> +}): JSX.Element => ( + <A + href={`/${props.slug}/session/${props.session.id}`} + class={`flex items-center justify-between gap-3 min-w-0 text-left w-full focus:outline-none transition-[padding] ${props.mobile ? "pr-7" : ""} group-hover/session:pr-7 group-focus-within/session:pr-7 group-active/session:pr-7 ${props.dense ? "py-0.5" : "py-1"}`} + onPointerDown={props.warmPress} + onPointerEnter={props.warmHover} + onPointerLeave={props.cancelHoverPrefetch} + onFocus={props.warmFocus} + onClick={() => { + props.setHoverSession(undefined) + if (props.sidebarOpened()) return + props.clearHoverProjectSoon() + }} + > + <div class="flex items-center gap-1 w-full"> + <div + class="shrink-0 size-6 flex items-center justify-center" + style={{ color: props.tint() ?? "var(--icon-interactive-base)" }} + > + <Switch fallback={<Icon name="dash" size="small" class="text-icon-weak" />}> + <Match when={props.isWorking()}> + <Spinner class="size-[15px]" /> + </Match> + <Match when={props.hasPermissions()}> + <div class="size-1.5 rounded-full bg-surface-warning-strong" /> + </Match> + <Match when={props.hasError()}> + <div class="size-1.5 rounded-full bg-text-diff-delete-base" /> + </Match> + <Match when={props.unseenCount() > 0}> + <div class="size-1.5 rounded-full bg-text-interactive-base" /> + </Match> + </Switch> </div> - </A> - ) -} + <span class="text-14-regular text-text-strong grow-1 min-w-0 overflow-hidden text-ellipsis truncate"> + {props.session.title} + </span> + </div> + </A> +) const SessionHoverPreview = (props: { mobile?: boolean @@ -268,19 +219,7 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { }) const tint = createMemo(() => { - const messages = sessionStore.message[props.session.id] - if (!messages) return undefined - let user: Message | undefined - for (let i = messages.length - 1; i >= 0; i--) { - const message = messages[i] - if (message.role !== "user") continue - user = message - break - } - if (!user?.agent) return undefined - - const agent = sessionStore.agent.find((a) => a.name === user.agent) - return agentColor(user.agent, agent?.color) + return messageAgentColor(sessionStore.message[props.session.id], sessionStore.agent) }) const hoverMessages = createMemo(() => @@ -359,7 +298,7 @@ export const SessionItem = (props: SessionItemProps): JSX.Element => { return ( <div data-session-id={props.session.id} - class="group/session relative w-full rounded-md cursor-default pl-3 pr-3 transition-colors + class="group/session relative w-full rounded-md cursor-default pl-2 pr-3 transition-colors hover:bg-surface-raised-base-hover [&:has(:focus-visible)]:bg-surface-raised-base-hover has-[[data-expanded]]:bg-surface-raised-base-hover has-[.active]:bg-surface-base-active" > <Show diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx index b4a740c60..74f2e8c2c 100644 --- a/packages/app/src/pages/session/message-timeline.tsx +++ b/packages/app/src/pages/session/message-timeline.tsx @@ -27,6 +27,7 @@ import { usePlatform } from "@/context/platform" import { useSettings } from "@/context/settings" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" +import { messageAgentColor } from "@/utils/agent" import { parseCommentNote, readCommentMetadata } from "@/utils/comment-note" type MessageComment = { @@ -246,6 +247,7 @@ export function MessageTimeline(props: { return sync.data.session_status[id] ?? idle }) const working = createMemo(() => !!pending() || sessionStatus().type !== "idle") + const tint = createMemo(() => messageAgentColor(sessionMessages(), sync.data.agent)) const [slot, setSlot] = createStore({ open: false, @@ -689,7 +691,7 @@ export function MessageTimeline(props: { "opacity-0": slot.fade, }} > - <Spinner class="size-4" style={{ color: "var(--icon-interactive-base)" }} /> + <Spinner class="size-4" style={{ color: tint() ?? "var(--icon-interactive-base)" }} /> </div> </Show> </div> |
