Skip to content

Commit 9bdf37c

Browse files
committed
Visualizer lane improvements
1 parent e251df9 commit 9bdf37c

3 files changed

Lines changed: 74 additions & 62 deletions

File tree

frontend/src/components/pages/rp-connect/pipeline/pipeline-flow-canvas-nodes.tsx

Lines changed: 58 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ const SECTION_LABEL: Record<string, string> = {
9191
resource: 'Resource',
9292
};
9393

94-
// A colored left accent gives each role a quick visual identity: sources, transforms,
95-
// sinks, and shared resources read apart at a glance.
94+
// Each role gets a quick visual identity from its colour: sources, transforms, sinks,
95+
// and shared resources read apart at a glance.
9696
export const SECTION_ACCENT: Record<string, string> = {
9797
input: 'var(--color-green-500)',
9898
processor: 'var(--color-blue-500)',
@@ -104,24 +104,23 @@ export function sectionAccent(section?: string): string | undefined {
104104
return section ? SECTION_ACCENT[section] : undefined;
105105
}
106106

107-
// The role accent shown as a solid bar down a card's left edge. Cards keep their
108-
// neutral border; only the left side takes the role colour, so the role reads at a
109-
// glance without recolouring the whole card.
110-
function accentBarStyle(accent?: string): React.CSSProperties | undefined {
111-
return accent ? { borderLeftStyle: 'solid', borderLeftWidth: 3, borderLeftColor: accent } : undefined;
107+
// The role colour lives in a tinted title band rather than a border: a faint wash over
108+
// the card surface behind the kind label / logo / name, with the body left clean. This
109+
// reads as a clear role identity without recolouring the whole card or competing with
110+
// the selection / error rings. Opaque (mixed over the card colour) so it layers
111+
// correctly on both leaf cards and container headers.
112+
function headerTintStyle(accent?: string): React.CSSProperties | undefined {
113+
return accent ? { backgroundColor: `color-mix(in srgb, ${accent} 10%, var(--color-card))` } : undefined;
112114
}
113115

114-
// A faint wash of the role colour behind the connector logo, so the icon sits in a
115-
// small tinted chip that echoes the accent bar.
116-
function accentChipStyle(accent?: string): React.CSSProperties | undefined {
117-
return accent ? { backgroundColor: `color-mix(in srgb, ${accent} 12%, transparent)` } : undefined;
118-
}
119-
120-
// The connector logo in a small rounded chip tinted with the role accent.
121-
const LogoChip = ({ name, accent, compact }: { name: string; accent?: string; compact?: boolean }) => (
116+
// The connector logo in a small elevated tile, so the icon sits cleanly on the tinted
117+
// header band.
118+
const LogoTile = ({ name, compact }: { name: string; compact?: boolean }) => (
122119
<span
123-
className={cn('flex shrink-0 items-center justify-center rounded-md', compact ? 'size-6' : 'size-7')}
124-
style={accentChipStyle(accent)}
120+
className={cn(
121+
'flex shrink-0 items-center justify-center rounded-md border border-border/60 bg-background',
122+
compact ? 'size-6' : 'size-7'
123+
)}
125124
>
126125
<ConnectorLogo className={compact ? 'size-4' : 'size-5'} fallback={Box} name={name as ComponentName} />
127126
</span>
@@ -287,7 +286,7 @@ const MetaRows = ({ data }: { data: FlowCardData }) => {
287286
return null;
288287
}
289288
return (
290-
<div className="flex flex-col gap-1.5 border-border/60 border-t px-3 py-2">
289+
<div className="flex flex-col gap-1.5 px-3 py-2">
291290
<TopicChips topics={data.topics} />
292291
{data.meta?.map((entry) => (
293292
<div className="flex items-baseline gap-1.5 text-xs" key={`${entry.label}-${entry.value}`}>
@@ -379,23 +378,17 @@ const PlaceholderCard = ({ data }: { data: FlowCardData }) => {
379378

380379
// A compact sidebar card: logo + name, with the label (e.g. a resource's label)
381380
// on its own row beneath so neither it nor the name gets truncated against the other.
382-
const CompactCard = ({ data }: { data: FlowCardData }) => {
383-
const accent = sectionAccent(data.section);
384-
return (
385-
<div
386-
className="group flex flex-col gap-1 rounded-md border border-border bg-card px-2.5 py-1.5 shadow-sm transition-shadow hover:shadow-md"
387-
style={accent ? { borderLeftStyle: 'solid', borderLeftWidth: 2, borderLeftColor: accent } : undefined}
388-
>
389-
<div className="flex items-center gap-2">
390-
<ConnectorLogo className="size-4 shrink-0" fallback={Box} name={data.label as ComponentName} />
391-
<Text as="span" className="min-w-0 flex-1 truncate font-medium text-sm" title={data.label}>
392-
{data.label}
393-
</Text>
394-
</div>
395-
{data.labelText ? <LabelBadge className="max-w-full self-start" label={data.labelText} /> : null}
381+
const CompactCard = ({ data }: { data: FlowCardData }) => (
382+
<div className="group flex flex-col gap-1 rounded-md border border-border bg-card px-2.5 py-1.5 shadow-sm transition-shadow hover:shadow-md">
383+
<div className="flex items-center gap-2">
384+
<ConnectorLogo className="size-4 shrink-0" fallback={Box} name={data.label as ComponentName} />
385+
<Text as="span" className="min-w-0 flex-1 truncate font-medium text-sm" title={data.label}>
386+
{data.label}
387+
</Text>
396388
</div>
397-
);
398-
};
389+
{data.labelText ? <LabelBadge className="max-w-full self-start" label={data.labelText} /> : null}
390+
</div>
391+
);
399392

400393
// The selection ring shown on the node the inspector is editing. Uses `primary`
401394
// (the conventional "selected" colour); the selected node still reads clearly
@@ -459,28 +452,35 @@ const ComponentCard = ({ data, selectable }: { data: FlowCardData; selectable?:
459452
selectable && 'cursor-pointer',
460453
cardRing(data)
461454
)}
462-
style={accentBarStyle(accent)}
463455
>
464-
<div className="flex items-center gap-1.5 px-3 pt-2 pb-0.5">
465-
<Text
466-
as="span"
467-
className="shrink-0 uppercase tracking-wide"
468-
style={accent ? { color: accent } : undefined}
469-
variant="captionStrongMedium"
470-
>
471-
{kindLabel}
472-
</Text>
473-
<BranchConditionChip data={data} />
474-
<LintBadge errors={data.lintErrors} />
475-
</div>
476-
<div className="flex w-full items-center gap-2 px-3 pb-2 text-left">
477-
<LogoChip accent={accent} name={data.label} />
478-
<Text as="span" className="min-w-0 flex-1 truncate font-semibold" title={data.label} variant="bodyStrongMedium">
479-
{data.label}
480-
</Text>
456+
{/* Tinted title band carries the role colour; the body below stays clean. */}
457+
<div className="border-border/60 border-b" style={headerTintStyle(accent)}>
458+
<div className="flex items-center gap-1.5 px-3 pt-2 pb-1">
459+
<Text
460+
as="span"
461+
className="shrink-0 uppercase tracking-wide"
462+
style={accent ? { color: accent } : undefined}
463+
variant="captionStrongMedium"
464+
>
465+
{kindLabel}
466+
</Text>
467+
<BranchConditionChip data={data} />
468+
<LintBadge errors={data.lintErrors} />
469+
</div>
470+
<div className="flex w-full items-center gap-2 px-3 pb-2.5 text-left">
471+
<LogoTile name={data.label} />
472+
<Text
473+
as="span"
474+
className="min-w-0 flex-1 truncate font-semibold"
475+
title={data.label}
476+
variant="bodyStrongMedium"
477+
>
478+
{data.label}
479+
</Text>
480+
</div>
481481
</div>
482482
{data.labelText ? (
483-
<div className="px-3 pb-2">
483+
<div className="px-3 pt-2">
484484
<LabelBadge label={data.labelText} />
485485
</div>
486486
) : null}
@@ -583,7 +583,7 @@ const ContainerHeaderTitle = ({ data, accent }: { data: FlowCardData; accent?: s
583583
}
584584
return (
585585
<>
586-
<LogoChip accent={accent} compact={data.compact} name={data.label} />
586+
<LogoTile compact={data.compact} name={data.label} />
587587
<ContainerTitleText accent={accent} data={data} />
588588
<LabelBadge className="max-w-[35%]" label={data.labelText} />
589589
<BranchConditionChip className="max-w-[45%]" data={data} />
@@ -614,17 +614,19 @@ const FlowContainerNode = ({ data }: { data: FlowCardData }) => {
614614
'flex h-full w-full flex-col rounded-lg border border-border border-dashed bg-muted/20 shadow-sm',
615615
cardRing(data)
616616
)}
617-
style={accentBarStyle(accent)}
618617
>
619618
<div
620619
className={cn(
621-
'flex items-center gap-2 bg-card/80',
620+
'flex items-center gap-2',
622621
selectable && 'cursor-pointer',
623622
data.compact ? 'px-2.5 py-1.5' : 'px-3 py-2',
624623
// Collapsed: the header is the whole card, so fill + centre it (no divider)
625624
// so the spine arrows align with its middle. Expanded: header on top.
626625
data.collapsed ? 'h-full rounded-lg' : 'rounded-t-lg border-border/60 border-b'
627626
)}
627+
// Tinted title band (role colour) over the card surface; falls back to a
628+
// plain card header when the section has no accent.
629+
style={headerTintStyle(accent) ?? { backgroundColor: 'var(--color-card)' }}
628630
>
629631
<ContainerHeaderTitle accent={accent} data={data} />
630632
<LintBadge errors={data.lintErrors} />

frontend/src/components/pages/rp-connect/pipeline/pipeline-structure-tree.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,17 @@ const NodeRow = ({ node, depth, maps, collapsedIds, toggle, selectedId, onSelect
8787
)}
8888
<button
8989
className={cn(
90-
'group flex min-w-0 flex-1 cursor-pointer items-center gap-1.5 rounded-md border-transparent border-l-2 py-1 pr-2 pl-1.5 text-left text-sm transition-colors',
91-
selected ? 'bg-primary/10 text-foreground' : 'text-foreground hover:bg-muted/50'
90+
'group flex min-w-0 flex-1 cursor-pointer items-center gap-1.5 rounded-md py-1 pr-2 pl-1.5 text-left text-sm transition-colors',
91+
selected ? 'font-medium text-foreground' : 'text-foreground hover:bg-muted/50'
9292
)}
93+
// Selected row carries a faint wash of its role colour (matching the card
94+
// title bands) instead of a left accent border.
9395
onClick={() => onSelect(node.id, editableAncestorId(node, maps))}
94-
style={selected && accent ? { borderLeftColor: accent } : undefined}
96+
style={
97+
selected
98+
? { backgroundColor: accent ? `color-mix(in srgb, ${accent} 16%, transparent)` : 'var(--color-muted)' }
99+
: undefined
100+
}
95101
title={node.label}
96102
type="button"
97103
>

frontend/src/components/pages/rp-connect/pipeline/visual-editor-design.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,13 @@ Supporting polish:
107107
resource's x is aligned to the (absolute) x of its referencing component, then a
108108
left→right sweep de-overlaps the lane — so a `uses` edge is a short drop, not a
109109
full-canvas traversal (`resourceLaneX`/`absoluteX`).
110-
- **Section colour accents.** Cards/containers carry a left accent + tinted kind
111-
label by role (input green, processor blue, output purple, resource orange) so
112-
sources/transforms/sinks/resources read apart at a glance (`SECTION_ACCENT`).
110+
- **Section colour accents.** A card/container's role (input green, processor blue,
111+
output purple, resource orange — `SECTION_ACCENT`) reads from a **tinted title band**
112+
(`headerTintStyle`, a faint wash of the role colour over the card behind the kind
113+
label / logo / name) plus the colour-matched kind label, with the body left clean.
114+
No left bar or full colour border, so the role cue never competes with the selection
115+
(primary) / error (destructive) rings. The connector logo sits in an elevated tile
116+
(`LogoTile`) on the band.
113117
- **Adaptive edge legend.** The full canvas shows a small bottom-left legend that
114118
lists only the edge kinds actually present (flow / copy-merge / error / uses).
115119
- **Roomy container routing.** A container reserves a wider routing gutter

0 commit comments

Comments
 (0)