File size: 4,396 Bytes
518343a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import {
  Activity,
  ArrowDownRight,
  ArrowRight,
  ArrowUpRight,
  Briefcase,
  Building2,
  Scale,
  ShieldAlert,
  Ship,
  User,
  Users,
} from 'lucide-react';
import type { ElementType } from 'react';
import { Line, LineChart, ResponsiveContainer, YAxis } from 'recharts';
import type { DomainData } from '../types';

const DOMAIN_ICONS: Record<string, ElementType> = {
  ShieldAlert,
  Ship,
  Briefcase,
  Activity,
  Scale,
  Building2,
  Users,
  User,
};

interface DomainCardProps {
  data: DomainData;
}

export function DomainCard({ data }: DomainCardProps) {
  const Icon = DOMAIN_ICONS[data.icon] ?? Activity;
  const chartData = data.sparkline.map((val, i) => ({ value: val, index: i }));
  const min = Math.min(...data.sparkline);
  const max = Math.max(...data.sparkline);

  const alertColors: Record<string, string> = {
    critical: 'var(--color-critical)',
    high: 'var(--color-high)',
    medium: 'var(--color-medium)',
    low: 'var(--color-low)',
    info: 'var(--color-info)',
  };
  const alertColor = alertColors[data.alerts.severity] ?? 'var(--color-fg-muted)';

  return (
    <a
      href={`${import.meta.env.BASE_URL?.replace(/\/$/, '') || '/a11oy'}/domain/${data.id}`}
      className="block group"
      data-testid={`card-domain-${data.id}`}
    >
      <div
        className="flex flex-col h-full rounded-xl overflow-hidden transition-colors"
        style={{
          backgroundColor: 'var(--color-surface-base)',
          border: '1px solid var(--color-surface-border)',
        }}
      >
        <div className="p-5 flex flex-col gap-4 flex-1">
          <div className="flex items-start justify-between">
            <div className="flex items-center gap-2">
              <Icon className="w-5 h-5" style={{ color: data.color }} />
              <h3 className="font-bold text-sm tracking-wide" style={{ color: data.color }}>
                {data.name}
              </h3>
            </div>
            {data.alerts.count > 0 && (
              <div
                className="px-2 py-0.5 text-[10px] font-bold uppercase tracking-wider rounded border"
                style={{
                  color: alertColor,
                  borderColor: alertColor,
                  backgroundColor: `color-mix(in srgb, ${alertColor} 10%, transparent)`,
                }}
                data-testid={`badge-alerts-${data.id}`}
              >
                {data.alerts.count} Alert{data.alerts.count > 1 ? 's' : ''}
              </div>
            )}
          </div>

          <div className="flex flex-col gap-2 mt-1">
            {data.kpis.map((kpi, i) => (
              <div key={i} className="flex items-center justify-between text-sm">
                <span style={{ color: 'var(--color-fg-muted)' }}>{kpi.label}</span>
                <div className="flex items-center gap-1.5 font-mono">
                  <span style={{ color: 'var(--color-fg-primary)' }}>{kpi.value}</span>
                  {kpi.trend === 'up' ? (
                    <ArrowUpRight className="w-3 h-3" style={{ color: 'var(--color-low)' }} />
                  ) : kpi.trend === 'down' ? (
                    <ArrowDownRight
                      className="w-3 h-3"
                      style={{ color: 'var(--color-critical)' }}
                    />
                  ) : (
                    <ArrowRight
                      className="w-3 h-3"
                      style={{ color: 'var(--color-fg-muted)', opacity: 0.5 }}
                    />
                  )}
                </div>
              </div>
            ))}
          </div>
        </div>

        <div
          className="h-16 w-full"
          style={{
            borderTop: '1px solid var(--color-surface-border)',
            backgroundColor: 'color-mix(in srgb, var(--color-bg-primary) 50%, transparent)',
          }}
        >
          <ResponsiveContainer width="100%" height="100%">
            <LineChart data={chartData} margin={{ top: 5, right: 0, left: 0, bottom: 5 }}>
              <YAxis domain={[min - 2, max + 2]} hide />
              <Line
                type="monotone"
                dataKey="value"
                stroke={data.color}
                strokeWidth={1.5}
                dot={false}
                isAnimationActive={false}
              />
            </LineChart>
          </ResponsiveContainer>
        </div>
      </div>
    </a>
  );
}