NextLink.tsx 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import Link, { LinkProps } from 'next/link';
  2. import { Link as ScrollLink } from 'react-scroll';
  3. import { useSiteUrl } from '~/stores/context';
  4. const isAnchorLink = (href: string): boolean => {
  5. return href.toString().length > 0 && href[0] === '#';
  6. };
  7. const isExternalLink = (href: string, siteUrl: string | undefined): boolean => {
  8. const baseUrl = new URL(siteUrl ?? 'https://example.com');
  9. const hrefUrl = new URL(href, baseUrl);
  10. return baseUrl.host !== hrefUrl.host;
  11. };
  12. type Props = Omit<LinkProps, 'href'> & {
  13. children: React.ReactNode,
  14. href?: string,
  15. className?: string,
  16. };
  17. export const NextLink = ({
  18. href, children, className, ...props
  19. }: Props): JSX.Element => {
  20. const { data: siteUrl } = useSiteUrl();
  21. if (href == null) {
  22. return <a className={className}>{children}</a>;
  23. }
  24. // when href is an anchor link
  25. if (isAnchorLink(href)) {
  26. const to = href.slice(1);
  27. return (
  28. <Link href={href} scroll={false}>
  29. <ScrollLink href={href} to={to} className={className} smooth="easeOutQuart" offset={-100} duration={800}>
  30. {children}
  31. </ScrollLink>
  32. </Link>
  33. );
  34. }
  35. if (isExternalLink(href, siteUrl)) {
  36. return (
  37. <a href={href} className={className} target="_blank" rel="noopener noreferrer">
  38. {children}&nbsp;<i className='icon-share-alt small'></i>
  39. </a>
  40. );
  41. }
  42. return (
  43. <Link {...props} href={href} prefetch={false}>
  44. <a href={href} className={className}>{children}</a>
  45. </Link>
  46. );
  47. };