@arbidocs/blocks 0.3.127 → 0.3.128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -520,23 +520,50 @@ interface WorkspaceCardMember {
520
520
  }
521
521
  interface WorkspaceCardProps {
522
522
  name: string;
523
- /** Uppercase eyebrow above the description, e.g. the matter/project name. */
523
+ /** Uppercase eyebrow under the name, e.g. the matter reference. Omit to let
524
+ * the name and description carry the card on their own. */
524
525
  matterRef?: string;
525
526
  description?: string;
526
527
  docCount: number;
528
+ /** Conversation count, shown as a third stat. Omit to hide the stat entirely. */
529
+ chatCount?: number;
527
530
  /** Defaults to `members.length` when omitted. */
528
531
  memberCount?: number;
529
- /** Drives the overlapping avatar stack (shows up to 4, then a `+N` overflow). */
532
+ /** Drives the overlapping avatar stack (shows up to 3, then a `+N` overflow). */
530
533
  members?: WorkspaceCardMember[];
531
- /** ISO timestamp — renders "Updated {relative} ago" when present. */
534
+ /**
535
+ * The member list is not visible to this viewer (e.g. row-level security hides
536
+ * the members of a public workspace you haven't joined). Renders an em dash in
537
+ * place of the count and drops the avatar stack, rather than lying with a `0`.
538
+ */
539
+ membersHidden?: boolean;
540
+ /** ISO timestamp — renders a centred "Updated {relative} ago" on the footer
541
+ * line at rest, which gives way to the Open button on hover. */
532
542
  updatedAt?: string;
533
- /** Marks this as the current workspace: a done-badge + disabled footer button. */
543
+ /** Marks this as the current workspace: a ring on the card, and the footer says
544
+ * so in words instead of offering an Open button. */
534
545
  active?: boolean;
535
- /** Shows a spinner in the footer button while a switch is in flight. */
546
+ /** Shows a spinner in the Open button while a switch is in flight. */
536
547
  busy?: boolean;
537
548
  onOpen?: () => void;
538
549
  /** Icon in the header tile. Defaults to a lock/folder glyph. */
539
550
  icon?: LucideIcon;
551
+ /** Replaces the whole header icon tile — for a richer, app-supplied glyph. */
552
+ iconSlot?: ReactNode;
553
+ /**
554
+ * Secondary context for the card (the ARBI app puts the owning project here).
555
+ * Sits top-right and is revealed on hover/focus, so the resting card stays
556
+ * about the workspace itself.
557
+ */
558
+ cornerSlot?: ReactNode;
559
+ /**
560
+ * Accent as a theme colour-token key (e.g. `emerald`, or a firm's own brand
561
+ * token), resolved to `var(--color-<accent>)` at render — same contract as
562
+ * MetricCard. Tints the icon tile and the Open button, so a firm can accent
563
+ * the card without its brand classes leaking into the kit. `'default'` (or
564
+ * omitted) uses the semantic `primary` token.
565
+ */
566
+ accent?: string;
540
567
  /** Stable id for the card root; the footer button gets `${testId}-open`. */
541
568
  testId?: string;
542
569
  /** Overrides the footer button's test id when a caller needs a specific one. */
@@ -544,16 +571,23 @@ interface WorkspaceCardProps {
544
571
  className?: string;
545
572
  }
546
573
  /**
547
- * The one true workspace card. A themeable, source-agnostic tile — icon,
548
- * Active/Encrypted badge, title + uppercase matter eyebrow, a two-line
549
- * description, a doc/member stat row, an overlapping member avatar stack, an
550
- * "Updated … ago" line and a full-width Open / Current-workspace footer button.
574
+ * The one true workspace card. A themeable, source-agnostic tile, in three bands:
575
+ *
576
+ * 1. header — icon + workspace name; secondary context (`cornerSlot`) hides
577
+ * top-right until hover, keeping the resting card about the workspace.
578
+ * 2. body — two-line description, then one stat line: doc/chat/member counts
579
+ * on the left, the member avatar stack right-justified on the same row.
580
+ * 3. footer — one centred line with the full width to itself: "Updated … ago"
581
+ * at rest, swapping to the Open button on hover. The current
582
+ * workspace says so in words there instead.
583
+ *
584
+ * State is said once, in words. There is deliberately no status badge.
551
585
  *
552
586
  * Styled with the kit's SEMANTIC tokens only (foreground, muted-foreground,
553
587
  * primary, card, border, accent), so every firm gets it in its own colours
554
588
  * without any firm-branded classes leaking in.
555
589
  */
556
- declare function WorkspaceCard({ name, matterRef, description, docCount, memberCount, members, updatedAt, active, busy, onOpen, icon: Icon, testId, buttonTestId, className, }: WorkspaceCardProps): react.JSX.Element;
590
+ declare function WorkspaceCard({ name, matterRef, description, docCount, chatCount, memberCount, members, membersHidden, updatedAt, active, busy, onOpen, icon: Icon, iconSlot, cornerSlot, accent, testId, buttonTestId, className, }: WorkspaceCardProps): react.JSX.Element;
557
591
 
558
592
  interface StatItem {
559
593
  value: string;
package/dist/index.d.ts CHANGED
@@ -520,23 +520,50 @@ interface WorkspaceCardMember {
520
520
  }
521
521
  interface WorkspaceCardProps {
522
522
  name: string;
523
- /** Uppercase eyebrow above the description, e.g. the matter/project name. */
523
+ /** Uppercase eyebrow under the name, e.g. the matter reference. Omit to let
524
+ * the name and description carry the card on their own. */
524
525
  matterRef?: string;
525
526
  description?: string;
526
527
  docCount: number;
528
+ /** Conversation count, shown as a third stat. Omit to hide the stat entirely. */
529
+ chatCount?: number;
527
530
  /** Defaults to `members.length` when omitted. */
528
531
  memberCount?: number;
529
- /** Drives the overlapping avatar stack (shows up to 4, then a `+N` overflow). */
532
+ /** Drives the overlapping avatar stack (shows up to 3, then a `+N` overflow). */
530
533
  members?: WorkspaceCardMember[];
531
- /** ISO timestamp — renders "Updated {relative} ago" when present. */
534
+ /**
535
+ * The member list is not visible to this viewer (e.g. row-level security hides
536
+ * the members of a public workspace you haven't joined). Renders an em dash in
537
+ * place of the count and drops the avatar stack, rather than lying with a `0`.
538
+ */
539
+ membersHidden?: boolean;
540
+ /** ISO timestamp — renders a centred "Updated {relative} ago" on the footer
541
+ * line at rest, which gives way to the Open button on hover. */
532
542
  updatedAt?: string;
533
- /** Marks this as the current workspace: a done-badge + disabled footer button. */
543
+ /** Marks this as the current workspace: a ring on the card, and the footer says
544
+ * so in words instead of offering an Open button. */
534
545
  active?: boolean;
535
- /** Shows a spinner in the footer button while a switch is in flight. */
546
+ /** Shows a spinner in the Open button while a switch is in flight. */
536
547
  busy?: boolean;
537
548
  onOpen?: () => void;
538
549
  /** Icon in the header tile. Defaults to a lock/folder glyph. */
539
550
  icon?: LucideIcon;
551
+ /** Replaces the whole header icon tile — for a richer, app-supplied glyph. */
552
+ iconSlot?: ReactNode;
553
+ /**
554
+ * Secondary context for the card (the ARBI app puts the owning project here).
555
+ * Sits top-right and is revealed on hover/focus, so the resting card stays
556
+ * about the workspace itself.
557
+ */
558
+ cornerSlot?: ReactNode;
559
+ /**
560
+ * Accent as a theme colour-token key (e.g. `emerald`, or a firm's own brand
561
+ * token), resolved to `var(--color-<accent>)` at render — same contract as
562
+ * MetricCard. Tints the icon tile and the Open button, so a firm can accent
563
+ * the card without its brand classes leaking into the kit. `'default'` (or
564
+ * omitted) uses the semantic `primary` token.
565
+ */
566
+ accent?: string;
540
567
  /** Stable id for the card root; the footer button gets `${testId}-open`. */
541
568
  testId?: string;
542
569
  /** Overrides the footer button's test id when a caller needs a specific one. */
@@ -544,16 +571,23 @@ interface WorkspaceCardProps {
544
571
  className?: string;
545
572
  }
546
573
  /**
547
- * The one true workspace card. A themeable, source-agnostic tile — icon,
548
- * Active/Encrypted badge, title + uppercase matter eyebrow, a two-line
549
- * description, a doc/member stat row, an overlapping member avatar stack, an
550
- * "Updated … ago" line and a full-width Open / Current-workspace footer button.
574
+ * The one true workspace card. A themeable, source-agnostic tile, in three bands:
575
+ *
576
+ * 1. header — icon + workspace name; secondary context (`cornerSlot`) hides
577
+ * top-right until hover, keeping the resting card about the workspace.
578
+ * 2. body — two-line description, then one stat line: doc/chat/member counts
579
+ * on the left, the member avatar stack right-justified on the same row.
580
+ * 3. footer — one centred line with the full width to itself: "Updated … ago"
581
+ * at rest, swapping to the Open button on hover. The current
582
+ * workspace says so in words there instead.
583
+ *
584
+ * State is said once, in words. There is deliberately no status badge.
551
585
  *
552
586
  * Styled with the kit's SEMANTIC tokens only (foreground, muted-foreground,
553
587
  * primary, card, border, accent), so every firm gets it in its own colours
554
588
  * without any firm-branded classes leaking in.
555
589
  */
556
- declare function WorkspaceCard({ name, matterRef, description, docCount, memberCount, members, updatedAt, active, busy, onOpen, icon: Icon, testId, buttonTestId, className, }: WorkspaceCardProps): react.JSX.Element;
590
+ declare function WorkspaceCard({ name, matterRef, description, docCount, chatCount, memberCount, members, membersHidden, updatedAt, active, busy, onOpen, icon: Icon, iconSlot, cornerSlot, accent, testId, buttonTestId, className, }: WorkspaceCardProps): react.JSX.Element;
557
591
 
558
592
  interface StatItem {
559
593
  value: string;
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { tid, initials, fromNow, fmtDate, assetRefId, applyStoredTheme, AssetResolverProvider, ThemeEditor, applyThemeVars, SectionHeading, PricingTable, Tabs as Tabs$1, Accordion, Gallery, VideoEmbed, ContactForm, Banner, MediaText, TeamGrid, Steps, TestimonialGrid, Columns, Spacer, Container, Hero, FeatureGrid, Testimonial, CTABanner, LogoCloud, FAQ, RichTextBlock, Callout, BlockImage, AvatarBlock, Navbar, Footer, ListBlock, isAssetRef, asAssetRef } from './chunk-L6GG4KN2.js';
2
2
  export { ASSET_REF_PREFIX, Accordion, AssetResolverProvider, AvatarBlock, Banner, BlockImage, BlockLink, CTABanner, Callout, Columns, ContactForm, Container, FAQ, FONT_PAIRINGS, FeatureGrid, Footer, Gallery, Hero, ListBlock, LogoCloud, MediaText, Navbar, PricingTable, RichTextBlock, SectionHeading, Spacer, Steps, THEME_STYLE_ID, Tabs, TeamGrid, Testimonial, TestimonialGrid, ThemeEditor, VideoEmbed, applyFontVars, applyStoredTheme, applyThemeVars, asAssetRef, assetRefId, clearFontVars, clearThemeVars, createThemeStore, daysUntil, fmtDate, fmtDateTime, fontPackages, fromNow, gbp, getFontPairing, hrs, initials, isAssetRef, matchFontPairing, pct, tid, toEmbedUrl, toHslTriplet, useAssetRenderer, useAssetResolverActive } from './chunk-L6GG4KN2.js';
3
3
  import { createContext, useState, useCallback, useMemo, useContext, useRef, useEffect } from 'react';
4
- import { useArbi, ArbiProvider, useAiTask, useWorkspaceDocs as useWorkspaceDocs$1, useSemanticSearch as useSemanticSearch$1, cn, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Input, Card, CardHeader, Badge, CardTitle, CardDescription, CardContent, Avatar, AvatarImage, AvatarFallback, CardFooter, Button, TooltipProvider, NotificationBell, UserMenu, useThumbnails, Switch, useConfigs, useAgents, Checkbox, Tabs, TabsList, TabsTrigger, TabsContent, Separator, ArbiWebSocketProvider, useDocuments, ImageCropModal, DEFAULT_ASPECT_OPTIONS, useConversations } from '@arbidocs/react';
4
+ import { useArbi, ArbiProvider, useAiTask, useWorkspaceDocs as useWorkspaceDocs$1, useSemanticSearch as useSemanticSearch$1, cn, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Input, Card, CardHeader, CardTitle, CardDescription, CardContent, Avatar, AvatarImage, AvatarFallback, CardFooter, Button, TooltipProvider, NotificationBell, UserMenu, useThumbnails, Badge, Switch, useConfigs, useAgents, Checkbox, Tabs, TabsList, TabsTrigger, TabsContent, Separator, ArbiWebSocketProvider, useDocuments, ImageCropModal, DEFAULT_ASPECT_OPTIONS, useConversations } from '@arbidocs/react';
5
5
  export { DocumentCard, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, redlineStats, textToArtifact, toRedlineMarkdown } from '@arbidocs/react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from '@tanstack/react-query';
8
8
  import { AgGridReact } from 'ag-grid-react';
9
9
  import { themeQuartz, AllCommunityModule } from 'ag-grid-community';
10
- import { MessageSquare, Cpu, Code, Cloud, Layers, Target, Award, MapPin, Phone, Mail, Lock, Globe, Heart, Star, Rocket, Shield, Zap, Sparkles, Gavel, Scale, Bell, Activity, BarChart3, DollarSign, TrendingUp, Info, AlertCircle, CheckCircle, Clock, Calendar, Briefcase, Users, Folder, FileText, Loader2, UploadCloud, Search, ArrowUpRight, ArrowDownRight, FolderLock, CheckCircle2, ArrowLeftRight, X, Menu, ArrowLeft, Palette, RotateCcw, ChevronUp, ChevronDown, BrainCircuit, Bot, LayoutGrid, FileJson, Download, Crop, ImagePlus, Upload, Link2, Check, MessagesSquare } from 'lucide-react';
10
+ import { MessageSquare, Cpu, Code, Cloud, Layers, Target, Award, MapPin, Phone, Mail, Lock, Globe, Heart, Star, Rocket, Shield, Zap, Sparkles, Gavel, Scale, Bell, Activity, BarChart3, DollarSign, TrendingUp, Info, AlertCircle, CheckCircle, Clock, Calendar, Briefcase, Users, Folder, FileText, Loader2, UploadCloud, Search, ArrowUpRight, ArrowDownRight, FolderLock, MessagesSquare, CheckCircle2, ArrowLeftRight, X, Menu, ArrowLeft, Palette, RotateCcw, ChevronUp, ChevronDown, BrainCircuit, Bot, LayoutGrid, FileJson, Download, Crop, ImagePlus, Upload, Link2, Check } from 'lucide-react';
11
11
  import { useLocation, Link, useParams, NavLink } from 'react-router-dom';
12
12
  import { Puck, Render } from '@measured/puck';
13
13
  import { create } from 'zustand';
@@ -1057,82 +1057,152 @@ function MetricCard({
1057
1057
  ] })
1058
1058
  ] });
1059
1059
  }
1060
- var MAX_AVATARS = 4;
1060
+ var MAX_AVATARS = 3;
1061
+ var ON_HOVER = "opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100";
1061
1062
  function WorkspaceCard({
1062
1063
  name,
1063
1064
  matterRef,
1064
1065
  description,
1065
1066
  docCount,
1067
+ chatCount,
1066
1068
  memberCount,
1067
1069
  members = [],
1070
+ membersHidden = false,
1068
1071
  updatedAt,
1069
1072
  active = false,
1070
1073
  busy = false,
1071
1074
  onOpen,
1072
1075
  icon: Icon = FolderLock,
1076
+ iconSlot,
1077
+ cornerSlot,
1078
+ accent = "default",
1073
1079
  testId,
1074
1080
  buttonTestId,
1075
1081
  className
1076
1082
  }) {
1077
1083
  const totalMembers = memberCount ?? members.length;
1078
- const shownMembers = members.slice(0, MAX_AVATARS);
1084
+ const shownMembers = membersHidden ? [] : members.slice(0, MAX_AVATARS);
1079
1085
  const extraMembers = totalMembers - shownMembers.length;
1080
1086
  const btnTestId = buttonTestId ?? (testId ? `${testId}-open` : void 0);
1087
+ const hue = accent && accent !== "default" ? `var(--color-${accent})` : null;
1088
+ const tileStyle = hue ? { backgroundColor: `color-mix(in oklab, ${hue} 14%, transparent)`, color: hue } : void 0;
1089
+ const buttonStyle = hue ? { backgroundColor: hue, color: "var(--color-primary-foreground)" } : void 0;
1081
1090
  return /* @__PURE__ */ jsxs(
1082
1091
  Card,
1083
1092
  {
1084
1093
  variant: "outline",
1085
- className: cn("card-hover flex flex-col p-5", className),
1094
+ className: cn(
1095
+ "card-hover group flex flex-col gap-3 p-4",
1096
+ // The current workspace is marked by a ring, not a badge — the footer
1097
+ // already says "Current workspace" in words.
1098
+ active && "ring-1 ring-primary",
1099
+ className
1100
+ ),
1086
1101
  "data-testid": testId,
1087
1102
  children: [
1088
- /* @__PURE__ */ jsxs(CardHeader, { className: "p-0", children: [
1089
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
1090
- /* @__PURE__ */ jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Icon, { className: "size-5" }) }),
1091
- active ? /* @__PURE__ */ jsxs(Badge, { children: [
1092
- /* @__PURE__ */ jsx(CheckCircle2, { className: "mr-1 size-3" }),
1093
- " Active"
1094
- ] }) : /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: "Encrypted" })
1103
+ /* @__PURE__ */ jsxs(CardHeader, { className: "flex flex-row items-start gap-3 p-0", children: [
1104
+ iconSlot ?? /* @__PURE__ */ jsx(
1105
+ "div",
1106
+ {
1107
+ className: "flex size-9 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary",
1108
+ style: tileStyle,
1109
+ children: /* @__PURE__ */ jsx(Icon, { className: "size-5" })
1110
+ }
1111
+ ),
1112
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1113
+ /* @__PURE__ */ jsx(
1114
+ CardTitle,
1115
+ {
1116
+ className: "line-clamp-2 text-base leading-tight",
1117
+ "data-testid": testId && `${testId}-title`,
1118
+ children: name
1119
+ }
1120
+ ),
1121
+ matterRef && /* @__PURE__ */ jsx(CardDescription, { className: "mt-0.5 truncate text-xs font-medium uppercase tracking-wide text-muted-foreground", children: matterRef })
1095
1122
  ] }),
1096
- /* @__PURE__ */ jsx(CardTitle, { className: "mt-3 text-base", children: name }),
1097
- matterRef && /* @__PURE__ */ jsx(CardDescription, { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: matterRef })
1123
+ cornerSlot && /* @__PURE__ */ jsx("div", { className: cn("shrink-0", ON_HOVER), children: cornerSlot })
1098
1124
  ] }),
1099
- /* @__PURE__ */ jsxs(CardContent, { className: "mt-3 flex-1 space-y-4 p-0", children: [
1125
+ /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-1 flex-col gap-2 p-0", children: [
1100
1126
  description && /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-sm text-muted-foreground", children: description }),
1101
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-sm", children: [
1102
- /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-foreground", children: [
1103
- /* @__PURE__ */ jsx(FileText, { className: "size-4 text-muted-foreground" }),
1104
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: docCount.toLocaleString() }),
1105
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "docs" })
1127
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3 text-sm", children: [
1128
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Documents", children: [
1129
+ /* @__PURE__ */ jsx(FileText, { className: "size-3.5 text-muted-foreground" }),
1130
+ /* @__PURE__ */ jsx("span", { className: "font-medium tabular-nums", children: docCount.toLocaleString() })
1106
1131
  ] }),
1107
- /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-foreground", children: [
1108
- /* @__PURE__ */ jsx(Users, { className: "size-4 text-muted-foreground" }),
1109
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: totalMembers }),
1110
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "members" })
1111
- ] })
1112
- ] }),
1113
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
1114
- /* @__PURE__ */ jsxs("div", { className: "flex -space-x-2", children: [
1115
- shownMembers.map((m, i) => /* @__PURE__ */ jsxs(Avatar, { className: "size-7 border-2 border-card", title: m.name, children: [
1132
+ chatCount !== void 0 && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Chats", children: [
1133
+ /* @__PURE__ */ jsx(MessagesSquare, { className: "size-3.5 text-muted-foreground" }),
1134
+ /* @__PURE__ */ jsx("span", { className: "font-medium tabular-nums", children: chatCount.toLocaleString() })
1135
+ ] }),
1136
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-foreground", title: "Members", children: [
1137
+ /* @__PURE__ */ jsx(Users, { className: "size-3.5 text-muted-foreground" }),
1138
+ /* @__PURE__ */ jsx(
1139
+ "span",
1140
+ {
1141
+ className: "font-medium tabular-nums",
1142
+ "data-testid": testId && `${testId}-member-count`,
1143
+ children: membersHidden ? "\u2014" : totalMembers
1144
+ }
1145
+ )
1146
+ ] }),
1147
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex shrink-0 -space-x-2", children: [
1148
+ shownMembers.map((m, i) => /* @__PURE__ */ jsxs(Avatar, { className: "size-6 border-2 border-card", title: m.name, children: [
1116
1149
  m.picture && /* @__PURE__ */ jsx(AvatarImage, { src: m.picture, alt: m.name }),
1117
- /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-foreground text-[10px] font-medium text-background", children: initials(m.name || "?") })
1150
+ /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-foreground text-[9px] font-medium text-background", children: initials(m.name || "?") })
1118
1151
  ] }, i)),
1119
- extraMembers > 0 && /* @__PURE__ */ jsx(Avatar, { className: "size-7 border-2 border-card", children: /* @__PURE__ */ jsxs(AvatarFallback, { className: "bg-accent text-[10px] font-medium text-muted-foreground", children: [
1152
+ !membersHidden && extraMembers > 0 && /* @__PURE__ */ jsx(Avatar, { className: "size-6 border-2 border-card", children: /* @__PURE__ */ jsxs(AvatarFallback, { className: "bg-accent text-[9px] font-medium text-muted-foreground", children: [
1120
1153
  "+",
1121
1154
  extraMembers
1122
1155
  ] }) })
1123
- ] }),
1124
- updatedAt && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", title: fmtDate(updatedAt), children: [
1125
- "Updated ",
1126
- fromNow(updatedAt)
1127
1156
  ] })
1128
1157
  ] })
1129
1158
  ] }),
1130
- /* @__PURE__ */ jsx(CardFooter, { className: "mt-4 p-0", children: active ? /* @__PURE__ */ jsxs(Button, { variant: "outline", className: "w-full", disabled: true, "data-testid": btnTestId, children: [
1131
- /* @__PURE__ */ jsx(CheckCircle2, { className: "size-4" }),
1132
- " Current workspace"
1133
- ] }) : /* @__PURE__ */ jsxs(Button, { className: "w-full", onClick: onOpen, disabled: busy, "data-testid": btnTestId, children: [
1134
- busy ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsx(ArrowLeftRight, { className: "size-4" }),
1135
- "Open"
1159
+ /* @__PURE__ */ jsx(CardFooter, { className: "grid min-h-8 place-items-center p-0", children: active ? (
1160
+ // Reads as a statement, not a call to action — but stays clickable, so
1161
+ // re-entering the workspace you're already in still works.
1162
+ /* @__PURE__ */ jsxs(
1163
+ Button,
1164
+ {
1165
+ variant: "ghost",
1166
+ size: "sm",
1167
+ className: "col-start-1 row-start-1 h-8 whitespace-nowrap px-2 text-xs font-medium text-primary hover:bg-primary/10",
1168
+ onClick: onOpen,
1169
+ "data-testid": btnTestId,
1170
+ children: [
1171
+ /* @__PURE__ */ jsx(CheckCircle2, { className: "size-3.5" }),
1172
+ " Current workspace"
1173
+ ]
1174
+ }
1175
+ )
1176
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
1177
+ updatedAt && /* @__PURE__ */ jsxs(
1178
+ "span",
1179
+ {
1180
+ className: cn(
1181
+ "col-start-1 row-start-1 whitespace-nowrap text-xs text-muted-foreground",
1182
+ "transition-opacity group-hover:opacity-0 group-focus-within:opacity-0"
1183
+ ),
1184
+ title: fmtDate(updatedAt),
1185
+ children: [
1186
+ "Updated ",
1187
+ fromNow(updatedAt)
1188
+ ]
1189
+ }
1190
+ ),
1191
+ /* @__PURE__ */ jsxs(
1192
+ Button,
1193
+ {
1194
+ size: "sm",
1195
+ className: cn("col-start-1 row-start-1 whitespace-nowrap", ON_HOVER),
1196
+ style: buttonStyle,
1197
+ onClick: onOpen,
1198
+ disabled: busy,
1199
+ "data-testid": btnTestId,
1200
+ children: [
1201
+ busy ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsx(ArrowLeftRight, { className: "size-3.5" }),
1202
+ "Open"
1203
+ ]
1204
+ }
1205
+ )
1136
1206
  ] }) })
1137
1207
  ]
1138
1208
  }