TASKS-1823 WebManager module
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import { cn } from '@crux-kit/utils';
|
||||
import { toPublicHref } from '#i18n/content-href';
|
||||
import { buttonVariants } from '#shared/ui/Button';
|
||||
import type { NavigationLink } from '../types';
|
||||
|
||||
export function safeHref(link: NavigationLink): string | null {
|
||||
const href = link.href || link.externalUrl;
|
||||
if (!href) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (href.startsWith('/')) {
|
||||
return toPublicHref(href);
|
||||
}
|
||||
|
||||
if (href.startsWith('#')) {
|
||||
return href;
|
||||
}
|
||||
|
||||
try {
|
||||
const url = new URL(href);
|
||||
return ['http:', 'https:', 'mailto:', 'tel:'].includes(url.protocol) ? href : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function PageLink({ link, className = '' }: { link: NavigationLink; className?: string }) {
|
||||
const href = safeHref(link);
|
||||
const classes = cn(buttonVariants({ variant: link.variant }), className);
|
||||
|
||||
if (!href) {
|
||||
return <span className={cn(classes, 'cursor-not-allowed opacity-45')}>{link.label}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
className={classes}
|
||||
target={link.openInNewTab ? '_blank' : undefined}
|
||||
rel={link.openInNewTab ? 'noreferrer noopener' : undefined}
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
export function LinkList({
|
||||
links,
|
||||
className = ''
|
||||
}: {
|
||||
links: NavigationLink[];
|
||||
className?: string;
|
||||
}) {
|
||||
if (links.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-wrap items-center gap-3', className)}>
|
||||
{links.map((link, index) => (
|
||||
<PageLink key={`${link.label}-${index}`} link={link} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user