mirror of
https://github.com/lux-tel/websites.git
synced 2026-10-30 20:31:36 +00:00
155 lines
5.3 KiB
TypeScript
155 lines
5.3 KiB
TypeScript
'use client';
|
|
|
|
import { NodeCard, NodeCardText, NodeCardTitle } from '@/components/NodeCard';
|
|
import type { ButtonDataTestId } from '@/testing/data-test-ids';
|
|
import { PubKey } from '@session/ui/components/PubKey';
|
|
import { TextSeparator } from '@session/ui/components/Separator';
|
|
import {
|
|
StatusIndicator,
|
|
type StatusIndicatorVariants,
|
|
} from '@session/ui/components/StatusIndicator';
|
|
import { cn } from '@session/ui/lib/utils';
|
|
import { Button, ButtonSkeleton } from '@session/ui/ui/button';
|
|
import { Skeleton } from '@session/ui/ui/skeleton';
|
|
import { useTranslations } from 'next-intl';
|
|
import Link from 'next/link';
|
|
import { type HTMLAttributes, type ReactNode, forwardRef } from 'react';
|
|
|
|
export type InfoNodeCardProps = HTMLAttributes<HTMLDivElement> & {
|
|
pubKey: string;
|
|
buttonSiblings?: ReactNode;
|
|
isActive?: boolean;
|
|
forceSmall?: boolean;
|
|
button?: {
|
|
text: string;
|
|
link: string;
|
|
dataTestId: ButtonDataTestId;
|
|
ariaLabel: string;
|
|
};
|
|
warnings?: ReactNode;
|
|
statusIndicatorColour?: StatusIndicatorVariants['status'];
|
|
};
|
|
|
|
export const InfoNodeCard = forwardRef<HTMLDivElement, InfoNodeCardProps>(
|
|
(
|
|
{
|
|
statusIndicatorColour,
|
|
buttonSiblings,
|
|
isActive,
|
|
className,
|
|
forceSmall,
|
|
pubKey,
|
|
button,
|
|
warnings,
|
|
children,
|
|
...props
|
|
},
|
|
ref
|
|
) => {
|
|
const generalNodeDictionary = useTranslations('sessionNodes.general');
|
|
const titleFormat = useTranslations('modules.title');
|
|
return (
|
|
<NodeCard
|
|
ref={ref}
|
|
{...props}
|
|
className={cn(
|
|
'flex flex-row flex-wrap items-center justify-between gap-2 border border-transparent align-middle reduced-motion:transition-none transition-all duration-500 ease-in-out',
|
|
forceSmall ? '' : 'md:gap-10',
|
|
isActive && 'border-session-green',
|
|
className
|
|
)}
|
|
>
|
|
<div className="flex flex-row gap-2 md:gap-4">
|
|
{warnings ? (
|
|
<div className="flex w-max flex-row items-center gap-2 align-middle">{warnings}</div>
|
|
) : null}
|
|
<div className={cn('text-start', className)}>
|
|
<div className="flex w-full cursor-pointer items-baseline gap-1 align-middle md:gap-3">
|
|
{statusIndicatorColour ? (
|
|
<div className="scale-75 p-0 sm:mb-0.5 sm:pt-0.5 md:scale-100 md:pt-0">
|
|
<StatusIndicator status={statusIndicatorColour} />
|
|
</div>
|
|
) : null}
|
|
<NodeCardTitle
|
|
className={cn(
|
|
'inline-flex flex-wrap gap-1.5',
|
|
forceSmall ? 'text-xs md:text-base' : 'text-sm md:text-lg'
|
|
)}
|
|
>
|
|
<span className="text-nowrap font-normal">
|
|
{titleFormat('format', { title: generalNodeDictionary('publicKeyShort') })}
|
|
</span>
|
|
<PubKey pubKey={pubKey} force="collapse" leadingChars={8} trailingChars={4} />
|
|
</NodeCardTitle>
|
|
</div>
|
|
<NodeCardText
|
|
className={cn(
|
|
'col-span-10 inline-flex max-h-max flex-row-reverse justify-start gap-2 text-center align-middle font-normal sm:text-start md:mt-0 md:flex-row',
|
|
forceSmall ? 'text-xs md:text-xs' : 'text-xs md:text-base'
|
|
)}
|
|
>
|
|
{children}
|
|
</NodeCardText>
|
|
</div>
|
|
</div>
|
|
<div className="flex w-full flex-row items-center gap-2 align-middle sm:w-auto">
|
|
{buttonSiblings}
|
|
{button ? (
|
|
<Link href={button.link} className="w-full md:w-auto" prefetch>
|
|
<Button
|
|
variant={isActive ? 'default' : 'outline'}
|
|
size={forceSmall ? 'sm' : 'md'}
|
|
rounded="md"
|
|
aria-label={button.ariaLabel}
|
|
data-testid={button.dataTestId}
|
|
className="w-full md:w-auto"
|
|
>
|
|
{button.text}
|
|
</Button>
|
|
</Link>
|
|
) : null}
|
|
</div>
|
|
</NodeCard>
|
|
);
|
|
}
|
|
);
|
|
|
|
export function InfoNodeCardSkeleton() {
|
|
return (
|
|
<div className="flex w-full flex-row items-center justify-between gap-3 rounded-xl border-2 border-muted p-6">
|
|
<div className="-bottom-1/2 flex w-full flex-col gap-3">
|
|
<div className="flex w-full items-center gap-3 align-middle">
|
|
<div className="-mr-2 scale-75 p-0 sm:mr-0 md:scale-100 md:p-0.5">
|
|
<Skeleton className="h-4 w-4 rounded-full" />
|
|
</div>
|
|
<div className="inline-flex gap-2">
|
|
<Skeleton className="h-6 w-40 sm:w-60" />
|
|
</div>
|
|
</div>
|
|
<Skeleton className="h-4 w-9/12" />
|
|
</div>
|
|
<ButtonSkeleton variant="outline" rounded="md" className="h-8 w-16" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export const NodeItem = ({ children, className }: { children: ReactNode; className?: string }) => (
|
|
<span className={className}>{children}</span>
|
|
);
|
|
|
|
export const NodeItemSeparator = ({ className }: { className?: string }) => (
|
|
<TextSeparator className={className} />
|
|
);
|
|
|
|
export const NodeItemLabel = ({
|
|
children,
|
|
className,
|
|
}: {
|
|
children: ReactNode;
|
|
className?: string;
|
|
}) => <span className={cn('font-normal', className)}> {children}</span>;
|
|
|
|
export const NodeItemValue = ({ children }: { children: ReactNode }) => (
|
|
<span className="text-nowrap font-semibold"> {children}</span>
|
|
);
|