aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-10-19 19:30:54 +0200
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:14:41 +0100
commitc3cde71e60ae22d17c1d162f678f592915ac5398 (patch)
tree770856e0876b8c613a21fa79199d6d40609d73e6 /src
parent94448fa278ab352a741ff13f22d6104869571144 (diff)
refactor(components): rewrite NavLink component
* handle style variants to avoid declaring the styles in consumers
Diffstat (limited to 'src')
-rw-r--r--src/components/molecules/nav/nav-link/nav-link.module.scss119
-rw-r--r--src/components/molecules/nav/nav-link/nav-link.stories.tsx89
-rw-r--r--src/components/molecules/nav/nav-link/nav-link.test.tsx6
-rw-r--r--src/components/molecules/nav/nav-link/nav-link.tsx34
-rw-r--r--src/components/molecules/nav/nav-list.module.scss10
-rw-r--r--src/components/molecules/nav/nav-list.tsx5
6 files changed, 190 insertions, 73 deletions
diff --git a/src/components/molecules/nav/nav-link/nav-link.module.scss b/src/components/molecules/nav/nav-link/nav-link.module.scss
index 8a7d371..ac20c73 100644
--- a/src/components/molecules/nav/nav-link/nav-link.module.scss
+++ b/src/components/molecules/nav/nav-link/nav-link.module.scss
@@ -2,60 +2,97 @@
@use "../../../../styles/abstracts/placeholders";
.link {
- --draw-border-thickness: #{fun.convert-px(4)};
- --draw-border-color1: var(--color-primary-light);
- --draw-border-color2: var(--color-primary-lighter);
-
- display: flex;
- flex-flow: row wrap;
- place-items: center;
- place-content: center;
- row-gap: var(--spacing-2xs);
- min-width: var(--link-min-width, fun.convert-px(80));
- padding: var(--spacing-xs) var(--spacing-xs) var(--spacing-2xs);
- background: none;
- border-radius: 8%;
- font-size: var(--font-size-sm);
- font-variant: small-caps;
- font-weight: 600;
- text-align: center;
- text-decoration: none;
+ &--block,
+ &--main,
+ &--regular#{&}--stack {
+ display: flex;
+ place-items: center;
+ place-content: center;
+ row-gap: var(--spacing-2xs);
+ }
- &--inline {
- width: fit-content;
+ &--block {
+ padding: var(--spacing-2xs) var(--spacing-xs);
+ font-weight: 500;
+ text-decoration: underline solid transparent 0;
- .logo {
- margin-right: var(--spacing-xs);
+ &:hover,
+ &:focus {
+ background: var(--color-bg-secondary);
}
- }
- &--stack {
- .logo {
- flex: 0 0 100%;
- display: flex;
- place-content: center;
+ &:focus {
+ color: var(--color-primary);
+ text-decoration-color: var(--color-primary-light);
+ text-decoration-thickness: 0.25ex;
}
- }
- &:hover,
- &:focus {
- @extend %draw-borders;
+ &:active {
+ background: var(--color-bg-tertiary);
+ text-decoration-color: transparent;
+ text-decoration-thickness: 0;
+ }
}
- &:hover {
- color: var(--color-primary-light);
+ &--main {
+ --draw-border-thickness: #{fun.convert-px(4)};
+ --draw-border-color1: var(--color-primary-light);
+ --draw-border-color2: var(--color-primary-lighter);
+
+ min-width: var(--link-min-width, fun.convert-px(82));
+ padding: var(--spacing-xs);
+ background: none;
+ border-radius: 8%;
+ font-size: var(--font-size-sm);
+ font-variant: small-caps;
+ font-weight: 600;
+ line-height: initial;
+ text-align: center;
+ text-decoration: none;
+
+ &:hover,
+ &:focus {
+ @extend %draw-borders;
+ }
+
+ &:hover {
+ color: var(--color-primary-light);
+ }
+
+ &:focus {
+ color: var(--color-primary-light);
+ }
+
+ &:active {
+ --draw-border-color1: var(--color-primary-dark);
+ --draw-border-color2: var(--color-primary-light);
+
+ color: var(--color-primary-dark);
+
+ @extend %draw-borders;
+ }
}
- &:focus {
- color: var(--color-primary-light);
+ &--inline {
+ .logo {
+ margin-right: var(--spacing-xs);
+ }
}
- &:active {
- --draw-border-color1: var(--color-primary-dark);
- --draw-border-color2: var(--color-primary-light);
+ &--inline#{&}--regular {
+ .logo {
+ display: inline-block;
+ vertical-align: middle;
+ }
+ }
- color: var(--color-primary-dark);
+ &--stack {
+ flex-flow: column wrap;
- @extend %draw-borders;
+ .logo {
+ flex: 0 0 100%;
+ display: flex;
+ place-content: center;
+ }
}
}
diff --git a/src/components/molecules/nav/nav-link/nav-link.stories.tsx b/src/components/molecules/nav/nav-link/nav-link.stories.tsx
index 4e8400f..b0ad76a 100644
--- a/src/components/molecules/nav/nav-link/nav-link.stories.tsx
+++ b/src/components/molecules/nav/nav-link/nav-link.stories.tsx
@@ -49,31 +49,100 @@ const Template: ComponentStory<typeof NavLinkComponent> = (args) => (
);
/**
- * NavLink Stories - Default
+ * NavLink Stories - Regular
*/
-export const Default = Template.bind({});
-Default.args = {
+export const Regular = Template.bind({});
+Regular.args = {
href: '#',
label: 'A nav link',
};
/**
- * NavLink Stories - StackWithLogo
+ * NavLink Stories - RegularInlineWithLogo
*/
-export const StackWithLogo = Template.bind({});
-StackWithLogo.args = {
+export const RegularInlineWithLogo = Template.bind({});
+RegularInlineWithLogo.args = {
href: '#example',
+ isStack: false,
label: 'A nav link',
logo: <Icon aria-hidden shape="home" />,
};
/**
- * NavLink Stories - InlineWithLogo
+ * NavLink Stories - RegularStackWithLogo
*/
-export const InlineWithLogo = Template.bind({});
-InlineWithLogo.args = {
+export const RegularStackWithLogo = Template.bind({});
+RegularStackWithLogo.args = {
href: '#example',
- isInline: true,
+ isStack: true,
label: 'A nav link',
logo: <Icon aria-hidden shape="home" />,
};
+
+/**
+ * NavLink Stories - Block
+ */
+export const Block = Template.bind({});
+Block.args = {
+ href: '#',
+ label: 'A nav link',
+ variant: 'block',
+};
+
+/**
+ * NavLink Stories - BlockInlineWithLogo
+ */
+export const BlockInlineWithLogo = Template.bind({});
+BlockInlineWithLogo.args = {
+ href: '#example',
+ isStack: false,
+ label: 'A nav link',
+ logo: <Icon aria-hidden shape="home" />,
+ variant: 'block',
+};
+
+/**
+ * NavLink Stories - BlockStackWithLogo
+ */
+export const BlockStackWithLogo = Template.bind({});
+BlockStackWithLogo.args = {
+ href: '#example',
+ isStack: true,
+ label: 'A nav link',
+ logo: <Icon aria-hidden shape="home" />,
+ variant: 'block',
+};
+
+/**
+ * NavLink Stories - Main
+ */
+export const Main = Template.bind({});
+Main.args = {
+ href: '#',
+ label: 'A nav link',
+ variant: 'main',
+};
+
+/**
+ * NavLink Stories - MainInlineWithLogo
+ */
+export const MainInlineWithLogo = Template.bind({});
+MainInlineWithLogo.args = {
+ href: '#example',
+ isStack: false,
+ label: 'A nav link',
+ logo: <Icon aria-hidden shape="home" />,
+ variant: 'main',
+};
+
+/**
+ * NavLink Stories - MainStackWithLogo
+ */
+export const MainStackWithLogo = Template.bind({});
+MainStackWithLogo.args = {
+ href: '#example',
+ isStack: true,
+ label: 'A nav link',
+ logo: <Icon aria-hidden shape="home" />,
+ variant: 'main',
+};
diff --git a/src/components/molecules/nav/nav-link/nav-link.test.tsx b/src/components/molecules/nav/nav-link/nav-link.test.tsx
index aa9b557..e4c2d57 100644
--- a/src/components/molecules/nav/nav-link/nav-link.test.tsx
+++ b/src/components/molecules/nav/nav-link/nav-link.test.tsx
@@ -15,14 +15,14 @@ describe('NavLink', () => {
);
});
- it('can render a nav link with inlined contents', () => {
+ it('can render a nav link with stacked contents', () => {
const label = 'eius';
const target = '#harum';
- render(<NavLink href={target} isInline label={label} />);
+ render(<NavLink href={target} isStack label={label} />);
expect(rtlScreen.getByRole('link', { name: label })).toHaveClass(
- 'link--inline'
+ 'link--stack'
);
});
});
diff --git a/src/components/molecules/nav/nav-link/nav-link.tsx b/src/components/molecules/nav/nav-link/nav-link.tsx
index f9fc529..c2b0f5f 100644
--- a/src/components/molecules/nav/nav-link/nav-link.tsx
+++ b/src/components/molecules/nav/nav-link/nav-link.tsx
@@ -8,33 +8,55 @@ import styles from './nav-link.module.scss';
export type NavLinkProps = Omit<LinkProps, 'children' | 'disableTransition'> & {
/**
- * Should the logo and label be inlined?
+ * Should the logo be above the label?
*
* @default false
*/
- isInline?: boolean;
+ isStack?: boolean;
/**
* The link label.
*/
- label: string;
+ label: ReactNode;
/**
* The link logo.
*/
logo?: ReactNode;
+ /**
+ * The link variant.
+ *
+ * @default 'regular'
+ */
+ variant?: 'block' | 'main' | 'regular';
};
const NavLinkWithRef: ForwardRefRenderFunction<
HTMLAnchorElement,
NavLinkProps
-> = ({ className = '', isInline = false, label, logo, ...props }, ref) => {
+> = (
+ {
+ className = '',
+ isStack = false,
+ label,
+ logo,
+ variant = 'regular',
+ ...props
+ },
+ ref
+) => {
const linkClass = [
styles.link,
- styles[isInline ? 'link--inline' : 'link--stack'],
+ styles[`link--${variant}`],
+ styles[isStack ? 'link--stack' : 'link--inline'],
className,
].join(' ');
return (
- <Link {...props} className={linkClass} disableTransition ref={ref}>
+ <Link
+ {...props}
+ className={linkClass}
+ disableTransition={variant === 'main'}
+ ref={ref}
+ >
{logo ? <span className={styles.logo}>{logo}</span> : null}
{label}
</Link>
diff --git a/src/components/molecules/nav/nav-list.module.scss b/src/components/molecules/nav/nav-list.module.scss
index 316638e..ff99581 100644
--- a/src/components/molecules/nav/nav-list.module.scss
+++ b/src/components/molecules/nav/nav-list.module.scss
@@ -1,14 +1,4 @@
.nav {
- &--main {
- width: fit-content;
- }
-
- &--main & {
- &__item {
- flex: 1;
- }
- }
-
&--footer & {
&__item:not(:first-child) {
&::before {
diff --git a/src/components/molecules/nav/nav-list.tsx b/src/components/molecules/nav/nav-list.tsx
index b3c7138..a6acdcf 100644
--- a/src/components/molecules/nav/nav-list.tsx
+++ b/src/components/molecules/nav/nav-list.tsx
@@ -49,8 +49,7 @@ export const NavList: FC<NavListProps> = ({
listClassName = '',
...props
}) => {
- const kindClass = `nav--${kind}`;
- const navClass = `${styles.nav} ${styles[kindClass]} ${className}`;
+ const navClass = [styles[`nav--${kind}`], className].join(' ');
/**
* Get the nav items.
@@ -60,7 +59,7 @@ export const NavList: FC<NavListProps> = ({
items.map(({ id, href, label, logo }) => (
<ListItem key={id} className={styles.nav__item}>
{kind === 'main' ? (
- <NavLink href={href} label={label} logo={logo} />
+ <NavLink href={href} label={label} logo={logo} variant="main" />
) : (
<Link href={href}>{label}</Link>
)}