mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 04:20:39 +00:00
INK, the band that drops to true black on dark, stayed black on a light page while its headings and paragraphs took the light theme's dark ink: 1.06:1 on /payments, /analytics and /kai/guide, and /commerce's use cases sat on --black the same way. INK is light-dark() now, the quiet card surface on light and pure black on dark as before, and /commerce and /kai/guide name it instead of a black of their own. Sixteen page roots inked their whole tree --white, so anything that inherits (card headings, bullets) was white on light; they take --foreground, the ink the rest of the site is set in. Measured with a contrast walk over fourteen of those pages in light: 57 runs under 3:1 on /analytics and 13 on /payments before, 7 left across all of them (chart labels and two install chips), and none new on dark.
112 lines
4.0 KiB
TypeScript
112 lines
4.0 KiB
TypeScript
|
|
import React from "react";
|
|
import { Box, XStack, YStack } from '@/components/ui'
|
|
import { Band, Head, INK, Words } from '@/components/marketing/band'
|
|
|
|
// The `color` prop is gone. It was interpolated into class names
|
|
// (`text-${color}-400`, `from-${color}-500/20`), and Tailwind only generates a
|
|
// utility it can SEE spelled out in the source — an interpolated name is never
|
|
// spelled out, so those three classes emitted no rule and the amber accent has
|
|
// never rendered. The brand is monochrome anyway; these are now the site's own
|
|
// foreground tokens, written literally.
|
|
//
|
|
// NO TAILWIND. The section frame is `Band` + `Head`; the cards and the wash
|
|
// are gui props. "Learn more" is `More`, @hanzo/ui's quiet link — the
|
|
// hover it used to carry asked for the ink it already rested at, so nothing is
|
|
// lost and the role's own lift replaces it.
|
|
interface UseCaseCardProps {
|
|
title: string;
|
|
description: string;
|
|
image?: string;
|
|
index: number;
|
|
}
|
|
|
|
/** The frame each card is cut from. */
|
|
const EDGE = {
|
|
position: 'relative',
|
|
overflow: 'hidden',
|
|
height: '100%',
|
|
borderWidth: 1,
|
|
borderColor: 'var(--neutral-800)',
|
|
borderRadius: 'var(--radius-xl)',
|
|
} as const
|
|
|
|
/** The wash over the numeral. */
|
|
const WASH = 'linear-gradient(to bottom right in oklab, color-mix(in oklab, var(--pure-white) 10%, transparent), transparent)'
|
|
|
|
const UseCaseCard = ({ title, description, image, index }: UseCaseCardProps) => {
|
|
return (
|
|
<YStack {...EDGE} $md={{ flexDirection: index % 2 === 0 ? 'row-reverse' : 'row' }}>
|
|
<YStack width="100%" p="$6" justify="center" $md={{ width: '50%' }}>
|
|
<Words render="h3" mb={16} fontSize="$7" lineHeight="1.3333" weight="700" color="var(--foreground)">{title}</Words>
|
|
<Words render="p" mb={16} color="var(--muted-foreground)">{description}</Words>
|
|
</YStack>
|
|
<Box
|
|
position="relative"
|
|
overflow="hidden"
|
|
width="100%"
|
|
height={192}
|
|
bg="$panel"
|
|
$md={{ width: '50%', height: 'auto' }}
|
|
>
|
|
<Box position="absolute" t={0} r={0} b={0} l={0} opacity={0.5} backgroundImage={WASH} />
|
|
<XStack
|
|
position="absolute"
|
|
t={0}
|
|
r={0}
|
|
b={0}
|
|
l={0}
|
|
items="center"
|
|
justify="center"
|
|
>
|
|
{/* The display ramp's top rung, which gui's size table does not carry. */}
|
|
<Words fontSize="var(--text-9xl)" lineHeight="1" weight="700" opacity={0.1} color="var(--foreground)">{index + 1}</Words>
|
|
</XStack>
|
|
</Box>
|
|
</YStack>
|
|
);
|
|
};
|
|
|
|
const UseCases = () => {
|
|
const useCases = [
|
|
{
|
|
title: "A storefront you designed",
|
|
description: "You have a front end you like and do not want a theme system telling you how it works. This gives you the catalogue, the cart and the checkout as calls, and stays out of the rendering."
|
|
},
|
|
{
|
|
title: "One catalogue, several stores",
|
|
description: "A brand with regional shops, or an agency running stores for clients. Stores are scoped by organisation and can price the same product differently."
|
|
},
|
|
{
|
|
title: "Selling a subscription and a thing",
|
|
description: "Hardware with a plan, or a course with a membership. Orders and subscriptions are in one service, so the customer has one history rather than two accounts."
|
|
},
|
|
{
|
|
title: "Taking payment inside your own product",
|
|
description: "You are not building a shop, you are charging for what you already made. Use the checkout, the invoices and the meters, and ignore the rest."
|
|
}
|
|
];
|
|
|
|
return (
|
|
<Band rule={false} pad="$10" ground={INK}>
|
|
<Head
|
|
title="When to reach for it"
|
|
lede="Four shapes that fit. If none of them is yours, a hosted shop is probably the easier answer."
|
|
/>
|
|
|
|
<YStack gap="$6">
|
|
{useCases.map((useCase, index) => (
|
|
<UseCaseCard
|
|
key={index}
|
|
title={useCase.title}
|
|
description={useCase.description}
|
|
index={index}
|
|
/>
|
|
))}
|
|
</YStack>
|
|
</Band>
|
|
);
|
|
};
|
|
|
|
export default UseCases;
|