Merge origin/main into feat/graph-data-viz
Resolve App.tsx header conflict: keep main's "Privacy-limited" badge AND the "Team memory" graph button (both in the header action group). server.ts and backend/package.json auto-merged cleanly — main's closeMemory/shutdown and the graph:seed script are both preserved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -50,10 +50,10 @@ export function CreatePodForm({
|
||||
if (!open) {
|
||||
return (
|
||||
<button
|
||||
className="group flex min-h-64 flex-col items-center justify-center gap-3 rounded-xl border border-dashed bg-card p-6 text-center transition hover:bg-muted/30"
|
||||
className="group flex min-h-64 flex-col items-center justify-center gap-3 rounded-lg border border-dashed bg-card p-6 text-center shadow-sm transition hover:bg-muted/30 hover:ring-1 hover:ring-black/10"
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<span className="grid size-9 place-items-center rounded-lg bg-muted transition group-hover:bg-background">
|
||||
<span className="grid size-9 place-items-center rounded-md bg-muted transition group-hover:bg-background">
|
||||
<PlusIcon className="size-4 text-muted-foreground" />
|
||||
</span>
|
||||
<span className="text-sm font-medium">New pod</span>
|
||||
@@ -68,7 +68,7 @@ export function CreatePodForm({
|
||||
<Card className={cn(compact && 'w-full border-0 shadow-none ring-0')}>
|
||||
<CardHeader>
|
||||
<CardTitle>New pod</CardTitle>
|
||||
<CardDescription>Keep the room name short and specific.</CardDescription>
|
||||
<CardDescription>Create a focused room.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
@@ -117,7 +117,7 @@ export function CreatePodForm({
|
||||
Cancel
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={submit} disabled={busy || !name.trim()}>
|
||||
<Button className="min-w-20" onClick={submit} disabled={busy || !name.trim()}>
|
||||
Create
|
||||
</Button>
|
||||
</CardFooter>
|
||||
|
||||
@@ -84,10 +84,12 @@ export function PodCard({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card className="min-h-64 transition duration-200 hover:-translate-y-0.5 hover:ring-foreground/15">
|
||||
<Card className="min-h-64 transition duration-200 hover:-translate-y-0.5 hover:shadow-[0_2px_6px_rgba(0,0,0,0.06),0_28px_70px_rgba(0,0,0,0.06)] hover:ring-black/15">
|
||||
<CardHeader>
|
||||
<CardTitle className="truncate">{pod.name}</CardTitle>
|
||||
<CardDescription className="truncate">{pod.repo || 'No repository set'}</CardDescription>
|
||||
<CardTitle className="truncate text-[1.05rem]">{pod.name}</CardTitle>
|
||||
<CardDescription className="truncate font-mono text-xs">
|
||||
{pod.repo || 'No repository set'}
|
||||
</CardDescription>
|
||||
<CardAction>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
@@ -121,7 +123,7 @@ export function PodCard({
|
||||
{pod.description || 'Focused workspace for live engineering coordination.'}
|
||||
</p>
|
||||
</div>
|
||||
<Badge variant={active ? 'default' : 'secondary'}>
|
||||
<Badge variant={active ? 'default' : 'secondary'} className="rounded-md">
|
||||
{active ? `${presence.length} live` : 'quiet'}
|
||||
</Badge>
|
||||
</div>
|
||||
@@ -175,7 +177,11 @@ export function PodCard({
|
||||
<VideoIcon data-icon="inline-start" />
|
||||
Join
|
||||
</Button>
|
||||
<Button onClick={() => submitMember(true)} disabled={busy || !newMember.trim()}>
|
||||
<Button
|
||||
className="min-w-28"
|
||||
onClick={() => submitMember(true)}
|
||||
disabled={busy || !newMember.trim()}
|
||||
>
|
||||
Add and join
|
||||
</Button>
|
||||
</CardFooter>
|
||||
|
||||
@@ -185,8 +185,8 @@ export function PodView({
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background text-foreground">
|
||||
<div className="mx-auto flex min-h-screen w-full max-w-7xl flex-col gap-5 px-4 py-4 sm:px-6 lg:px-8">
|
||||
<header className="flex items-center justify-between gap-4 border-b pb-4">
|
||||
<div className="mx-auto flex min-h-screen w-full max-w-[1440px] flex-col gap-5 px-4 py-4 sm:px-6 lg:px-8">
|
||||
<header className="sticky top-0 z-10 -mx-4 flex flex-col gap-3 border-b bg-background/86 px-4 pb-4 pt-2 backdrop-blur-xl sm:-mx-6 sm:px-6 md:flex-row md:items-center md:justify-between lg:-mx-8 lg:px-8">
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
@@ -200,13 +200,15 @@ export function PodView({
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<h1 className="truncate text-xl font-semibold tracking-tight">{team.name}</h1>
|
||||
<Badge variant={room ? 'default' : 'secondary'}>{room ? 'live' : 'local'}</Badge>
|
||||
<Badge variant={room ? 'default' : 'secondary'} className="rounded-md">
|
||||
{room ? 'live' : 'local'}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="truncate text-sm text-muted-foreground">{team.repo}</p>
|
||||
<p className="truncate font-mono text-xs text-muted-foreground">{team.repo}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="grid grid-cols-2 gap-2 sm:flex sm:items-center">
|
||||
<Button variant="outline" onClick={toggleBeat} disabled={!room}>
|
||||
<Volume2Icon data-icon="inline-start" />
|
||||
{playingBeat ? 'Stop audio' : 'Test audio'}
|
||||
@@ -244,8 +246,8 @@ export function PodView({
|
||||
|
||||
<Card className="flex-1">
|
||||
<CardHeader>
|
||||
<CardTitle>Room</CardTitle>
|
||||
<CardDescription>Only the signals that matter right now.</CardDescription>
|
||||
<CardTitle>Room state</CardTitle>
|
||||
<CardDescription>People and media currently visible to PodMan.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{participants.length === 0 ? (
|
||||
@@ -278,9 +280,9 @@ export function PodView({
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Intervention</CardTitle>
|
||||
<CardDescription>PodMan stays quiet until the signal is useful.</CardDescription>
|
||||
<CardDescription>Card first, voice only for urgent escalation.</CardDescription>
|
||||
<CardAction>
|
||||
<Badge variant={active ? 'default' : 'secondary'}>
|
||||
<Badge variant={active ? 'default' : 'secondary'} className="rounded-md">
|
||||
{active ? 'active' : 'clear'}
|
||||
</Badge>
|
||||
</CardAction>
|
||||
@@ -288,7 +290,7 @@ export function PodView({
|
||||
<CardContent>
|
||||
{active ? (
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="rounded-xl border bg-muted/30 p-3">
|
||||
<div className="rounded-lg border bg-muted/35 p-3">
|
||||
<p className="text-sm leading-6">{active.message}</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3 text-sm">
|
||||
@@ -306,8 +308,8 @@ export function PodView({
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No collision detected</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Share your screen when ready. The agent will surface only meaningful
|
||||
overlap.
|
||||
Share your screen when ready. PodMan will stay quiet until there is a useful
|
||||
signal.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
</Empty>
|
||||
@@ -372,7 +374,7 @@ function Participant({ participant }: { participant: PInfo }) {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex min-h-16 items-center justify-between gap-3 rounded-xl border bg-muted/20 px-3 transition',
|
||||
'flex min-h-16 items-center justify-between gap-3 rounded-lg border bg-muted/20 px-3 transition',
|
||||
participant.speaking && 'bg-muted',
|
||||
)}
|
||||
>
|
||||
@@ -386,7 +388,7 @@ function Participant({ participant }: { participant: PInfo }) {
|
||||
<p className="text-xs text-muted-foreground">{participant.isLocal ? 'you' : 'remote'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant={participant.speaking ? 'default' : 'secondary'}>
|
||||
<Badge variant={participant.speaking ? 'default' : 'secondary'} className="rounded-md">
|
||||
{participant.speaking ? 'speaking' : 'connected'}
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Slot } from 'radix-ui';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
const buttonVariants = cva(
|
||||
"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
"group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
@@ -23,14 +23,13 @@ const buttonVariants = cva(
|
||||
size: {
|
||||
default:
|
||||
'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
|
||||
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
||||
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
||||
xs: "h-6 gap-1 rounded-md px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
||||
sm: "h-7 gap-1 rounded-md px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
||||
lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
|
||||
icon: 'size-8',
|
||||
'icon-xs':
|
||||
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
||||
'icon-sm':
|
||||
'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',
|
||||
"size-6 rounded-md in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
|
||||
'icon-sm': 'size-7 rounded-md in-data-[slot=button-group]:rounded-md',
|
||||
'icon-lg': 'size-9',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,7 +12,7 @@ function Card({
|
||||
data-slot="card"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
'group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl',
|
||||
'group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-lg bg-card py-(--card-spacing) text-sm text-card-foreground shadow-[0_1px_2px_rgba(0,0,0,0.04),0_20px_60px_rgba(0,0,0,0.04)] ring-1 ring-black/[0.07] [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-lg *:[img:last-child]:rounded-b-lg',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
@@ -25,7 +25,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
<div
|
||||
data-slot="card-header"
|
||||
className={cn(
|
||||
'group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)',
|
||||
'group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-lg px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
@@ -77,7 +77,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
<div
|
||||
data-slot="card-footer"
|
||||
className={cn(
|
||||
'flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)',
|
||||
'flex items-center rounded-b-lg border-t bg-muted/35 p-(--card-spacing)',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
Reference in New Issue
Block a user