Build compliance portal home page sections
Add the frameworks (Compliance), security commitments, trusted-by, and recent updates sections to the home page, plus a site-wide "Powered by Probo" footer. Frameworks, references, and updates are relay-driven; the security commitments section uses placeholder POJO data until a backend exists. Keep generic primitives in the v2 kit (ProboLogo, a faint Text tone, and a soft Card variant with padding="none") and place the product-specific cards under the app's components folder, composing the base Card. Resolve each framework's themed logo in the graph via Framework.themedLogoUrl, mirroring the trust center logo resolver. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -24,10 +24,10 @@ export type CardProps = ComponentProps<"div"> & VariantProps<typeof card>;
|
||||
// clickable card set `interactive` and wrap the content in an anchor/link. Use
|
||||
// CardInset for content that should bleed to the card's edges.
|
||||
export function Card(props: CardProps) {
|
||||
const { size = 1, variant, interactive, className, children, ...rest } = props;
|
||||
const { size = 1, padding = size, variant, interactive, className, children, ...rest } = props;
|
||||
|
||||
return (
|
||||
<div className={card({ size, variant, interactive, className })} {...rest}>
|
||||
<div className={card({ size, padding, variant, interactive, className })} {...rest}>
|
||||
<CardProvider value={size}>{children}</CardProvider>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -19,17 +19,29 @@ import { tv } from "tailwind-variants/lite";
|
||||
export const card = tv({
|
||||
base: "block overflow-hidden",
|
||||
variants: {
|
||||
// Padding scales with size; radius scales with it too (per the Figma).
|
||||
// Radius scales with size (per the Figma).
|
||||
size: {
|
||||
1: "rounded-4 p-3",
|
||||
2: "rounded-4 p-4",
|
||||
3: "rounded-5 p-5",
|
||||
4: "rounded-5 p-6",
|
||||
5: "rounded-6 p-8",
|
||||
1: "rounded-4",
|
||||
2: "rounded-4",
|
||||
3: "rounded-5",
|
||||
4: "rounded-5",
|
||||
5: "rounded-6",
|
||||
},
|
||||
// Padding defaults to match `size` (set in Card.tsx); pass `padding="none"`
|
||||
// for cards whose regions own their own padding (e.g. full-bleed media).
|
||||
padding: {
|
||||
1: "p-3",
|
||||
2: "p-4",
|
||||
3: "p-5",
|
||||
4: "p-6",
|
||||
5: "p-8",
|
||||
none: "p-0",
|
||||
},
|
||||
variant: {
|
||||
surface: "border border-sand-6 bg-sand-2",
|
||||
classic: "border border-sand-6 bg-sand-2 shadow-2",
|
||||
// Soft surface: translucent neutral border on the app background.
|
||||
soft: "border border-sand-a3 bg-sand-1",
|
||||
ghost: "",
|
||||
},
|
||||
// Hover/active affordance for clickable cards. This tunes look only; wrap
|
||||
@@ -40,7 +52,7 @@ export const card = tv({
|
||||
},
|
||||
},
|
||||
compoundVariants: [
|
||||
{ variant: ["surface", "classic"], interactive: true, class: "hover:bg-sand-3 active:bg-sand-4" },
|
||||
{ variant: ["surface", "classic", "soft"], interactive: true, class: "hover:bg-sand-3 active:bg-sand-4" },
|
||||
{ variant: "ghost", interactive: true, class: "hover:bg-sand-3 active:bg-sand-4" },
|
||||
],
|
||||
defaultVariants: {
|
||||
|
||||
37
packages/ui/src/v2/ProboLogo/ProboLogo.stories.tsx
Normal file
37
packages/ui/src/v2/ProboLogo/ProboLogo.stories.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import { ProboLogo } from "./ProboLogo";
|
||||
|
||||
export default {
|
||||
title: "v2/ProboLogo",
|
||||
component: ProboLogo,
|
||||
render: () => <ProboLogo className="h-6 w-auto text-sand-12" />,
|
||||
} satisfies Meta<typeof ProboLogo>;
|
||||
|
||||
type Story = StoryObj<typeof ProboLogo>;
|
||||
|
||||
export const Playground: Story = {};
|
||||
|
||||
export const Sizes: Story = {
|
||||
render: () => (
|
||||
<div className="flex items-center gap-6 text-sand-11">
|
||||
<ProboLogo className="h-4 w-auto" />
|
||||
<ProboLogo className="h-6 w-auto" />
|
||||
<ProboLogo className="h-10 w-auto" />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
53
packages/ui/src/v2/ProboLogo/ProboLogo.tsx
Normal file
53
packages/ui/src/v2/ProboLogo/ProboLogo.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import type { ComponentProps } from "react";
|
||||
import { useId } from "react";
|
||||
|
||||
export type ProboLogoProps = ComponentProps<"svg">;
|
||||
|
||||
// The Probo brand logo (picto + wordmark). Rendered in `currentColor`; the
|
||||
// picto's mark is a transparent cutout (via mask) so the underlying surface
|
||||
// shows through on any background. Size it with a height class (e.g. `h-6`).
|
||||
export function ProboLogo(props: ProboLogoProps) {
|
||||
const maskId = useId();
|
||||
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 90 24"
|
||||
role="img"
|
||||
{...props}
|
||||
>
|
||||
<mask id={maskId} maskUnits="userSpaceOnUse">
|
||||
<rect width="24" height="24" x=".85" fill="#fff" rx="5.14" />
|
||||
<path
|
||||
stroke="#000"
|
||||
strokeWidth="3.53"
|
||||
d="M20.57 6.17c2.96 4.47-6.43 13.97-20.32 5.66"
|
||||
/>
|
||||
<path
|
||||
fill="#000"
|
||||
d="M19.07 7.1a1.77 1.77 0 0 0 3-1.86l-1.5.93-1.5.94ZM8.82 25.18l1.71-.41c-2.3-9.67.01-14.66 2.54-16.83A6.25 6.25 0 0 1 17 6.33c1.22-.01 1.87.44 2.08.78l1.5-.94 1.5-.93c-1.1-1.74-3.16-2.46-5.13-2.44-2.03.03-4.26.81-6.17 2.45-3.9 3.35-6.16 9.92-3.67 20.33l1.72-.41Z"
|
||||
/>
|
||||
</mask>
|
||||
<rect width="24" height="24" x=".85" fill="currentColor" rx="5.14" mask={`url(#${maskId})`} />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M66.87 0v7.32a4.84 4.84 0 0 1 1.48-.74 5.63 5.63 0 0 1 1.76-.28c1.63 0 3 .55 4.1 1.68a5.5 5.5 0 0 1 1.67 4.06c0 1.6-.56 2.93-1.69 4.06a5.49 5.49 0 0 1-4.08 1.69 5.8 5.8 0 0 1-4.06-1.56 5.48 5.48 0 0 1-1.71-4.27V0h2.53Zm3.24 8.72a3.2 3.2 0 0 0-3.24 3.32 3.18 3.18 0 0 0 3.24 3.32 3.2 3.2 0 0 0 3.24-3.32c0-1.9-1.43-3.32-3.24-3.32ZM52.75 7.98a5.53 5.53 0 0 1 4.08-1.68c1.61 0 2.93.55 4.06 1.68a5.51 5.51 0 0 1 1.69 4.06c0 1.58-.55 2.95-1.69 4.09a5.59 5.59 0 0 1-4.06 1.66 5.64 5.64 0 0 1-4.08-1.66 5.53 5.53 0 0 1-1.69-4.09c0-1.6.56-2.92 1.7-4.06Zm.84 4.06c0 .98.32 1.77.93 2.4.63.6 1.4.92 2.31.92.92 0 1.7-.31 2.3-.92.63-.64.94-1.42.94-2.4 0-.97-.31-1.76-.94-2.37a3.03 3.03 0 0 0-2.3-.95 3.22 3.22 0 0 0-3.24 3.32ZM79.32 7.98A5.53 5.53 0 0 1 83.4 6.3c1.6 0 2.93.55 4.06 1.68a5.51 5.51 0 0 1 1.69 4.06c0 1.58-.56 2.95-1.7 4.09a5.59 5.59 0 0 1-4.05 1.66 5.64 5.64 0 0 1-4.08-1.66 5.53 5.53 0 0 1-1.69-4.09c0-1.6.55-2.92 1.69-4.06Zm.84 4.06c0 .98.32 1.77.92 2.4.64.6 1.4.92 2.32.92.92 0 1.69-.31 2.3-.92.63-.64.94-1.42.94-2.4 0-.97-.31-1.76-.95-2.37a3.03 3.03 0 0 0-2.29-.95 3.22 3.22 0 0 0-3.24 3.32ZM34.24 16.76V24h-2.53V12.12c0-1.82.58-3.24 1.71-4.27a5.87 5.87 0 0 1 4.06-1.55c1.56 0 2.98.55 4.08 1.68a5.51 5.51 0 0 1 1.7 4.06 5.66 5.66 0 0 1-5.77 5.75 5.43 5.43 0 0 1-2.88-.77l-.36-.26Zm3.24-8.04a3.2 3.2 0 0 0-3.24 3.32c0 1.9 1.42 3.32 3.24 3.32a3.2 3.2 0 0 0 3.24-3.32 3.2 3.2 0 0 0-3.24-3.32ZM47.4 17.65h-2.5v-6.7c0-3.23 1.82-4.52 4.27-4.52h.6v2.42h-.47c-1.26 0-1.9.71-1.9 2.1v6.7Z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -46,8 +46,10 @@ const typographyVariants = {
|
||||
},
|
||||
// Hue only; the resolved text step comes from the color × highContrast
|
||||
// compound variants below (step 11 low-contrast, step 12 high-contrast).
|
||||
// `faint` is a de-emphasized neutral (sand alpha 8) for fine-print metadata.
|
||||
color: {
|
||||
neutral: "",
|
||||
faint: "",
|
||||
gold: "",
|
||||
red: "",
|
||||
green: "",
|
||||
@@ -63,6 +65,9 @@ const typographyVariants = {
|
||||
const colorCompoundVariants = [
|
||||
{ color: "neutral", highContrast: false, class: "text-sand-11" },
|
||||
{ color: "neutral", highContrast: true, class: "text-sand-12" },
|
||||
// Faint metadata; a single de-emphasized step regardless of highContrast.
|
||||
{ color: "faint", highContrast: false, class: "text-sand-a8" },
|
||||
{ color: "faint", highContrast: true, class: "text-sand-a8" },
|
||||
{ color: "gold", highContrast: false, class: "text-gold-11" },
|
||||
{ color: "gold", highContrast: true, class: "text-gold-12" },
|
||||
{ color: "red", highContrast: false, class: "text-red-11" },
|
||||
|
||||
Reference in New Issue
Block a user