Skip to content

Commit 6797b9b

Browse files
committed
refactor(ui): replace inline styles with Tailwind classnames
Convert all remaining inline styles across docs and product-page components to Tailwind utility classes. Remove useState hover tracking from FeatureCard, IntegrationCard, and IntegrationItem in favour of CSS group-hover. Replace onMouseEnter/Leave handlers in ProductPageLayout with hover: variants. Dynamic runtime values (color-mix from a color prop, linear-gradient backgrounds) are the only remaining style={} attributes.
1 parent 7e2b1cd commit 6797b9b

10 files changed

Lines changed: 84 additions & 456 deletions

File tree

crowdsec-docs/src/components/docs/AccessCard/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default function AccessCard({ icon, title, command, ctaLabel, ctaHref }:
3636
</div>
3737
{command && (
3838
<div className="flex items-center gap-2 py-[9px] px-[14px] bg-cs-bg border border-cs-border rounded-[7px] font-cs-mono text-[12.5px] text-cs-teal">
39-
<span style={{ color: "var(--cs-ink-mute)" }}>$</span>
39+
<span className="text-cs-ink-mute">$</span>
4040
<span>{command}</span>
4141
</div>
4242
)}

crowdsec-docs/src/components/docs/ChallengeGrid/index.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,14 @@ export default function ChallengeGrid({ challenges }: Props) {
3232
<div className="flex items-center gap-3 mb-[10px]">
3333
{iconEl && (
3434
<div
35+
className="w-9 h-9 rounded-[9px] flex items-center justify-center shrink-0"
3536
style={{
36-
width: 36,
37-
height: 36,
38-
borderRadius: 9,
3937
background: `${c.color}14`,
4038
border: `1px solid ${c.color}33`,
41-
display: "flex",
42-
alignItems: "center",
43-
justifyContent: "center",
4439
color: c.color,
45-
flexShrink: 0,
4640
}}
4741
>
48-
<div style={{ width: 17, height: 17, display: "flex" }}>{iconEl}</div>
42+
<div className="w-[17px] h-[17px] flex">{iconEl}</div>
4943
</div>
5044
)}
5145
<div className="font-cs-mono text-[11px] text-cs-ink-mute tracking-[0.10em]">

crowdsec-docs/src/components/docs/DocCard/index.tsx

Lines changed: 20 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -63,85 +63,39 @@ export default function DocCard({
6363

6464
const card = (
6565
<div
66-
style={{
67-
padding: 20,
68-
borderRadius: 12,
69-
background: "var(--cs-surface)",
70-
border: "1px solid var(--cs-border)",
71-
display: "flex",
72-
flexDirection: "column",
73-
gap: 12,
74-
height: "100%",
75-
boxSizing: "border-box",
76-
textDecoration: "none",
77-
color: "inherit",
78-
transition: href ? "border-color 0.15s, box-shadow 0.15s" : undefined,
79-
}}
66+
className={`p-5 rounded-xl bg-cs-surface border border-cs-border flex flex-col gap-3 h-full${href ? " transition-[border-color,box-shadow] duration-150" : ""}`}
8067
>
8168
{/* Header: icon + title + premium badge */}
82-
<div style={{ display: "flex", alignItems: "flex-start", gap: 12 }}>
69+
<div className="flex items-start gap-3">
8370
{resolvedIcon && (
8471
<div
72+
className="w-9 h-9 rounded-[9px] flex items-center justify-center shrink-0"
8573
style={{
86-
width: 36,
87-
height: 36,
88-
borderRadius: 9,
8974
background: mix(color, 14),
9075
border: `1px solid ${mix(color, 28)}`,
91-
display: "flex",
92-
alignItems: "center",
93-
justifyContent: "center",
9476
color,
95-
flexShrink: 0,
9677
}}
9778
>
98-
<div style={{ width: 17, height: 17, display: "flex" }}>{resolvedIcon}</div>
79+
<div className="w-[17px] h-[17px] flex">{resolvedIcon}</div>
9980
</div>
10081
)}
101-
<div style={{ flex: 1, minWidth: 0 }}>
82+
<div className="flex-1 min-w-0">
10283
{badge && (
10384
<div
85+
className="inline-flex self-start px-2 py-[2px] rounded-full font-cs-mono text-[9.5px] tracking-[0.08em] font-semibold mb-1.5"
10486
style={{
105-
display: "inline-flex",
106-
alignSelf: "flex-start",
107-
padding: "2px 8px",
108-
borderRadius: 100,
109-
fontFamily: "var(--cs-font-mono)",
110-
fontSize: 9.5,
111-
letterSpacing: "0.08em",
112-
fontWeight: 600,
11387
color,
11488
border: `1px solid ${mix(color, 30)}`,
11589
background: mix(color, 10),
116-
marginBottom: 6,
11790
}}
11891
>
11992
{badge}
12093
</div>
12194
)}
122-
<div
123-
style={{
124-
display: "flex",
125-
alignItems: "center",
126-
gap: 8,
127-
flexWrap: "wrap",
128-
}}
129-
>
130-
<div style={{ fontSize: 15, fontWeight: 600, color: "var(--cs-ink)", lineHeight: 1.3 }}>{title}</div>
95+
<div className="flex items-center gap-2 flex-wrap">
96+
<div className="text-[15px] font-semibold text-cs-ink leading-[1.3]">{title}</div>
13197
{premium && (
132-
<span
133-
style={{
134-
fontFamily: "var(--cs-font-mono)",
135-
fontSize: 9.5,
136-
letterSpacing: "0.08em",
137-
textTransform: "uppercase",
138-
padding: "2px 6px",
139-
borderRadius: 4,
140-
background: mix("var(--cs-orange)", 14),
141-
color: "var(--cs-orange)",
142-
fontWeight: 600,
143-
}}
144-
>
98+
<span className="font-cs-mono text-[9.5px] tracking-[0.08em] uppercase px-[6px] py-[2px] rounded bg-[color-mix(in_srgb,var(--cs-orange)_14%,transparent)] text-cs-orange font-semibold">
14599
Premium
146100
</span>
147101
)}
@@ -150,58 +104,28 @@ export default function DocCard({
150104
</div>
151105

152106
{/* Description */}
153-
{desc && <div style={{ fontSize: 13.5, color: "var(--cs-ink-dim)", lineHeight: 1.55, flex: 1 }}>{desc}</div>}
107+
{desc && <div className="text-[13.5px] text-cs-ink-dim leading-[1.55] flex-1">{desc}</div>}
154108

155109
{/* Extra content slot */}
156-
{children && <div style={{ flex: 1 }}>{children}</div>}
110+
{children && <div className="flex-1">{children}</div>}
157111

158112
{/* Command block */}
159113
{command && (
160-
<div
161-
style={{
162-
padding: "9px 12px",
163-
borderRadius: 8,
164-
background: "var(--cs-bg)",
165-
border: "1px solid var(--cs-border)",
166-
fontFamily: "var(--cs-font-mono)",
167-
fontSize: 12,
168-
color,
169-
display: "flex",
170-
alignItems: "center",
171-
gap: 10,
172-
}}
173-
>
174-
<span style={{ color: "var(--cs-ink-mute)", userSelect: "none" }}>$</span>
175-
<span
176-
style={{
177-
flex: 1,
178-
overflow: "hidden",
179-
textOverflow: "ellipsis",
180-
whiteSpace: "nowrap",
181-
color: "var(--cs-ink)",
182-
}}
183-
>
184-
{command}
185-
</span>
114+
<div className="py-[9px] px-3 rounded-lg bg-cs-bg border border-cs-border font-cs-mono text-xs flex items-center gap-[10px]">
115+
<span className="text-cs-ink-mute select-none">$</span>
116+
<span className="flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-cs-ink">{command}</span>
186117
</div>
187118
)}
188119

189120
{/* Link list */}
190121
{links && links.length > 0 && (
191-
<div style={{ display: "flex", flexDirection: "column", gap: 5, marginTop: 4 }}>
122+
<div className="flex flex-col gap-[5px] mt-1">
192123
{links.map((l) => (
193124
<a
194125
key={l.href}
195126
href={l.href}
196-
style={{
197-
fontSize: 12.5,
198-
fontWeight: 600,
199-
color,
200-
textDecoration: "none",
201-
display: "inline-flex",
202-
alignItems: "center",
203-
gap: 4,
204-
}}
127+
className="text-[12.5px] font-semibold no-underline inline-flex items-center gap-1"
128+
style={{ color }}
205129
>
206130
{l.label}
207131
{l.external ? <ExternalArrow /> : <ArrowRight />}
@@ -212,26 +136,8 @@ export default function DocCard({
212136

213137
{/* CTA — explicit label, or auto arrow footer for href-only clickable cards */}
214138
{href && (ctaLabel || (!links?.length && !command)) && (
215-
<div
216-
style={{
217-
marginTop: "auto",
218-
paddingTop: 12,
219-
borderTop: "1px dashed var(--cs-border)",
220-
display: "flex",
221-
alignItems: "center",
222-
justifyContent: "space-between",
223-
}}
224-
>
225-
<span
226-
style={{
227-
fontSize: 12.5,
228-
fontWeight: 600,
229-
color,
230-
display: "inline-flex",
231-
alignItems: "center",
232-
gap: 5,
233-
}}
234-
>
139+
<div className="mt-auto pt-3 border-t border-dashed border-cs-border flex items-center justify-between">
140+
<span className="text-[12.5px] font-semibold inline-flex items-center gap-[5px]" style={{ color }}>
235141
{ctaLabel ?? title} <ArrowRight />
236142
</span>
237143
</div>
@@ -241,7 +147,7 @@ export default function DocCard({
241147

242148
if (href && !ctaLabel && !links) {
243149
return (
244-
<a href={href} style={{ textDecoration: "none", display: "block" }}>
150+
<a href={href} className="no-underline block">
245151
{card}
246152
</a>
247153
);

crowdsec-docs/src/components/docs/DocCardGrid/index.tsx

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,5 @@ type Props = {
66
};
77

88
export default function DocCardGrid({ children, cols = 3 }: Props) {
9-
return (
10-
<div
11-
style={{
12-
display: "grid",
13-
gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
14-
gap: 14,
15-
margin: "16px 0 24px",
16-
}}
17-
>
18-
{children}
19-
</div>
20-
);
9+
return <div className={`grid gap-[14px] my-4 mb-6 ${cols === 2 ? "grid-cols-2" : "grid-cols-3"}`}>{children}</div>;
2110
}

crowdsec-docs/src/components/docs/GuidedSetupCard/index.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,12 @@ export default function GuidedSetupCard({ title, desc, primaryCta, secondaryCta
1515
<div className="relative py-6 px-7 rounded-[14px] bg-cs-surface border border-cs-border overflow-hidden flex items-center gap-6 my-7 flex-wrap">
1616
{/* Corner glow */}
1717
<div
18-
className="absolute -top-[60px] -left-[60px] w-[220px] h-[220px] rounded-full blur-[80px] opacity-10 pointer-events-none"
19-
style={{ background: "var(--cs-violet)" }}
18+
className="absolute -top-[60px] -left-[60px] w-[220px] h-[220px] rounded-full blur-[80px] opacity-10 pointer-events-none bg-cs-violet"
2019
aria-hidden="true"
2120
/>
2221

2322
{/* Icon */}
24-
<div
25-
className="w-14 h-14 rounded-[14px] flex items-center justify-center shrink-0"
26-
style={{
27-
background: "color-mix(in srgb, var(--cs-violet) 14%, transparent)",
28-
border: "1px solid color-mix(in srgb, var(--cs-violet) 30%, transparent)",
29-
color: "var(--cs-violet)",
30-
}}
31-
>
23+
<div className="w-14 h-14 rounded-[14px] flex items-center justify-center shrink-0 bg-[color-mix(in_srgb,var(--cs-violet)_14%,transparent)] border border-[color-mix(in_srgb,var(--cs-violet)_30%,transparent)] text-cs-violet">
3224
<CIcon icon={cilCompass} style={{ width: 26, height: 26 }} />
3325
</div>
3426

@@ -42,8 +34,7 @@ export default function GuidedSetupCard({ title, desc, primaryCta, secondaryCta
4234
<div className="flex gap-[10px] flex-wrap shrink-0">
4335
<a
4436
href={primaryCta.href}
45-
className="py-[10px] px-4 rounded-[9px] bg-cs-violet text-cs-btn-text font-semibold text-[13.5px] no-underline inline-flex items-center gap-2"
46-
style={{ boxShadow: "0 8px 24px color-mix(in srgb, var(--cs-violet) 30%, transparent)" }}
37+
className="py-[10px] px-4 rounded-[9px] bg-cs-violet text-cs-btn-text font-semibold text-[13.5px] no-underline inline-flex items-center gap-2 shadow-[0_8px_24px_color-mix(in_srgb,var(--cs-violet)_30%,transparent)]"
4738
>
4839
<CIcon icon={cilCompass} style={{ width: 14, height: 14 }} />
4940
{primaryCta.label}

crowdsec-docs/src/components/docs/QuickStrip/index.tsx

Lines changed: 15 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function ExternalArrow() {
3030
strokeLinecap="round"
3131
strokeLinejoin="round"
3232
aria-hidden="true"
33-
style={{ opacity: 0.5, flexShrink: 0 }}
33+
className="opacity-50 shrink-0"
3434
>
3535
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
3636
<polyline points="15 3 21 3 21 9" />
@@ -42,66 +42,29 @@ function ExternalArrow() {
4242
export default function QuickStrip({ label, title, subtitle, links }: QuickStripProps) {
4343
return (
4444
<div
45-
style={{
46-
display: "flex",
47-
alignItems: "center",
48-
gap: 18,
49-
flexWrap: "wrap",
50-
padding: "14px 18px",
51-
background: "linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0))",
52-
border: "1px solid var(--cs-border)",
53-
borderRadius: 12,
54-
margin: "16px 0",
55-
}}
45+
className="flex items-center gap-[18px] flex-wrap py-[14px] px-[18px] border border-cs-border rounded-xl my-4"
46+
style={{ background: "linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0))" }}
5647
>
5748
{/* Left: simple label OR rich title+subtitle */}
5849
{(label || title) && (
59-
<div style={{ flexShrink: 0 }}>
50+
<div className="shrink-0">
6051
{label && (
61-
<div
62-
style={{
63-
fontFamily: "var(--cs-font-mono)",
64-
fontSize: 11,
65-
letterSpacing: "0.18em",
66-
textTransform: "uppercase",
67-
color: "var(--cs-ink-mute)",
68-
fontWeight: 500,
69-
}}
70-
>
71-
{label}
72-
</div>
52+
<div className="font-cs-mono text-[11px] tracking-[0.18em] uppercase text-cs-ink-mute font-medium">{label}</div>
7353
)}
74-
{title && (
75-
<div style={{ fontWeight: 700, fontSize: 13.5, color: "var(--cs-ink)", marginBottom: subtitle ? 2 : 0 }}>
76-
{title}
77-
</div>
78-
)}
79-
{subtitle && <div style={{ fontSize: 12, color: "var(--cs-ink-dim)" }}>{subtitle}</div>}
54+
{title && <div className={`font-bold text-[13.5px] text-cs-ink${subtitle ? " mb-0.5" : ""}`}>{title}</div>}
55+
{subtitle && <div className="text-xs text-cs-ink-dim">{subtitle}</div>}
8056
</div>
8157
)}
8258

83-
<div style={{ flex: 1 }} />
59+
<div className="flex-1" />
8460

8561
{/* Right: pill links */}
86-
<div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
62+
<div className="flex flex-wrap gap-2">
8763
{links.map((l) => (
8864
<a
8965
key={l.href}
9066
href={l.href}
91-
style={{
92-
display: "inline-flex",
93-
alignItems: "center",
94-
gap: 7,
95-
padding: "6px 12px",
96-
borderRadius: 8,
97-
border: "1px solid var(--cs-border-hi)",
98-
background: "var(--cs-surface)",
99-
color: "var(--cs-ink)",
100-
fontSize: 13,
101-
fontWeight: 500,
102-
textDecoration: "none",
103-
transition: "border-color 0.12s, color 0.12s, background 0.12s",
104-
}}
67+
className="inline-flex items-center gap-[7px] py-[6px] px-3 rounded-lg border border-cs-border-hi bg-cs-surface text-cs-ink text-[13px] font-medium no-underline transition-[border-color,color,background] duration-[120ms]"
10568
onMouseEnter={(e) => {
10669
const el = e.currentTarget as HTMLAnchorElement;
10770
el.style.borderColor = l.color ?? "var(--cs-border-hi)";
@@ -115,7 +78,11 @@ export default function QuickStrip({ label, title, subtitle, links }: QuickStrip
11578
el.style.background = "";
11679
}}
11780
>
118-
{l.icon && <span style={{ color: l.color || "var(--cs-orange)", display: "flex", flexShrink: 0 }}>{l.icon}</span>}
81+
{l.icon && (
82+
<span className="flex shrink-0" style={{ color: l.color || "var(--cs-orange)" }}>
83+
{l.icon}
84+
</span>
85+
)}
11986
{l.label}
12087
{l.external && <ExternalArrow />}
12188
</a>

crowdsec-docs/src/components/docs/RunningStrip/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ export default function RunningStrip({ label = "Already running CrowdSec?", link
3636
(e.currentTarget as HTMLAnchorElement).style.background = "";
3737
}}
3838
>
39-
{l.icon && <span style={{ color: l.color || "var(--cs-orange)", display: "flex", flexShrink: 0 }}>{l.icon}</span>}
39+
{l.icon && (
40+
<span className="flex shrink-0" style={{ color: l.color || "var(--cs-orange)" }}>
41+
{l.icon}
42+
</span>
43+
)}
4044
{l.label}
4145
{l.external && (
4246
<CIcon

0 commit comments

Comments
 (0)