Skip to content

Commit

Permalink
add link-navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
mckelvey committed Nov 25, 2024
1 parent 1d3c4f3 commit de7d3eb
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
1 change: 1 addition & 0 deletions components/interactive/links/link-navigation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { LinkNavigation } from './link-navigation'
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/* eslint-disable import/no-default-export */
// eslint-disable-next-line import/no-extraneous-dependencies
import { fn } from '@storybook/test'
import { MouseEvent } from 'react'
import {
ButtonState,
buttonStates,
StatesGrid,
} from '@/components/helpers/states-grid'
import { LinkNavigation as LinkNavigationUi } from './link-navigation'
import type { Meta, StoryObj } from '@storybook/react'

const meta = {
title: 'Interactive / Links / Link Navigation',
component: LinkNavigationUi,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
children: {
control: {
type: 'text',
},
description: 'The button content',
table: {
defaultValue: {
summary: '[required]',
},
type: {
summary: 'ReactNode',
},
},
},
href: {
control: {
type: 'text',
},
description: 'The destination href',
table: {
defaultValue: {
summary: '[required]',
},
type: {
summary: 'string Url',
},
},
},
},
args: {
onClick: (event: MouseEvent<HTMLAnchorElement>) => {
event.stopPropagation()
event.preventDefault()
fn()
},
},
} satisfies Meta<typeof LinkNavigationUi>

export default meta
type Story = StoryObj<typeof meta>

export const States: Story = {
args: {
children: 'Button',
href: 'https://plasticlabs.ai',
},
decorators: [
(_, { args }) => {
const story: React.FC<{ column: string; row: string }> = ({ row }) => {
return <LinkNavigationUi {...args} data-state={row as ButtonState} />
}

return (
<StatesGrid columns={['State']} rows={buttonStates} Story={story} />
)
},
],
}

export const LinkNavigation: Story = {
args: {
children: 'Inline Link',
href: 'https://plasticlabs.ai',
},
}
94 changes: 94 additions & 0 deletions components/interactive/links/link-navigation/link-navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use client'

import Link from 'next/link'
import styled, { css } from 'styled-components'
import { isInternalUrl } from '@/utils/url'
import type { LinkNavigationProps } from './link-navigation.types'

const linkStyles = css`
// base styles
display: inline;
font-family: var(--font-family-roboto-mono);
font-size: 1rem;
font-weight: 400;
line-height: 1;
letter-spacing: -0.02em;
text-decoration: none;
white-space: nowrap;
transition: color var(--ui-transition-speed) ease;
user-select: none;
// states
&,
&:visited {
color: var(--color-primary-surface-contrast);
}
&:hover:not([href='']):not([href='#']):not([data-state]),
&[data-state='hover'] {
text-decoration: underline;
}
&:active:not([href='']):not([href='#']):not([data-state]),
&:hover:active:not([href='']):not([href='#']):not([data-state]),
&[data-state='pressed'] {
text-decoration: underline;
text-decoration-color: var(--color-primary-accent);
}
&[href='']:not([data-state]),
&[href='#']:not([data-state]),
&[data-state='disabled'] {
color: hsl(from var(--color-black) h s l / 0.6);
text-decoration: underline;
text-decoration-color: hsl(from var(--color-black) h s l / 0.3);
pointer-events: none;
cursor: default;
}
`

const StyledNextLink = styled(Link)`
${linkStyles}
`

const StyledAnchor = styled.a`
${linkStyles}
`

/**
* This component is for links which appear within the main navigation.
*/
export const LinkNavigation: React.FC<LinkNavigationProps> = ({
children,
href,
...props
}) => {
if (!children) {
return null
}

if (isInternalUrl(href)) {
return (
<StyledNextLink {...props} href={href}>
{children}
</StyledNextLink>
)
}

const { as, ...rest } = props

return (
<StyledAnchor
{...rest}
href={href.toString()}
rel="noopener"
target="_blank"
>
{children}
</StyledAnchor>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { LinkProps } from 'next/link'
import { AnchorHTMLAttributes, ReactNode } from 'react'

export interface LinkNavigationProps
extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>,
LinkProps {
children: ReactNode
}

0 comments on commit de7d3eb

Please sign in to comment.