Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions dashboard/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,44 @@ html.is-electron.is-fullscreen .app-shell {
30% { transform: translateY(-4px); opacity: 1; }
}

/* Chat stage — thought-bubble thinking dots */
.stage-thinking-dot {
animation: typing-dot 1.2s ease-in-out infinite;
}

/* Chat stage — slow ambient aurora drift behind the 3D agent */
@keyframes stage-aurora {
0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: 0.45; }
50% { transform: translate3d(4%, -3%, 0) scale(1.12); opacity: 0.75; }
}

.stage-aurora {
animation: stage-aurora 14s ease-in-out infinite;
}

.stage-aurora-slow {
animation: stage-aurora 22s ease-in-out infinite reverse;
}

/* Chat stage — gentle bob for the floating quick-action chips */
@keyframes stage-quick-float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-9px); }
}

.stage-quick-float {
animation: stage-quick-float 5.5s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
.stage-aurora,
.stage-aurora-slow,
.stage-thinking-dot,
.stage-quick-float {
animation: none;
}
}

/* Memory page — neural pulse traveling along SVG connection lines */
@keyframes dash-travel {
from { stroke-dashoffset: 24; }
Expand Down
48 changes: 47 additions & 1 deletion dashboard/src/v2/ChatPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { InvocationRoutingWidget } from "./components/chat/widgets/InvocationRou
import { InvocationContainerWidget } from "./components/chat/widgets/InvocationContainerWidget.js";
import { TruncatedSystemBubble } from "./components/chat/TruncatedSystemBubble.js";
import { WorkingBubble } from "./components/chat/WorkingBubble.js";
import { CinematicStage } from "./components/chat/cinematic/CinematicStage.js";
import { ConfirmDialog } from "./components/ui/ConfirmDialog.js";
import { ActionFeedbackRegion } from "./components/ui/ActionFeedbackRegion.js";
import { ProviderLogo } from "./components/ui/ProviderLogo.js";
Expand Down Expand Up @@ -354,6 +355,51 @@ export const ChatPage: FunctionComponent = () => {
};

const renderDetail = () => {
if (chatMode === "stage") {
// Prefer the preset of the most recent agent reply; fall back to the
// thread/connection-linked preset (getLinkedAgentPreset handles both).
let stagePreset;
for (let i = messages.length - 1; i >= 0 && !stagePreset; i--) {
const message = messages[i];
if (message.direction !== "dashboard_to_connection" && message.authorType !== "system") {
stagePreset = getLinkedAgentPreset(message);
}
}
if (!stagePreset) {
stagePreset = getLinkedAgentPreset({ metadata: undefined } as (typeof messages)[0]);
}
return (
<>
<ConfirmDialog isOpen={isConfirmOpen} options={confirmOptions} onConfirm={handleConfirm} onCancel={handleCancel} />
{feedback.status !== "idle" && (
<div className="absolute top-4 right-4 z-50 shadow-lg">
<ActionFeedbackRegion status={feedback.status} message={feedback.message} onDismiss={clearFeedback} />
</div>
)}
<div id="chat-panel" role="tabpanel" aria-labelledby="tab-stage" className="flex flex-1 min-h-0 flex-col overflow-hidden">
<CinematicStage
selectedProject={selectedProject}
selectedThread={selectedThread}
messages={messages}
threadMessagesLoading={threadsLoading || threadMessagesLoading}
hasWorkingReply={hasWorkingReply}
runningInvocationCount={runningInvocationCount}
sending={sending}
error={error}
input={input}
setInput={setInput}
handleSend={handleSend}
navigateHistory={navigateHistory}
composerRef={composerRef}
activeConnection={activeConnection}
agentPreset={stagePreset}
onOpenThreads={() => setChatMode("threads")}
/>
</div>
</>
);
}

if (chatMode === "threads") {
return (
<>
Expand Down Expand Up @@ -823,7 +869,7 @@ export const ChatPage: FunctionComponent = () => {
invocationCount={displayedInvocationTotal}
runningInvocationCount={runningInvocationCount}
error={error}
railSlot={renderRail()}
railSlot={chatMode === "stage" ? null : renderRail()}
detailSlot={renderDetail()}
/>
);
Expand Down
Loading