| author | |
| committer | |
| log | e420ef98333c97205f836201cfeb94682a41893c |
| tree | ca9dbc54a12fa1b5c91ce29892c3f81affdbb2ef |
| parent | 016cdb9622359967afe80a27c538056ef1e7b857 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>5 files changed, 231 insertions(+), 235 deletions(-)
apps/web/src/components/ChatMarkdown.tsx+25-24| ... | ... | @@ -844,32 +844,33 @@ function MarkdownDetails({ |
| 844 | 844 | const content = childNodes.filter((_, index) => index !== summaryIndex); |
| 845 | 845 | |
| 846 | 846 | return ( |
| 847 | <Collapsible | |
| 848 | defaultOpen={open} | |
| 849 | onOpenChange={setIsOpen} | |
| 850 | className="chat-markdown-details my-2 border-y border-border/60" | |
| 851 | data-markdown-details="" | |
| 852 | data-markdown-details-open={isOpen ? "true" : "false"} | |
| 853 | > | |
| 854 | <CollapsibleTrigger | |
| 855 | className="flex w-full items-center gap-2 py-2 text-left text-sm font-medium text-foreground data-panel-open:[&_svg]:rotate-90" | |
| 856 | data-markdown-details-summary="" | |
| 847 | <div className="my-2 border-y border-border/60"> | |
| 848 | <Collapsible | |
| 849 | defaultOpen={open} | |
| 850 | onOpenChange={setIsOpen} | |
| 851 | data-markdown-details="" | |
| 852 | data-markdown-details-open={isOpen ? "true" : "false"} | |
| 857 | 853 | > |
| 858 | <ChevronRightIcon | |
| 859 | className="size-4 shrink-0 text-muted-foreground transition-transform" | |
| 860 | aria-hidden | |
| 861 | /> | |
| 862 | <span>{summary}</span> | |
| 863 | </CollapsibleTrigger> | |
| 864 | <CollapsiblePanel> | |
| 865 | <div | |
| 866 | className="pb-3 ps-6 text-foreground/[calc(80%+var(--appearance-contrast-boost)/5)]" | |
| 867 | data-markdown-details-content="" | |
| 854 | <CollapsibleTrigger | |
| 855 | className="flex w-full items-center gap-2 py-2 text-left text-sm font-medium text-foreground data-panel-open:[&_svg]:rotate-90" | |
| 856 | data-markdown-details-summary="" | |
| 868 | 857 | > |
| 869 | {content} | |
| 870 | </div> | |
| 871 | </CollapsiblePanel> | |
| 872 | </Collapsible> | |
| 858 | <ChevronRightIcon | |
| 859 | className="size-4 shrink-0 text-muted-foreground transition-transform" | |
| 860 | aria-hidden | |
| 861 | /> | |
| 862 | <span>{summary}</span> | |
| 863 | </CollapsibleTrigger> | |
| 864 | <CollapsiblePanel> | |
| 865 | <div | |
| 866 | className="pb-3 ps-6 text-foreground/[calc(80%+var(--appearance-contrast-boost)/5)]" | |
| 867 | data-markdown-details-content="" | |
| 868 | > | |
| 869 | {content} | |
| 870 | </div> | |
| 871 | </CollapsiblePanel> | |
| 872 | </Collapsible> | |
| 873 | </div> | |
| 873 | 874 | ); |
| 874 | 875 | } |
| 875 | 876 |
apps/web/src/components/onboarding/WelcomeWizard.tsx+89-93| ... | ... | @@ -350,40 +350,38 @@ function ConnectionStep({ |
| 350 | 350 | onToggleEnvironment={onToggleEnvironment} |
| 351 | 351 | /> |
| 352 | 352 | ) : null} |
| 353 | <Collapsible | |
| 354 | open={pairingOpen} | |
| 355 | onOpenChange={setPairingOpen} | |
| 356 | className="rounded-lg border border-border bg-background" | |
| 357 | > | |
| 358 | <CollapsibleTrigger | |
| 359 | disabled={isPairing} | |
| 360 | render={ | |
| 361 | <Button | |
| 362 | variant="ghost" | |
| 363 | className="h-auto min-h-14 w-full justify-start gap-3 px-3 py-3 text-left whitespace-normal sm:h-auto" | |
| 364 | /> | |
| 365 | } | |
| 366 | > | |
| 367 | <LinkIcon className="size-4 text-muted-foreground" /> | |
| 368 | <span className="flex-1">Add a computer</span> | |
| 369 | <ChevronRightIcon | |
| 370 | className={cn("size-4 text-muted-foreground", pairingOpen && "rotate-90")} | |
| 371 | /> | |
| 372 | </CollapsibleTrigger> | |
| 373 | <CollapsiblePanel> | |
| 374 | <div className="px-3 pb-3"> | |
| 375 | <PairingForm | |
| 376 | isPairing={isPairing} | |
| 377 | setIsPairing={setIsPairing} | |
| 378 | onPaired={(environmentId) => { | |
| 379 | setPairingOpen(false); | |
| 380 | onPaired(environmentId); | |
| 381 | requestAnimationFrame(() => continueRef.current?.focus()); | |
| 382 | }} | |
| 353 | <div className="rounded-lg border border-border bg-background"> | |
| 354 | <Collapsible open={pairingOpen} onOpenChange={setPairingOpen}> | |
| 355 | <CollapsibleTrigger | |
| 356 | disabled={isPairing} | |
| 357 | render={ | |
| 358 | <Button | |
| 359 | variant="ghost" | |
| 360 | className="h-auto min-h-14 w-full justify-start gap-3 px-3 py-3 text-left whitespace-normal sm:h-auto" | |
| 361 | /> | |
| 362 | } | |
| 363 | > | |
| 364 | <LinkIcon className="size-4 text-muted-foreground" /> | |
| 365 | <span className="flex-1">Add a computer</span> | |
| 366 | <ChevronRightIcon | |
| 367 | className={cn("size-4 text-muted-foreground", pairingOpen && "rotate-90")} | |
| 383 | 368 | /> |
| 384 | </div> | |
| 385 | </CollapsiblePanel> | |
| 386 | </Collapsible> | |
| 369 | </CollapsibleTrigger> | |
| 370 | <CollapsiblePanel> | |
| 371 | <div className="px-3 pb-3"> | |
| 372 | <PairingForm | |
| 373 | isPairing={isPairing} | |
| 374 | setIsPairing={setIsPairing} | |
| 375 | onPaired={(environmentId) => { | |
| 376 | setPairingOpen(false); | |
| 377 | onPaired(environmentId); | |
| 378 | requestAnimationFrame(() => continueRef.current?.focus()); | |
| 379 | }} | |
| 380 | /> | |
| 381 | </div> | |
| 382 | </CollapsiblePanel> | |
| 383 | </Collapsible> | |
| 384 | </div> | |
| 387 | 385 | </div> |
| 388 | 386 | <div className="mt-6 flex items-center justify-end gap-3"> |
| 389 | 387 | <Button |
| ... | ... | @@ -419,69 +417,67 @@ function ConnectAccountOption({ |
| 419 | 417 | const onDiscoveryReady = useCallback(() => setDiscoveryReady(true), []); |
| 420 | 418 | |
| 421 | 419 | return ( |
| 422 | <Collapsible | |
| 423 | open={expanded && !!isSignedIn && discoveryReady} | |
| 424 | onOpenChange={setExpanded} | |
| 425 | className="rounded-lg border border-border bg-background" | |
| 426 | > | |
| 427 | <CollapsibleTrigger | |
| 428 | disabled={disabled || !isLoaded} | |
| 429 | onClick={(event) => { | |
| 430 | if (!isSignedIn) { | |
| 431 | event.preventDefault(); | |
| 432 | setExpanded(true); | |
| 433 | openAuthPrompt(); | |
| 420 | <div className="rounded-lg border border-border bg-background"> | |
| 421 | <Collapsible open={expanded && !!isSignedIn && discoveryReady} onOpenChange={setExpanded}> | |
| 422 | <CollapsibleTrigger | |
| 423 | disabled={disabled || !isLoaded} | |
| 424 | onClick={(event) => { | |
| 425 | if (!isSignedIn) { | |
| 426 | event.preventDefault(); | |
| 427 | setExpanded(true); | |
| 428 | openAuthPrompt(); | |
| 429 | } | |
| 430 | }} | |
| 431 | render={ | |
| 432 | <Button | |
| 433 | variant="ghost" | |
| 434 | className="h-auto min-h-14 w-full justify-start gap-3 px-3 py-3 text-left whitespace-normal sm:h-auto" | |
| 435 | /> | |
| 434 | 436 | } |
| 435 | }} | |
| 436 | render={ | |
| 437 | <Button | |
| 438 | variant="ghost" | |
| 439 | className="h-auto min-h-14 w-full justify-start gap-3 px-3 py-3 text-left whitespace-normal sm:h-auto" | |
| 437 | > | |
| 438 | <CloudIcon className="size-4 text-muted-foreground" /> | |
| 439 | <span className="flex-1">T3 Connect</span> | |
| 440 | <span className="text-xs text-muted-foreground"> | |
| 441 | {!isLoaded | |
| 442 | ? "Loading sign-in…" | |
| 443 | : !isSignedIn | |
| 444 | ? "Sign in" | |
| 445 | : !discoveryReady | |
| 446 | ? "Loading computers…" | |
| 447 | : null} | |
| 448 | </span> | |
| 449 | <ChevronRightIcon | |
| 450 | className={cn("size-4 text-muted-foreground", expanded && isSignedIn && "rotate-90")} | |
| 440 | 451 | /> |
| 441 | } | |
| 442 | > | |
| 443 | <CloudIcon className="size-4 text-muted-foreground" /> | |
| 444 | <span className="flex-1">T3 Connect</span> | |
| 445 | <span className="text-xs text-muted-foreground"> | |
| 446 | {!isLoaded | |
| 447 | ? "Loading sign-in…" | |
| 448 | : !isSignedIn | |
| 449 | ? "Sign in" | |
| 450 | : !discoveryReady | |
| 451 | ? "Loading computers…" | |
| 452 | : null} | |
| 453 | </span> | |
| 454 | <ChevronRightIcon | |
| 455 | className={cn("size-4 text-muted-foreground", expanded && isSignedIn && "rotate-90")} | |
| 456 | /> | |
| 457 | </CollapsibleTrigger> | |
| 458 | <CollapsiblePanel keepMounted> | |
| 459 | <div className="px-3 pb-3"> | |
| 460 | <div className="mb-3 space-y-1.5"> | |
| 461 | {isSignedIn ? ( | |
| 462 | <CloudEnvironmentConnectRows | |
| 463 | primaryEnvironmentId={null} | |
| 464 | savedEnvironments={environments} | |
| 465 | showSavedEnvironments | |
| 466 | onDiscoveryReady={onDiscoveryReady} | |
| 467 | selection={{ selectedIds, onChange: onToggleEnvironment, autoSelectedComputers }} | |
| 468 | refreshWhileEmpty | |
| 469 | empty={ | |
| 470 | <p className="py-3 text-sm text-muted-foreground">No computers linked yet.</p> | |
| 471 | } | |
| 472 | /> | |
| 473 | ) : null} | |
| 452 | </CollapsibleTrigger> | |
| 453 | <CollapsiblePanel keepMounted> | |
| 454 | <div className="px-3 pb-3"> | |
| 455 | <div className="mb-3 space-y-1.5"> | |
| 456 | {isSignedIn ? ( | |
| 457 | <CloudEnvironmentConnectRows | |
| 458 | primaryEnvironmentId={null} | |
| 459 | savedEnvironments={environments} | |
| 460 | showSavedEnvironments | |
| 461 | onDiscoveryReady={onDiscoveryReady} | |
| 462 | selection={{ selectedIds, onChange: onToggleEnvironment, autoSelectedComputers }} | |
| 463 | refreshWhileEmpty | |
| 464 | empty={ | |
| 465 | <p className="py-3 text-sm text-muted-foreground">No computers linked yet.</p> | |
| 466 | } | |
| 467 | /> | |
| 468 | ) : null} | |
| 469 | </div> | |
| 470 | <p className="text-sm text-muted-foreground"> | |
| 471 | Run this on each computer you want to connect. | |
| 472 | </p> | |
| 473 | <CommandBlock command="npx t3 connect" className="mt-3" /> | |
| 474 | <p className="mt-3 text-xs text-muted-foreground"> | |
| 475 | Keep T3 Code running. Select the computers you want to set up above. | |
| 476 | </p> | |
| 474 | 477 | </div> |
| 475 | <p className="text-sm text-muted-foreground"> | |
| 476 | Run this on each computer you want to connect. | |
| 477 | </p> | |
| 478 | <CommandBlock command="npx t3 connect" className="mt-3" /> | |
| 479 | <p className="mt-3 text-xs text-muted-foreground"> | |
| 480 | Keep T3 Code running. Select the computers you want to set up above. | |
| 481 | </p> | |
| 482 | </div> | |
| 483 | </CollapsiblePanel> | |
| 484 | </Collapsible> | |
| 478 | </CollapsiblePanel> | |
| 479 | </Collapsible> | |
| 480 | </div> | |
| 485 | 481 | ); |
| 486 | 482 | } |
| 487 | 483 |
apps/web/src/components/pullRequest/PullRequestCodeTab.tsx+53-53| ... | ... | @@ -1406,63 +1406,63 @@ function PullRequestCodeTab({ |
| 1406 | 1406 | {/* Above the code, closed, and counted: these belong to the change rather than to any |
| 1407 | 1407 | line of it, and in the stream they read as cards dropped into the patch. */} |
| 1408 | 1408 | {orphanFiles.size > 0 ? ( |
| 1409 | <Collapsible | |
| 1410 | className="shrink-0 border-b border-border/60" | |
| 1411 | open={orphansOpen} | |
| 1412 | onOpenChange={setOrphansOpen} | |
| 1413 | > | |
| 1414 | {/* Still a heading, so the section keeps its place in a screen reader's outline; | |
| 1409 | <div className="shrink-0 border-b border-border/60"> | |
| 1410 | <Collapsible open={orphansOpen} onOpenChange={setOrphansOpen}> | |
| 1411 | {/* Still a heading, so the section keeps its place in a screen reader's outline; | |
| 1415 | 1412 | the count is spelled out there rather than left as a bare number. */} |
| 1416 | <h2> | |
| 1417 | <CollapsibleTrigger className="flex w-full items-center gap-1.5 px-4 py-2 text-left text-xs text-muted-foreground"> | |
| 1418 | {/* While slices are still arriving a conversation may simply belong to a file | |
| 1413 | <h2> | |
| 1414 | <CollapsibleTrigger className="flex w-full items-center gap-1.5 px-4 py-2 text-left text-xs text-muted-foreground"> | |
| 1415 | {/* While slices are still arriving a conversation may simply belong to a file | |
| 1419 | 1416 | that has not landed yet, which is not the same as being off the diff. */} |
| 1420 | <span> | |
| 1421 | {nextCursor === null | |
| 1422 | ? "Conversations not on the current diff" | |
| 1423 | : "Conversations not on the diff loaded so far"} | |
| 1424 | </span> | |
| 1425 | <ChevronRightIcon | |
| 1426 | aria-hidden | |
| 1427 | className={cn("size-3.5 transition-transform", orphansOpen && "rotate-90")} | |
| 1428 | /> | |
| 1429 | <span aria-hidden className="tabular-nums"> | |
| 1430 | {orphanThreads.length} | |
| 1431 | </span> | |
| 1432 | <span className="sr-only"> | |
| 1433 | {orphanThreads.length === 1 | |
| 1434 | ? "1 conversation" | |
| 1435 | : `${orphanThreads.length} conversations`} | |
| 1436 | </span> | |
| 1437 | </CollapsibleTrigger> | |
| 1438 | </h2> | |
| 1439 | <CollapsiblePanel> | |
| 1440 | {/* Capped: opened on a change with dozens of them, this would otherwise leave no | |
| 1417 | <span> | |
| 1418 | {nextCursor === null | |
| 1419 | ? "Conversations not on the current diff" | |
| 1420 | : "Conversations not on the diff loaded so far"} | |
| 1421 | </span> | |
| 1422 | <ChevronRightIcon | |
| 1423 | aria-hidden | |
| 1424 | className={cn("size-3.5 transition-transform", orphansOpen && "rotate-90")} | |
| 1425 | /> | |
| 1426 | <span aria-hidden className="tabular-nums"> | |
| 1427 | {orphanThreads.length} | |
| 1428 | </span> | |
| 1429 | <span className="sr-only"> | |
| 1430 | {orphanThreads.length === 1 | |
| 1431 | ? "1 conversation" | |
| 1432 | : `${orphanThreads.length} conversations`} | |
| 1433 | </span> | |
| 1434 | </CollapsibleTrigger> | |
| 1435 | </h2> | |
| 1436 | <CollapsiblePanel> | |
| 1437 | {/* Capped: opened on a change with dozens of them, this would otherwise leave no | |
| 1441 | 1438 | room for the diff it sits above. */} |
| 1442 | <div className="max-h-64 space-y-3 overflow-auto px-4 pb-3"> | |
| 1443 | {[...orphanFiles].map(([path, threads]) => ( | |
| 1444 | <div key={path}> | |
| 1445 | <Tooltip> | |
| 1446 | <TooltipTrigger | |
| 1447 | render={<p className="truncate px-3 text-xs text-muted-foreground">{path}</p>} | |
| 1448 | /> | |
| 1449 | <TooltipPopup side="top">{path}</TooltipPopup> | |
| 1450 | </Tooltip> | |
| 1451 | <div className="mt-1 space-y-2"> | |
| 1452 | {threads.map((thread) => ( | |
| 1453 | <div key={thread.id}> | |
| 1454 | {thread.line === null ? null : ( | |
| 1455 | <p className="px-3 text-xs text-muted-foreground">Line {thread.line}</p> | |
| 1456 | )} | |
| 1457 | {renderThreadCard(thread)} | |
| 1458 | </div> | |
| 1459 | ))} | |
| 1439 | <div className="max-h-64 space-y-3 overflow-auto px-4 pb-3"> | |
| 1440 | {[...orphanFiles].map(([path, threads]) => ( | |
| 1441 | <div key={path}> | |
| 1442 | <Tooltip> | |
| 1443 | <TooltipTrigger | |
| 1444 | render={ | |
| 1445 | <p className="truncate px-3 text-xs text-muted-foreground">{path}</p> | |
| 1446 | } | |
| 1447 | /> | |
| 1448 | <TooltipPopup side="top">{path}</TooltipPopup> | |
| 1449 | </Tooltip> | |
| 1450 | <div className="mt-1 space-y-2"> | |
| 1451 | {threads.map((thread) => ( | |
| 1452 | <div key={thread.id}> | |
| 1453 | {thread.line === null ? null : ( | |
| 1454 | <p className="px-3 text-xs text-muted-foreground">Line {thread.line}</p> | |
| 1455 | )} | |
| 1456 | {renderThreadCard(thread)} | |
| 1457 | </div> | |
| 1458 | ))} | |
| 1459 | </div> | |
| 1460 | 1460 | </div> |
| 1461 | </div> | |
| 1462 | ))} | |
| 1463 | </div> | |
| 1464 | </CollapsiblePanel> | |
| 1465 | </Collapsible> | |
| 1461 | ))} | |
| 1462 | </div> | |
| 1463 | </CollapsiblePanel> | |
| 1464 | </Collapsible> | |
| 1465 | </div> | |
| 1466 | 1466 | ) : null} |
| 1467 | 1467 | <div className="flex min-h-0 flex-1 overflow-hidden"> |
| 1468 | 1468 | {/* Relative wrapper so the review overlay floats over the diff rather than pushing it |
apps/web/src/components/pullRequest/PullRequestSummaryTab.tsx+63-64| ... | ... | @@ -378,74 +378,73 @@ function CommentGroup({ |
| 378 | 378 | null, |
| 379 | 379 | ); |
| 380 | 380 | return ( |
| 381 | <Collapsible | |
| 382 | className="overflow-hidden rounded-lg border border-border/70 bg-muted/20" | |
| 383 | onOpenChange={onOpenChange} | |
| 384 | > | |
| 385 | <div className="flex items-center gap-3 pl-3"> | |
| 386 | <div className="flex shrink-0 -space-x-1.5"> | |
| 387 | {authors.slice(0, 3).map((actor) => ( | |
| 388 | <PullRequestActorLabel | |
| 389 | key={actor?.login ?? "ghost"} | |
| 390 | actor={actor} | |
| 391 | profileUrl={ | |
| 392 | detail.provider === "github" && actor | |
| 393 | ? new URL( | |
| 394 | actor.isBot || actor.login.endsWith("[bot]") | |
| 395 | ? `/apps/${encodeURIComponent(actor.login.replace(/\[bot\]$/, ""))}` | |
| 396 | : `/${encodeURIComponent(actor.login)}`, | |
| 397 | detail.url, | |
| 398 | ).toString() | |
| 399 | : null | |
| 400 | } | |
| 401 | labelClassName="sr-only" | |
| 402 | className="relative rounded-full bg-background ring-2 ring-background hover:z-10 focus-visible:z-10 [&>img]:size-6 [&>span:first-child]:size-6" | |
| 403 | /> | |
| 404 | ))} | |
| 405 | {authors.length > 3 ? ( | |
| 406 | <span className="relative flex size-6 items-center justify-center rounded-full bg-muted text-[10px] text-muted-foreground ring-2 ring-background"> | |
| 407 | +{authors.length - 3} | |
| 408 | </span> | |
| 409 | ) : null} | |
| 410 | </div> | |
| 411 | <CollapsibleTrigger | |
| 412 | aria-label={label} | |
| 413 | className="group flex min-w-0 flex-1 items-center gap-3 rounded-md py-3 pr-3 text-left hover:bg-muted/30" | |
| 414 | > | |
| 415 | <span className="min-w-0 flex-1 space-y-1"> | |
| 416 | <span className="block text-xs font-medium text-foreground/90">{label}</span> | |
| 417 | <span className="flex flex-wrap gap-x-1.5 text-[11px] text-muted-foreground"> | |
| 418 | <span> | |
| 419 | {authors.length} {authors.length === 1 ? "author" : "authors"} | |
| 381 | <div className="overflow-hidden rounded-lg border border-border bg-background"> | |
| 382 | <Collapsible onOpenChange={onOpenChange}> | |
| 383 | <div className="flex items-center gap-3 pl-3"> | |
| 384 | <div className="flex shrink-0 -space-x-1.5"> | |
| 385 | {authors.slice(0, 3).map((actor) => ( | |
| 386 | <PullRequestActorLabel | |
| 387 | key={actor?.login ?? "ghost"} | |
| 388 | actor={actor} | |
| 389 | profileUrl={ | |
| 390 | detail.provider === "github" && actor | |
| 391 | ? new URL( | |
| 392 | actor.isBot || actor.login.endsWith("[bot]") | |
| 393 | ? `/apps/${encodeURIComponent(actor.login.replace(/\[bot\]$/, ""))}` | |
| 394 | : `/${encodeURIComponent(actor.login)}`, | |
| 395 | detail.url, | |
| 396 | ).toString() | |
| 397 | : null | |
| 398 | } | |
| 399 | labelClassName="sr-only" | |
| 400 | className="relative rounded-full bg-background ring-2 ring-background hover:z-10 focus-visible:z-10 [&>img]:size-6 [&>span:first-child]:size-6" | |
| 401 | /> | |
| 402 | ))} | |
| 403 | {authors.length > 3 ? ( | |
| 404 | <span className="relative flex size-6 items-center justify-center rounded-full bg-muted text-[10px] text-muted-foreground ring-2 ring-background"> | |
| 405 | +{authors.length - 3} | |
| 420 | 406 | </span> |
| 421 | {fileCount > 0 ? ( | |
| 422 | <span> | |
| 423 | · {fileCount} {fileCount === 1 ? "file" : "files"} | |
| 424 | </span> | |
| 425 | ) : null} | |
| 426 | {latest ? ( | |
| 407 | ) : null} | |
| 408 | </div> | |
| 409 | <CollapsibleTrigger | |
| 410 | aria-label={label} | |
| 411 | className="group flex min-w-0 flex-1 items-center gap-3 rounded-md py-3 pr-3 text-left hover:bg-muted/30" | |
| 412 | > | |
| 413 | <span className="min-w-0 flex-1 space-y-1"> | |
| 414 | <span className="block text-xs font-medium text-foreground/90">{label}</span> | |
| 415 | <span className="flex flex-wrap gap-x-1.5 text-[11px] text-muted-foreground"> | |
| 427 | 416 | <span> |
| 428 | · Latest{" "} | |
| 429 | <Tooltip> | |
| 430 | <TooltipTrigger render={<time dateTime={latest} />}> | |
| 431 | {formatRelativeTimeLabel(latest)} | |
| 432 | </TooltipTrigger> | |
| 433 | <TooltipPopup>{new Date(latest).toLocaleString()}</TooltipPopup> | |
| 434 | </Tooltip> | |
| 417 | {authors.length} {authors.length === 1 ? "author" : "authors"} | |
| 435 | 418 | </span> |
| 436 | ) : null} | |
| 419 | {fileCount > 0 ? ( | |
| 420 | <span> | |
| 421 | · {fileCount} {fileCount === 1 ? "file" : "files"} | |
| 422 | </span> | |
| 423 | ) : null} | |
| 424 | {latest ? ( | |
| 425 | <span> | |
| 426 | · Latest{" "} | |
| 427 | <Tooltip> | |
| 428 | <TooltipTrigger render={<time dateTime={latest} />}> | |
| 429 | {formatRelativeTimeLabel(latest)} | |
| 430 | </TooltipTrigger> | |
| 431 | <TooltipPopup>{new Date(latest).toLocaleString()}</TooltipPopup> | |
| 432 | </Tooltip> | |
| 433 | </span> | |
| 434 | ) : null} | |
| 435 | </span> | |
| 437 | 436 | </span> |
| 438 | </span> | |
| 439 | <ChevronRightIcon | |
| 440 | aria-hidden | |
| 441 | className="size-3.5 shrink-0 text-muted-foreground transition-transform group-data-panel-open:rotate-90" | |
| 442 | /> | |
| 443 | </CollapsibleTrigger> | |
| 444 | </div> | |
| 445 | <CollapsiblePanel keepMounted> | |
| 446 | <div className="border-t border-border/60 px-3 pb-3">{children}</div> | |
| 447 | </CollapsiblePanel> | |
| 448 | </Collapsible> | |
| 437 | <ChevronRightIcon | |
| 438 | aria-hidden | |
| 439 | className="size-3.5 shrink-0 text-muted-foreground transition-transform group-data-panel-open:rotate-90" | |
| 440 | /> | |
| 441 | </CollapsibleTrigger> | |
| 442 | </div> | |
| 443 | <CollapsiblePanel keepMounted> | |
| 444 | <div className="border-t border-border/60 px-3 pb-3">{children}</div> | |
| 445 | </CollapsiblePanel> | |
| 446 | </Collapsible> | |
| 447 | </div> | |
| 449 | 448 | ); |
| 450 | 449 | } |
| 451 | 450 |
scripts/lint-restyle-ceiling.ts+1-1| ... | ... | @@ -8,7 +8,7 @@ import * as NodeURL from "node:url"; |
| 8 | 8 | // components/ui exports are migrated to variants (see vite.config.ts). This gate keeps the |
| 9 | 9 | // count from growing: CI fails when findings exceed the ceiling. Lower the ceiling when you |
| 10 | 10 | // migrate a file, and delete this script when the rule becomes an error. |
| 11 | export const RESTYLE_CEILING = 793; | |
| 11 | export const RESTYLE_CEILING = 776; | |
| 12 | 12 | |
| 13 | 13 | const RULE = "shadcn(no-restyle)"; |
| 14 | 14 |