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, usePreloadedQuery,
useQueryLoader, useQueryLoader,
} from "react-relay"; } from "react-relay";
import { Globe2, CheckCircle } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card"; import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Link } from "react-router"; import { Link } from "react-router";
import type { FrameworkListPageQuery as FrameworkListPageQueryType } from "./__generated__/FrameworkListPageQuery.graphql"; import type { FrameworkListPageQuery as FrameworkListPageQueryType } from "./__generated__/FrameworkListPageQuery.graphql";
import { Helmet } from "react-helmet-async"; import { Helmet } from "react-helmet-async";
const FrameworkListPageQuery = graphql` const FrameworkListPageQuery = graphql`
query FrameworkListPageQuery { query FrameworkListPageQuery {
node(id: "AZSfP_xAcAC5IAAAAAAltA") { 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({ function FrameworkListPageContent({
queryRef, queryRef,
}: { }: {
@@ -50,50 +92,40 @@ function FrameworkListPageContent({
data.node.frameworks?.edges.map((edge) => edge?.node) ?? []; data.node.frameworks?.edges.map((edge) => edge?.node) ?? [];
return ( return (
<div className="min-h-screen bg-background p-6"> <div className="container space-y-6 p-4 md:p-6 lg:p-8">
<div className="mb-8"> <div className="space-y-2">
<h1 className="text-2xl font-semibold mb-2">Framework</h1> <h1 className="text-3xl font-bold tracking-tight">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> </div>
<div className="grid gap-6 md:grid-cols-2"> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{frameworks.map((framework) => ( {frameworks.map((framework) => {
<Link key={framework?.id} to={`/frameworks/${framework.id}`}> const validatedControls = framework.controls.edges.filter(
<Card className="bg-card/50 hover:bg-card/70 transition-colors"> edge => edge?.node?.state === "IMPLEMENTED"
<CardContent className="p-6"> ).length;
<div className="relative mb-6"> const totalControls = framework.controls.edges.length;
<Badge className="absolute right-0 top-0 bg-green-500/10 text-green-500 hover:bg-green-500/20">
Active return (
</Badge> <Link key={framework.id} to={`/frameworks/${framework.id}`}>
<div className="bg-green-500/10 w-24 h-24 rounded-full flex items-center justify-center mb-4"> <FrameworkCard
<Globe2 className="w-12 h-12 text-green-500" /> title={framework.name}
<div className="absolute text-xs font-medium text-green-500"> description={framework.description}
{framework?.name} icon={
</div> <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> </div>
<h2 className="text-xl font-semibold mb-2"> }
{framework?.name} status={validatedControls === totalControls ? "Compliant" : undefined}
</h2> progress={
<p className="text-sm text-muted-foreground"> validatedControls === totalControls
{framework?.description} ? "All controls validated"
</p> : `${validatedControls}/${totalControls} Controls validated`
</div> }
<div className="flex items-center text-muted-foreground text-sm"> />
<div className="flex items-center"> </Link>
<CheckCircle className="w-4 h-4 mr-2" /> );
{framework?.controls?.edges.length} Controls })}
</div>
</div>
</CardContent>
</Card>
</Link>
))}
</div> </div>
</div> </div>
); );