mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 05:43:55 +00:00
fix(app): less auto-expand/collapse
This commit is contained in:
parent
f386137fba
commit
c53d1d3ad8
@ -58,11 +58,9 @@ export function ContextToolGroupHeader(props: {
|
||||
<ToolCall
|
||||
variant="row"
|
||||
icon="magnifying-glass-menu"
|
||||
open={!props.pending && props.open}
|
||||
showArrow={!props.pending}
|
||||
onOpenChange={(v) => {
|
||||
if (!props.pending) props.onOpenChange(v)
|
||||
}}
|
||||
open={props.open}
|
||||
showArrow
|
||||
onOpenChange={props.onOpenChange}
|
||||
trigger={
|
||||
<div data-component="context-tool-group-trigger" data-pending={props.pending || undefined}>
|
||||
<span
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { usePageVisibility } from "@solid-primitives/page-visibility"
|
||||
import { Component, createEffect, createMemo, createSignal, For, Match, on, Show, Switch, type JSX } from "solid-js"
|
||||
import stripAnsi from "strip-ansi"
|
||||
import { createStore } from "solid-js/store"
|
||||
@ -39,7 +38,7 @@ import { TextShimmer } from "./text-shimmer"
|
||||
import { list } from "./text-utils"
|
||||
import { GrowBox } from "./grow-box"
|
||||
import { COLLAPSIBLE_SPRING } from "./motion"
|
||||
import { busy, hold, createThrottledValue, useToolFade, useContextToolPending } from "./tool-utils"
|
||||
import { busy, createThrottledValue, useToolFade, useContextToolPending } from "./tool-utils"
|
||||
import { ContextToolGroupHeader, ContextToolExpandedList, ContextToolRollingResults } from "./context-tool-results"
|
||||
import { ShellRollingResults } from "./shell-rolling-results"
|
||||
|
||||
@ -273,19 +272,6 @@ function createGroupOpenState() {
|
||||
return { read, controlled, write }
|
||||
}
|
||||
|
||||
function shouldCollapseGroup(
|
||||
statuses: (string | undefined)[],
|
||||
opts: { afterTool?: boolean; groupTail?: boolean; working?: boolean },
|
||||
pageVisible: () => boolean,
|
||||
) {
|
||||
if (opts.afterTool) return true
|
||||
if (opts.groupTail === false) return true
|
||||
if (!pageVisible()) return false
|
||||
if (opts.working) return false
|
||||
if (!statuses.length) return false
|
||||
return !statuses.some((s) => busy(s))
|
||||
}
|
||||
|
||||
function renderable(part: PartType, showReasoningSummaries = true) {
|
||||
if (part.type === "tool") {
|
||||
if (HIDDEN_TOOLS.has(part.tool)) return false
|
||||
@ -363,7 +349,6 @@ export function AssistantParts(props: {
|
||||
}) {
|
||||
const data = useData()
|
||||
const emptyParts: PartType[] = []
|
||||
const pageVisible = usePageVisibility()
|
||||
const groupState = createGroupOpenState()
|
||||
const grouped = createMemo(() => {
|
||||
const keys: string[] = []
|
||||
@ -481,24 +466,9 @@ export function AssistantParts(props: {
|
||||
return COLLAPSIBLE_SPRING
|
||||
})
|
||||
const contextOpen = createMemo(() => {
|
||||
const collapse = (
|
||||
afterTool?: boolean,
|
||||
groupTail?: boolean,
|
||||
group?: { part: ToolPart; message: AssistantMessage }[],
|
||||
) =>
|
||||
shouldCollapseGroup(
|
||||
group?.map((item) => item.part.state.status) ?? [],
|
||||
{
|
||||
afterTool,
|
||||
groupTail,
|
||||
working: props.working,
|
||||
},
|
||||
pageVisible,
|
||||
)
|
||||
const value = ctx()
|
||||
if (value) return groupState.read(value.groupKey, collapse(value.afterTool, value.tail, value.parts))
|
||||
const entry = part()
|
||||
return groupState.read(entry?.groupKey, collapse(entry?.afterTool, entry?.groupTail, entry?.groupParts))
|
||||
if (value) return groupState.read(value.groupKey, true)
|
||||
return groupState.read(part()?.groupKey, true)
|
||||
})
|
||||
const visible = createMemo(() => {
|
||||
if (!context()) return true
|
||||
@ -544,9 +514,7 @@ export function AssistantParts(props: {
|
||||
ctxPartsPrev = result
|
||||
return result
|
||||
})
|
||||
const ctxPendingRaw = useContextToolPending(ctxParts, () => !!(props.working && ctx()?.tail))
|
||||
const ctxPending = ctxPendingRaw
|
||||
const ctxHoldOpen = hold(ctxPendingRaw)
|
||||
const ctxPending = useContextToolPending(ctxParts, () => !!(props.working && ctx()?.tail))
|
||||
const shell = createMemo(() => {
|
||||
const value = part()
|
||||
if (!value) return
|
||||
@ -598,12 +566,20 @@ export function AssistantParts(props: {
|
||||
onOpenChange={(value: boolean) => groupState.write(entry().groupKey, value)}
|
||||
/>
|
||||
</PartGrow>
|
||||
<ContextToolExpandedList parts={ctxParts()} expanded={!ctxPending() && contextOpen()} />
|
||||
<ContextToolRollingResults parts={ctxParts()} pending={ctxHoldOpen()} />
|
||||
<ContextToolExpandedList parts={ctxParts()} expanded={contextOpen() && !ctxPending()} />
|
||||
<ContextToolRollingResults parts={ctxParts()} pending={contextOpen() && ctxPending()} />
|
||||
</>
|
||||
)}
|
||||
</Show>
|
||||
<Show when={shell()}>{(value) => <ShellRollingResults part={value()} animate={props.animate} />}</Show>
|
||||
<Show when={shell()}>
|
||||
{(value) => (
|
||||
<ShellRollingResults
|
||||
part={value()}
|
||||
animate={props.animate}
|
||||
defaultOpen={props.shellToolDefaultOpen}
|
||||
/>
|
||||
)}
|
||||
</Show>
|
||||
<Show when={!shell() ? part() : undefined}>
|
||||
{(entry) => (
|
||||
<Show when={!entry().context}>
|
||||
|
||||
@ -10,15 +10,7 @@ import { TextShimmer } from "./text-shimmer"
|
||||
import { Tooltip } from "./tooltip"
|
||||
import { GROW_SPRING } from "./motion"
|
||||
import { useSpring } from "./motion-spring"
|
||||
import {
|
||||
busy,
|
||||
createThrottledValue,
|
||||
hold,
|
||||
updateScrollMask,
|
||||
useCollapsible,
|
||||
useRowWipe,
|
||||
useToolFade,
|
||||
} from "./tool-utils"
|
||||
import { busy, createThrottledValue, updateScrollMask, useCollapsible, useRowWipe, useToolFade } from "./tool-utils"
|
||||
|
||||
function ShellRollingSubtitle(props: { text: string; animate?: boolean }) {
|
||||
let ref: HTMLSpanElement | undefined
|
||||
@ -176,24 +168,17 @@ function ShellExpanded(props: { cmd: string; out: string; open: boolean }) {
|
||||
)
|
||||
}
|
||||
|
||||
export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }) {
|
||||
export function ShellRollingResults(props: { part: ToolPart; animate?: boolean; defaultOpen?: boolean }) {
|
||||
const i18n = useI18n()
|
||||
const reduce = useReducedMotion()
|
||||
const wiped = new Set<string>()
|
||||
const [mounted, setMounted] = createSignal(false)
|
||||
const [userToggled, setUserToggled] = createSignal(false)
|
||||
const [userOpen, setUserOpen] = createSignal(false)
|
||||
const [open, setOpen] = createSignal(props.defaultOpen ?? true)
|
||||
onMount(() => setMounted(true))
|
||||
const state = createMemo(() => props.part.state as Record<string, any>)
|
||||
const pending = createMemo(() => busy(props.part.state.status))
|
||||
const autoOpen = hold(pending, 2000)
|
||||
const effectiveOpen = createMemo(() => {
|
||||
if (pending()) return true
|
||||
if (userToggled()) return userOpen()
|
||||
return autoOpen()
|
||||
})
|
||||
const expanded = createMemo(() => !pending() && !autoOpen() && userToggled() && userOpen())
|
||||
const previewOpen = createMemo(() => effectiveOpen() && !expanded())
|
||||
const expanded = createMemo(() => open() && !pending())
|
||||
const previewOpen = createMemo(() => open() && pending())
|
||||
const command = createMemo(() => {
|
||||
const value = state().input?.command ?? state().metadata?.command
|
||||
if (typeof value === "string") return value
|
||||
@ -217,12 +202,10 @@ export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }
|
||||
const headerHeight = useSpring(() => (mounted() ? 37 : 0), GROW_SPRING)
|
||||
let headerClipRef: HTMLDivElement | undefined
|
||||
const handleHeaderClick = () => {
|
||||
if (pending()) return
|
||||
const el = headerClipRef
|
||||
const viewport = el?.closest(".scroll-view__viewport") as HTMLElement | null
|
||||
const beforeY = el?.getBoundingClientRect().top ?? 0
|
||||
setUserToggled(true)
|
||||
setUserOpen((prev) => !prev)
|
||||
setOpen((prev) => !prev)
|
||||
if (viewport && el) {
|
||||
requestAnimationFrame(() => {
|
||||
const afterY = el.getBoundingClientRect().top
|
||||
@ -249,7 +232,7 @@ export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }
|
||||
ref={headerClipRef}
|
||||
data-slot="shell-rolling-header-clip"
|
||||
data-scroll-preserve
|
||||
data-clickable={!pending() ? "true" : "false"}
|
||||
data-clickable="true"
|
||||
onClick={handleHeaderClick}
|
||||
style={{ height: `${skip() ? (mounted() ? 37 : 0) : headerHeight()}px`, overflow: "clip" }}
|
||||
>
|
||||
@ -258,13 +241,11 @@ export function ShellRollingResults(props: { part: ToolPart; animate?: boolean }
|
||||
<TextShimmer text={i18n.t("ui.tool.shell")} active={pending()} />
|
||||
</span>
|
||||
<Show when={subtitle()}>{(text) => <ShellRollingSubtitle text={text()} animate={props.animate} />}</Show>
|
||||
<Show when={!pending()}>
|
||||
<span data-slot="shell-rolling-actions">
|
||||
<span data-slot="shell-rolling-arrow" data-open={effectiveOpen() ? "true" : "false"}>
|
||||
<Icon name="chevron-down" size="small" />
|
||||
</span>
|
||||
<span data-slot="shell-rolling-actions">
|
||||
<span data-slot="shell-rolling-arrow" data-open={open() ? "true" : "false"}>
|
||||
<Icon name="chevron-down" size="small" />
|
||||
</span>
|
||||
</Show>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user