mirror of
https://github.com/lux-tel/websites.git
synced 2026-10-30 20:31:36 +00:00
122 lines
3.7 KiB
TypeScript
122 lines
3.7 KiB
TypeScript
import { PortableText, type PortableTextProps } from '@portabletext/react';
|
|
import { NavLink } from '@session/ui/components/NavLink';
|
|
import Typography from '@session/ui/components/Typography';
|
|
import { cn } from '@session/ui/lib/utils';
|
|
import logger from '../lib/logger';
|
|
import { cleanSanityString } from '../lib/string';
|
|
|
|
export type SanityPortableTextProps = PortableTextProps & {
|
|
className?: string;
|
|
wrapperComponent?: 'div' | 'main' | 'section' | 'article';
|
|
};
|
|
|
|
type BasicComponentsType = PortableTextProps['components'] & {
|
|
block: NonNullable<PortableTextProps['components']>['block'];
|
|
marks: NonNullable<PortableTextProps['components']>['marks'];
|
|
};
|
|
|
|
export const basicComponents: BasicComponentsType = {
|
|
block: {
|
|
h1: ({ children }) => <Typography variant="h1">{children}</Typography>,
|
|
h2: ({ children }) => (
|
|
<Typography variant="h2" className="mt-7 mb-3">
|
|
{children}
|
|
</Typography>
|
|
),
|
|
h3: ({ children }) => (
|
|
<Typography variant="h3" className="mt-5">
|
|
{children}
|
|
</Typography>
|
|
),
|
|
h4: ({ children }) => (
|
|
<Typography variant="h4" className="mt-4">
|
|
{children}
|
|
</Typography>
|
|
),
|
|
h5: ({ children }) => (
|
|
<Typography variant="h5" className="mt-3">
|
|
{children}
|
|
</Typography>
|
|
),
|
|
h6: ({ children }) => (
|
|
<Typography variant="h6" className="mt-3">
|
|
{children}
|
|
</Typography>
|
|
),
|
|
li: ({ children }) => <Typography variant="li">{children}</Typography>,
|
|
ol: ({ children }) => <Typography variant="ol">{children}</Typography>,
|
|
ul: ({ children }) => <Typography variant="ul">{children}</Typography>,
|
|
strong: ({ children }) => <Typography variant="strong">{children}</Typography>,
|
|
em: ({ children }) => <Typography variant="em">{children}</Typography>,
|
|
},
|
|
marks: {
|
|
link: ({ children, value }) => (
|
|
<NavLink href={value.href} unStyled className="text-session-green-link hover:underline">
|
|
{children}
|
|
</NavLink>
|
|
),
|
|
'big-bold': ({ children }) => (
|
|
<Typography variant="strong" className="text-lg md:text-xl">
|
|
{children}
|
|
</Typography>
|
|
),
|
|
},
|
|
};
|
|
|
|
export function SanityPortableText({ value, className, ...props }: SanityPortableTextProps) {
|
|
// biome-ignore lint/suspicious/noEvolvingTypes: TODO: type this
|
|
const blocks = [];
|
|
|
|
if (!Array.isArray(value)) {
|
|
logger.error('SanityPortableText: value is not an array');
|
|
return null;
|
|
}
|
|
|
|
let figureNumber = 1;
|
|
for (const block of value) {
|
|
if (block._type === 'block' && 'children' in block && block.children.length === 1) {
|
|
/** Remove empty blocks from the array */
|
|
const child = block.children[0];
|
|
if (
|
|
child &&
|
|
'_type' in child &&
|
|
child._type === 'span' &&
|
|
'text' in child &&
|
|
typeof child.text === 'string' &&
|
|
cleanSanityString(child.text) === ''
|
|
) {
|
|
continue;
|
|
}
|
|
} else if (block._type === 'image') {
|
|
if (blocks.length < 3) {
|
|
// Prioritize images in the first 5 blocks of the content
|
|
// @ts-expect-error - This is a workaround to make TS happy
|
|
block.priority = true;
|
|
}
|
|
if (
|
|
'caption' in block &&
|
|
block.caption?.length &&
|
|
'calculateFigureNumber' in block &&
|
|
block.calculateFigureNumber
|
|
) {
|
|
block.figureNumber = figureNumber;
|
|
figureNumber++;
|
|
}
|
|
}
|
|
blocks.push(block);
|
|
}
|
|
|
|
const Comp = props.wrapperComponent || 'div';
|
|
|
|
return (
|
|
<Comp
|
|
className={cn(
|
|
'flex flex-col items-start text-sm md:text-base [&>p]:mt-3.5 first:[&>p]:mt-0',
|
|
className
|
|
)}
|
|
>
|
|
<PortableText components={basicComponents} value={blocks} {...props} />
|
|
</Comp>
|
|
);
|
|
}
|