Group the rail's open bot with its sessions
The active row and its session previews now share one highlighted card, with a hairline thread from the bot's icon down to the last session.
This commit is contained in:
@@ -27,7 +27,8 @@ type Props = {
|
||||
/**
|
||||
* 48px rail row. Status is the face and the subtitle (the bot's status
|
||||
* line while it has one): no badges, spinners or state dots.
|
||||
* Selected is ink at 5%, never a hue.
|
||||
* The selected background (ink at 5%, never a hue) is painted by
|
||||
* RailBotCard, which also holds the sessions.
|
||||
*/
|
||||
export default function BotRow({ bot, href, selected, subtitle }: Props) {
|
||||
const hue = (bot.hue || null) as BotHue | null;
|
||||
@@ -48,7 +49,7 @@ export default function BotRow({ bot, href, selected, subtitle }: Props) {
|
||||
"flex shrink-0 h-12 items-center gap-3 rounded-default px-1 @rail:px-3 border-0 leading-normal",
|
||||
"hover:opacity-100 hover:bg-sunken transition-colors duration-[var(--m-fast)]",
|
||||
"focus-visible:ring-2 focus-visible:ring-ink focus-visible:ring-offset-2 focus-visible:ring-offset-paper",
|
||||
selected && "bg-ink/5 hover:bg-ink/5",
|
||||
selected && "hover:bg-transparent hover:dark:bg-transparent",
|
||||
)}
|
||||
>
|
||||
<BotAvatar image_media_id={bot.image_media_id} hue={hue} face={(bot.face || "idle") as BotFace} />
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import Stack from "@moduletrace/twui/layout/Stack";
|
||||
import type { ReactNode } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
type Props = {
|
||||
/**
|
||||
* Groups the open bot's row with its sessions, so the active background
|
||||
* covers both and the sessions read as belonging to that bot.
|
||||
*/
|
||||
selected?: boolean;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function RailBotCard({ selected, children }: Props) {
|
||||
return (
|
||||
<Stack
|
||||
className={twMerge(
|
||||
"w-full shrink-0 flex-col gap-0! items-stretch rounded-default py-1",
|
||||
selected && "bg-ink/5",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { BotWithLastMessage } from "@/src/types";
|
||||
import BotRow from "./bot-row";
|
||||
import RailBotCard from "./rail-bot-card";
|
||||
import RailBotSessions from "./rail-bot-sessions";
|
||||
import Divider from "@moduletrace/twui/layout/Divider";
|
||||
|
||||
type Props = {
|
||||
bot: BotWithLastMessage;
|
||||
@@ -12,11 +14,24 @@ type Props = {
|
||||
/**
|
||||
* A worker in the rail, and its sessions while it is the open conversation.
|
||||
*/
|
||||
export default function RailBotEntry({ bot, href, selected, workspace_id }: Props) {
|
||||
export default function RailBotEntry({
|
||||
bot,
|
||||
href,
|
||||
selected,
|
||||
workspace_id,
|
||||
}: Props) {
|
||||
return (
|
||||
<>
|
||||
<RailBotCard selected={selected}>
|
||||
<BotRow bot={bot} href={href} selected={selected} />
|
||||
{selected ? <RailBotSessions key={bot.id} bot={bot} workspace_id={workspace_id} /> : null}
|
||||
</>
|
||||
{selected ? (
|
||||
<>
|
||||
<RailBotSessions
|
||||
key={bot.id}
|
||||
bot={bot}
|
||||
workspace_id={workspace_id}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</RailBotCard>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export default function RailBotSessionRow({ session, loading, disabled, onOpen }
|
||||
buttonContentProps={{ className: "w-full min-w-0 flex-nowrap" }}
|
||||
className={twMerge(
|
||||
"w-full h-8 shrink-0 justify-start! items-center! gap-2! rounded-default px-2! @rail:pl-14! text-left text-ink dark:text-ink hover:bg-ink/5 hover:dark:bg-ink/5 focus-visible:ring-2 focus-visible:ring-ink",
|
||||
active && "bg-sunken hover:bg-sunken hover:dark:bg-sunken opacity-100!",
|
||||
active && "bg-transparent hover:bg-transparent hover:dark:bg-transparent opacity-100!",
|
||||
)}
|
||||
>
|
||||
<Span
|
||||
|
||||
@@ -30,15 +30,21 @@ export default function RailBotSessions({ bot, workspace_id }: Props) {
|
||||
|
||||
return (
|
||||
<Stack className="hidden @rail:flex w-full shrink-0 flex-col gap-0! items-stretch pb-1">
|
||||
{shown.map((session) => (
|
||||
<RailBotSessionRow
|
||||
key={session.id}
|
||||
session={session}
|
||||
loading={sessions.busy_id == session.id}
|
||||
disabled={Boolean(sessions.busy_id)}
|
||||
onOpen={() => sessions.reopenSession({ session_id: Number(session.id) })}
|
||||
<Stack className="relative w-full flex-col gap-0! items-stretch">
|
||||
<Span
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute left-7 -translate-x-1/2 -top-2 bottom-0 w-px bg-hairline"
|
||||
/>
|
||||
))}
|
||||
{shown.map((session) => (
|
||||
<RailBotSessionRow
|
||||
key={session.id}
|
||||
session={session}
|
||||
loading={sessions.busy_id == session.id}
|
||||
disabled={Boolean(sessions.busy_id)}
|
||||
onOpen={() => sessions.reopenSession({ session_id: Number(session.id) })}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
{sessions.sessions.length > AppData.RailRecentSessions ? (
|
||||
<BotSessionsModal
|
||||
bot={bot}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { AppContext } from "@/src/pages/__root";
|
||||
import canManageCrew from "@/src/utils/rbac/can-manage-crew";
|
||||
import type { BotWithLastMessage, WorkspaceWithActivity } from "@/src/types";
|
||||
import CoordinatorRow from "./coordinator-row";
|
||||
import RailBotCard from "./rail-bot-card";
|
||||
import RailBotSessions from "./rail-bot-sessions";
|
||||
import RailBotsSection from "./rail-bots-section";
|
||||
import RailSectionAddButton from "./rail-section-add-button";
|
||||
@@ -28,7 +29,7 @@ export default function RailCrewList({ bots, workspaces, selected_id }: Props) {
|
||||
return (
|
||||
<>
|
||||
{coordinator ? (
|
||||
<>
|
||||
<RailBotCard selected={coordinator.id === selected_id}>
|
||||
<CoordinatorRow
|
||||
bot={coordinator}
|
||||
bots={bots}
|
||||
@@ -37,7 +38,7 @@ export default function RailCrewList({ bots, workspaces, selected_id }: Props) {
|
||||
{coordinator.id === selected_id ? (
|
||||
<RailBotSessions key={coordinator.id} bot={coordinator} />
|
||||
) : null}
|
||||
</>
|
||||
</RailBotCard>
|
||||
) : null}
|
||||
<RailBotsSection
|
||||
action={<RailSectionAddButton title="Add a bot" onClick={() => openForm({ kind: "bot" })} />}
|
||||
|
||||
Reference in New Issue
Block a user