diff --git a/apps/app/src/components/promptbox/FollowUpPromptBox.stories.tsx b/apps/app/src/components/promptbox/FollowUpPromptBox.stories.tsx index 8478b7c755..5b444fd139 100644 --- a/apps/app/src/components/promptbox/FollowUpPromptBox.stories.tsx +++ b/apps/app/src/components/promptbox/FollowUpPromptBox.stories.tsx @@ -327,7 +327,6 @@ const dirtyContextBannerSection = const contextBannerElement: ReactNode = dirtyContextBannerSection ? ( @@ -349,13 +349,13 @@ const contextBannerElement: ReactNode = dirtyContextBannerSection ? ( const archivedContextBannerElement: ReactNode = ( @@ -363,13 +363,13 @@ const archivedContextBannerElement: ReactNode = ( const environmentGoneContextBannerElement: ReactNode = ( diff --git a/apps/app/src/components/promptbox/banner/QueuedMessagesList.stories.tsx b/apps/app/src/components/promptbox/banner/QueuedMessagesList.stories.tsx index 6621d70f06..02cd3e366f 100644 --- a/apps/app/src/components/promptbox/banner/QueuedMessagesList.stories.tsx +++ b/apps/app/src/components/promptbox/banner/QueuedMessagesList.stories.tsx @@ -281,14 +281,6 @@ function ReorderableQueuedMessagesList() { ); } -export function Reorderable() { - return ( - - - - ); -} - export function Overview() { return ( diff --git a/apps/app/src/components/promptbox/banner/ThreadGoalCard.stories.tsx b/apps/app/src/components/promptbox/banner/ThreadGoalCard.stories.tsx new file mode 100644 index 0000000000..1a44285cd7 --- /dev/null +++ b/apps/app/src/components/promptbox/banner/ThreadGoalCard.stories.tsx @@ -0,0 +1,96 @@ +import { useState } from "react"; +import type { ThreadTimelineGoal } from "@bb/domain"; +import { StoryCard, StoryRow } from "../../../../.ladle/story-card"; +import { ThreadGoalCard } from "./ThreadGoalCard"; + +export default { + title: "promptbox/banner/Goal Card", +}; + +function Stage({ children }: { children: React.ReactNode }) { + return
{children}
; +} + +const activeGoal: ThreadTimelineGoal = { + sourceSeq: 42, + updatedAt: Date.now() - 12_000, + objective: + "Ship the prompt context banner cleanup: keep active state segments first, compact metadata into icon-only controls, and preserve quick actions for single-segment states.", + status: "active", + tokenBudget: 80_000, + tokensUsed: 27_450, + timeUsedSeconds: 1_238, +}; + +const unboundedGoal: ThreadTimelineGoal = { + ...activeGoal, + sourceSeq: 43, + objective: + "Audit the composer stack and identify the smallest set of follow-up UI fixes needed before merging.", + tokenBudget: null, + tokensUsed: 9_820, + timeUsedSeconds: 412, +}; + +function ToggleableGoalCard({ + goal, + initiallyExpanded = false, +}: { + goal: ThreadTimelineGoal; + initiallyExpanded?: boolean; +}) { + const [expanded, setExpanded] = useState(initiallyExpanded); + return ( + setExpanded((value) => !value)} + /> + ); +} + +function FauxComposer() { + return ( +
+
+ Reply to the agent... +
+
+ + gpt-5.5 + +
+
+ ); +} + +export function Overview() { + return ( + + + +
+ + +
+
+
+ + + + + + + + + + +
+ ); +} diff --git a/apps/app/src/components/promptbox/banner/ThreadGoalCard.tsx b/apps/app/src/components/promptbox/banner/ThreadGoalCard.tsx index eec21cd6d6..2903317773 100644 --- a/apps/app/src/components/promptbox/banner/ThreadGoalCard.tsx +++ b/apps/app/src/components/promptbox/banner/ThreadGoalCard.tsx @@ -5,15 +5,6 @@ import { cn } from "@/lib/utils"; const GOAL_CARD_ROW_HEIGHT = 32; -function GoalActiveBadge() { - return ( - - - Active - - ); -} - function formatDuration(seconds: number): string { if (seconds < 60) { return `${Math.round(seconds)}s`; @@ -48,10 +39,10 @@ const TOGGLE_ID = "thread-goal-card-toggle"; /** * Collapsible goal card for the prompt stack above the composer. Surfaces the * provider's current durable objective (Codex `thread/goal/*` events projected - * onto the timeline). Collapsed: objective + Active badge. Expanded: full - * objective + token/time usage. Mirrors the ThreadPromptContextBanner section - * chrome. Only rendered while the goal is active — once the provider marks it - * complete (or paused / budget-limited) it drops out of the prompt stack. + * onto the timeline). Collapsed: objective. Expanded: full objective + + * token/time usage. Mirrors the ThreadPromptContextBanner section chrome. Only + * rendered while the goal is active — once the provider marks it complete (or + * paused / budget-limited) it drops out of the prompt stack. */ export function ThreadGoalCard({ goal, @@ -82,7 +73,10 @@ export function ThreadGoalCard({ className="size-3.5 shrink-0 text-muted-foreground" aria-hidden="true" /> - + {goal.objective}