Skip to content

Commit effe039

Browse files
committed
feat: dark mode improvements
1 parent 2604136 commit effe039

File tree

13 files changed

+227
-80
lines changed

13 files changed

+227
-80
lines changed

ui/src/components/cards/StateGraphInstanceCard.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const StateGraphInstanceCard: React.FC<StateGraphInstanceCardProps> = ({
3737
outline-primary-500
3838
hover:bg-nuances-white`,
3939

40-
dark: `bg-nuances-black
40+
dark: `bg-nuances-400
4141
text-nuances-50
4242
outline-nuances-50
4343
hover:bg-nuances-400`
@@ -106,6 +106,11 @@ const StateGraphInstanceCard: React.FC<StateGraphInstanceCardProps> = ({
106106
replace: 'fill-violet-600'
107107
}[futureKey as 'create' | 'update' | 'replace']
108108
: 'fill-primary-600';
109+
const mutedTextClass =
110+
variant === 'light' ? 'text-gray-500' : 'text-nuances-200';
111+
112+
const propertiesClass =
113+
variant === 'light' ? 'bg-nuances-300 text-nuances-white' : 'bg-nuances-100 text-nuances-black';
109114

110115
return (
111116
<div
@@ -137,15 +142,15 @@ const StateGraphInstanceCard: React.FC<StateGraphInstanceCardProps> = ({
137142
{isExpanded && attributes && (
138143
<div>
139144
{created_at && (
140-
<p className="text-sm text-gray-500 mb-2">
145+
<p className={twMerge('text-sm mb-2', mutedTextClass)}>
141146
Created at:{' '}
142147
<span className="font-medium">
143148
{new Date(created_at).toLocaleString()}
144149
</span>
145150
</p>
146151
)}
147152
{dependencies && dependencies.length > 0 && (
148-
<div className="text-sm text-gray-500 mb-2">
153+
<div className={twMerge('text-sm mb-2', mutedTextClass)}>
149154
<p>Dependencies:</p>
150155
<ul className="ml-4 list-disc">
151156
{dependencies.map((dep) => (
@@ -155,11 +160,13 @@ const StateGraphInstanceCard: React.FC<StateGraphInstanceCardProps> = ({
155160
</div>
156161
)}
157162
<div>
158-
<h3 className="text-sm text-gray-500 mb-2">Attributes:</h3>
163+
<h3 className={twMerge('text-sm mb-2', mutedTextClass)}>
164+
Attributes:
165+
</h3>
159166
</div>
160167
<div
161168
onClick={(e) => e.stopPropagation()}
162-
className="mt-2 bg-gray-50 dark:bg-nuances-black/70 text-sm shadow-light text-gray-900 dark:text-nuances-50 p-3 rounded-md overflow-auto max-h-48 font-mono whitespace-pre"
169+
className={twMerge(propertiesClass,"mt-2 text-sm shadow-light p-3 rounded-md overflow-auto max-h-48 font-mono whitespace-pre")}
163170
role="region"
164171
aria-label="attributes-json"
165172
>

ui/src/components/core/Button.tsx

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,23 @@ const Button: React.FC<ButtonProps> = ({
5959
tertiary: `
6060
text-primary-600
6161
underline
62-
hover:text-primary-400
63-
hover:fill-primary-400
64-
active:text-primary-400
65-
active:fill-primary-400
62+
hover:text-primary-500
63+
hover:fill-primary-500
64+
active:text-primary-500
65+
active:fill-primary-500
6666
focus-visible:outline-hidden
6767
fill-primary-600`
6868
},
6969

7070
disabled: {
71-
primary: `bg-nuances-50
72-
text-nuances-300
73-
fill-nuances-300
71+
primary: `disabled:bg-nuances-50
72+
disabled:text-nuances-300
7473
active: bg-nuances-50
7574
hover:bg-nuances-50
7675
`,
7776

78-
secondary: `bg-nuances-50
77+
secondary: `disabled:bg-nuances-50
78+
disabled:border-hidden
7979
text-nuances-300
8080
fill-nuances-300
8181
active: bg-nuances-50
@@ -93,27 +93,27 @@ const Button: React.FC<ButtonProps> = ({
9393
},
9494
dark: {
9595
base: {
96-
primary: `bg-nuances-black
97-
text-nuances-white
98-
hover:bg-nuances-400
99-
active:bg-nuances-400
96+
primary: `bg-nuances-white
97+
text-nuances-400
98+
hover:bg-nuances-100
99+
active:bg-nuances-100
100100
focus-visible:outline-solid
101101
focus-visible:outline-1
102102
focus-visible:outline-offset-[3px]
103103
focus-visible:outline-nuances-black
104104
fill-nuances-white`,
105105

106-
secondary: `bg-nuances-white
107-
text-nuances-black
106+
secondary: `bg-nuances-black
107+
text-nuances-white
108108
border
109-
border-nuances-black
110-
hover:bg-nuances-50
111-
active:bg-nuances-50
109+
border-nuances-white
110+
hover:bg-nuances-400
111+
active:bg-nuances-400
112112
focus-visible:outline-solid
113113
focus-visible:outline-1
114114
focus-visible:outline-offset-[3px]
115-
focus-visible:outline-nuances-white
116-
fill-nuances-black`,
115+
focus-visible:outline-nuances-black
116+
fill-nuances-white`,
117117

118118
tertiary: `bg-nuances-black
119119
text-primary-600

ui/src/components/status/LayerStatus.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const LayerStatus: React.FC<LayerStatusProps> = ({
5353
dark: `outline-blue-500`
5454
}
5555
};
56+
const mutedText = theme === 'light' ? 'text-gray-500' : 'text-nuances-200';
5657

5758
return (
5859
<div className={className}>
@@ -71,34 +72,34 @@ const LayerStatus: React.FC<LayerStatusProps> = ({
7172
{layer && variant==='lastOperation' &&
7273
<div className="flex">
7374
<div className="flex flex-col min-w-40">
74-
<span className="text-lg py-1 font-bold"> {layer.lastRun?.action && operationResult.find(op => op.value === layer.lastRun.action)?.label}</span>
75-
<span className="text-sm text-gray-500" title={lastRunAtTitle}> {lastRunAtText}</span>
76-
<span className="text-sm text-gray-500">Auto Apply is <span className="font-semibold">{layer.autoApply ? 'enabled' : 'disabled'}</span></span>
75+
<span className={twMerge("text-lg py-1 font-bold",mutedText)}> {layer.lastRun?.action && operationResult.find(op => op.value === layer.lastRun.action)?.label}</span>
76+
<span className={twMerge('text-sm', mutedText)} title={lastRunAtTitle}> {lastRunAtText}</span>
77+
<span className={twMerge('text-sm', mutedText)}>Auto Apply is <span className="font-semibold">{layer.autoApply ? 'enabled' : 'disabled'}</span></span>
7778
</div>
7879
<div className="flex flex-col min-w-32">
7980
<div className="grid grid-cols-[20%_80%] mt-4 gap-x-8">
80-
<span className="text-sm text-gray-500 text-right">Author:</span>
81-
<span className="text-sm text-gray-500 truncate pr-8" title={layer.lastRun?.author}>{layer.lastRun?.author}</span>
82-
<span className="text-sm text-gray-500 text-right">Message:</span>
83-
<span className="text-sm text-gray-500 truncate pr-8" title={layer.lastRun?.message}>{layer.lastRun?.message}</span>
84-
<span className="text-sm text-gray-500 text-right">Commit:</span>
85-
<span className="text-sm text-gray-500 truncate pr-8" title={layer.lastRun?.commit}>{layer.lastRun?.commit}</span>
81+
<span className={twMerge('text-sm text-right', mutedText)}>Author:</span>
82+
<span className={twMerge('text-sm truncate pr-8', mutedText)} title={layer.lastRun?.author}>{layer.lastRun?.author}</span>
83+
<span className={twMerge('text-sm text-right', mutedText)}>Message:</span>
84+
<span className={twMerge('text-sm truncate pr-8', mutedText)} title={layer.lastRun?.message}>{layer.lastRun?.message}</span>
85+
<span className={twMerge('text-sm text-right', mutedText)}>Commit:</span>
86+
<span className={twMerge('text-sm truncate pr-8', mutedText)} title={layer.lastRun?.commit}>{layer.lastRun?.commit}</span>
8687
</div>
8788
</div>
8889
</div>
8990
}
9091
{layer && variant==='details' &&
9192
<div className="flex flex-col min-w-58">
9293
<div className="grid grid-cols-[30%_70%] mt-4 gap-x-4">
93-
<span className="text-sm text-gray-500 text-right">Type:</span>
94-
<span className="text-sm text-gray-500 truncate pr-8">{getLayerType(layer)}</span>
94+
<span className={twMerge('text-sm text-right', mutedText)}>Type:</span>
95+
<span className={twMerge('text-sm truncate pr-8', mutedText)}>{getLayerType(layer)}</span>
9596
{layer.terragrunt &&
96-
<span className="text-sm text-gray-500 text-right">Terragrunt Enabled</span>
97+
<span className={twMerge('text-sm text-right', mutedText)}>Terragrunt Enabled</span>
9798
}
98-
<span className="text-sm text-gray-500 text-right">Git ref:</span>
99-
<span className="text-sm text-gray-500 truncate pr-8">{layer.branch}</span>
100-
<span className="text-sm text-gray-500 text-right">Code path:</span>
101-
<span className="text-sm text-gray-500 truncate pr-8" title={layer.path}>{layer.path || '/'}</span>
99+
<span className={twMerge('text-sm text-right', mutedText)}>Git ref:</span>
100+
<span className={twMerge('text-sm truncate pr-8', mutedText)}>{layer.branch}</span>
101+
<span className={twMerge('text-sm text-right', mutedText)}>Code path:</span>
102+
<span className={twMerge('text-sm truncate pr-8', mutedText)} title={layer.path}>{layer.path || '/'}</span>
102103
</div>
103104
</div>
104105
}

ui/src/components/tools/LayerStateGraph.tsx

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { buildReactFlow, type ReactFlowGraph } from '@/utils/stateGraph';
77
import { StateGraph, StateGraphNode } from '@/clients/layers/types';
88
import type { ParsedTerraformPlan } from '@/utils/terraformPlan';
99
import { augmentStateGraphWithPlan } from '@/utils/terraformPlan';
10+
import { twMerge } from 'tailwind-merge';
1011

1112
export interface LayerStateGraphProps {
1213
variant?: 'light' | 'dark';
@@ -48,11 +49,21 @@ const LayerStateGraph: React.FC<LayerStateGraphProps> = ({
4849
setGraph(augmentedGraph);
4950
buildReactFlow(augmentedGraph).then((res) => {
5051
if (cancelled) return;
52+
const withVariant = {
53+
nodes: res.nodes.map((node) => ({
54+
...node,
55+
data: {
56+
...node.data,
57+
variant
58+
}
59+
})),
60+
edges: res.edges
61+
};
5162
if (!plan) {
52-
setRf(res);
63+
setRf(withVariant);
5364
return;
5465
}
55-
const nodesWithPlan = res.nodes.map((node) => {
66+
const nodesWithPlan = withVariant.nodes.map((node) => {
5667
const exact = plan.byAddr.get(node.id);
5768
const base = plan.byBase.get(node.id);
5869
const change = exact?.action ?? base?.action ?? null;
@@ -75,27 +86,31 @@ const LayerStateGraph: React.FC<LayerStateGraphProps> = ({
7586
}
7687
};
7788
});
78-
setRf({ nodes: nodesWithPlan, edges: res.edges });
89+
setRf({ nodes: nodesWithPlan, edges: withVariant.edges });
7990
});
8091
return () => {
8192
cancelled = true;
8293
};
83-
}, [augmentedGraph, plan]);
94+
}, [augmentedGraph, plan, variant]);
8495

8596
const hasGraphData = (graph?.nodes?.length ?? 0) > 0;
97+
const infoTextClass =
98+
variant === 'light' ? 'text-slate-500' : 'text-nuances-200';
99+
const errorTextClass =
100+
variant === 'light' ? 'text-red-500' : 'text-red-400';
86101

87102
if (layerQuery.isLoading) {
88103
return (
89104
<div className="flex items-center justify-center h-full p-4">
90-
<div className="text-slate-500">Loading layer...</div>
105+
<div className={twMerge(infoTextClass)}>Loading layer...</div>
91106
</div>
92107
);
93108
}
94109

95110
if (layerQuery.isError) {
96111
return (
97112
<div className="flex items-center justify-center h-full p-4">
98-
<div className="text-red-500">
113+
<div className={twMerge(errorTextClass)}>
99114
Error loading layer: {(layerQuery.error as Error).message}
100115
</div>
101116
</div>
@@ -105,7 +120,7 @@ const LayerStateGraph: React.FC<LayerStateGraphProps> = ({
105120
if (!hasGraphData && (stateGraphQuery.isLoading || planLoading)) {
106121
return (
107122
<div className="flex items-center justify-center h-full p-4">
108-
<div className="text-slate-500">Loading state graph...</div>
123+
<div className={twMerge(infoTextClass)}>Loading state graph...</div>
109124
</div>
110125
);
111126
}
@@ -118,7 +133,7 @@ const LayerStateGraph: React.FC<LayerStateGraphProps> = ({
118133
) {
119134
return (
120135
<div className="flex items-center justify-center h-full p-4">
121-
<div className="text-slate-500">
136+
<div className={twMerge(infoTextClass)}>
122137
No state graph available for this layer
123138
</div>
124139
</div>
@@ -128,7 +143,7 @@ const LayerStateGraph: React.FC<LayerStateGraphProps> = ({
128143
if (!hasGraphData || rf.nodes.length === 0) {
129144
return (
130145
<div className="flex items-center justify-center h-full p-4">
131-
<div className="text-slate-500">
146+
<div className={twMerge(infoTextClass)}>
132147
No state graph data available for this layer
133148
</div>
134149
</div>

ui/src/components/tools/ReactFlowView.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import ReactFlow, {
1010
import 'reactflow/dist/style.css';
1111
import ResourceNode from './ResourceNode';
1212
import { ReactFlowGraph } from '@/utils/stateGraph';
13+
import { twMerge } from 'tailwind-merge';
1314

1415
const nodeTypes = { resource: ResourceNode };
1516

@@ -52,6 +53,12 @@ const ReactFlowView: React.FC<ReactFlowViewProps> = ({
5253
);
5354

5455
const fitViewOptions = useMemo(() => ({ padding: 0.2 }), []);
56+
const flowClass = twMerge(
57+
'rounded-2xl outline-1',
58+
variant === 'light'
59+
? 'bg-nuances-white outline-primary-500'
60+
: 'bg-nuances-400 outline-nuances-50 react-flow-dark'
61+
);
5562

5663
return (
5764
<ReactFlow
@@ -64,7 +71,7 @@ const ReactFlowView: React.FC<ReactFlowViewProps> = ({
6471
fitView
6572
fitViewOptions={fitViewOptions}
6673
onNodeClick={(_, n) => onNodeClick && onNodeClick(n.id)}
67-
className='bg-nuances-white rounded-2xl outline-1 outline-primary-500'
74+
className={flowClass}
6875
>
6976
<Background
7077
gap={32}

ui/src/components/tools/ResourceNode.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import { Handle, Position } from 'reactflow';
3+
import { twMerge } from 'tailwind-merge';
34

45
type ResourceNodeData = {
56
id: string;
@@ -9,6 +10,7 @@ type ResourceNodeData = {
910
provider: string;
1011
module: string;
1112
change: 'create' | 'delete' | 'update' | 'replace' | null;
13+
variant?: 'light' | 'dark';
1214
};
1315

1416
type ResourceNodeProps = {
@@ -18,6 +20,7 @@ type ResourceNodeProps = {
1820
const ResourceNode: React.FC<ResourceNodeProps> = ({ data }) => {
1921
const count = data.count || 0;
2022
const change = data.change || null;
23+
const variant = data.variant ?? 'light';
2124

2225
const planColorMap: Record<'create' | 'delete' | 'update' | 'replace', string> = {
2326
create: '#10b981',
@@ -35,10 +38,24 @@ const ResourceNode: React.FC<ResourceNodeProps> = ({ data }) => {
3538

3639
const accentColor = change ? planColorMap[change] : undefined;
3740
const changeSymbol = change ? planSymbolMap[change] : undefined;
41+
const containerClass = twMerge(
42+
'rounded-sm border px-3 py-2 shadow-sm relative transition-colors',
43+
variant === 'light'
44+
? 'bg-nuances-white border-slate-300 text-nuances-black'
45+
: 'bg-nuances-400 border-nuances-200 text-nuances-50'
46+
);
47+
const typeClass =
48+
variant === 'light' ? 'text-primary-200' : 'text-nuances-200';
49+
const nameClass =
50+
variant === 'light' ? 'text-nuances-black' : 'text-nuances-50';
51+
const countClass = twMerge(
52+
'absolute -top-2 -right-2 inline-flex items-center justify-center h-5 min-w-[20px] px-1 rounded-full text-[10px] font-semibold shadow',
53+
variant === 'light' ? 'text-primary-100 bg-nuances-black' : 'text-nuances-black bg-nuances-50'
54+
);
3855

3956
return (
4057
<div
41-
className="rounded-sm border border-slate-300 bg-white px-3 py-2 shadow-sm relative"
58+
className={containerClass}
4259
style={accentColor ? { boxShadow: `inset 0 0 0 2px ${accentColor}33` } : undefined}
4360
>
4461
{/* Provide handles on all sides with stable ids for edge anchoring */}
@@ -77,8 +94,10 @@ const ResourceNode: React.FC<ResourceNodeProps> = ({ data }) => {
7794
aria-hidden
7895
/>
7996
)}
80-
<div className="text-[10px] tracking-wide text-primary-200">{data.type}</div>
81-
<div className="text-sm text-nuances-black text-lg font-semibold flex items-center gap-2">
97+
<div className={twMerge('text-[10px] tracking-wide uppercase', typeClass)}>
98+
{data.type}
99+
</div>
100+
<div className={twMerge('text-lg font-semibold flex items-center gap-2', nameClass)}>
82101
<span className="truncate max-w-[200px]" title={data.name}>
83102
{data.name}
84103
</span>
@@ -94,7 +113,7 @@ const ResourceNode: React.FC<ResourceNodeProps> = ({ data }) => {
94113
</div>
95114
{count > 1 && (
96115
<span
97-
className="absolute -top-2 -right-2 inline-flex items-center justify-center h-5 min-w-[20px] px-1 rounded-full text-primary-100 bg-nuances-black text-[10px] font-semibold shadow"
116+
className={countClass}
98117
title={`${count} instances`}
99118
aria-label={`${count} instances`}
100119
>

0 commit comments

Comments
 (0)