@handled-ai/design-system 0.20.21 → 0.20.22

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.
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const badgeVariants: (props?: ({
6
- variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | null | undefined;
6
+ variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
7
7
  } & class_variance_authority_types.ClassProp) | undefined) => string;
8
8
  declare function Badge({ className, variant, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
9
9
  asChild?: boolean;
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import { VariantProps } from 'class-variance-authority';
4
4
 
5
5
  declare const buttonVariants: (props?: ({
6
- variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | null | undefined;
6
+ variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
7
7
  size?: "default" | "sm" | "lg" | "icon" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
@@ -12,7 +12,7 @@ import { VariantProps } from 'class-variance-authority';
12
12
  */
13
13
  type PillStatus = "success" | "warning" | "error" | "neutral" | "info";
14
14
  declare const pillVariants: (props?: ({
15
- variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "error" | "neutral" | "info" | "success" | "warning" | null | undefined;
15
+ variant?: "error" | "default" | "secondary" | "destructive" | "outline" | "ghost" | "neutral" | "info" | "success" | "warning" | null | undefined;
16
16
  } & class_variance_authority_types.ClassProp) | undefined) => string;
17
17
  interface PillProps extends React.ComponentProps<"span">, VariantProps<typeof pillVariants> {
18
18
  }
@@ -5,7 +5,7 @@ import { Tabs as Tabs$1 } from 'radix-ui';
5
5
 
6
6
  declare function Tabs({ className, orientation, ...props }: React.ComponentProps<typeof Tabs$1.Root>): React.JSX.Element;
7
7
  declare const tabsListVariants: (props?: ({
8
- variant?: "default" | "line" | null | undefined;
8
+ variant?: "line" | "default" | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  declare function TabsList({ className, variant, ...props }: React.ComponentProps<typeof Tabs$1.List> & VariantProps<typeof tabsListVariants>): React.JSX.Element;
11
11
  declare function TabsTrigger({ className, ...props }: React.ComponentProps<typeof Tabs$1.Trigger>): React.JSX.Element;
@@ -31,6 +31,51 @@ interface TimelineEvent {
31
31
  * existing consumers are unaffected.
32
32
  */
33
33
  bodyHtml?: string;
34
+ /**
35
+ * Sender signature HTML, split out of the main body by the consuming app's
36
+ * email pipeline. When present, it is hidden behind a subtle "Show
37
+ * signature" toggle (collapsed by default) so signatures don't add noise to
38
+ * the timeline. Sanitized before rendering. Optional — when absent the body
39
+ * renders exactly as before. Mirrors `signatureHtml` on EmailPreviewCard.
40
+ */
41
+ signatureHtml?: string | null;
42
+ /**
43
+ * Quoted / trailing thread content (the "On <date> X wrote:" history) split
44
+ * out of the main body. When present, it is hidden behind a subtle "Show
45
+ * quoted text" toggle (collapsed by default). Sanitized before rendering.
46
+ * Optional — when absent the body renders exactly as before.
47
+ */
48
+ quotedHtml?: string | null;
49
+ };
50
+ /**
51
+ * Gong call payload. When present, the card renders a dedicated, first-class
52
+ * Gong call card (mirroring the `email` treatment) instead of generic
53
+ * content: a collapsed duration + brief-snippet preview, and an expanded
54
+ * card with the call title, start time, direction/outcome chips, the AI
55
+ * brief, key points, next steps, and a "View in Gong" link. Opt-in: when
56
+ * absent, existing consumers are unaffected. Every field except `title` is
57
+ * optional/nullable and renders nothing when absent (no empty sections,
58
+ * no "null"/"undefined", no "Invalid Date").
59
+ */
60
+ gongCall?: {
61
+ /** Gong call title. */
62
+ title: string;
63
+ /** ISO datetime of the call start. */
64
+ startTime?: string | null;
65
+ /** Call length in seconds. Formatted to a human duration when present. */
66
+ durationSeconds?: number | null;
67
+ /** Call direction, e.g. "Outbound" / "Inbound". */
68
+ direction?: string | null;
69
+ /** Call outcome, e.g. "Connected". */
70
+ outcome?: string | null;
71
+ /** Gong AI call brief (plain text, may be multi-paragraph). */
72
+ brief?: string | null;
73
+ /** Gong AI key points (plain text, often newline-delimited bullets). */
74
+ keyPoints?: string | null;
75
+ /** Gong AI highlights / next steps (plain text). */
76
+ nextSteps?: string | null;
77
+ /** Deep link to the call in Gong. */
78
+ url?: string | null;
34
79
  };
35
80
  content?: React.ReactNode;
36
81
  source?: {
@@ -4,7 +4,7 @@
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import * as React from "react";
6
6
  import { cn } from "../lib/utils.js";
7
- import { ChevronDown, ChevronUp, ExternalLink } from "lucide-react";
7
+ import { ChevronDown, ChevronUp, ExternalLink, Phone } from "lucide-react";
8
8
  import { EmailBody as SharedEmailBody } from "./email-body.js";
9
9
  import {
10
10
  decodeEmailDisplayText,
@@ -78,7 +78,7 @@ const TIMELINE_VARIANT_CLASSES = {
78
78
  title: "min-w-0 pr-1 text-[13.5px] font-medium leading-tight text-foreground",
79
79
  time: "shrink-0 whitespace-nowrap pt-px text-[11px] leading-tight text-muted-foreground/60",
80
80
  cardContainer: "overflow-hidden rounded-lg border border-border/70 bg-card",
81
- cardHeader: "flex items-center justify-between border-b border-border/60 bg-muted/30 px-3 py-1.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/70",
81
+ cardHeader: "flex items-start justify-between border-b border-border/60 bg-muted/30 px-3 py-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/70",
82
82
  cardBody: "px-3 py-2.5 text-[13px] leading-relaxed",
83
83
  cardFooter: "border-t border-border/60 bg-muted/10 px-3 py-1.5",
84
84
  collapsedPreview: "flex items-center justify-between gap-2 px-3 py-2 text-[13px] text-muted-foreground",
@@ -135,6 +135,7 @@ function TimelineItem({
135
135
  const [showAllRecipients, setShowAllRecipients] = React.useState(false);
136
136
  const hasContent = !!event.content;
137
137
  const hasEmail = !!event.email;
138
+ const hasGongCall = !!event.gongCall;
138
139
  const classes = TIMELINE_VARIANT_CLASSES[variant];
139
140
  const toneStyle = event.tone ? TONE_CLASSES[event.tone] : null;
140
141
  const dotClasses = toneStyle ? toneStyle.dot : NEUTRAL_DOT_CLASSES;
@@ -148,7 +149,16 @@ function TimelineItem({
148
149
  /* @__PURE__ */ jsx("span", { className: classes.time, children: event.time })
149
150
  ] }),
150
151
  event.actor && /* @__PURE__ */ jsx(ActorByline, { actor: event.actor, time: event.time }),
151
- (hasContent || hasEmail) && /* @__PURE__ */ jsx("div", { className: "mt-2", children: event.isInteractive ? hasEmail ? /* @__PURE__ */ jsx(
152
+ (hasContent || hasEmail || hasGongCall) && /* @__PURE__ */ jsx("div", { className: "mt-2", children: event.isInteractive ? hasGongCall ? /* @__PURE__ */ jsx(
153
+ GongCallCard,
154
+ {
155
+ event,
156
+ expanded,
157
+ setExpanded,
158
+ variant,
159
+ classes
160
+ }
161
+ ) : hasEmail ? /* @__PURE__ */ jsx(
152
162
  EmailCard,
153
163
  {
154
164
  event,
@@ -176,6 +186,33 @@ function reactNodeToDisplayText(value) {
176
186
  if (typeof value === "string" || typeof value === "number") return decodeEmailDisplayText(String(value));
177
187
  return "";
178
188
  }
189
+ function formatCallDuration(durationSeconds) {
190
+ if (durationSeconds == null || !Number.isFinite(durationSeconds) || durationSeconds <= 0) return "";
191
+ const totalMinutes = Math.round(durationSeconds / 60);
192
+ if (totalMinutes < 1) return "< 1 min";
193
+ if (totalMinutes < 60) return `${totalMinutes} min`;
194
+ const hours = Math.floor(totalMinutes / 60);
195
+ const minutes = totalMinutes % 60;
196
+ return minutes === 0 ? `${hours} h` : `${hours} h ${minutes} min`;
197
+ }
198
+ function cleanGongText(value) {
199
+ if (!value) return "";
200
+ return decodeEmailDisplayText(value).trim();
201
+ }
202
+ function getTimelineGongCallDisplay(gongCall) {
203
+ var _a, _b, _c, _d;
204
+ const title = cleanGongText(gongCall.title);
205
+ const startTime = (_a = formatEmailTimestamp(gongCall.startTime)) != null ? _a : "";
206
+ const duration = formatCallDuration(gongCall.durationSeconds);
207
+ const direction = cleanGongText(gongCall.direction);
208
+ const outcome = cleanGongText(gongCall.outcome);
209
+ const brief = cleanGongText(gongCall.brief);
210
+ const keyPoints = cleanGongText(gongCall.keyPoints);
211
+ const nextSteps = cleanGongText(gongCall.nextSteps);
212
+ const url = ((_b = gongCall.url) == null ? void 0 : _b.trim()) || "";
213
+ const snippet = (_d = (_c = brief.split("\n").find((line) => line.trim())) == null ? void 0 : _c.trim()) != null ? _d : "";
214
+ return { title, startTime, duration, direction, outcome, brief, keyPoints, nextSteps, url, snippet };
215
+ }
179
216
  function getTimelineEmailDisplay(email) {
180
217
  var _a, _b, _c, _d, _e;
181
218
  const sender = normalizeEmailSender({ name: email.from, email: email.fromEmail });
@@ -186,7 +223,8 @@ function getTimelineEmailDisplay(email) {
186
223
  const subject = email.subject ? decodeEmailDisplayText(email.subject) : "";
187
224
  const bodyText = reactNodeToDisplayText(email.body);
188
225
  const snippet = emailBodySnippet({ bodyHtml: email.bodyHtml, body: bodyText }, 140);
189
- return { sender, to, cc, bcc, date, subject, bodyText, snippet };
226
+ const hasRecipients = Boolean(to || cc || bcc);
227
+ return { sender, to, cc, bcc, date, subject, bodyText, snippet, hasRecipients };
190
228
  }
191
229
  function EmailMetadata({
192
230
  email,
@@ -194,6 +232,7 @@ function EmailMetadata({
194
232
  setShowAllRecipients
195
233
  }) {
196
234
  const display = getTimelineEmailDisplay(email);
235
+ const hasExpandableRecipients = Boolean(display.cc || display.bcc);
197
236
  return /* @__PURE__ */ jsxs(Fragment, { children: [
198
237
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
199
238
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-baseline gap-1.5", children: [
@@ -202,37 +241,78 @@ function EmailMetadata({
202
241
  ] }),
203
242
  display.date ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground/50 whitespace-nowrap", children: display.date }) : null
204
243
  ] }),
205
- /* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex items-center gap-1 text-xs text-muted-foreground", children: [
206
- /* @__PURE__ */ jsxs("span", { className: "truncate", children: [
207
- "To ",
208
- display.to || "no recipient yet",
209
- !showAllRecipients && (display.cc || display.bcc) ? /* @__PURE__ */ jsx(Fragment, { children: ", ..." }) : null,
210
- showAllRecipients && display.cc ? /* @__PURE__ */ jsxs(Fragment, { children: [
211
- ", ",
212
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "cc" }),
213
- " ",
214
- display.cc
215
- ] }) : null,
216
- showAllRecipients && display.bcc ? /* @__PURE__ */ jsxs(Fragment, { children: [
217
- " ",
218
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "bcc" }),
219
- " ",
220
- display.bcc
221
- ] }) : null
244
+ display.hasRecipients ? /* @__PURE__ */ jsxs("div", { className: "mt-0.5 text-xs text-muted-foreground", children: [
245
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
246
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 truncate", children: [
247
+ display.to ? /* @__PURE__ */ jsxs(Fragment, { children: [
248
+ "To ",
249
+ display.to
250
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
251
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "cc" }),
252
+ " ",
253
+ display.cc || display.bcc
254
+ ] }),
255
+ display.to && !showAllRecipients && hasExpandableRecipients ? /* @__PURE__ */ jsx(Fragment, { children: ", \u2026" }) : null
256
+ ] }),
257
+ hasExpandableRecipients ? /* @__PURE__ */ jsx(
258
+ "button",
259
+ {
260
+ type: "button",
261
+ onClick: (e) => {
262
+ e.stopPropagation();
263
+ setShowAllRecipients((prev) => !prev);
264
+ },
265
+ className: "shrink-0 text-muted-foreground/40 hover:text-muted-foreground transition-colors",
266
+ "aria-label": showAllRecipients ? "Hide cc and bcc" : "Show cc and bcc",
267
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-3 w-3 transition-transform", showAllRecipients && "rotate-180") })
268
+ }
269
+ ) : null
222
270
  ] }),
223
- display.cc || display.bcc ? /* @__PURE__ */ jsx(
224
- "button",
225
- {
226
- type: "button",
227
- onClick: (e) => {
228
- e.stopPropagation();
229
- setShowAllRecipients((prev) => !prev);
230
- },
231
- className: "shrink-0 text-muted-foreground/40 hover:text-muted-foreground transition-colors",
232
- children: /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-3 w-3 transition-transform", showAllRecipients && "rotate-180") })
233
- }
234
- ) : null
235
- ] })
271
+ showAllRecipients && display.to && display.cc ? /* @__PURE__ */ jsxs("div", { className: "truncate", children: [
272
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "cc" }),
273
+ " ",
274
+ display.cc
275
+ ] }) : null,
276
+ showAllRecipients && display.bcc ? /* @__PURE__ */ jsxs("div", { className: "truncate", children: [
277
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "bcc" }),
278
+ " ",
279
+ display.bcc
280
+ ] }) : null
281
+ ] }) : null
282
+ ] });
283
+ }
284
+ function SuppressedHtmlSection({
285
+ html,
286
+ showLabel,
287
+ hideLabel,
288
+ slot
289
+ }) {
290
+ const [open, setOpen] = React.useState(false);
291
+ return /* @__PURE__ */ jsxs("div", { className: "mt-2", "data-slot": slot, children: [
292
+ /* @__PURE__ */ jsxs(
293
+ "button",
294
+ {
295
+ type: "button",
296
+ onClick: (e) => {
297
+ e.stopPropagation();
298
+ setOpen((value) => !value);
299
+ },
300
+ "aria-expanded": open,
301
+ className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[11px] text-muted-foreground/70 transition-colors hover:bg-muted hover:text-foreground",
302
+ children: [
303
+ open ? hideLabel : showLabel,
304
+ /* @__PURE__ */ jsx(ChevronDown, { className: cn("h-3 w-3 transition-transform", open && "rotate-180") })
305
+ ]
306
+ }
307
+ ),
308
+ open ? /* @__PURE__ */ jsx(
309
+ "div",
310
+ {
311
+ "data-slot": `${slot}-content`,
312
+ className: "mt-2 border-l-2 border-border pl-3 text-sm leading-relaxed text-muted-foreground",
313
+ children: /* @__PURE__ */ jsx(SharedEmailBody, { html, variant: "history", collapseDetails: false })
314
+ }
315
+ ) : null
236
316
  ] });
237
317
  }
238
318
  function TimelineEmailBody({ email }) {
@@ -251,7 +331,32 @@ function TimelineEmailBody({ email }) {
251
331
  className: "text-sm leading-relaxed"
252
332
  }
253
333
  );
254
- return email.bodyHtml ? /* @__PURE__ */ jsx("div", { "data-slot": "timeline-email-html", children: body }) : body;
334
+ const hasSignature = Boolean(email.signatureHtml && email.signatureHtml.trim());
335
+ const hasQuoted = Boolean(email.quotedHtml && email.quotedHtml.trim());
336
+ if (!hasSignature && !hasQuoted) {
337
+ return email.bodyHtml ? /* @__PURE__ */ jsx("div", { "data-slot": "timeline-email-html", children: body }) : body;
338
+ }
339
+ return /* @__PURE__ */ jsxs("div", { "data-slot": email.bodyHtml ? "timeline-email-html" : void 0, children: [
340
+ body,
341
+ hasSignature ? /* @__PURE__ */ jsx(
342
+ SuppressedHtmlSection,
343
+ {
344
+ html: email.signatureHtml,
345
+ showLabel: "Show signature",
346
+ hideLabel: "Hide signature",
347
+ slot: "timeline-email-signature"
348
+ }
349
+ ) : null,
350
+ hasQuoted ? /* @__PURE__ */ jsx(
351
+ SuppressedHtmlSection,
352
+ {
353
+ html: email.quotedHtml,
354
+ showLabel: "Show quoted text",
355
+ hideLabel: "Hide quoted text",
356
+ slot: "timeline-email-quoted"
357
+ }
358
+ ) : null
359
+ ] });
255
360
  }
256
361
  function renderDecodedPreview(preview) {
257
362
  if (typeof preview === "string" || typeof preview === "number") return decodeEmailDisplayText(String(preview));
@@ -267,7 +372,7 @@ function CollapsedEmailPreview({
267
372
  const display = email ? getTimelineEmailDisplay(email) : null;
268
373
  const previewContent = (display == null ? void 0 : display.snippet) || renderDecodedPreview(preview);
269
374
  return /* @__PURE__ */ jsxs("div", { className, onClick, children: [
270
- /* @__PURE__ */ jsxs("span", { className: "line-clamp-1 pr-3 text-[13px]", children: [
375
+ /* @__PURE__ */ jsxs("span", { className: "line-clamp-1 min-w-0 flex-1 pr-3 text-[13px]", children: [
271
376
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: display == null ? void 0 : display.sender.name }),
272
377
  /* @__PURE__ */ jsx("span", { className: "mx-1.5 text-muted-foreground/40", children: "\xB7" }),
273
378
  (display == null ? void 0 : display.subject) ? /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -292,6 +397,28 @@ function ShowLessButton({
292
397
  /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3" })
293
398
  ] });
294
399
  }
400
+ function CollapseTopButton({
401
+ onClick,
402
+ className
403
+ }) {
404
+ return /* @__PURE__ */ jsxs(
405
+ "button",
406
+ {
407
+ type: "button",
408
+ onClick,
409
+ "aria-label": "Show less",
410
+ "data-slot": "timeline-collapse-top",
411
+ className: cn(
412
+ "shrink-0 inline-flex items-center gap-1 text-[11px] font-medium text-muted-foreground/60 transition-colors hover:text-foreground",
413
+ className
414
+ ),
415
+ children: [
416
+ /* @__PURE__ */ jsx("span", { className: "sr-only sm:not-sr-only", children: "Show less" }),
417
+ /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3" })
418
+ ]
419
+ }
420
+ );
421
+ }
295
422
  function SourceAction({
296
423
  source,
297
424
  onSourceClick,
@@ -330,6 +457,204 @@ function SourceAction({
330
457
  }
331
458
  );
332
459
  }
460
+ function GongLinkAction({
461
+ url,
462
+ className
463
+ }) {
464
+ return /* @__PURE__ */ jsxs(
465
+ "a",
466
+ {
467
+ href: url,
468
+ target: "_blank",
469
+ rel: "noopener noreferrer",
470
+ onClick: (e) => e.stopPropagation(),
471
+ className,
472
+ "data-slot": "timeline-gong-link",
473
+ children: [
474
+ "View in Gong",
475
+ /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3" })
476
+ ]
477
+ }
478
+ );
479
+ }
480
+ function TimelineGongCallBody({
481
+ display,
482
+ labelClassName
483
+ }) {
484
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", "data-slot": "timeline-gong-body", children: [
485
+ display.brief ? /* @__PURE__ */ jsx("div", { className: "whitespace-pre-line text-sm leading-relaxed text-foreground/90", children: display.brief }) : null,
486
+ display.keyPoints ? /* @__PURE__ */ jsxs("div", { "data-slot": "timeline-gong-key-points", children: [
487
+ /* @__PURE__ */ jsx("div", { className: labelClassName, children: "Key points" }),
488
+ /* @__PURE__ */ jsx("div", { className: "mt-1 whitespace-pre-line text-sm leading-relaxed text-foreground/90", children: display.keyPoints })
489
+ ] }) : null,
490
+ display.nextSteps ? /* @__PURE__ */ jsxs("div", { "data-slot": "timeline-gong-next-steps", children: [
491
+ /* @__PURE__ */ jsx("div", { className: labelClassName, children: "Next steps" }),
492
+ /* @__PURE__ */ jsx("div", { className: "mt-1 whitespace-pre-line text-sm leading-relaxed text-foreground/90", children: display.nextSteps })
493
+ ] }) : null
494
+ ] });
495
+ }
496
+ function GongCallHeader({
497
+ display
498
+ }) {
499
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
500
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
501
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [
502
+ /* @__PURE__ */ jsx(Phone, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground/60" }),
503
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate font-semibold text-foreground text-[13px]", children: display.title })
504
+ ] }),
505
+ display.startTime ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground/50 whitespace-nowrap", children: display.startTime }) : null
506
+ ] }),
507
+ display.duration || display.direction || display.outcome ? /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [
508
+ display.duration ? /* @__PURE__ */ jsx("span", { "data-slot": "timeline-gong-duration", children: display.duration }) : null,
509
+ display.direction ? /* @__PURE__ */ jsx("span", { className: "rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground", children: display.direction }) : null,
510
+ display.outcome ? /* @__PURE__ */ jsx("span", { className: "rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground", children: display.outcome }) : null
511
+ ] }) : null
512
+ ] });
513
+ }
514
+ function CollapsedGongCallPreview({
515
+ display,
516
+ className,
517
+ actionClassName,
518
+ onClick
519
+ }) {
520
+ return /* @__PURE__ */ jsxs("div", { className, onClick, children: [
521
+ /* @__PURE__ */ jsxs("span", { className: "line-clamp-1 min-w-0 flex-1 pr-3 text-[13px] text-muted-foreground", children: [
522
+ display.duration ? /* @__PURE__ */ jsxs(Fragment, { children: [
523
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
524
+ /* @__PURE__ */ jsx(Phone, { className: "h-3 w-3" }),
525
+ display.duration
526
+ ] }),
527
+ display.snippet ? /* @__PURE__ */ jsx("span", { className: "mx-1.5 text-muted-foreground/40", children: "\xB7" }) : null
528
+ ] }) : null,
529
+ display.snippet ? /* @__PURE__ */ jsx("span", { children: display.snippet }) : null
530
+ ] }),
531
+ /* @__PURE__ */ jsxs("button", { type: "button", className: actionClassName, children: [
532
+ "Expand ",
533
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
534
+ ] })
535
+ ] });
536
+ }
537
+ function GongCallCard({
538
+ event,
539
+ expanded,
540
+ setExpanded,
541
+ variant,
542
+ classes
543
+ }) {
544
+ const gongCall = event.gongCall;
545
+ const display = getTimelineGongCallDisplay(gongCall);
546
+ if (variant === "default") {
547
+ return /* @__PURE__ */ jsx("div", { className: classes.cardContainer, "data-variant": variant, "data-slot": "timeline-gong-card", children: /* @__PURE__ */ jsx(
548
+ "div",
549
+ {
550
+ className: cn(
551
+ "px-3 py-2.5 text-sm",
552
+ !expanded && "cursor-pointer hover:bg-muted/30 transition-colors"
553
+ ),
554
+ onClick: () => !expanded && setExpanded(true),
555
+ children: expanded ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
556
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
557
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(GongCallHeader, { display }) }),
558
+ /* @__PURE__ */ jsx(
559
+ CollapseTopButton,
560
+ {
561
+ onClick: (e) => {
562
+ e.stopPropagation();
563
+ setExpanded(false);
564
+ },
565
+ className: "mt-0.5"
566
+ }
567
+ )
568
+ ] }),
569
+ /* @__PURE__ */ jsx(
570
+ TimelineGongCallBody,
571
+ {
572
+ display,
573
+ labelClassName: "text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70"
574
+ }
575
+ ),
576
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-3", children: [
577
+ display.url ? /* @__PURE__ */ jsx(
578
+ GongLinkAction,
579
+ {
580
+ url: display.url,
581
+ className: "mr-auto inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground"
582
+ }
583
+ ) : null,
584
+ /* @__PURE__ */ jsx(
585
+ ShowLessButton,
586
+ {
587
+ onClick: (e) => {
588
+ e.stopPropagation();
589
+ setExpanded(false);
590
+ },
591
+ className: "flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground"
592
+ }
593
+ )
594
+ ] })
595
+ ] }) : /* @__PURE__ */ jsx(
596
+ CollapsedGongCallPreview,
597
+ {
598
+ display,
599
+ className: "flex items-center justify-between gap-2 text-muted-foreground",
600
+ actionClassName: "flex shrink-0 items-center gap-1 text-[11px] font-semibold uppercase tracking-wider transition-colors hover:text-foreground"
601
+ }
602
+ )
603
+ }
604
+ ) });
605
+ }
606
+ return /* @__PURE__ */ jsx("div", { className: classes.cardContainer, "data-variant": variant, "data-slot": "timeline-gong-card", children: expanded ? /* @__PURE__ */ jsxs(Fragment, { children: [
607
+ /* @__PURE__ */ jsxs("div", { className: classes.cardHeader, "data-slot": "timeline-card-header", children: [
608
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 normal-case tracking-normal", children: /* @__PURE__ */ jsx(GongCallHeader, { display }) }),
609
+ /* @__PURE__ */ jsx(
610
+ CollapseTopButton,
611
+ {
612
+ onClick: (e) => {
613
+ e.stopPropagation();
614
+ setExpanded(false);
615
+ },
616
+ className: "ml-3 normal-case tracking-normal"
617
+ }
618
+ )
619
+ ] }),
620
+ /* @__PURE__ */ jsx("div", { className: classes.cardBody, "data-slot": "timeline-card-body", children: /* @__PURE__ */ jsx(
621
+ TimelineGongCallBody,
622
+ {
623
+ display,
624
+ labelClassName: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/70"
625
+ }
626
+ ) }),
627
+ /* @__PURE__ */ jsxs(
628
+ "div",
629
+ {
630
+ className: cn(classes.cardFooter, classes.actionLinkRow, display.url ? "justify-between" : "justify-end"),
631
+ "data-slot": "timeline-card-footer",
632
+ children: [
633
+ display.url ? /* @__PURE__ */ jsx(GongLinkAction, { url: display.url, className: classes.actionLink }) : null,
634
+ /* @__PURE__ */ jsx(
635
+ ShowLessButton,
636
+ {
637
+ type: "button",
638
+ onClick: (e) => {
639
+ e.stopPropagation();
640
+ setExpanded(false);
641
+ },
642
+ className: classes.actionLink
643
+ }
644
+ )
645
+ ]
646
+ }
647
+ )
648
+ ] }) : /* @__PURE__ */ jsx(
649
+ CollapsedGongCallPreview,
650
+ {
651
+ display,
652
+ className: cn(classes.collapsedPreview, "cursor-pointer hover:bg-muted/30 transition-colors"),
653
+ actionClassName: cn(classes.actionLink, "shrink-0"),
654
+ onClick: () => setExpanded(true)
655
+ }
656
+ ) });
657
+ }
333
658
  function EmailCard({
334
659
  event,
335
660
  expanded,
@@ -349,14 +674,26 @@ function EmailCard({
349
674
  ),
350
675
  onClick: () => !expanded && setExpanded(true),
351
676
  children: expanded && event.email ? /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
352
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
353
- EmailMetadata,
354
- {
355
- email: event.email,
356
- showAllRecipients,
357
- setShowAllRecipients
358
- }
359
- ) }),
677
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
678
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx(
679
+ EmailMetadata,
680
+ {
681
+ email: event.email,
682
+ showAllRecipients,
683
+ setShowAllRecipients
684
+ }
685
+ ) }),
686
+ /* @__PURE__ */ jsx(
687
+ CollapseTopButton,
688
+ {
689
+ onClick: (e) => {
690
+ e.stopPropagation();
691
+ setExpanded(false);
692
+ },
693
+ className: "mt-0.5"
694
+ }
695
+ )
696
+ ] }),
360
697
  /* @__PURE__ */ jsx(TimelineEmailBody, { email: event.email }),
361
698
  event.content ? /* @__PURE__ */ jsx("div", { className: "rounded-md bg-muted/30 px-2.5 py-2 text-xs text-muted-foreground", children: event.content }) : null,
362
699
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-3", children: [
@@ -392,14 +729,26 @@ function EmailCard({
392
729
  ) });
393
730
  }
394
731
  return /* @__PURE__ */ jsx("div", { className: classes.cardContainer, "data-variant": variant, children: expanded && event.email ? /* @__PURE__ */ jsxs(Fragment, { children: [
395
- /* @__PURE__ */ jsx("div", { className: classes.cardHeader, "data-slot": "timeline-card-header", children: /* @__PURE__ */ jsx(
396
- EmailMetadata,
397
- {
398
- email: event.email,
399
- showAllRecipients,
400
- setShowAllRecipients
401
- }
402
- ) }),
732
+ /* @__PURE__ */ jsxs("div", { className: classes.cardHeader, "data-slot": "timeline-card-header", children: [
733
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 normal-case tracking-normal", children: /* @__PURE__ */ jsx(
734
+ EmailMetadata,
735
+ {
736
+ email: event.email,
737
+ showAllRecipients,
738
+ setShowAllRecipients
739
+ }
740
+ ) }),
741
+ /* @__PURE__ */ jsx(
742
+ CollapseTopButton,
743
+ {
744
+ onClick: (e) => {
745
+ e.stopPropagation();
746
+ setExpanded(false);
747
+ },
748
+ className: "ml-3 normal-case tracking-normal"
749
+ }
750
+ )
751
+ ] }),
403
752
  /* @__PURE__ */ jsxs("div", { className: classes.cardBody, "data-slot": "timeline-card-body", children: [
404
753
  /* @__PURE__ */ jsx(TimelineEmailBody, { email: event.email }),
405
754
  event.content ? /* @__PURE__ */ jsx("div", { className: "mt-3 rounded-md bg-muted/30 px-2.5 py-2 text-xs text-muted-foreground", children: event.content }) : null