Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
41aecb7
feat(ui): apply CrowdSec Docs visual refresh
ziracmo May 7, 2026
cfb3914
fix(ui): apply visual feedback corrections
ziracmo May 7, 2026
e87241c
feat(ui): refactor home page components to use them across the global…
ziracmo May 7, 2026
186f390
feat(ui): restyle inline code, admonitions, code blocks, tables, tabs
ziracmo May 7, 2026
48b7ee7
feat(ui): visual refresh for product pages, cards, and doc navigation
ziracmo May 7, 2026
9485d87
fix(lint): resolve all Biome errors across new UI components
ziracmo May 7, 2026
fbb2309
feat(ui): replace homemade SVGs with CoreUI icons and polish components
ziracmo May 7, 2026
02789bf
fix(lint): clean up biome errors from icon migration
ziracmo May 7, 2026
5743c5d
refactor(ui): deduplicate shared utilities and remove dead code
ziracmo May 7, 2026
7e2b1cd
refactor(ui): replace CSS module files with Tailwind classnames
ziracmo May 7, 2026
6797b9b
refactor(ui): replace inline styles with Tailwind classnames
ziracmo May 7, 2026
340bf68
refactor(ui): simplify components per code review
ziracmo May 7, 2026
7713bc4
feat(ui): restyle cookie consent banner with design tokens
ziracmo May 7, 2026
aa34179
feat(blocklists): redesign getting started page with path cards and c…
ziracmo May 7, 2026
8944c46
fix(blocklists): add explicit DocCard/DocCardGrid imports for MDX v3
ziracmo May 7, 2026
8fe9ae2
feat(blocklists): redesign getting started page with path cards and c…
ziracmo May 7, 2026
dfe887e
refactor: JDE feedbacks on labels and content
ziracmo May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 47 additions & 12 deletions crowdsec-docs/docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import sidebarsUnversioned from "./sidebarsUnversioned";

const extractPreprocessor = require("./plugins/extract-preprocessor");

const generateCurrentAndNextRedirects = (s) => [
const generateCurrentAndNextRedirects = (s: string): { from: string; to: string }[] => [
{
from: `/docs/${s}`,
to: `/u/${s}`,
Expand All @@ -19,7 +19,9 @@ const generateCurrentAndNextRedirects = (s) => [
},
];

function handleSidebarItems(items) {
type SidebarItem = string | { id?: string; link?: { id?: string }; items?: SidebarItem[] };

function handleSidebarItems(items: SidebarItem[]): { from: string; to: string }[] {
const arr = [];
for (const item of items) {
if (typeof item === "string") {
Expand All @@ -32,7 +34,7 @@ function handleSidebarItems(items) {
}

// This function generates redirects for all items in the unversioned sidebars, so that if we move a doc from versioned to unversioned, we don't break existing links. It handles both string items (doc ids) and nested objects (categories with their own items).
const backportRedirect = (s) => {
const backportRedirect = (s: SidebarItem): { from: string; to: string }[] => {
const arr = [];
if (typeof s === "string") {
arr.push(...generateCurrentAndNextRedirects(s));
Expand Down Expand Up @@ -153,7 +155,7 @@ const FOOTER_LINKS = [
},
{ label: "Discourse", href: "https://discourse.crowdsec.net/" },
{ label: "Discord", href: "https://discord.gg/crowdsec" },
{ label: "Twitter", href: "https://twitter.com/crowd_security" },
{ label: "X", href: "https://x.com/crowd_security" },
{ label: "LinkedIn", href: "https://www.linkedin.com/company/crowdsec/" },
{ label: "YouTube", href: "https://www.youtube.com/@crowdsec" },
],
Expand All @@ -169,7 +171,10 @@ const FOOTER_LINKS = [
href: "https://crowdsec.net/blog/category/tutorial/",
},
{ label: "Academy", href: "https://academy.crowdsec.net/" },
{ label: "Custom GPT", href: "https://chatgpt.com/g/g-682c3a61a78081918417571116c2b563-crowdsec-documentation" },
{
label: "Custom GPT",
href: "https://chatgpt.com/g/g-682c3a61a78081918417571116c2b563-crowdsec-documentation",
},
],
},
];
Expand Down Expand Up @@ -202,15 +207,33 @@ const redirects = [
},
// CTI Web UI pages moved to console/ip_reputation
{ from: "/u/cti_api/getting_started", to: "/u/console/ip_reputation/intro" },
{ from: "/u/cti_api/api_getting_started", to: "/u/console/ip_reputation/api_keys" },
{
from: "/u/cti_api/api_getting_started",
to: "/u/console/ip_reputation/api_keys",
},
{ from: "/u/cti_api/ip_report", to: "/u/console/ip_reputation/ip_report" },
{ from: "/u/cti_api/search_queries", to: "/u/console/ip_reputation/search_ui" },
{ from: "/u/cti_api/advanced_search", to: "/u/console/ip_reputation/search_ui_advanced" },
{ from: "/u/cti_api/cve_explorer", to: "/u/console/ip_reputation/intro#live-exploit-tracker" },
{
from: "/u/cti_api/search_queries",
to: "/u/console/ip_reputation/search_ui",
},
{
from: "/u/cti_api/advanced_search",
to: "/u/console/ip_reputation/search_ui_advanced",
},
{
from: "/u/cti_api/cve_explorer",
to: "/u/console/ip_reputation/intro#live-exploit-tracker",
},
// other CTI pages redirect / fixes
{ from: "/next/cti_api/intro", to: "/u/console/ip_reputation/api_keys" },
{ from: "/next/cti_api/getting_started", to: "/u/console/ip_reputation/api_keys" },
{ from: "/u/console/ip_reputation/api_keys_premium", to: "/u/console/ip_reputation/api_keys" },
{
from: "/next/cti_api/getting_started",
to: "/u/console/ip_reputation/api_keys",
},
{
from: "/u/console/ip_reputation/api_keys_premium",
to: "/u/console/ip_reputation/api_keys",
},
];

function redirectsGlobalDataPlugin() {
Expand Down Expand Up @@ -251,14 +274,18 @@ const config: Config = {
{
href: "https://fonts.googleapis.com/icon?family=Material+Icons",
},
{
href: "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap",
rel: "stylesheet",
},
],
themes: ["@docusaurus/theme-mermaid"],
themeConfig: {
image: "img/crowdsec_og_image.png",
colorMode: {
defaultMode: "dark",
disableSwitch: false,
respectPrefersColorScheme: true,
respectPrefersColorScheme: false,
},
announcementBar: {
id: "banner_docs",
Expand Down Expand Up @@ -318,6 +345,10 @@ const config: Config = {
path: "/next",
},
},
admonitions: {
keywords: ["premium"],
extendDefaults: true,
},
},
blog: {
showReadingTime: true,
Expand All @@ -338,6 +369,10 @@ const config: Config = {
path: "unversioned",
routeBasePath: "u",
sidebarPath: "./sidebarsUnversioned.ts",
admonitions: {
keywords: ["premium"],
extendDefaults: true,
},
},
],

Expand Down
6 changes: 4 additions & 2 deletions crowdsec-docs/plugins/gtag/gtag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ const clientModule = {
setTimeout(() => {
// Always refer to the variable on window in case it gets overridden
// elsewhere.
window.gtag("set", "page_path", location.pathname + location.search + location.hash)
window.gtag("event", "page_view")
if (typeof window.gtag === "function") {
window.gtag("set", "page_path", location.pathname + location.search + location.hash)
window.gtag("event", "page_view")
}
})
}
},
Expand Down
90 changes: 52 additions & 38 deletions crowdsec-docs/plugins/gtag/theme/cookieconsent.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,56 @@
import clsx from 'clsx';
import styles from './styles.module.css';
import {createStorageSlot} from '@docusaurus/theme-common';
import React, {useState} from 'react';
import { createStorageSlot } from "@docusaurus/theme-common";
import React, { useState } from "react";

const storage = createStorageSlot('docusaurus.cookieConsent');
const storage = createStorageSlot("docusaurus.cookieConsent");

export default function CookieConsent() {
const [dismissed, setDismissed] = useState(false);
if (dismissed) {
return null;
}
return (
<div className={styles.banner}>
<p className={styles.text}>
This website uses cookies to help us improve. Click &quot;accept&quot;
to allow us to continue using cookies.
</p>
<div className={styles.buttons}>
<button
type="button"
className={clsx('clean-btn', styles.button)}
onClick={() => {
storage.set('true');
window.dispatchEvent(new CustomEvent('cookieConsentAccepted'));
setDismissed(true);
}}>
Accept
</button>
<button
type="button"
className={clsx('clean-btn', styles.button)}
onClick={() => {
storage.set('false');
setDismissed(true);
}}>
Decline
</button>
</div>
</div>
);
const [dismissed, setDismissed] = useState(false);
if (dismissed) return null;

return (
<div className="fixed bottom-6 left-6 w-80 rounded-[14px] bg-cs-surface border border-cs-border-hi z-[9999] flex flex-col gap-3.5 p-5 pb-4"
style={{ boxShadow: "0 16px 48px rgba(0,0,0,0.35), 0 0 0 1px rgba(148,163,184,0.06)" }}
>
{/* Eyebrow */}
<div className="font-cs-mono text-[10px] tracking-[0.18em] uppercase text-cs-orange font-semibold">
CrowdSec Docs
</div>

{/* Title + body */}
<div>
<div className="text-sm font-semibold text-cs-ink mb-1.5">
We use cookies
</div>
<p className="m-0 text-[13px] text-cs-ink-dim leading-[1.55]">
This site uses cookies to help us improve your experience. You can
accept or decline below.
</p>
</div>

{/* Actions */}
<div className="flex gap-2">
<button
type="button"
onClick={() => {
storage.set("true");
window.dispatchEvent(new CustomEvent("cookieConsentAccepted"));
setDismissed(true);
}}
className="flex-1 py-2 px-3 rounded-lg bg-cs-orange text-cs-btn-text font-sans text-[13px] font-semibold border-0 cursor-pointer"
>
Accept
</button>
<button
type="button"
onClick={() => {
storage.set("false");
setDismissed(true);
}}
className="flex-1 py-2 px-3 rounded-lg bg-cs-surface-2 text-cs-ink-dim font-sans text-[13px] font-semibold border border-cs-border-hi cursor-pointer"
>
Decline
</button>
</div>
</div>
);
}
39 changes: 1 addition & 38 deletions crowdsec-docs/plugins/gtag/theme/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,38 +1 @@
.banner {
background-color: var(--ifm-color-emphasis-200);
position: fixed;
bottom: 20px;
right: 20px;
width: 300px;
height: 200px;
border-radius: var(--ifm-global-radius);
box-shadow: 0 1.5px 6px 0 rgba(0, 0, 0, 0.15) inset;
z-index: 1000;
}

.text {
font-size: small;
padding: 30px;
}

.buttons {
position: absolute;
bottom: 20px;
display: flex;
justify-content: center;
width: 100%;
}

.button {
width: 100px;
background-color: #d0d0d0 !important;
margin: 10px;
/* TODO this is because the CSS is imported as a client module as well, and happens to be before Infima */
padding: 5px !important;
border-radius: var(--ifm-global-radius);
}

html[data-theme='dark'] .button {
background: #333333 !important;
}

/* Cookie consent styles moved to inline styles in cookieconsent.js */
5 changes: 0 additions & 5 deletions crowdsec-docs/sidebarsUnversioned.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,11 +451,6 @@ const sidebarsUnversionedConfig: SidebarConfig = {
tag: "otherSection",
},
},
{
type: "doc",
label: "IP Reputation Report",
id: "console/ip_reputation/ip_report",
},
],
},
{
Expand Down
51 changes: 51 additions & 0 deletions crowdsec-docs/src/components/docs/AccessCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react";

type Props = {
icon?: React.ReactNode;
title: string;
command?: string;
ctaLabel: string;
ctaHref: string;
};

function DefaultIcon() {
return (
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={1.6}
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<rect x="2" y="3" width="20" height="14" rx="2" />
<polyline points="8 21 12 17 16 21" />
</svg>
);
}

export default function AccessCard({ icon, title, command, ctaLabel, ctaHref }: Props) {
return (
<div className="flex flex-col gap-3 py-5 px-[22px] bg-cs-surface border border-cs-border-hi rounded-xl my-4">
<div className="flex items-center gap-3">
<div className="w-[38px] h-[38px] rounded-[9px] bg-cs-orange-soft border border-[color-mix(in_srgb,var(--cs-orange)_25%,transparent)] flex items-center justify-center text-cs-orange shrink-0 [&>svg]:w-[18px] [&>svg]:h-[18px]">
{icon ?? <DefaultIcon />}
</div>
<div className="text-[14.5px] font-semibold text-cs-ink">{title}</div>
</div>
{command && (
<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">
<span className="text-cs-ink-mute">$</span>
<span>{command}</span>
</div>
)}
<a
href={ctaHref}
className="cs-btn inline-flex items-center gap-1.5 py-2 px-[18px] rounded-[7px] bg-cs-orange text-cs-btn-text text-[13px] font-semibold no-underline self-start hover:no-underline hover:text-cs-btn-text"
>
{ctaLabel} →
</a>
</div>
);
}
Loading
Loading