| author | |
| committer | |
| log | c77a7b7eebd6ea8a3a63bbcaaa7c1707fe65c86e |
| tree | fc7f1ad3f6e5f714631d976b371b7715d4d7fc19 |
| parent | bd2346eda2e2c380d1844869c7fd16c279d2190f |
| signature | Signed by PGP key B5690EEEBB952194 |
9 files changed, 58 insertions(+), 27 deletions(-)
apps/web/src/components/BranchToolbarBranchSelector.tsx+5-1| ... | @@ -779,7 +779,11 @@ export function BranchToolbarBranchSelector({ | ... | @@ -779,7 +779,11 @@ export function BranchToolbarBranchSelector({ |
| 779 | )} | 779 | )} |
| 780 | /> | 780 | /> |
| 781 | <ComposerContextLabel displayMode={displayMode}> | 781 | <ComposerContextLabel displayMode={displayMode}> |
| 782 | <MiddleTruncate value={triggerLabel} className="w-full" /> | 782 | <MiddleTruncate |
| 783 | value={triggerLabel} | ||
| 784 | variant={displayMode === "panel" ? "cap-aligned" : "default"} | ||
| 785 | className="w-full" | ||
| 786 | /> | ||
| 783 | </ComposerContextLabel> | 787 | </ComposerContextLabel> |
| 784 | {displayMode !== "panel" ? ( | 788 | {displayMode !== "panel" ? ( |
| 785 | <ChevronDownIcon className="size-3 shrink-0 opacity-50" /> | 789 | <ChevronDownIcon className="size-3 shrink-0 opacity-50" /> |
apps/web/src/components/ComposerContextLabel.tsx+3-1| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | import type { ReactNode } from "react"; | 1 | import type { ReactNode } from "react"; |
| 2 | 2 | ||
| 3 | import { cn } from "../lib/utils"; | 3 | import { cn } from "../lib/utils"; |
| 4 | import { THREAD_DETAILS_PANEL_LABEL_CLASS } from "./chat/threadDetailsPanelStyles"; | ||
| 4 | 5 | ||
| 5 | /** Keeps text measurable while the composer's outer label box collapses. */ | 6 | /** Keeps text measurable while the composer's outer label box collapses. */ |
| 6 | export function ComposerContextLabel({ | 7 | export function ComposerContextLabel({ |
| ... | @@ -16,7 +17,7 @@ export function ComposerContextLabel({ | ... | @@ -16,7 +17,7 @@ export function ComposerContextLabel({ |
| 16 | className={cn( | 17 | className={cn( |
| 17 | "min-w-0", | 18 | "min-w-0", |
| 18 | displayMode === "panel" | 19 | displayMode === "panel" |
| 19 | ? "flex-1 truncate text-left" | 20 | ? "flex-1 overflow-x-clip overflow-y-visible text-left" |
| 20 | : "max-w-[240px] group-data-[compact]/composer-context:max-w-0", | 21 | : "max-w-[240px] group-data-[compact]/composer-context:max-w-0", |
| 21 | )} | 22 | )} |
| 22 | > | 23 | > |
| ... | @@ -24,6 +25,7 @@ export function ComposerContextLabel({ | ... | @@ -24,6 +25,7 @@ export function ComposerContextLabel({ |
| 24 | data-composer-label-motion | 25 | data-composer-label-motion |
| 25 | className={cn( | 26 | className={cn( |
| 26 | "block w-full min-w-0 truncate", | 27 | "block w-full min-w-0 truncate", |
| 28 | displayMode === "panel" && THREAD_DETAILS_PANEL_LABEL_CLASS, | ||
| 27 | displayMode === "toolbar" && | 29 | displayMode === "toolbar" && |
| 28 | "max-w-[240px] transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none", | 30 | "max-w-[240px] transition-opacity duration-180 ease-drawer group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none", |
| 29 | )} | 31 | )} |
apps/web/src/components/GitActionsControl.tsx+23-18| ... | @@ -127,6 +127,7 @@ import { type DraftId, useComposerDraftStore } from "~/composerDraftStore"; | ... | @@ -127,6 +127,7 @@ import { type DraftId, useComposerDraftStore } from "~/composerDraftStore"; |
| 127 | import { | 127 | import { |
| 128 | THREAD_DETAILS_PANEL_CHEVRON_CLASS, | 128 | THREAD_DETAILS_PANEL_CHEVRON_CLASS, |
| 129 | THREAD_DETAILS_PANEL_ICON_CLASS, | 129 | THREAD_DETAILS_PANEL_ICON_CLASS, |
| 130 | THREAD_DETAILS_PANEL_LABEL_CLASS, | ||
| 130 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, | 131 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, |
| 131 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, | 132 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, |
| 132 | } from "./chat/threadDetailsPanelStyles"; | 133 | } from "./chat/threadDetailsPanelStyles"; |
| ... | @@ -441,23 +442,25 @@ function GitActionProgressButtonContent({ | ... | @@ -441,23 +442,25 @@ function GitActionProgressButtonContent({ |
| 441 | aria-live="polite" | 442 | aria-live="polite" |
| 442 | className={cn( | 443 | className={cn( |
| 443 | "grid min-w-0 flex-1 items-center", | 444 | "grid min-w-0 flex-1 items-center", |
| 444 | // Pin the title row to the button's minimum content height (min-height | 445 | // Pin the title row to the button's minimum content height so output |
| 445 | // minus vertical padding and border) so revealing the output row | 446 | // expands below it. Panel controls leave 24px after padding and border. |
| 446 | // extends the button downward without re-centering — the title must | 447 | // No row gap: collapsed output must not add height. The panel's elapsed |
| 447 | // not shift. No row gap: the collapsed output row must contribute zero | 448 | // counter uses the menu-chevron slot, so it has no trailing column. |
| 448 | // height so the single-line running button matches the static button | ||
| 449 | // exactly. The panel column gap matches the static row's icon-to-label | ||
| 450 | // distance (gap-2.5 plus the label's ml-0.5). In the panel the elapsed | ||
| 451 | // counter renders outside the button (in the menu-chevron slot), so | ||
| 452 | // there is no trailing column. | ||
| 453 | isPanel | 449 | isPanel |
| 454 | ? "grid-cols-[auto_minmax(0,1fr)] grid-rows-[1.75rem] gap-x-3" | 450 | ? "grid-cols-[auto_minmax(0,1fr)] grid-rows-[1.5rem] gap-x-3" |
| 455 | : "grid-cols-[auto_minmax(0,1fr)_auto] grid-rows-[1.25rem] gap-x-2.5 sm:grid-rows-[1rem]", | 451 | : "grid-cols-[auto_minmax(0,1fr)_auto] grid-rows-[1.25rem] gap-x-2.5 sm:grid-rows-[1rem]", |
| 456 | )} | 452 | )} |
| 457 | role="status" | 453 | role="status" |
| 458 | > | 454 | > |
| 459 | <Spinner aria-hidden="true" className="row-start-1 -mx-0.5 shrink-0" /> | 455 | <Spinner aria-hidden="true" className="row-start-1 -mx-0.5 shrink-0" /> |
| 460 | <p className="row-start-1 min-w-0 truncate text-left">{progress.status}</p> | 456 | <p |
| 457 | className={cn( | ||
| 458 | "row-start-1 min-w-0 truncate text-left", | ||
| 459 | isPanel && THREAD_DETAILS_PANEL_LABEL_CLASS, | ||
| 460 | )} | ||
| 461 | > | ||
| 462 | {progress.status} | ||
| 463 | </p> | ||
| 461 | {!isPanel ? ( | 464 | {!isPanel ? ( |
| 462 | <GitActionElapsedTime | 465 | <GitActionElapsedTime |
| 463 | startedAtMs={progress.startedAtMs} | 466 | startedAtMs={progress.startedAtMs} |
| ... | @@ -496,11 +499,13 @@ function GitActionSuccessButtonContent({ success }: { success: InlineGitActionSu | ... | @@ -496,11 +499,13 @@ function GitActionSuccessButtonContent({ success }: { success: InlineGitActionSu |
| 496 | return ( | 499 | return ( |
| 497 | <div | 500 | <div |
| 498 | aria-live="polite" | 501 | aria-live="polite" |
| 499 | className="grid min-w-0 flex-1 grid-cols-[auto_minmax(0,1fr)] grid-rows-[1.75rem] items-center gap-x-3" | 502 | className="grid min-w-0 flex-1 grid-cols-[auto_minmax(0,1fr)] grid-rows-[1.5rem] items-center gap-x-3" |
| 500 | role="status" | 503 | role="status" |
| 501 | > | 504 | > |
| 502 | <CheckIcon aria-hidden="true" className="size-3.5 shrink-0 text-success" /> | 505 | <CheckIcon aria-hidden="true" className="size-3.5 shrink-0 text-success" /> |
| 503 | <p className="min-w-0 truncate text-left">{success.title}</p> | 506 | <p className={cn("min-w-0 truncate text-left", THREAD_DETAILS_PANEL_LABEL_CLASS)}> |
| 507 | {success.title} | ||
| 508 | </p> | ||
| 504 | <div | 509 | <div |
| 505 | className={cn( | 510 | className={cn( |
| 506 | "col-start-2 grid min-w-0 transition-[grid-template-rows,opacity] duration-200 ease-out motion-reduce:transition-none", | 511 | "col-start-2 grid min-w-0 transition-[grid-template-rows,opacity] duration-200 ease-out motion-reduce:transition-none", |
| ... | @@ -1704,7 +1709,7 @@ export default function GitActionsControl({ | ... | @@ -1704,7 +1709,7 @@ export default function GitActionsControl({ |
| 1704 | <PopoverTrigger | 1709 | <PopoverTrigger |
| 1705 | openOnHover | 1710 | openOnHover |
| 1706 | nativeButton={false} | 1711 | nativeButton={false} |
| 1707 | render={<span className="block w-max cursor-not-allowed" />} | 1712 | render={<span className="block w-full cursor-not-allowed" />} |
| 1708 | > | 1713 | > |
| 1709 | <MenuItem | 1714 | <MenuItem |
| 1710 | density={presentation === "menu" ? "touch" : "default"} | 1715 | density={presentation === "menu" ? "touch" : "default"} |
| ... | @@ -1824,7 +1829,7 @@ export default function GitActionsControl({ | ... | @@ -1824,7 +1829,7 @@ export default function GitActionsControl({ |
| 1824 | onClick={initializeGit} | 1829 | onClick={initializeGit} |
| 1825 | > | 1830 | > |
| 1826 | <GitBranchPlusIcon className="size-3.5" aria-hidden /> | 1831 | <GitBranchPlusIcon className="size-3.5" aria-hidden /> |
| 1827 | <span className="ml-0.5"> | 1832 | <span className={cn("ml-0.5", isPanel && THREAD_DETAILS_PANEL_LABEL_CLASS)}> |
| 1828 | {initAction.isPending ? "Initializing..." : "Initialize Git"} | 1833 | {initAction.isPending ? "Initializing..." : "Initialize Git"} |
| 1829 | </span> | 1834 | </span> |
| 1830 | </ThreadDetailsControl> | 1835 | </ThreadDetailsControl> |
| ... | @@ -1882,7 +1887,7 @@ export default function GitActionsControl({ | ... | @@ -1882,7 +1887,7 @@ export default function GitActionsControl({ |
| 1882 | <span | 1887 | <span |
| 1883 | className={cn( | 1888 | className={cn( |
| 1884 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", | 1889 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", |
| 1885 | isPanel && "not-sr-only ml-0 truncate", | 1890 | isPanel && cn("not-sr-only ml-0 truncate", THREAD_DETAILS_PANEL_LABEL_CLASS), |
| 1886 | )} | 1891 | )} |
| 1887 | > | 1892 | > |
| 1888 | {quickAction.label} | 1893 | {quickAction.label} |
| ... | @@ -1909,7 +1914,7 @@ export default function GitActionsControl({ | ... | @@ -1909,7 +1914,7 @@ export default function GitActionsControl({ |
| 1909 | <span | 1914 | <span |
| 1910 | className={cn( | 1915 | className={cn( |
| 1911 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", | 1916 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", |
| 1912 | isPanel && "not-sr-only ml-0 truncate", | 1917 | isPanel && cn("not-sr-only ml-0 truncate", THREAD_DETAILS_PANEL_LABEL_CLASS), |
| 1913 | )} | 1918 | )} |
| 1914 | > | 1919 | > |
| 1915 | {quickAction.label} | 1920 | {quickAction.label} |
| ... | @@ -1979,7 +1984,7 @@ export default function GitActionsControl({ | ... | @@ -1979,7 +1984,7 @@ export default function GitActionsControl({ |
| 1979 | onClick={onOpenChanges} | 1984 | onClick={onOpenChanges} |
| 1980 | > | 1985 | > |
| 1981 | <FileDiffIcon className={THREAD_DETAILS_PANEL_ICON_CLASS} aria-hidden /> | 1986 | <FileDiffIcon className={THREAD_DETAILS_PANEL_ICON_CLASS} aria-hidden /> |
| 1982 | <span className="flex-1 text-left">Changes</span> | 1987 | <span className={cn("flex-1 text-left", THREAD_DETAILS_PANEL_LABEL_CLASS)}>Changes</span> |
| 1983 | <span className="flex items-center gap-1 font-mono text-2xs tabular-nums"> | 1988 | <span className="flex items-center gap-1 font-mono text-2xs tabular-nums"> |
| 1984 | <span className="text-success">+{changesTotals?.insertions ?? 0}</span> | 1989 | <span className="text-success">+{changesTotals?.insertions ?? 0}</span> |
| 1985 | <span className="text-destructive">-{changesTotals?.deletions ?? 0}</span> | 1990 | <span className="text-destructive">-{changesTotals?.deletions ?? 0}</span> |
apps/web/src/components/ProjectScriptsControl.tsx+6-3| ... | @@ -50,6 +50,7 @@ import { cn } from "~/lib/utils"; | ... | @@ -50,6 +50,7 @@ import { cn } from "~/lib/utils"; |
| 50 | import { | 50 | import { |
| 51 | THREAD_DETAILS_PANEL_CHEVRON_CLASS, | 51 | THREAD_DETAILS_PANEL_CHEVRON_CLASS, |
| 52 | THREAD_DETAILS_PANEL_ICON_CLASS, | 52 | THREAD_DETAILS_PANEL_ICON_CLASS, |
| 53 | THREAD_DETAILS_PANEL_LABEL_CLASS, | ||
| 53 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, | 54 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, |
| 54 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, | 55 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, |
| 55 | } from "./chat/threadDetailsPanelStyles"; | 56 | } from "./chat/threadDetailsPanelStyles"; |
| ... | @@ -322,7 +323,7 @@ export default function ProjectScriptsControl({ | ... | @@ -322,7 +323,7 @@ export default function ProjectScriptsControl({ |
| 322 | <span | 323 | <span |
| 323 | className={cn( | 324 | className={cn( |
| 324 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", | 325 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", |
| 325 | isPanel && "not-sr-only ml-0 truncate", | 326 | isPanel && cn("not-sr-only ml-0 truncate", THREAD_DETAILS_PANEL_LABEL_CLASS), |
| 326 | )} | 327 | )} |
| 327 | > | 328 | > |
| 328 | {primaryScript.name} | 329 | {primaryScript.name} |
| ... | @@ -387,7 +388,9 @@ export default function ProjectScriptsControl({ | ... | @@ -387,7 +388,9 @@ export default function ProjectScriptsControl({ |
| 387 | onClick={() => setActionsMenuOpen({ presentation, scripts: false, imports: true })} | 388 | onClick={() => setActionsMenuOpen({ presentation, scripts: false, imports: true })} |
| 388 | > | 389 | > |
| 389 | <WrenchIcon className={THREAD_DETAILS_PANEL_ICON_CLASS} /> | 390 | <WrenchIcon className={THREAD_DETAILS_PANEL_ICON_CLASS} /> |
| 390 | <span className="min-w-0 truncate">Actions</span> | 391 | <span className={cn("min-w-0 truncate", THREAD_DETAILS_PANEL_LABEL_CLASS)}> |
| 392 | Actions | ||
| 393 | </span> | ||
| 391 | </ThreadDetailsControl> | 394 | </ThreadDetailsControl> |
| 392 | <span aria-hidden="true" className={THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS} /> | 395 | <span aria-hidden="true" className={THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS} /> |
| 393 | <Menu | 396 | <Menu |
| ... | @@ -456,7 +459,7 @@ export default function ProjectScriptsControl({ | ... | @@ -456,7 +459,7 @@ export default function ProjectScriptsControl({ |
| 456 | <span | 459 | <span |
| 457 | className={cn( | 460 | className={cn( |
| 458 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", | 461 | "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", |
| 459 | isPanel && "not-sr-only ml-0.5", | 462 | isPanel && cn("not-sr-only ml-0.5", THREAD_DETAILS_PANEL_LABEL_CLASS), |
| 460 | )} | 463 | )} |
| 461 | > | 464 | > |
| 462 | {isPanel ? "Add project script" : "Add action"} | 465 | {isPanel ? "Add project script" : "Add action"} |
apps/web/src/components/chat/ComposerPrimaryActions.tsx+1-1| ... | @@ -370,7 +370,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({ | ... | @@ -370,7 +370,7 @@ export const ComposerPrimaryActions = memo(function ComposerPrimaryActions({ |
| 370 | <button | 370 | <button |
| 371 | type="button" | 371 | type="button" |
| 372 | className={cn( | 372 | className={cn( |
| 373 | "flex h-7 shrink-0 cursor-pointer items-center gap-1.5 rounded-full border px-2.5 text-xs tabular-nums outline-none transition-colors focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 [&_svg]:pointer-events-none [&_svg]:size-3.5", | 373 | "flex h-9 shrink-0 cursor-pointer items-center gap-1.5 rounded-full border px-2.5 text-xs tabular-nums outline-none transition-colors focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 sm:h-8 [&_svg]:pointer-events-none [&_svg]:size-3.5", |
| 374 | keepFullHistory | 374 | keepFullHistory |
| 375 | ? "border-border text-muted-foreground hover:text-foreground" | 375 | ? "border-border text-muted-foreground hover:text-foreground" |
| 376 | : "border-warning/40 text-warning hover:bg-warning/8", | 376 | : "border-warning/40 text-warning hover:bg-warning/8", |
apps/web/src/components/chat/OpenInPicker.tsx+2-1| ... | @@ -64,6 +64,7 @@ import { useAtomCommand } from "~/state/use-atom-command"; | ... | @@ -64,6 +64,7 @@ import { useAtomCommand } from "~/state/use-atom-command"; |
| 64 | import { | 64 | import { |
| 65 | THREAD_DETAILS_PANEL_CHEVRON_CLASS, | 65 | THREAD_DETAILS_PANEL_CHEVRON_CLASS, |
| 66 | THREAD_DETAILS_PANEL_ICON_CLASS, | 66 | THREAD_DETAILS_PANEL_ICON_CLASS, |
| 67 | THREAD_DETAILS_PANEL_LABEL_CLASS, | ||
| 67 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, | 68 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, |
| 68 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, | 69 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, |
| 69 | } from "./threadDetailsPanelStyles"; | 70 | } from "./threadDetailsPanelStyles"; |
| ... | @@ -421,7 +422,7 @@ export const OpenInPicker = memo(function OpenInPicker({ | ... | @@ -421,7 +422,7 @@ export const OpenInPicker = memo(function OpenInPicker({ |
| 421 | compact | 422 | compact |
| 422 | ? "sr-only" | 423 | ? "sr-only" |
| 423 | : "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", | 424 | : "sr-only @3xl/header-actions:not-sr-only @3xl/header-actions:ml-0.5", |
| 424 | isPanel && "not-sr-only ml-0 min-w-0 truncate", | 425 | isPanel && cn("not-sr-only ml-0 min-w-0 truncate", THREAD_DETAILS_PANEL_LABEL_CLASS), |
| 425 | )} | 426 | )} |
| 426 | > | 427 | > |
| 427 | {primaryLabel} | 428 | {primaryLabel} |
apps/web/src/components/chat/ThreadDetailsPrRow.tsx+4-1| ... | @@ -75,6 +75,7 @@ import { Button } from "../ui/button"; | ... | @@ -75,6 +75,7 @@ import { Button } from "../ui/button"; |
| 75 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; | 75 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 76 | import { | 76 | import { |
| 77 | THREAD_DETAILS_PANEL_ICON_CLASS, | 77 | THREAD_DETAILS_PANEL_ICON_CLASS, |
| 78 | THREAD_DETAILS_PANEL_LABEL_CLASS, | ||
| 78 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, | 79 | THREAD_DETAILS_PANEL_SPLIT_GROUP_CLASS, |
| 79 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, | 80 | THREAD_DETAILS_PANEL_SPLIT_SEPARATOR_CLASS, |
| 80 | } from "./threadDetailsPanelStyles"; | 81 | } from "./threadDetailsPanelStyles"; |
| ... | @@ -398,7 +399,9 @@ export function ThreadDetailsPrRow({ | ... | @@ -398,7 +399,9 @@ export function ThreadDetailsPrRow({ |
| 398 | } | 399 | } |
| 399 | > | 400 | > |
| 400 | {icon} | 401 | {icon} |
| 401 | <span className="min-w-0 flex-1 truncate text-left">{text}</span> | 402 | <span className={cn("min-w-0 flex-1 truncate text-left", THREAD_DETAILS_PANEL_LABEL_CLASS)}> |
| 403 | {text} | ||
| 404 | </span> | ||
| 402 | </TooltipTrigger> | 405 | </TooltipTrigger> |
| 403 | {rowTooltip} | 406 | {rowTooltip} |
| 404 | </Tooltip> | 407 | </Tooltip> |
apps/web/src/components/chat/threadDetailsPanelStyles.ts+5| ... | @@ -14,6 +14,11 @@ const THREAD_DETAILS_PANEL_SPLIT_GROUP_SURFACE_CLASS = `${THREAD_DETAILS_PANEL_H | ... | @@ -14,6 +14,11 @@ const THREAD_DETAILS_PANEL_SPLIT_GROUP_SURFACE_CLASS = `${THREAD_DETAILS_PANEL_H |
| 14 | 14 | ||
| 15 | export const THREAD_DETAILS_PANEL_ROW_CONTENT_CLASS = "gap-2.5 px-2.5 text-left"; | 15 | export const THREAD_DETAILS_PANEL_ROW_CONTENT_CLASS = "gap-2.5 px-2.5 text-left"; |
| 16 | 16 | ||
| 17 | // Center capitals with icons. Only clip horizontally so truncated labels retain | ||
| 18 | // accents and descenders outside the trimmed text box. | ||
| 19 | export const THREAD_DETAILS_PANEL_LABEL_CLASS = | ||
| 20 | "[text-box:trim-both_cap_alphabetic] overflow-x-clip overflow-y-visible"; | ||
| 21 | |||
| 17 | const THREAD_DETAILS_PANEL_CONTROL_CLASS = `h-8 min-w-0 rounded-lg border-transparent ${THREAD_DETAILS_PANEL_ROW_CONTENT_CLASS} text-[13px] font-medium text-foreground/80`; | 22 | const THREAD_DETAILS_PANEL_CONTROL_CLASS = `h-8 min-w-0 rounded-lg border-transparent ${THREAD_DETAILS_PANEL_ROW_CONTENT_CLASS} text-[13px] font-medium text-foreground/80`; |
| 18 | 23 | ||
| 19 | export const THREAD_DETAILS_PANEL_ROW_CLASS = `${THREAD_DETAILS_PANEL_CONTROL_CLASS} w-full justify-start ${THREAD_DETAILS_PANEL_ROW_SURFACE_CLASS}`; | 24 | export const THREAD_DETAILS_PANEL_ROW_CLASS = `${THREAD_DETAILS_PANEL_CONTROL_CLASS} w-full justify-start ${THREAD_DETAILS_PANEL_ROW_SURFACE_CLASS}`; |
apps/web/src/components/ui/middle-truncate.tsx+9-1| ... | @@ -16,6 +16,7 @@ export function MiddleTruncate({ | ... | @@ -16,6 +16,7 @@ export function MiddleTruncate({ |
| 16 | value, | 16 | value, |
| 17 | tail, | 17 | tail, |
| 18 | showTitle = true, | 18 | showTitle = true, |
| 19 | variant = "default", | ||
| 19 | className, | 20 | className, |
| 20 | ...props | 21 | ...props |
| 21 | }: Omit<ComponentProps<"span">, "children"> & { | 22 | }: Omit<ComponentProps<"span">, "children"> & { |
| ... | @@ -24,12 +25,19 @@ export function MiddleTruncate({ | ... | @@ -24,12 +25,19 @@ export function MiddleTruncate({ |
| 24 | tail?: number; | 25 | tail?: number; |
| 25 | /** The full value on hover. Off where a tooltip already carries it. */ | 26 | /** The full value on hover. Off where a tooltip already carries it. */ |
| 26 | showTitle?: boolean; | 27 | showTitle?: boolean; |
| 28 | /** Align capital letters with adjacent icons while preserving accents and descenders. */ | ||
| 29 | variant?: "default" | "cap-aligned"; | ||
| 27 | }) { | 30 | }) { |
| 28 | const split = splitForMiddleTruncate(value, tail); | 31 | const split = splitForMiddleTruncate(value, tail); |
| 29 | return ( | 32 | return ( |
| 30 | <span | 33 | <span |
| 31 | {...(showTitle ? { title: value } : {})} | 34 | {...(showTitle ? { title: value } : {})} |
| 32 | className={cn("inline-flex min-w-0 max-w-full overflow-hidden whitespace-nowrap", className)} | 35 | className={cn( |
| 36 | "inline-flex min-w-0 max-w-full overflow-hidden whitespace-nowrap", | ||
| 37 | variant === "cap-aligned" && | ||
| 38 | "overflow-x-clip overflow-y-visible [&>span]:[text-box:trim-both_cap_alphabetic] [&>span]:overflow-x-clip [&>span]:overflow-y-visible", | ||
| 39 | className, | ||
| 40 | )} | ||
| 33 | {...props} | 41 | {...props} |
| 34 | > | 42 | > |
| 35 | {split ? ( | 43 | {split ? ( |