mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-28 21:27:14 +00:00
fix(agents): improve diagram contrast in dark mode
This commit is contained in:
@@ -145,7 +145,7 @@ export default function AgentCreateContent({
|
|||||||
<Icon className="size-4" />
|
<Icon className="size-4" />
|
||||||
</span>
|
</span>
|
||||||
<span className="min-w-0 space-y-1.5">
|
<span className="min-w-0 space-y-1.5">
|
||||||
<span className="block text-sm font-medium">
|
<span className="block text-sm font-medium text-foreground">
|
||||||
{option.title}
|
{option.title}
|
||||||
</span>
|
</span>
|
||||||
<span className="block text-sm font-normal leading-relaxed text-muted-foreground">
|
<span className="block text-sm font-normal leading-relaxed text-muted-foreground">
|
||||||
@@ -226,7 +226,7 @@ export default function AgentCreateContent({
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Card className="min-h-[600px] overflow-hidden py-0 lg:min-h-[680px]">
|
<Card className="min-h-[600px] overflow-hidden py-0 dark:border-white/16 lg:min-h-[680px]">
|
||||||
<CardContent className="flex h-full items-center p-0">
|
<CardContent className="flex h-full items-center p-0">
|
||||||
<ProcessorTypeDiagram kind={kind} />
|
<ProcessorTypeDiagram kind={kind} />
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -13,8 +13,32 @@ function DiagramMotionStyles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes processor-link-breathe {
|
@keyframes processor-link-breathe {
|
||||||
0%, 100% { stroke-opacity: 0.28; }
|
0%, 100% { stroke-opacity: var(--processor-relation-opacity-min); }
|
||||||
50% { stroke-opacity: 0.72; }
|
50% { stroke-opacity: var(--processor-relation-opacity-max); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.processor-diagram {
|
||||||
|
--processor-blue-node-fill: color-mix(in srgb, ${LANGBOT_BLUE} 7%, var(--card));
|
||||||
|
--processor-cyan-node-fill: color-mix(in srgb, ${LANGBOT_CYAN} 7%, var(--card));
|
||||||
|
--processor-node-stroke-opacity: 0.18;
|
||||||
|
--processor-flow-opacity: 0.34;
|
||||||
|
--processor-relation-opacity-min: 0.28;
|
||||||
|
--processor-relation-opacity-max: 0.72;
|
||||||
|
--processor-capability-fill: color-mix(in srgb, ${LANGBOT_CYAN} 4%, var(--card));
|
||||||
|
--processor-capability-stroke-opacity: 0.45;
|
||||||
|
--processor-icon-fill: color-mix(in srgb, ${LANGBOT_CYAN} 10%, var(--card));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .processor-diagram {
|
||||||
|
--processor-blue-node-fill: color-mix(in srgb, ${LANGBOT_BLUE} 17%, var(--card));
|
||||||
|
--processor-cyan-node-fill: color-mix(in srgb, ${LANGBOT_CYAN} 15%, var(--card));
|
||||||
|
--processor-node-stroke-opacity: 0.5;
|
||||||
|
--processor-flow-opacity: 0.72;
|
||||||
|
--processor-relation-opacity-min: 0.58;
|
||||||
|
--processor-relation-opacity-max: 1;
|
||||||
|
--processor-capability-fill: color-mix(in srgb, ${LANGBOT_CYAN} 10%, var(--card));
|
||||||
|
--processor-capability-stroke-opacity: 0.78;
|
||||||
|
--processor-icon-fill: color-mix(in srgb, ${LANGBOT_CYAN} 20%, var(--card));
|
||||||
}
|
}
|
||||||
|
|
||||||
.processor-line-flow {
|
.processor-line-flow {
|
||||||
@@ -105,7 +129,7 @@ function AgentDiagram() {
|
|||||||
viewBox="0 0 760 620"
|
viewBox="0 0 760 620"
|
||||||
role="img"
|
role="img"
|
||||||
aria-label={t('agents.agentDiagramTitle')}
|
aria-label={t('agents.agentDiagramTitle')}
|
||||||
className="h-full w-full"
|
className="processor-diagram h-full w-full"
|
||||||
data-testid="agent-diagram"
|
data-testid="agent-diagram"
|
||||||
>
|
>
|
||||||
<desc>{t('agents.agentDiagramDescription')}</desc>
|
<desc>{t('agents.agentDiagramDescription')}</desc>
|
||||||
@@ -132,7 +156,7 @@ function AgentDiagram() {
|
|||||||
stroke={LANGBOT_BLUE}
|
stroke={LANGBOT_BLUE}
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
strokeDasharray="4 11"
|
strokeDasharray="4 11"
|
||||||
opacity="0.32"
|
opacity="var(--processor-flow-opacity)"
|
||||||
markerEnd={`url(#${arrowId})`}
|
markerEnd={`url(#${arrowId})`}
|
||||||
className="processor-line-flow"
|
className="processor-line-flow"
|
||||||
data-motion="flow"
|
data-motion="flow"
|
||||||
@@ -144,7 +168,9 @@ function AgentDiagram() {
|
|||||||
width="158"
|
width="158"
|
||||||
height="58"
|
height="58"
|
||||||
rx="14"
|
rx="14"
|
||||||
fill={`color-mix(in srgb, ${LANGBOT_BLUE} 7%, var(--card))`}
|
fill="var(--processor-blue-node-fill)"
|
||||||
|
stroke={LANGBOT_BLUE}
|
||||||
|
strokeOpacity="var(--processor-node-stroke-opacity)"
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx="91"
|
cx="91"
|
||||||
@@ -201,7 +227,6 @@ function AgentDiagram() {
|
|||||||
stroke={LANGBOT_CYAN}
|
stroke={LANGBOT_CYAN}
|
||||||
strokeWidth="1.8"
|
strokeWidth="1.8"
|
||||||
strokeDasharray="5 6"
|
strokeDasharray="5 6"
|
||||||
opacity="0.48"
|
|
||||||
className="processor-link-breathe"
|
className="processor-link-breathe"
|
||||||
data-motion="relation"
|
data-motion="relation"
|
||||||
style={{ animationDelay: `${index * -0.45}s` }}
|
style={{ animationDelay: `${index * -0.45}s` }}
|
||||||
@@ -212,18 +237,18 @@ function AgentDiagram() {
|
|||||||
width="158"
|
width="158"
|
||||||
height="58"
|
height="58"
|
||||||
rx="14"
|
rx="14"
|
||||||
fill="var(--card)"
|
fill="var(--processor-capability-fill)"
|
||||||
stroke={LANGBOT_CYAN}
|
stroke={LANGBOT_CYAN}
|
||||||
strokeOpacity="0.45"
|
strokeOpacity="var(--processor-capability-stroke-opacity)"
|
||||||
strokeWidth="1.5"
|
strokeWidth="1.5"
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx="565"
|
cx="565"
|
||||||
cy={item.y + 29}
|
cy={item.y + 29}
|
||||||
r="11"
|
r="11"
|
||||||
fill={`color-mix(in srgb, ${LANGBOT_CYAN} 10%, var(--card))`}
|
fill="var(--processor-icon-fill)"
|
||||||
stroke={LANGBOT_CYAN}
|
stroke={LANGBOT_CYAN}
|
||||||
strokeOpacity="0.5"
|
strokeOpacity="var(--processor-capability-stroke-opacity)"
|
||||||
/>
|
/>
|
||||||
<CapabilityIcon kind={item.kind} x={565} y={item.y + 29} />
|
<CapabilityIcon kind={item.kind} x={565} y={item.y + 29} />
|
||||||
<text
|
<text
|
||||||
@@ -257,7 +282,7 @@ function PipelineDiagram() {
|
|||||||
viewBox="0 0 760 620"
|
viewBox="0 0 760 620"
|
||||||
role="img"
|
role="img"
|
||||||
aria-label={t('agents.pipelineDiagramTitle')}
|
aria-label={t('agents.pipelineDiagramTitle')}
|
||||||
className="h-full w-full"
|
className="processor-diagram h-full w-full"
|
||||||
data-testid="pipeline-diagram"
|
data-testid="pipeline-diagram"
|
||||||
>
|
>
|
||||||
<desc>{t('agents.pipelineDiagramDescription')}</desc>
|
<desc>{t('agents.pipelineDiagramDescription')}</desc>
|
||||||
@@ -279,7 +304,7 @@ function PipelineDiagram() {
|
|||||||
fill="none"
|
fill="none"
|
||||||
stroke={LANGBOT_BLUE}
|
stroke={LANGBOT_BLUE}
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
opacity="0.32"
|
opacity="var(--processor-flow-opacity)"
|
||||||
markerEnd={`url(#${arrowId})`}
|
markerEnd={`url(#${arrowId})`}
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
@@ -308,7 +333,19 @@ function PipelineDiagram() {
|
|||||||
fill={
|
fill={
|
||||||
active
|
active
|
||||||
? LANGBOT_BLUE
|
? LANGBOT_BLUE
|
||||||
: `color-mix(in srgb, ${index === 3 ? LANGBOT_CYAN : LANGBOT_BLUE} 7%, var(--card))`
|
: index === 3
|
||||||
|
? 'var(--processor-cyan-node-fill)'
|
||||||
|
: 'var(--processor-blue-node-fill)'
|
||||||
|
}
|
||||||
|
stroke={
|
||||||
|
active
|
||||||
|
? LANGBOT_BLUE
|
||||||
|
: index === 3
|
||||||
|
? LANGBOT_CYAN
|
||||||
|
: LANGBOT_BLUE
|
||||||
|
}
|
||||||
|
strokeOpacity={
|
||||||
|
active ? 1 : 'var(--processor-node-stroke-opacity)'
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{!active && (
|
{!active && (
|
||||||
|
|||||||
@@ -191,6 +191,15 @@ test.describe('frontend CRUD smoke flows', () => {
|
|||||||
).toHaveCount(3);
|
).toHaveCount(3);
|
||||||
await expect(page.getByTestId('pipeline-diagram')).toHaveCount(0);
|
await expect(page.getByTestId('pipeline-diagram')).toHaveCount(0);
|
||||||
|
|
||||||
|
await page.evaluate(() => document.documentElement.classList.add('dark'));
|
||||||
|
await expect(page.getByTestId('agent-diagram')).toHaveCSS(
|
||||||
|
'--processor-flow-opacity',
|
||||||
|
'0.72',
|
||||||
|
);
|
||||||
|
await expect(page.getByTestId('agent-diagram')).toHaveCSS(
|
||||||
|
'--processor-node-stroke-opacity',
|
||||||
|
'0.5',
|
||||||
|
);
|
||||||
await page.getByRole('radio', { name: /^Pipeline/ }).click();
|
await page.getByRole('radio', { name: /^Pipeline/ }).click();
|
||||||
await expect(pipelineTypeCard).toHaveAttribute('aria-checked', 'true');
|
await expect(pipelineTypeCard).toHaveAttribute('aria-checked', 'true');
|
||||||
await expect(page.getByTestId('pipeline-diagram')).toBeVisible();
|
await expect(page.getByTestId('pipeline-diagram')).toBeVisible();
|
||||||
@@ -198,7 +207,6 @@ test.describe('frontend CRUD smoke flows', () => {
|
|||||||
page.getByTestId('pipeline-diagram').locator('[data-motion="flow"]'),
|
page.getByTestId('pipeline-diagram').locator('[data-motion="flow"]'),
|
||||||
).toHaveAttribute('data-dash-cycle', '15');
|
).toHaveAttribute('data-dash-cycle', '15');
|
||||||
await expect(page.getByTestId('agent-diagram')).toHaveCount(0);
|
await expect(page.getByTestId('agent-diagram')).toHaveCount(0);
|
||||||
|
|
||||||
await expect(page.locator('input[name="name"]')).toBeVisible();
|
await expect(page.locator('input[name="name"]')).toBeVisible();
|
||||||
await page.locator('input[name="name"]').fill('Escalation Pipeline');
|
await page.locator('input[name="name"]').fill('Escalation Pipeline');
|
||||||
await page
|
await page
|
||||||
|
|||||||
Reference in New Issue
Block a user