Improve framework list style

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-02-19 08:49:41 +01:00
parent f347e60085
commit 52db2d5f63

View File

@@ -5,12 +5,11 @@ import {
usePreloadedQuery,
useQueryLoader,
} from "react-relay";
import { Globe2, CheckCircle } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Link } from "react-router";
import type { FrameworkListPageQuery as FrameworkListPageQueryType } from "./__generated__/FrameworkListPageQuery.graphql";
import { Helmet } from "react-helmet-async";
const FrameworkListPageQuery = graphql`
query FrameworkListPageQuery {
node(id: "AZSfP_xAcAC5IAAAAAAltA") {
@@ -40,6 +39,49 @@ const FrameworkListPageQuery = graphql`
}
`;
function FrameworkCard({
title,
description,
icon,
status,
progress,
}: {
title: string;
description: string;
icon: React.ReactNode;
status?: string;
progress?: string;
}) {
return (
<Card className="relative overflow-hidden border bg-card p-6">
<div className="flex flex-col gap-4">
<div className="size-16">
{icon}
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">
<h3 className="font-semibold">{title}</h3>
{status && (
<span className="rounded-full bg-green-100 px-2 py-0.5 text-xs text-green-700">
{status}
</span>
)}
</div>
<p className="text-sm text-muted-foreground">{description}</p>
</div>
{progress && (
<div className="flex items-center gap-2 text-sm">
<span className="size-2 rounded-full bg-yellow-400" />
{progress}
</div>
)}
</div>
</Card>
);
}
function FrameworkListPageContent({
queryRef,
}: {
@@ -50,50 +92,40 @@ function FrameworkListPageContent({
data.node.frameworks?.edges.map((edge) => edge?.node) ?? [];
return (
<div className="min-h-screen bg-background p-6">
<div className="mb-8">
<h1 className="text-2xl font-semibold mb-2">Framework</h1>
<p className="text-muted-foreground">
Compliance frameworks like SOC 2 and ISO 27001 provide guidelines to
secure sensitive data, manage risks, and build trust. SOC 2 focuses on
customer data protection via five Trust Principles, while ISO 27001
establishes a comprehensive Information Security Management System for
global standards.
</p>
<div className="container space-y-6 p-4 md:p-6 lg:p-8">
<div className="space-y-2">
<h1 className="text-3xl font-bold tracking-tight">Framework</h1>
</div>
<div className="grid gap-6 md:grid-cols-2">
{frameworks.map((framework) => (
<Link key={framework?.id} to={`/frameworks/${framework.id}`}>
<Card className="bg-card/50 hover:bg-card/70 transition-colors">
<CardContent className="p-6">
<div className="relative mb-6">
<Badge className="absolute right-0 top-0 bg-green-500/10 text-green-500 hover:bg-green-500/20">
Active
</Badge>
<div className="bg-green-500/10 w-24 h-24 rounded-full flex items-center justify-center mb-4">
<Globe2 className="w-12 h-12 text-green-500" />
<div className="absolute text-xs font-medium text-green-500">
{framework?.name}
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{frameworks.map((framework) => {
const validatedControls = framework.controls.edges.filter(
edge => edge?.node?.state === "IMPLEMENTED"
).length;
const totalControls = framework.controls.edges.length;
return (
<Link key={framework.id} to={`/frameworks/${framework.id}`}>
<FrameworkCard
title={framework.name}
description={framework.description}
icon={
<div className="flex size-full items-center justify-center rounded-full bg-blue-100">
<span className="text-lg font-semibold text-blue-900">
{framework.name.split(' ')[0]}
</span>
</div>
<h2 className="text-xl font-semibold mb-2">
{framework?.name}
</h2>
<p className="text-sm text-muted-foreground">
{framework?.description}
</p>
</div>
<div className="flex items-center text-muted-foreground text-sm">
<div className="flex items-center">
<CheckCircle className="w-4 h-4 mr-2" />
{framework?.controls?.edges.length} Controls
</div>
</div>
</CardContent>
</Card>
</Link>
))}
}
status={validatedControls === totalControls ? "Compliant" : undefined}
progress={
validatedControls === totalControls
? "All controls validated"
: `${validatedControls}/${totalControls} Controls validated`
}
/>
</Link>
);
})}
</div>
</div>
);