From 080d206b137d58cf33cdf4f84aa2316f12e73827 Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Tue, 10 Jun 2025 13:32:17 -0700 Subject: [PATCH 1/8] Initial basis for Navbar component --- package-lock.json | 12 ++++++++++- package.json | 3 ++- src/Navbar/Navbar.stories.ts | 31 ++++++++++++++++++++++++++++ src/Navbar/index.scss | 30 +++++++++++++++++++++++++++ src/Navbar/index.tsx | 39 ++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/Navbar/Navbar.stories.ts create mode 100644 src/Navbar/index.scss create mode 100644 src/Navbar/index.tsx diff --git a/package-lock.json b/package-lock.json index 0a3ad5a..eb4e8eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "@shikijs/engine-javascript": "^3.5.0", "@shikijs/langs": "^3.5.0", "@shikijs/themes": "^3.5.0", - "@shikijs/types": "^3.5.0" + "@shikijs/types": "^3.5.0", + "clsx": "^2.1.1" }, "devDependencies": { "@rollup/plugin-commonjs": "^28.0.3", @@ -2863,6 +2864,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", diff --git a/package.json b/package.json index 0ca22d6..d33a662 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "@shikijs/engine-javascript": "^3.5.0", "@shikijs/langs": "^3.5.0", "@shikijs/themes": "^3.5.0", - "@shikijs/types": "^3.5.0" + "@shikijs/types": "^3.5.0", + "clsx": "^2.1.1" } } diff --git a/src/Navbar/Navbar.stories.ts b/src/Navbar/Navbar.stories.ts new file mode 100644 index 0000000..336dbad --- /dev/null +++ b/src/Navbar/Navbar.stories.ts @@ -0,0 +1,31 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import Navbar from "."; + +const meta = { + title: "Atoms/Navbar", + component: Navbar, + parameters: { + layout: "centered", + }, + argTypes: { + children: { type: "string" }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const White: Story = { + args: { + children: "White navbar", + color: "white", + }, +}; + +export const Black: Story = { + args: { + children: "Black navbar", + color: "black", + }, +}; diff --git a/src/Navbar/index.scss b/src/Navbar/index.scss new file mode 100644 index 0000000..9546e08 --- /dev/null +++ b/src/Navbar/index.scss @@ -0,0 +1,30 @@ +@use "sass:map"; + +@use "../sass/tokens"; + +.navbar { + display: block; + + height: 5rem; + width: 100%; + + &.navbar--container { + margin: 0 auto; + + &.navbar--brand { + } + + &.navbar--menu { + } + } + + &.navbar--black { + background-color: map.get(tokens.$brand, black); + color: map.get(tokens.$brand, white); + } + + &.navbar--white { + background-color: map.get(tokens.$brand, white); + color: map.get(tokens.$brand, black); + } +} diff --git a/src/Navbar/index.tsx b/src/Navbar/index.tsx new file mode 100644 index 0000000..206f569 --- /dev/null +++ b/src/Navbar/index.tsx @@ -0,0 +1,39 @@ +import type { FC, PropsWithChildren } from "react"; + +import "./index.scss"; +import clsx from "clsx"; + +export type NavbarColor = "black" | "white"; + +export interface NavbarProps { + /** + * Whether the navbar stays in place upon scroll. + */ + fixed?: boolean; + + /** + * The navbar's basic color scheme. + */ + color: NavbarColor; +} + +/** + * A standard navbar at the top of the page. + */ +const Navbar: FC> = ({ + children, + fixed = false, + color, +}) => ( + +); + +export default Navbar; From 02ebb5e0090c10fd5e98ca766a4ff017e3d5a7d4 Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Tue, 10 Jun 2025 15:11:56 -0700 Subject: [PATCH 2/8] More variants for navbar --- src/MacInstaller/index.scss | 4 +- src/Navbar/Navbar.stories.ts | 31 --------------- src/Navbar/Navbar.stories.tsx | 51 ++++++++++++++++++++++++ src/Navbar/index.scss | 73 +++++++++++++++++++++++++++++------ src/Navbar/index.tsx | 45 ++++++++++++++++++--- src/sass/_tokens.scss | 2 +- 6 files changed, 155 insertions(+), 51 deletions(-) delete mode 100644 src/Navbar/Navbar.stories.ts create mode 100644 src/Navbar/Navbar.stories.tsx diff --git a/src/MacInstaller/index.scss b/src/MacInstaller/index.scss index 4e0972b..19df743 100644 --- a/src/MacInstaller/index.scss +++ b/src/MacInstaller/index.scss @@ -11,7 +11,7 @@ align-items: center; background-color: map.get(tokens.$brand, black); - border: 1px solid map.get(tokens.$brand, purple); + border: 1px solid map.get(tokens.$brand, magenta); color: map.get(tokens.$brand, white); text-decoration: none; @@ -25,7 +25,7 @@ &:hover, &:focus { background-color: color.scale( - map.get(tokens.$brand, purple), + map.get(tokens.$brand, magenta), $blackness: 50% ); } diff --git a/src/Navbar/Navbar.stories.ts b/src/Navbar/Navbar.stories.ts deleted file mode 100644 index 336dbad..0000000 --- a/src/Navbar/Navbar.stories.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; - -import Navbar from "."; - -const meta = { - title: "Atoms/Navbar", - component: Navbar, - parameters: { - layout: "centered", - }, - argTypes: { - children: { type: "string" }, - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const White: Story = { - args: { - children: "White navbar", - color: "white", - }, -}; - -export const Black: Story = { - args: { - children: "Black navbar", - color: "black", - }, -}; diff --git a/src/Navbar/Navbar.stories.tsx b/src/Navbar/Navbar.stories.tsx new file mode 100644 index 0000000..ecb8ca6 --- /dev/null +++ b/src/Navbar/Navbar.stories.tsx @@ -0,0 +1,51 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import Navbar, { type NavbarMenuItem } from "."; + +const meta = { + title: "Atoms/Navbar", + component: Navbar, + parameters: { + layout: "fullscreen", + }, +} satisfies Meta; + +export default meta; +//type Story = StoryObj; + +const items: NavbarMenuItem[] = [ + { + text: "One", + href: "#", + }, + { + text: "Two", + href: "#", + }, + { + text: "Three", + href: "#", + }, + { + text: "Four", + href: "#", + }, +]; + +export const All = () => ( +
+ + + + + +
+); diff --git a/src/Navbar/index.scss b/src/Navbar/index.scss index 9546e08..e715aad 100644 --- a/src/Navbar/index.scss +++ b/src/Navbar/index.scss @@ -1,30 +1,79 @@ @use "sass:map"; +@use "../sass/mixins"; @use "../sass/tokens"; .navbar { - display: block; + top: 0; + left: 0; + + display: flex; + align-items: center; height: 5rem; - width: 100%; - &.navbar--container { + font-family: map.get(tokens.$fonts, sans); + + .navbar--fixed { + position: fixed; + } + + .navbar--container { margin: 0 auto; + width: 90%; + display: flex; + justify-content: space-between; - &.navbar--brand { + .navbar--brand a { + text-decoration: none; + @include mixins.transition(color, shortish); + font-weight: 600; } - &.navbar--menu { + .navbar--menu { + display: flex; + align-items: center; + gap: 1rem; + + a { + text-decoration: none; + @include mixins.transition(color, shortish); + } } } - &.navbar--black { - background-color: map.get(tokens.$brand, black); - color: map.get(tokens.$brand, white); - } + @each $color, + $scheme + in ( + "black": ( + "bg": black, + "text": white, + "hover": yellow, + ), + "white": ( + "bg": white, + "text": black, + "hover": magenta, + ), + "gray": ( + "bg": gray, + "text": white, + "hover": orange, + ) + ) + { + &.navbar--#{$color} { + background-color: map.get(tokens.$brand, map.get($scheme, bg)); - &.navbar--white { - background-color: map.get(tokens.$brand, white); - color: map.get(tokens.$brand, black); + .navbar--brand, + .navbar--menu { + a { + color: map.get(tokens.$brand, map.get($scheme, text)); + &:hover { + color: map.get(tokens.$brand, map.get($scheme, hover)); + } + } + } + } } } diff --git a/src/Navbar/index.tsx b/src/Navbar/index.tsx index 206f569..52acb08 100644 --- a/src/Navbar/index.tsx +++ b/src/Navbar/index.tsx @@ -1,11 +1,26 @@ -import type { FC, PropsWithChildren } from "react"; +import type { FC } from "react"; import "./index.scss"; import clsx from "clsx"; -export type NavbarColor = "black" | "white"; +export type NavbarMenuItem = { + text: string; + href: string; +}; + +export type NavbarColor = "black" | "white" | "gray"; export interface NavbarProps { + /** + * The main title. + */ + title: string; + + /** + * Link in brand. + */ + href: string; + /** * Whether the navbar stays in place upon scroll. */ @@ -15,24 +30,44 @@ export interface NavbarProps { * The navbar's basic color scheme. */ color: NavbarColor; + + /** + * Menu items. + */ + items?: NavbarMenuItem[]; } /** * A standard navbar at the top of the page. */ -const Navbar: FC> = ({ - children, +const Navbar: FC = ({ + title, + href, fixed = false, color, + items = [], }) => ( ); diff --git a/src/sass/_tokens.scss b/src/sass/_tokens.scss index 0217743..aa1b4a8 100644 --- a/src/sass/_tokens.scss +++ b/src/sass/_tokens.scss @@ -3,7 +3,7 @@ $brand: ( red: #ec2c5b, blue-a: #086bb5, yellow: #faa61a, - purple: #cd1e88, + magenta: #cd1e88, blue-b: #034d9c, light-blue: #1e9fd9, orange: #ea741f, From 6c8fe120a14a36617403ac577f885b82d098fcdc Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Wed, 11 Jun 2025 11:56:57 -0700 Subject: [PATCH 3/8] Add NavbarBrand and NavbarMenu components --- src/Navbar/Navbar.stories.tsx | 68 +++++++++++++++++++++++------------ src/Navbar/index.scss | 22 ++++-------- src/Navbar/index.tsx | 45 +++++++---------------- src/sass/_mixins.scss | 5 +++ 4 files changed, 69 insertions(+), 71 deletions(-) diff --git a/src/Navbar/Navbar.stories.tsx b/src/Navbar/Navbar.stories.tsx index ecb8ca6..c793e07 100644 --- a/src/Navbar/Navbar.stories.tsx +++ b/src/Navbar/Navbar.stories.tsx @@ -1,6 +1,9 @@ import type { Meta, StoryObj } from "@storybook/react"; +import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; -import Navbar, { type NavbarMenuItem } from "."; +import Navbar, { NavbarBrand, NavbarMenu, type NavbarMenuItem } from "."; +import { Button } from ".."; +import { action } from "@storybook/addon-actions"; const meta = { title: "Atoms/Navbar", @@ -13,25 +16,6 @@ const meta = { export default meta; //type Story = StoryObj; -const items: NavbarMenuItem[] = [ - { - text: "One", - href: "#", - }, - { - text: "Two", - href: "#", - }, - { - text: "Three", - href: "#", - }, - { - text: "Four", - href: "#", - }, -]; - export const All = () => (
( gap: "1rem", }} > - + + + White + + + One + Two + Three + + + + + + Black + + + One + Two + Three + + - + + + Gray + + + One + Two + Three + + - + + + White with shadow + + + One + Two + Three + +
); diff --git a/src/Navbar/index.scss b/src/Navbar/index.scss index e715aad..336b38f 100644 --- a/src/Navbar/index.scss +++ b/src/Navbar/index.scss @@ -5,13 +5,10 @@ .navbar { top: 0; - left: 0; display: flex; align-items: center; - height: 5rem; - font-family: map.get(tokens.$fonts, sans); .navbar--fixed { @@ -19,26 +16,21 @@ } .navbar--container { - margin: 0 auto; - width: 90%; + margin: auto; display: flex; justify-content: space-between; + width: 80%; // TODO: make this responsive - .navbar--brand a { - text-decoration: none; - @include mixins.transition(color, shortish); - font-weight: 600; + .navbar--brand { + display: flex; + align-items: center; + gap: 1rem; // TODO: make this responsive } .navbar--menu { display: flex; align-items: center; - gap: 1rem; - - a { - text-decoration: none; - @include mixins.transition(color, shortish); - } + gap: 1rem; // TODO: make this responsive } } diff --git a/src/Navbar/index.tsx b/src/Navbar/index.tsx index 52acb08..16c211b 100644 --- a/src/Navbar/index.tsx +++ b/src/Navbar/index.tsx @@ -1,4 +1,4 @@ -import type { FC } from "react"; +import type { FC, PropsWithChildren } from "react"; import "./index.scss"; import clsx from "clsx"; @@ -11,16 +11,6 @@ export type NavbarMenuItem = { export type NavbarColor = "black" | "white" | "gray"; export interface NavbarProps { - /** - * The main title. - */ - title: string; - - /** - * Link in brand. - */ - href: string; - /** * Whether the navbar stays in place upon scroll. */ @@ -30,22 +20,15 @@ export interface NavbarProps { * The navbar's basic color scheme. */ color: NavbarColor; - - /** - * Menu items. - */ - items?: NavbarMenuItem[]; } /** * A standard navbar at the top of the page. */ -const Navbar: FC = ({ - title, - href, +const Navbar: FC> = ({ + children, fixed = false, color, - items = [], }) => ( ); +export const NavbarBrand: FC = ({ children }) => ( +
{children}
+); + +export const NavbarMenu: FC = ({ children }) => ( + {children} +); + export default Navbar; diff --git a/src/sass/_mixins.scss b/src/sass/_mixins.scss index e9318c9..15f05b3 100644 --- a/src/sass/_mixins.scss +++ b/src/sass/_mixins.scss @@ -2,6 +2,11 @@ @use "tokens"; +// A helper to sprinkle around during development. Just don't commit it in actual components! +@mixin dev { + outline: 1.5px solid red; +} + @mixin light-mode { @media (prefers-color-scheme: light) { @content; From 0fb623a428bc5db01fbdc667f778e6e3d6f165e2 Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Wed, 11 Jun 2025 11:58:17 -0700 Subject: [PATCH 4/8] Remove unused param --- src/Navbar/Navbar.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Navbar/Navbar.stories.tsx b/src/Navbar/Navbar.stories.tsx index c793e07..7120b2f 100644 --- a/src/Navbar/Navbar.stories.tsx +++ b/src/Navbar/Navbar.stories.tsx @@ -14,7 +14,7 @@ const meta = { } satisfies Meta; export default meta; -//type Story = StoryObj; +type Story = StoryObj; export const All = () => (
( - + White with shadow From 1fdaeffb6a8339a4342a77527f9cd3921eed2326 Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Wed, 11 Jun 2025 11:59:49 -0700 Subject: [PATCH 5/8] Remove unused imports and types --- src/Navbar/Navbar.stories.tsx | 8 ++------ src/Navbar/index.tsx | 9 +-------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/Navbar/Navbar.stories.tsx b/src/Navbar/Navbar.stories.tsx index 7120b2f..b50fd8f 100644 --- a/src/Navbar/Navbar.stories.tsx +++ b/src/Navbar/Navbar.stories.tsx @@ -1,9 +1,6 @@ -import type { Meta, StoryObj } from "@storybook/react"; -import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import type { Meta } from "@storybook/react"; -import Navbar, { NavbarBrand, NavbarMenu, type NavbarMenuItem } from "."; -import { Button } from ".."; -import { action } from "@storybook/addon-actions"; +import { Navbar, NavbarBrand, NavbarMenu } from "."; const meta = { title: "Atoms/Navbar", @@ -14,7 +11,6 @@ const meta = { } satisfies Meta; export default meta; -type Story = StoryObj; export const All = () => (
> = ({ +export const Navbar: FC> = ({ children, fixed = false, color, @@ -49,5 +44,3 @@ export const NavbarBrand: FC = ({ children }) => ( export const NavbarMenu: FC = ({ children }) => ( {children} ); - -export default Navbar; From 873c9cfcfb0135ce01b645ca61cc37e69759c8a3 Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Wed, 11 Jun 2025 12:01:38 -0700 Subject: [PATCH 6/8] Remove unnecessary styles in @each iterator --- src/Navbar/index.scss | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Navbar/index.scss b/src/Navbar/index.scss index 336b38f..b3eafd5 100644 --- a/src/Navbar/index.scss +++ b/src/Navbar/index.scss @@ -40,32 +40,20 @@ "black": ( "bg": black, "text": white, - "hover": yellow, ), "white": ( "bg": white, "text": black, - "hover": magenta, ), "gray": ( "bg": gray, "text": white, - "hover": orange, ) ) { &.navbar--#{$color} { background-color: map.get(tokens.$brand, map.get($scheme, bg)); - - .navbar--brand, - .navbar--menu { - a { - color: map.get(tokens.$brand, map.get($scheme, text)); - &:hover { - color: map.get(tokens.$brand, map.get($scheme, hover)); - } - } - } + color: map.get(tokens.$brand, map.get($scheme, text)); } } } From 73ed03f8da495f0ddc7bcd39c49c6cbd1e2812e3 Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Wed, 11 Jun 2025 12:05:04 -0700 Subject: [PATCH 7/8] Add better styles to example navbars --- src/Navbar/Navbar.stories.tsx | 60 +++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/src/Navbar/Navbar.stories.tsx b/src/Navbar/Navbar.stories.tsx index b50fd8f..9e5ddbb 100644 --- a/src/Navbar/Navbar.stories.tsx +++ b/src/Navbar/Navbar.stories.tsx @@ -15,7 +15,6 @@ export default meta; export const All = () => ( From 972d7faca40f95c02e36e53f15d930e8e0cc016a Mon Sep 17 00:00:00 2001 From: Luc Perkins Date: Wed, 11 Jun 2025 12:07:16 -0700 Subject: [PATCH 8/8] Apply text color to inner elements --- src/Navbar/Navbar.stories.tsx | 24 ++++++++++++------------ src/Navbar/index.scss | 4 +++- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/Navbar/Navbar.stories.tsx b/src/Navbar/Navbar.stories.tsx index 9e5ddbb..53e3684 100644 --- a/src/Navbar/Navbar.stories.tsx +++ b/src/Navbar/Navbar.stories.tsx @@ -23,18 +23,18 @@ export const All = () => ( > - + White - + One - + Two - + Three @@ -42,18 +42,18 @@ export const All = () => ( - + Black - + One - + Two - + Three @@ -61,18 +61,18 @@ export const All = () => ( - + Gray - + One - + Two - + Three diff --git a/src/Navbar/index.scss b/src/Navbar/index.scss index b3eafd5..57eafe3 100644 --- a/src/Navbar/index.scss +++ b/src/Navbar/index.scss @@ -53,7 +53,9 @@ { &.navbar--#{$color} { background-color: map.get(tokens.$brand, map.get($scheme, bg)); - color: map.get(tokens.$brand, map.get($scheme, text)); + * { + color: map.get(tokens.$brand, map.get($scheme, text)); + } } } }