@aiready/visualizer 0.1.37 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +46 -17
- package/dist/cli.js.map +1 -1
- package/dist/graph/index.js +36 -13
- package/dist/graph/index.js.map +1 -1
- package/dist/index.js +36 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/web/dist/assets/{index-C9b__qGk.js → index-5leRjvmV.js} +1 -1
- package/web/dist/index.html +2 -2
- package/web/dist/report-data.json +224 -742
- package/web/index.html +1 -1
- package/web/package.json +1 -1
- package/web/public/report-data.json +224 -742
- package/web/src/App.tsx +61 -47
- package/web/src/components/ErrorDisplay.tsx +31 -17
- package/web/src/components/GraphCanvas.tsx +90 -24
- package/web/src/components/LegendPanel.tsx +242 -139
- package/web/src/components/LoadingSpinner.tsx +6 -3
- package/web/src/components/Navbar.tsx +66 -52
- package/web/src/components/NodeDetails.tsx +98 -68
- package/web/src/hooks/useTheme.ts +5 -2
- package/web/src/main.tsx +1 -1
- package/web/src/style.css +14 -2
- package/web/src/styles/index.css +7 -5
- package/web/src/utils.ts +86 -25
- package/web/tsconfig.json +1 -1
- package/web/vite.config.ts +10 -5
|
@@ -2,15 +2,15 @@ import { ThemeColors, GraphData, Theme, BusinessMetrics } from '../types';
|
|
|
2
2
|
|
|
3
3
|
// Icons as inline SVG components for the theme toggle
|
|
4
4
|
const SunIcon = ({ className }: { className?: string }) => (
|
|
5
|
-
<svg
|
|
5
|
+
<svg
|
|
6
6
|
className={className}
|
|
7
|
-
width="16"
|
|
8
|
-
height="16"
|
|
9
|
-
viewBox="0 0 24 24"
|
|
10
|
-
fill="none"
|
|
11
|
-
stroke="currentColor"
|
|
12
|
-
strokeWidth="2"
|
|
13
|
-
strokeLinecap="round"
|
|
7
|
+
width="16"
|
|
8
|
+
height="16"
|
|
9
|
+
viewBox="0 0 24 24"
|
|
10
|
+
fill="none"
|
|
11
|
+
stroke="currentColor"
|
|
12
|
+
strokeWidth="2"
|
|
13
|
+
strokeLinecap="round"
|
|
14
14
|
strokeLinejoin="round"
|
|
15
15
|
>
|
|
16
16
|
<circle cx="12" cy="12" r="4" />
|
|
@@ -26,15 +26,15 @@ const SunIcon = ({ className }: { className?: string }) => (
|
|
|
26
26
|
);
|
|
27
27
|
|
|
28
28
|
const MoonIcon = ({ className }: { className?: string }) => (
|
|
29
|
-
<svg
|
|
29
|
+
<svg
|
|
30
30
|
className={className}
|
|
31
|
-
width="16"
|
|
32
|
-
height="16"
|
|
33
|
-
viewBox="0 0 24 24"
|
|
34
|
-
fill="none"
|
|
35
|
-
stroke="currentColor"
|
|
36
|
-
strokeWidth="2"
|
|
37
|
-
strokeLinecap="round"
|
|
31
|
+
width="16"
|
|
32
|
+
height="16"
|
|
33
|
+
viewBox="0 0 24 24"
|
|
34
|
+
fill="none"
|
|
35
|
+
stroke="currentColor"
|
|
36
|
+
strokeWidth="2"
|
|
37
|
+
strokeLinecap="round"
|
|
38
38
|
strokeLinejoin="round"
|
|
39
39
|
>
|
|
40
40
|
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
|
|
@@ -42,15 +42,15 @@ const MoonIcon = ({ className }: { className?: string }) => (
|
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
const SystemIcon = ({ className }: { className?: string }) => (
|
|
45
|
-
<svg
|
|
45
|
+
<svg
|
|
46
46
|
className={className}
|
|
47
|
-
width="16"
|
|
48
|
-
height="16"
|
|
49
|
-
viewBox="0 0 24 24"
|
|
50
|
-
fill="none"
|
|
51
|
-
stroke="currentColor"
|
|
52
|
-
strokeWidth="2"
|
|
53
|
-
strokeLinecap="round"
|
|
47
|
+
width="16"
|
|
48
|
+
height="16"
|
|
49
|
+
viewBox="0 0 24 24"
|
|
50
|
+
fill="none"
|
|
51
|
+
stroke="currentColor"
|
|
52
|
+
strokeWidth="2"
|
|
53
|
+
strokeLinecap="round"
|
|
54
54
|
strokeLinejoin="round"
|
|
55
55
|
>
|
|
56
56
|
<rect width="20" height="14" x="2" y="3" rx="2" />
|
|
@@ -67,37 +67,43 @@ interface NavbarProps {
|
|
|
67
67
|
metadata?: BusinessMetrics;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
export function Navbar({
|
|
70
|
+
export function Navbar({
|
|
71
|
+
colors,
|
|
72
|
+
theme,
|
|
73
|
+
setTheme,
|
|
74
|
+
data,
|
|
75
|
+
metadata,
|
|
76
|
+
}: NavbarProps) {
|
|
71
77
|
return (
|
|
72
|
-
<nav
|
|
78
|
+
<nav
|
|
73
79
|
className="h-16 backdrop-blur-md border-b flex items-center justify-between px-6 z-50 relative"
|
|
74
|
-
style={{
|
|
75
|
-
backgroundColor: `${colors.panel}f5`,
|
|
76
|
-
borderColor: colors.panelBorder
|
|
80
|
+
style={{
|
|
81
|
+
backgroundColor: `${colors.panel}f5`,
|
|
82
|
+
borderColor: colors.panelBorder,
|
|
77
83
|
}}
|
|
78
84
|
>
|
|
79
85
|
{/* Subtle gradient overlay */}
|
|
80
|
-
<div
|
|
86
|
+
<div
|
|
81
87
|
className="absolute inset-0 pointer-events-none"
|
|
82
88
|
style={{
|
|
83
89
|
background: `linear-gradient(90deg, ${colors.panel}80 0%, transparent 50%, ${colors.panel}80 100%)`,
|
|
84
90
|
}}
|
|
85
91
|
/>
|
|
86
|
-
|
|
92
|
+
|
|
87
93
|
<div className="flex items-center gap-5 relative z-10">
|
|
88
94
|
<div className="flex items-center justify-center">
|
|
89
|
-
<img
|
|
90
|
-
src="/logo-transparent-bg.png"
|
|
91
|
-
alt="AIReady"
|
|
92
|
-
className="h-9 w-auto"
|
|
95
|
+
<img
|
|
96
|
+
src="/logo-transparent-bg.png"
|
|
97
|
+
alt="AIReady"
|
|
98
|
+
className="h-9 w-auto"
|
|
93
99
|
/>
|
|
94
100
|
</div>
|
|
95
|
-
<div
|
|
96
|
-
className="h-7 w-px"
|
|
97
|
-
style={{ backgroundColor: colors.panelBorder }}
|
|
101
|
+
<div
|
|
102
|
+
className="h-7 w-px"
|
|
103
|
+
style={{ backgroundColor: colors.panelBorder }}
|
|
98
104
|
/>
|
|
99
|
-
<h1
|
|
100
|
-
className="text-sm font-semibold tracking-wide uppercase"
|
|
105
|
+
<h1
|
|
106
|
+
className="text-sm font-semibold tracking-wide uppercase"
|
|
101
107
|
style={{ color: colors.textMuted }}
|
|
102
108
|
>
|
|
103
109
|
Codebase
|
|
@@ -106,7 +112,14 @@ export function Navbar({ colors, theme, setTheme, data, metadata }: NavbarProps)
|
|
|
106
112
|
|
|
107
113
|
<div className="flex items-center gap-6 relative z-10">
|
|
108
114
|
{/* Modern Theme Toggle */}
|
|
109
|
-
<div
|
|
115
|
+
<div
|
|
116
|
+
className="flex items-center rounded-lg border px-4 py-3"
|
|
117
|
+
style={{
|
|
118
|
+
borderColor: colors.panelBorder,
|
|
119
|
+
backgroundColor: `${colors.panel}80`,
|
|
120
|
+
gap: '12px',
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
110
123
|
{[
|
|
111
124
|
{ key: 'dark', icon: MoonIcon, label: 'Dark' },
|
|
112
125
|
{ key: 'light', icon: SunIcon, label: 'Light' },
|
|
@@ -125,7 +138,7 @@ export function Navbar({ colors, theme, setTheme, data, metadata }: NavbarProps)
|
|
|
125
138
|
}}
|
|
126
139
|
title={`Switch to ${label} theme`}
|
|
127
140
|
>
|
|
128
|
-
<Icon
|
|
141
|
+
<Icon
|
|
129
142
|
className="transition-transform duration-200"
|
|
130
143
|
style={{ transform: theme === key ? 'scale(1.1)' : 'scale(1)' }}
|
|
131
144
|
/>
|
|
@@ -136,10 +149,10 @@ export function Navbar({ colors, theme, setTheme, data, metadata }: NavbarProps)
|
|
|
136
149
|
|
|
137
150
|
{data && (
|
|
138
151
|
<div className="flex items-center" style={{ gap: '12px' }}>
|
|
139
|
-
<div
|
|
152
|
+
<div
|
|
140
153
|
className="rounded-lg border text-xs font-medium flex items-center"
|
|
141
|
-
style={{
|
|
142
|
-
backgroundColor: `${colors.cardBg}cc`,
|
|
154
|
+
style={{
|
|
155
|
+
backgroundColor: `${colors.cardBg}cc`,
|
|
143
156
|
borderColor: colors.cardBorder,
|
|
144
157
|
padding: '8px 14px',
|
|
145
158
|
gap: '8px',
|
|
@@ -149,10 +162,10 @@ export function Navbar({ colors, theme, setTheme, data, metadata }: NavbarProps)
|
|
|
149
162
|
<span style={{ color: colors.textMuted }}>Files</span>
|
|
150
163
|
<span style={{ color: colors.text }}>{data.nodes.length}</span>
|
|
151
164
|
</div>
|
|
152
|
-
<div
|
|
165
|
+
<div
|
|
153
166
|
className="rounded-lg border text-xs font-medium flex items-center"
|
|
154
|
-
style={{
|
|
155
|
-
backgroundColor: `${colors.cardBg}cc`,
|
|
167
|
+
style={{
|
|
168
|
+
backgroundColor: `${colors.cardBg}cc`,
|
|
156
169
|
borderColor: colors.cardBorder,
|
|
157
170
|
padding: '8px 14px',
|
|
158
171
|
gap: '8px',
|
|
@@ -163,10 +176,10 @@ export function Navbar({ colors, theme, setTheme, data, metadata }: NavbarProps)
|
|
|
163
176
|
<span style={{ color: colors.text }}>{data.edges.length}</span>
|
|
164
177
|
</div>
|
|
165
178
|
{metadata?.estimatedMonthlyCost !== undefined && (
|
|
166
|
-
<div
|
|
179
|
+
<div
|
|
167
180
|
className="rounded-lg border text-xs font-medium flex items-center"
|
|
168
|
-
style={{
|
|
169
|
-
backgroundColor: `${colors.cardBg}cc`,
|
|
181
|
+
style={{
|
|
182
|
+
backgroundColor: `${colors.cardBg}cc`,
|
|
170
183
|
borderColor: colors.cardBorder,
|
|
171
184
|
padding: '8px 14px',
|
|
172
185
|
gap: '8px',
|
|
@@ -178,7 +191,8 @@ export function Navbar({ colors, theme, setTheme, data, metadata }: NavbarProps)
|
|
|
178
191
|
<span style={{ color: '#f59e0b', fontWeight: 600 }}>
|
|
179
192
|
{metadata.estimatedMonthlyCost >= 1000
|
|
180
193
|
? `$${(metadata.estimatedMonthlyCost / 1000).toFixed(1)}k`
|
|
181
|
-
: `$${metadata.estimatedMonthlyCost.toFixed(0)}`}
|
|
194
|
+
: `$${metadata.estimatedMonthlyCost.toFixed(0)}`}
|
|
195
|
+
/mo
|
|
182
196
|
</span>
|
|
183
197
|
</div>
|
|
184
198
|
)}
|
|
@@ -1,34 +1,29 @@
|
|
|
1
1
|
import { ThemeColors, FileNode } from '../types';
|
|
2
2
|
|
|
3
3
|
// Info Row Component for consistent styling
|
|
4
|
-
function InfoRow({
|
|
5
|
-
label,
|
|
6
|
-
value,
|
|
4
|
+
function InfoRow({
|
|
5
|
+
label,
|
|
6
|
+
value,
|
|
7
7
|
valueColor = 'inherit',
|
|
8
8
|
highlight = false,
|
|
9
|
-
colors
|
|
10
|
-
}: {
|
|
11
|
-
label: string;
|
|
9
|
+
colors,
|
|
10
|
+
}: {
|
|
11
|
+
label: string;
|
|
12
12
|
value: string | number;
|
|
13
13
|
valueColor?: string;
|
|
14
14
|
highlight?: boolean;
|
|
15
15
|
colors: ThemeColors;
|
|
16
16
|
}) {
|
|
17
17
|
return (
|
|
18
|
-
<div
|
|
19
|
-
className="
|
|
20
|
-
>
|
|
21
|
-
<span
|
|
22
|
-
className="text-xs font-medium"
|
|
23
|
-
style={{ color: colors.textMuted }}
|
|
24
|
-
>
|
|
18
|
+
<div className="flex justify-between items-center py-2.5 px-3 rounded-lg transition-colors hover:bg-white/5">
|
|
19
|
+
<span className="text-xs font-medium" style={{ color: colors.textMuted }}>
|
|
25
20
|
{label}
|
|
26
21
|
</span>
|
|
27
|
-
<span
|
|
22
|
+
<span
|
|
28
23
|
className={`text-xs font-semibold ${highlight ? 'px-3 py-1 rounded-full' : ''}`}
|
|
29
|
-
style={{
|
|
24
|
+
style={{
|
|
30
25
|
color: valueColor,
|
|
31
|
-
backgroundColor: highlight ? `${valueColor}25` : 'transparent'
|
|
26
|
+
backgroundColor: highlight ? `${valueColor}25` : 'transparent',
|
|
32
27
|
}}
|
|
33
28
|
>
|
|
34
29
|
{value}
|
|
@@ -43,128 +38,163 @@ interface NodeDetailsProps {
|
|
|
43
38
|
onClose?: () => void;
|
|
44
39
|
}
|
|
45
40
|
|
|
46
|
-
export function NodeDetails({
|
|
41
|
+
export function NodeDetails({
|
|
42
|
+
colors,
|
|
43
|
+
selectedNode,
|
|
44
|
+
onClose,
|
|
45
|
+
}: NodeDetailsProps) {
|
|
47
46
|
return (
|
|
48
|
-
<div
|
|
49
|
-
style={{
|
|
47
|
+
<div
|
|
48
|
+
style={{
|
|
50
49
|
padding: '16px 16px',
|
|
51
50
|
height: '100%',
|
|
52
51
|
overflowY: 'auto',
|
|
53
52
|
overflowX: 'hidden',
|
|
54
|
-
animation: 'fadeIn 0.2s ease-in'
|
|
53
|
+
animation: 'fadeIn 0.2s ease-in',
|
|
55
54
|
}}
|
|
56
55
|
>
|
|
57
56
|
{/* Header */}
|
|
58
|
-
<div
|
|
57
|
+
<div
|
|
58
|
+
className="flex justify-between items-center"
|
|
59
|
+
style={{ marginBottom: '16px' }}
|
|
60
|
+
>
|
|
59
61
|
<div className="flex items-center gap-2">
|
|
60
|
-
<div
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<h3
|
|
64
|
-
className="text-xs font-bold uppercase tracking-widest"
|
|
62
|
+
<div className="w-2 h-2 rounded-full bg-cyan-400 animate-pulse" />
|
|
63
|
+
<h3
|
|
64
|
+
className="text-xs font-bold uppercase tracking-widest"
|
|
65
65
|
style={{ color: colors.textMuted }}
|
|
66
66
|
>
|
|
67
67
|
Selected Node
|
|
68
68
|
</h3>
|
|
69
69
|
</div>
|
|
70
70
|
{onClose && (
|
|
71
|
-
<button
|
|
71
|
+
<button
|
|
72
72
|
onClick={onClose}
|
|
73
73
|
className="p-2 rounded-lg hover:bg-white/10 transition-colors"
|
|
74
74
|
style={{ color: colors.textMuted }}
|
|
75
75
|
title="Close details"
|
|
76
76
|
>
|
|
77
|
-
<svg
|
|
77
|
+
<svg
|
|
78
|
+
width="14"
|
|
79
|
+
height="14"
|
|
80
|
+
viewBox="0 0 24 24"
|
|
81
|
+
fill="none"
|
|
82
|
+
stroke="currentColor"
|
|
83
|
+
strokeWidth="2"
|
|
84
|
+
>
|
|
78
85
|
<path d="M18 6L6 18M6 6l12 12" />
|
|
79
86
|
</svg>
|
|
80
87
|
</button>
|
|
81
88
|
)}
|
|
82
89
|
</div>
|
|
83
|
-
|
|
90
|
+
|
|
84
91
|
{selectedNode ? (
|
|
85
92
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
|
86
93
|
{/* File Name - No border, just padding */}
|
|
87
|
-
<div
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
<div
|
|
95
|
+
className="p-4 rounded-xl"
|
|
96
|
+
style={{
|
|
97
|
+
backgroundColor: `${colors.cardBg}80`,
|
|
90
98
|
}}
|
|
91
99
|
>
|
|
92
100
|
<div className="flex items-center gap-2 mb-2">
|
|
93
|
-
<svg
|
|
101
|
+
<svg
|
|
102
|
+
width="16"
|
|
103
|
+
height="16"
|
|
104
|
+
viewBox="0 0 24 24"
|
|
105
|
+
fill="none"
|
|
106
|
+
stroke="currentColor"
|
|
107
|
+
strokeWidth="2"
|
|
108
|
+
className="text-amber-400"
|
|
109
|
+
>
|
|
94
110
|
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" />
|
|
95
111
|
<polyline points="14,2 14,8 20,8" />
|
|
96
112
|
</svg>
|
|
97
|
-
<h4
|
|
113
|
+
<h4
|
|
114
|
+
className="font-semibold text-sm truncate"
|
|
115
|
+
style={{ color: colors.text }}
|
|
116
|
+
>
|
|
98
117
|
{selectedNode.label}
|
|
99
118
|
</h4>
|
|
100
119
|
</div>
|
|
101
|
-
<p
|
|
102
|
-
className="text-xs break-all truncate"
|
|
120
|
+
<p
|
|
121
|
+
className="text-xs break-all truncate"
|
|
103
122
|
style={{ color: colors.textMuted }}
|
|
104
123
|
title={selectedNode.id}
|
|
105
124
|
>
|
|
106
125
|
{selectedNode.label}
|
|
107
126
|
</p>
|
|
108
127
|
</div>
|
|
109
|
-
|
|
128
|
+
|
|
110
129
|
{/* Metrics - No border */}
|
|
111
130
|
<div className="rounded-xl p-1">
|
|
112
131
|
<div className="px-3 py-2">
|
|
113
|
-
<span
|
|
132
|
+
<span
|
|
133
|
+
className="text-xs font-semibold uppercase tracking-wider"
|
|
134
|
+
style={{ color: colors.textMuted }}
|
|
135
|
+
>
|
|
114
136
|
Metrics
|
|
115
137
|
</span>
|
|
116
138
|
</div>
|
|
117
139
|
<div className="p-1">
|
|
118
|
-
<InfoRow
|
|
119
|
-
label="Severity"
|
|
120
|
-
value={selectedNode.severity || 'none'}
|
|
140
|
+
<InfoRow
|
|
141
|
+
label="Severity"
|
|
142
|
+
value={selectedNode.severity || 'none'}
|
|
121
143
|
valueColor={selectedNode.color}
|
|
122
144
|
highlight
|
|
123
145
|
colors={colors}
|
|
124
146
|
/>
|
|
125
|
-
<InfoRow
|
|
126
|
-
label="Token Cost"
|
|
127
|
-
value={selectedNode.tokenCost?.toLocaleString() || '0'}
|
|
147
|
+
<InfoRow
|
|
148
|
+
label="Token Cost"
|
|
149
|
+
value={selectedNode.tokenCost?.toLocaleString() || '0'}
|
|
128
150
|
valueColor="#22d3ee"
|
|
129
151
|
colors={colors}
|
|
130
152
|
/>
|
|
131
153
|
{selectedNode.duplicates !== undefined && (
|
|
132
|
-
<InfoRow
|
|
133
|
-
label="Issues Found"
|
|
134
|
-
value={selectedNode.duplicates}
|
|
154
|
+
<InfoRow
|
|
155
|
+
label="Issues Found"
|
|
156
|
+
value={selectedNode.duplicates}
|
|
135
157
|
valueColor="#c084fc"
|
|
136
158
|
colors={colors}
|
|
137
159
|
/>
|
|
138
160
|
)}
|
|
139
161
|
</div>
|
|
140
162
|
</div>
|
|
141
|
-
|
|
163
|
+
|
|
142
164
|
{/* Description/Details - No border */}
|
|
143
165
|
{selectedNode.title && (
|
|
144
|
-
<div
|
|
166
|
+
<div
|
|
145
167
|
className="rounded-xl p-4"
|
|
146
|
-
style={{
|
|
147
|
-
backgroundColor: `${colors.cardBg}80
|
|
168
|
+
style={{
|
|
169
|
+
backgroundColor: `${colors.cardBg}80`,
|
|
148
170
|
}}
|
|
149
171
|
>
|
|
150
172
|
<div className="flex items-center gap-2 mb-3">
|
|
151
|
-
<svg
|
|
173
|
+
<svg
|
|
174
|
+
width="14"
|
|
175
|
+
height="14"
|
|
176
|
+
viewBox="0 0 24 24"
|
|
177
|
+
fill="none"
|
|
178
|
+
stroke="currentColor"
|
|
179
|
+
strokeWidth="2"
|
|
180
|
+
style={{ color: colors.textMuted }}
|
|
181
|
+
>
|
|
152
182
|
<circle cx="12" cy="12" r="10" />
|
|
153
183
|
<path d="M12 16v-4M12 8h.01" />
|
|
154
184
|
</svg>
|
|
155
|
-
<h5
|
|
156
|
-
className="text-xs font-semibold uppercase tracking-wider"
|
|
185
|
+
<h5
|
|
186
|
+
className="text-xs font-semibold uppercase tracking-wider"
|
|
157
187
|
style={{ color: colors.textMuted }}
|
|
158
188
|
>
|
|
159
189
|
Details
|
|
160
190
|
</h5>
|
|
161
191
|
</div>
|
|
162
|
-
<pre
|
|
192
|
+
<pre
|
|
163
193
|
className="text-xs whitespace-pre-wrap font-mono leading-relaxed p-3 rounded-lg"
|
|
164
|
-
style={{
|
|
194
|
+
style={{
|
|
165
195
|
color: colors.textMuted,
|
|
166
196
|
backgroundColor: colors.panel,
|
|
167
|
-
overflow: 'auto'
|
|
197
|
+
overflow: 'auto',
|
|
168
198
|
}}
|
|
169
199
|
>
|
|
170
200
|
{selectedNode.title}
|
|
@@ -173,18 +203,18 @@ export function NodeDetails({ colors, selectedNode, onClose }: NodeDetailsProps)
|
|
|
173
203
|
)}
|
|
174
204
|
</div>
|
|
175
205
|
) : (
|
|
176
|
-
<div
|
|
206
|
+
<div
|
|
177
207
|
className="flex flex-col items-center justify-center py-10 text-center rounded-xl"
|
|
178
|
-
style={{
|
|
179
|
-
backgroundColor: `${colors.cardBg}50
|
|
208
|
+
style={{
|
|
209
|
+
backgroundColor: `${colors.cardBg}50`,
|
|
180
210
|
}}
|
|
181
211
|
>
|
|
182
|
-
<svg
|
|
183
|
-
width="48"
|
|
184
|
-
height="48"
|
|
185
|
-
viewBox="0 0 24 24"
|
|
186
|
-
fill="none"
|
|
187
|
-
stroke="currentColor"
|
|
212
|
+
<svg
|
|
213
|
+
width="48"
|
|
214
|
+
height="48"
|
|
215
|
+
viewBox="0 0 24 24"
|
|
216
|
+
fill="none"
|
|
217
|
+
stroke="currentColor"
|
|
188
218
|
strokeWidth="1.5"
|
|
189
219
|
className="mb-3 opacity-40"
|
|
190
220
|
style={{ color: colors.textMuted }}
|
|
@@ -192,8 +222,8 @@ export function NodeDetails({ colors, selectedNode, onClose }: NodeDetailsProps)
|
|
|
192
222
|
<circle cx="11" cy="11" r="8" />
|
|
193
223
|
<path d="m21 21-4.3-4.3" />
|
|
194
224
|
</svg>
|
|
195
|
-
<p
|
|
196
|
-
className="text-sm font-medium"
|
|
225
|
+
<p
|
|
226
|
+
className="text-sm font-medium"
|
|
197
227
|
style={{ color: colors.textMuted }}
|
|
198
228
|
>
|
|
199
229
|
Click a node to view details
|
|
@@ -3,11 +3,14 @@ import { Theme, EffectiveTheme } from '../types';
|
|
|
3
3
|
|
|
4
4
|
export function useTheme() {
|
|
5
5
|
const getSystemTheme = (): EffectiveTheme => {
|
|
6
|
-
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
6
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
7
|
+
? 'dark'
|
|
8
|
+
: 'light';
|
|
7
9
|
};
|
|
8
10
|
|
|
9
11
|
const [theme, setTheme] = useState<Theme>('system');
|
|
10
|
-
const [systemTheme, setSystemTheme] =
|
|
12
|
+
const [systemTheme, setSystemTheme] =
|
|
13
|
+
useState<EffectiveTheme>(getSystemTheme());
|
|
11
14
|
|
|
12
15
|
useEffect(() => {
|
|
13
16
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
package/web/src/main.tsx
CHANGED
package/web/src/style.css
CHANGED
package/web/src/styles/index.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@import
|
|
1
|
+
@import 'tailwindcss';
|
|
2
2
|
|
|
3
3
|
/* Base styles */
|
|
4
4
|
* {
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
padding: 0;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
html,
|
|
10
|
+
html,
|
|
11
|
+
body,
|
|
12
|
+
#root {
|
|
11
13
|
height: 100%;
|
|
12
14
|
width: 100%;
|
|
13
15
|
overflow: hidden;
|
|
@@ -15,9 +17,9 @@ html, body, #root {
|
|
|
15
17
|
|
|
16
18
|
body {
|
|
17
19
|
margin: 0;
|
|
18
|
-
font-family:
|
|
19
|
-
|
|
20
|
-
sans-serif;
|
|
20
|
+
font-family:
|
|
21
|
+
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
|
22
|
+
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
21
23
|
-webkit-font-smoothing: antialiased;
|
|
22
24
|
-moz-osx-font-smoothing: grayscale;
|
|
23
25
|
}
|