From 34aedc6e0fed63ac3219fe8fa0c1c83064ff3c65 Mon Sep 17 00:00:00 2001 From: Gil Balsiger Date: Sun, 8 Dec 2024 14:59:16 +0100 Subject: [PATCH] feat: buttons OK --- src/button/button.css | 128 ++++++++++++++++++++++-------- src/button/button.stories.ts | 48 +++++------ src/button/icon-button.stories.ts | 31 +++++--- src/select/Select.stories.ts | 33 -------- src/style.css | 24 +++++- 5 files changed, 157 insertions(+), 107 deletions(-) delete mode 100644 src/select/Select.stories.ts diff --git a/src/button/button.css b/src/button/button.css index 027c800..238d8f1 100644 --- a/src/button/button.css +++ b/src/button/button.css @@ -3,6 +3,7 @@ --bl-btn-color: var(--bl-clr-gray-800); --bl-btn-hover-background: var(--bl-clr-gray-300); --bl-btn-border-radius: var(--bl-border-radius); + --bl-btn-border: solid 1px transparent; appearance: none; white-space: nowrap; @@ -20,7 +21,7 @@ cursor: pointer; transition-property: color, background-color, border-color; transition-duration: var(--bl-transition); - border: none; + border: var(--bl-btn-border); position: relative; user-select: none; line-height: 1.25rem; @@ -31,57 +32,61 @@ } } -.btn-ghost { - --bl-btn-background: transparent; - --bl-btn-hover-background: var(--bl-clr-gray-200); -} - .btn-icon { min-width: 2.5rem; padding: 0; } +/* Colors */ + .btn-primary { - --bl-btn-background: var(--bl-clr-primary); - --bl-btn-hover-background: color-mix( - in srgb, - var(--bl-clr-primary), - #fff 10% - ); + --bl-btn-background: var(--bl-clr-primary-600); + --bl-btn-hover-background: var(--bl-clr-primary-500); --bl-btn-color: #fff; } .btn-danger { - --bl-btn-background: var(--bl-clr-red-700); - --bl-btn-hover-background: var(--bl-clr-red-600); + --bl-btn-background: var(--bl-clr-red-600); + --bl-btn-hover-background: var(--bl-clr-red-500); --bl-btn-color: #fff; } -.dark, -[data-theme="dark"] { - .btn { - --bl-btn-background: var(--bl-clr-gray-800); - --bl-btn-color: #fff; - --bl-btn-hover-background: var(--bl-clr-gray-700); +/* Variants */ + +.btn-ghost { + --bl-btn-background: transparent; + --bl-btn-color: var(--bl-clr-gray-800); + + &.btn-primary { + --bl-btn-hover-background: var(--bl-clr-primary-600); } - .btn-ghost { - --bl-btn-background: transparent; - --bl-btn-hover-background: var(--bl-clr-gray-800); + &.btn-danger { + --bl-btn-hover-background: var(--bl-clr-red-600); } - .btn-primary { - --bl-btn-background: var(--bl-clr-primary); - --bl-btn-hover-background: color-mix( - in srgb, - var(--bl-clr-primary), - var(--bl-clr-gray-950) 20% - ); + &.btn-primary:hover, + &.btn-danger:hover { + --bl-btn-color: #fff; } +} - .btn-danger { - --bl-btn-background: var(--bl-clr-red-700); - --bl-btn-hover-background: var(--bl-clr-red-800); +.btn-outline { + --bl-btn-background: transparent; + --bl-btn-hover-background: var(--bl-clr-gray-200); + --bl-btn-color: var(--bl-clr-gray-800); + --bl-btn-border: 1px solid var(--bl-clr-gray-300); + + &.btn-primary { + --bl-btn-color: var(--bl-clr-primary-600); + --bl-btn-border: 1px solid var(--bl-clr-primary-600); + --bl-btn-hover-background: var(--bl-clr-primary-100); + } + + &.btn-danger { + --bl-btn-color: var(--bl-clr-red-600); + --bl-btn-border: 1px solid var(--bl-clr-red-600); + --bl-btn-hover-background: var(--bl-clr-red-100); } } @@ -127,6 +132,63 @@ } } +/* Dark theme */ +.dark, +[data-theme="dark"] { + .btn { + --bl-btn-background: var(--bl-clr-gray-800); + --bl-btn-color: #fff; + --bl-btn-hover-background: var(--bl-clr-gray-700); + } + + .btn-primary { + --bl-btn-background: var(--bl-clr-primary-500); + --bl-btn-hover-background: var(--bl-clr-primary-600); + } + + .btn-danger { + --bl-btn-background: var(--bl-clr-red-700); + --bl-btn-hover-background: var(--bl-clr-red-800); + } + + .btn-ghost { + --bl-btn-background: transparent; + --bl-btn-color: var(--bl-clr-gray-200); + + &.btn-primary { + --bl-btn-hover-background: var(--bl-clr-primary-400); + } + + &.btn-danger { + --bl-btn-hover-background: var(--bl-clr-red-500); + } + + &.btn-primary:hover, + &.btn-danger:hover { + --bl-btn-color: var(--bl-clr-gray-900); + } + } + + .btn-outline { + --bl-btn-background: transparent; + --bl-btn-hover-background: var(--bl-clr-gray-800); + --bl-btn-color: var(--bl-clr-gray-200); + --bl-btn-border: 1px solid var(--bl-clr-gray-700); + + &.btn-primary { + --bl-btn-color: var(--bl-clr-primary-400); + --bl-btn-border: 1px solid var(--bl-clr-primary-400); + --bl-btn-hover-background: var(--bl-clr-primary-900); + } + + &.btn-danger { + --bl-btn-color: var(--bl-clr-red-400); + --bl-btn-border: 1px solid var(--bl-clr-red-400); + --bl-btn-hover-background: var(--bl-clr-red-900); + } + } +} + @keyframes spin { to { transform: rotate(360deg); diff --git a/src/button/button.stories.ts b/src/button/button.stories.ts index ad66bc3..252ee13 100644 --- a/src/button/button.stories.ts +++ b/src/button/button.stories.ts @@ -1,17 +1,22 @@ import type { Meta, StoryObj } from "@storybook/html"; -type ButtonArgs = { +export type ButtonArgs = { label: string; - type: string; + color: string; + variant: string; isLoading: boolean; }; const meta: Meta = { title: "Button", argTypes: { - type: { + color: { control: "select", - options: ["primary", "secondary", "ghost"], + options: ["default", "primary", "danger"], + }, + variant: { + control: "select", + options: ["default", "outline", "ghost"], }, isLoading: { control: "boolean", @@ -22,10 +27,16 @@ const meta: Meta = { btn.innerText = args.label; btn.classList.add("btn"); - if (args.type === "primary") { + if (args.color === "primary") { btn.classList.add("btn-primary"); - } else if (args.type === "ghost") { + } else if (args.color === "danger") { + btn.classList.add("btn-danger"); + } + + if (args.variant === "ghost") { btn.classList.add("btn-ghost"); + } else if (args.variant === "outline") { + btn.classList.add("btn-outline"); } if (args.isLoading) { @@ -42,7 +53,8 @@ type Story = StoryObj; export const Primary: Story = { args: { label: "Press me", - type: "primary", + color: "primary", + variant: "default", isLoading: false, }, }; @@ -50,26 +62,6 @@ export const Primary: Story = { export const Secondary: Story = { args: { ...Primary.args, - type: "secondary", - }, -}; - -export const WithIcon: Story = { - render: (args) => { - const btn = document.createElement("button"); - btn.classList.add("btn"); - const icon = document.createElement("i"); - icon.classList.add("fas", "fa-save"); - btn.appendChild(icon); - btn.appendChild(document.createTextNode(args.label)); - - if (args.isLoading) { - btn.classList.add("btn-loading"); - } - - return btn; - }, - args: { - label: "Press me", + color: "default", }, }; diff --git a/src/button/icon-button.stories.ts b/src/button/icon-button.stories.ts index ef8cd5c..5cf386c 100644 --- a/src/button/icon-button.stories.ts +++ b/src/button/icon-button.stories.ts @@ -1,16 +1,16 @@ import type { Meta, StoryObj } from "@storybook/html"; - -type ButtonArgs = { - type: string; - isLoading: boolean; -}; +import { ButtonArgs } from "./button.stories"; const meta: Meta = { title: "Icon button", argTypes: { - type: { + color: { + control: "select", + options: ["default", "primary", "danger"], + }, + variant: { control: "select", - options: ["primary", "secondary", "ghost"], + options: ["default", "outline", "ghost"], }, isLoading: { control: "boolean", @@ -22,10 +22,16 @@ const meta: Meta = { btn.classList.add("btn", "btn-icon"); btn.ariaLabel = "Save"; - if (args.type === "primary") { + if (args.color === "primary") { btn.classList.add("btn-primary"); - } else if (args.type === "ghost") { + } else if (args.color === "danger") { + btn.classList.add("btn-danger"); + } + + if (args.variant === "ghost") { btn.classList.add("btn-ghost"); + } else if (args.variant === "outline") { + btn.classList.add("btn-outline"); } if (args.isLoading) { @@ -41,14 +47,15 @@ type Story = StoryObj; export const Primary: Story = { args: { - type: "primary", + color: "primary", + variant: "default", isLoading: false, }, }; -export const Secondary: Story = { +export const Outline: Story = { args: { ...Primary.args, - type: "secondary", + variant: "outline", }, }; diff --git a/src/select/Select.stories.ts b/src/select/Select.stories.ts deleted file mode 100644 index 09cf0d4..0000000 --- a/src/select/Select.stories.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { StoryObj, Meta } from "@storybook/html"; -import { SelectProps } from "./Select"; - -const meta = { - title: "Select", - tags: ["autodocs"], - render: (args) => { - return ` -
Option 1
-
Option 2
-
Option 3
-
Option 4
-
`; - }, - argTypes: {}, - args: { - placeholder: "Select an option", - searchable: false, - clearable: false, - multiple: false, - disabled: false, - noResultsText: "No results found", - }, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Basic: Story = { - args: {}, -}; diff --git a/src/style.css b/src/style.css index 0fea180..757c00d 100644 --- a/src/style.css +++ b/src/style.css @@ -9,7 +9,17 @@ @import "button/button.css"; :root { - --bl-clr-primary: #006aa6; + --bl-clr-primary-50: var(--bl-clr-teal-50); + --bl-clr-primary-100: var(--bl-clr-teal-100); + --bl-clr-primary-200: var(--bl-clr-teal-200); + --bl-clr-primary-300: var(--bl-clr-teal-300); + --bl-clr-primary-400: var(--bl-clr-teal-400); + --bl-clr-primary-500: var(--bl-clr-teal-500); + --bl-clr-primary-600: var(--bl-clr-teal-600); + --bl-clr-primary-700: var(--bl-clr-teal-700); + --bl-clr-primary-800: var(--bl-clr-teal-800); + --bl-clr-primary-900: var(--bl-clr-teal-900); + --bl-clr-primary-950: var(--bl-clr-teal-950); --bl-clr-text: var(--bl-clr-gray-900); @@ -37,6 +47,18 @@ --bl-clr-blue-900: #1e3a8a; --bl-clr-blue-950: #172554; + --bl-clr-teal-50: #f0fdfa; + --bl-clr-teal-100: #ccfbf1; + --bl-clr-teal-200: #99f6e4; + --bl-clr-teal-300: #5eead4; + --bl-clr-teal-400: #2dd4bf; + --bl-clr-teal-500: #14b8a6; + --bl-clr-teal-600: #0d9488; + --bl-clr-teal-700: #0f766e; + --bl-clr-teal-800: #115e59; + --bl-clr-teal-900: #134e4a; + --bl-clr-teal-950: #042f2e; + --bl-clr-red-50: #fef2f2; --bl-clr-red-100: #fee2e2; --bl-clr-red-200: #fecaca;