mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-28 07:32:52 +00:00
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
'use client'
|
|
|
|
import React, { type ComponentProps } from "react";
|
|
import { MARK_HEIGHT, type PartnerLogo } from "@/lib/constants/partner-logos";
|
|
import { View, XStack } from '@hanzo/ui'
|
|
|
|
/**
|
|
* A row of marks, centred, wrapping until there is room for one line.
|
|
*
|
|
* NO TAILWIND. What a caller used to say through `className` it says as gui
|
|
* props — the row IS an `XStack`, so it takes an XStack's props and a caller
|
|
* states `columnGap` or `opacity` directly instead of naming a utility this
|
|
* component would have to pass through untouched.
|
|
*
|
|
* A MARK RESTS AT 70% AND COMES TO FULL ON APPROACH: `opacity` and
|
|
* `hoverStyle` on the cell that holds it, so the rest and the hover are one
|
|
* gui style and neither out-ranks the other. Its height is DATA, because
|
|
* Techstars' glyphs fill a third of their viewBox and a literal height match
|
|
* renders them tiny beside a wordmark, so lib/constants/partner-logos.ts
|
|
* carries a px value per logo and this reads it.
|
|
*
|
|
* The marks are drawn black. `invert` turns them white always; `invert="dark"`
|
|
* only on the dark theme, so a reader who picks light keeps them black.
|
|
*
|
|
* FLEX, NOT GRID, and deliberately: this row WRAPS below `$md` and grid's
|
|
* auto-flow has no wrap — a track list would put nine marks on one line and
|
|
* overflow a phone. Grid is the site's default for a row of a known width;
|
|
* a row that reflows is still flex's job.
|
|
*/
|
|
interface PartnerLogoRowProps extends ComponentProps<typeof XStack> {
|
|
logos: PartnerLogo[];
|
|
invert?: boolean | 'dark';
|
|
}
|
|
|
|
const PartnerLogoRow: React.FC<PartnerLogoRowProps> = ({
|
|
logos,
|
|
invert = false,
|
|
...rest
|
|
}) => {
|
|
return (
|
|
<XStack
|
|
flexWrap="wrap"
|
|
justify="center"
|
|
items="center"
|
|
columnGap={32}
|
|
rowGap={16}
|
|
{...rest}
|
|
>
|
|
{logos.map((logo) => {
|
|
const img = (
|
|
<View
|
|
render={<img src={logo.src} alt={`${logo.name} logo`} loading="lazy" />}
|
|
display="inline"
|
|
height={logo.height ?? MARK_HEIGHT}
|
|
width="auto"
|
|
filter={invert === true ? 'invert(1)' : undefined}
|
|
/>
|
|
);
|
|
return (
|
|
<XStack
|
|
key={logo.name}
|
|
items="center"
|
|
justify="center"
|
|
opacity={0.7}
|
|
hoverStyle={{ opacity: 1 }}
|
|
$theme-dark={invert === 'dark' ? { filter: 'invert(1)' } : undefined}
|
|
transition="quickest"
|
|
>
|
|
{logo.href ? (
|
|
<a href={logo.href} target="_blank" rel="noopener noreferrer">{img}</a>
|
|
) : img}
|
|
</XStack>
|
|
);
|
|
})}
|
|
</XStack>
|
|
);
|
|
};
|
|
|
|
export default PartnerLogoRow;
|