diff --git a/bin/create_component.sh b/bin/create_component.sh index bbf72860..7b6a2a11 100755 --- a/bin/create_component.sh +++ b/bin/create_component.sh @@ -118,4 +118,4 @@ create_component_file $component_name_lowercase $component_dir # Update components/index.ts file update_index_file -echo "Component '$component_name' created successfully." +echo "Component '$component_name_lowercase' created successfully." diff --git a/package-lock.json b/package-lock.json index 2818501a..0871d5fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "license": "MIT", "dependencies": { + "@heroicons/react": "^2.1.1", "clsx": "^2.1.0" }, "devDependencies": { @@ -37,6 +38,7 @@ "http-server": "^14.1.1", "husky": "^8.0.3", "lint-staged": "^15.2.0", + "postcss-url": "^10.1.3", "prettier": "^3.1.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -2672,6 +2674,14 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@heroicons/react": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.1.tgz", + "integrity": "sha512-JyyN9Lo66kirbCMuMMRPtJxtKJoIsXKS569ebHGGRKbl8s4CtUfLnyKJxteA+vIKySocO4s1SkTkGS4xtG/yEA==", + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -10941,6 +10951,12 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "dev": true }, + "node_modules/cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", + "dev": true + }, "node_modules/cwd": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", @@ -17943,8 +17959,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "3.14.1", @@ -18560,7 +18575,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -19477,7 +19491,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -20868,6 +20881,58 @@ "postcss": "^8.2.15" } }, + "node_modules/postcss-url": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz", + "integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==", + "dev": true, + "dependencies": { + "make-dir": "~3.1.0", + "mime": "~2.5.2", + "minimatch": "~3.0.4", + "xxhashjs": "~0.2.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-url/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/postcss-url/node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss-url/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -21292,7 +21357,6 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -24910,6 +24974,15 @@ "node": ">=0.4" } }, + "node_modules/xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "dependencies": { + "cuint": "^0.2.2" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index a4d11861..8f0eb323 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "http-server": "^14.1.1", "husky": "^8.0.3", "lint-staged": "^15.2.0", + "postcss-url": "^10.1.3", "prettier": "^3.1.1", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -83,6 +84,7 @@ "readme": "ERROR: No README data found!", "_id": "maykin-ui@0.0.0", "dependencies": { + "@heroicons/react": "^2.1.1", "clsx": "^2.1.0" } } diff --git a/rollup.config.mjs b/rollup.config.mjs index 161b68af..0de34551 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -4,6 +4,7 @@ import terser from "@rollup/plugin-terser"; import typescript from "@rollup/plugin-typescript"; import peerDepsExternal from "rollup-plugin-peer-deps-external"; import postcss from "rollup-plugin-postcss"; +import postcss_url from "postcss-url"; export default [ { @@ -24,6 +25,12 @@ export default [ extract: true, minimize: true, sourceMap: true, + plugins: [ + postcss_url({ + basePath: process.cwd(), + url: 'inline' + }), + ], }), terser(), ], diff --git a/src/components/button/button.scss b/src/components/button/button.scss new file mode 100644 index 00000000..3b7e41bb --- /dev/null +++ b/src/components/button/button.scss @@ -0,0 +1,57 @@ +@use '../../settings/style'; + +.mykn-button { + --mykn-button-color-background: var(--theme-color-primary-800); + --mykn-button-color-shadow: var(--theme-shade-1000); + --mykn-button-color-text: var(--theme-shade-0); + --mykn-button-offset: 0px; + + appearance: none; + margin: 0; + padding: var(--spacing-v-s) var(--spacing-h-s); + background-color: var(--mykn-button-color-background); + border: 1px solid var(--mykn-button-color-border); + border-radius: 4px; + box-shadow: 0 calc(var(--mykn-button-offset) * -1) var(--mykn-button-color-shadow); + box-sizing: border-box; + color: var(--mykn-button-color-text); + cursor: pointer; + display: inline-block; + font-family: Inter, sans-serif; + font-size: var(--typography-font-size-body-s); + line-height: var(--typography-line-height-body-s); + text-align: center; + text-decoration: none; + transition: all var(--animation-duration) var(--animation-timing-function); + transform: translateY(var(--mykn-button-offset)); + + + &--variant-primary { + &:focus, + &:hover { + --mykn-button-color-background: var(--theme-color-primary-700); + --mykn-button-offset: -2px; + } + + &:active { + --mykn-button-color-background: var(--theme-color-primary-800); + --mykn-button-offset: 0px; + } + } + + &--variant-transparent { + --mykn-button-color-background: transparent; + --mykn-button-color-shadow: currentColor; + --mykn-button-color-text: var(--theme-shade-700); + + &:focus, + &:hover { + --mykn-button-color-background: var(--theme-color-primary-200); + --mykn-button-offset: -2px; + } + + &:active { + --mykn-button-offset: 0px; + } + } +} diff --git a/src/components/button/button.stories.tsx b/src/components/button/button.stories.tsx new file mode 100644 index 00000000..2baba761 --- /dev/null +++ b/src/components/button/button.stories.tsx @@ -0,0 +1,66 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { userEvent } from "@storybook/test"; +import React from "react"; + +import { Button, ButtonLink } from "./button"; + +const meta = { + title: "Controls/Button", + component: Button, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const ButtonComponent: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + }, +}; + +export const TransparentButton: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + variant: "transparent", + }, +}; + +export const ButtonAnimatesOnHoverAndClick: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + }, + play: async () => { + await userEvent.tab({ delay: 10 }); + }, +}; + +export const ButtonLinkComponent: StoryObj = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + href: "https://www.example.com", + target: "_blank", + }, + render: (args) => , +}; + +export const TransparentButtonLink: StoryObj = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + href: "https://www.example.com", + target: "_blank", + variant: "transparent", + }, + render: (args) => , +}; + +export const ButtonLinkAnimatesOnHoverAndClick: StoryObj = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + href: "https://www.example.com", + target: "_blank", + }, + play: async () => { + await userEvent.tab({ delay: 10 }); + }, + render: (args) => , +}; diff --git a/src/components/button/button.tsx b/src/components/button/button.tsx new file mode 100644 index 00000000..ca329cbb --- /dev/null +++ b/src/components/button/button.tsx @@ -0,0 +1,73 @@ +import clsx from "clsx"; +import React from "react"; + +import "./button.scss"; + +export type ButtonProps = React.PropsWithChildren<{ + variant?: "primary" | "transparent"; +}>; + +/** + * Higher-order component (HOC) applying button logic to WrappedComponent + * @param WrappedComponent + * @private + */ +const withButtonBehavior =

( + WrappedComponent: React.ComponentType

, +) => { + // Define the enhanced component + const EnhancedButton: React.FC

= ({ + children, + variant = "primary", + ...props + }) => { + return ( + + {children} + + ); + }; + + return EnhancedButton; +}; + +/** + * Base template for Button component + * @private + */ +const BaseButton: React.FC< + ButtonProps & React.ButtonHTMLAttributes +> = (props) => { + return ; +}; + +/** + * Base template for ButtonLink component + * @private + */ +const BaseButtonLink: React.FC< + ButtonProps & React.AnchorHTMLAttributes +> = (props) => { + return {props.children}; +}; + +/** + * Button component + * @param children + * @param type + * @param props + * @constructor + */ +export const Button = withButtonBehavior(BaseButton); + +/** + * Anchor () version of button component + * @param children + * @param type + * @param props + * @constructor + */ +export const ButtonLink = withButtonBehavior(BaseButtonLink); diff --git a/src/components/button/index.ts b/src/components/button/index.ts new file mode 100644 index 00000000..98d55acd --- /dev/null +++ b/src/components/button/index.ts @@ -0,0 +1 @@ +export * from "./button"; diff --git a/src/components/icon/icon.scss b/src/components/icon/icon.scss new file mode 100644 index 00000000..202258c4 --- /dev/null +++ b/src/components/icon/icon.scss @@ -0,0 +1,10 @@ +.mykn-icon { + height: 1.2em; + vertical-align: middle; + width: 1.2em; + margin: 0 0.5em; + + &:first-child { + margin-inline-start: 0; + } +} diff --git a/src/components/icon/icon.stories.tsx b/src/components/icon/icon.stories.tsx new file mode 100644 index 00000000..68d22dd0 --- /dev/null +++ b/src/components/icon/icon.stories.tsx @@ -0,0 +1,112 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; + +import { Button, ButtonLink } from "../button"; +import { Body, H1, H2, H3, P } from "../typography"; +import { Outline, Solid } from "./icon"; + +const meta = { + title: "Icon/Icon", + parameters: { + docs: { + description: { + component: `Heroicons (https://heroicons.com/) are used for this project, wrappers are provided by the icon + component which finalizes the styling. Please use the wrapped versions instead of importing Heroicons directly. + FIXME: Auto-completion might not fully work. + + + import { Outline, Solid } from "maykin-ui/icon"; + + `, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const AllIcons: Story = { + args: {}, + render: () => { + return ( + <> +

Outline (click to copy)

+ {Object.entries(Outline).map(([name, Icon]) => ( + navigator.clipboard.writeText(``)} + /> + ))} + +

Solid (click to copy)

+ {Object.entries(Solid).map(([name, Icon]) => ( + navigator.clipboard.writeText(``)} + /> + ))} + + ); + }, +}; + +export const IconsInButtons: Story = { + args: {}, + render: () => { + return ( + <> + + + + + Click me! + + + + Click me! + + + ); + }, +}; + +export const IconsInTypographicComponents: Story = { + args: {}, + render: () => { + return ( + +

+ + The quick brown fox jumps over the lazy dog. +

+

+ + The quick brown fox jumps over the lazy dog. +

+

+ + The quick brown fox jumps over the lazy dog. +

+

+ + The quick brown fox jumps over the lazy dog. +

+

+ + The quick brown fox jumps over the lazy dog. +

+ + ); + }, +}; diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx new file mode 100644 index 00000000..8551e8e8 --- /dev/null +++ b/src/components/icon/icon.tsx @@ -0,0 +1,28 @@ +import * as outlineHeroIcons from "@heroicons/react/24/outline"; +import * as solidHeroIcons from "@heroicons/react/24/solid"; +import React from "react"; + +import "./icon.scss"; + +export type IconProps = React.SVGProps; + +/** + * Takes Object containing (Heroicons) React.FC components. Each component is + * mapped to implement IconProps. + * @param heroIcons e.g.: import * as heroIcons from "@heroicons/react/24/outline"; + */ +const mapIcons = (heroIcons: { [index: string]: React.FC }) => + Object.fromEntries( + Object.entries(heroIcons).map(([name, Component]) => { + const Icon = ({ ...props }: IconProps) => ( + + ); + + return [name, Icon]; + }), + ); + +const Outline = mapIcons(outlineHeroIcons); +const Solid = mapIcons(solidHeroIcons); + +export { Outline, Solid }; diff --git a/src/components/icon/index.ts b/src/components/icon/index.ts new file mode 100644 index 00000000..b975409a --- /dev/null +++ b/src/components/icon/index.ts @@ -0,0 +1 @@ +export * from "./icon"; diff --git a/src/components/index.ts b/src/components/index.ts index 6b1afc76..3fd9914f 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,4 +1,8 @@ // Auto-generated file. Do not modify manually. +export * from "./button"; +export * from "./icon"; export * from "./layout"; export * from "./logo"; export * from "./page"; +export * from "./toolbar"; +export * from "./typography"; diff --git a/src/components/layout/column/column.scss b/src/components/layout/column/column.scss index 9d068281..01aabd7e 100644 --- a/src/components/layout/column/column.scss +++ b/src/components/layout/column/column.scss @@ -1,33 +1,33 @@ -@import '../../../settings/style'; +@use "../../../settings/style"; .mykn-column { grid-column: auto / 6 span; -} -.mykn-column--debug { - outline: 1px solid blue; -} + &--debug { + outline: 1px solid blue; + } -.mykn-column--debug:before { - color: blue; - content: "Mobile (full span)"; - display: block; - font-family: monospace; - text-align: center; -} + &--debug:before { + color: blue; + content: "Mobile (full span)"; + display: block; + font-family: monospace; + text-align: center; + } -.mykn-column--debug[data-testid]:before { - content: attr(data-testid)!important; -} + &--debug[data-testid]:before { + content: attr(data-testid)!important; + } -@media screen and (min-width: $breakpoint-desktop) { - @for $i from 1 through 12 { - .mykn-column--span-#{$i} { - grid-column: auto / span #{$i}; - } + @media screen and (min-width: style.$breakpoint-desktop) { + @for $i from 1 through 12 { + &--span-#{$i} { + grid-column: auto / span #{$i}; + } - .mykn-column--debug.mykn-column--span-#{$i}:before { - content: "Span #{$i}"; + &--debug#{&}--span-#{$i}:before { + content: "Span #{$i}"; + } } } } diff --git a/src/components/layout/column/column.tsx b/src/components/layout/column/column.tsx index c976b6e2..71be986c 100644 --- a/src/components/layout/column/column.tsx +++ b/src/components/layout/column/column.tsx @@ -6,7 +6,7 @@ import "./column.scss"; export type ColumnProps = React.PropsWithChildren<{ span: number; - /** If set, show the outline of the column. */ + /** If set, show the Outline of the column. */ debug?: boolean; /** Gets passed as props. */ diff --git a/src/components/layout/container/container.scss b/src/components/layout/container/container.scss index ed09014f..926cde19 100644 --- a/src/components/layout/container/container.scss +++ b/src/components/layout/container/container.scss @@ -2,20 +2,20 @@ margin: 0 auto; max-width: 1240px; width: 100%; -} -.mykn-container--debug { - outline: 1px solid red; -} + &--debug { + outline: 1px solid red; + } -.mykn-container--debug[data-testid]:before { - content: attr(data-testid); - color: red; - display: block; - font-family: monospace; - text-align: center; -} + &--debug[data-testid]:before { + content: attr(data-testid); + color: red; + display: block; + font-family: monospace; + text-align: center; + } -.mykn-container--debug[data-testid]:before { - content: attr(data-testid); + &--debug[data-testid]:before { + content: attr(data-testid); + } } diff --git a/src/components/layout/container/container.tsx b/src/components/layout/container/container.tsx index 09e9aa8e..e2a72c43 100644 --- a/src/components/layout/container/container.tsx +++ b/src/components/layout/container/container.tsx @@ -4,7 +4,7 @@ import React from "react"; import "./container.scss"; export type ContainerProps = React.PropsWithChildren<{ - /** If set, show the outline of the container. */ + /** If set, show the Outline of the container. */ debug?: boolean; /** Gets passed as props. */ diff --git a/src/components/layout/grid/grid.scss b/src/components/layout/grid/grid.scss index 8283701e..de591c5b 100644 --- a/src/components/layout/grid/grid.scss +++ b/src/components/layout/grid/grid.scss @@ -1,32 +1,32 @@ -@import '../../../settings/style'; +@use "../../../settings/style"; .mykn-grid { display: grid; grid-template-columns: repeat(6, auto); gap: 12px; width: 100%; -} -.mykn-grid--debug { - outline: 1px solid green; -} + &--debug { + outline: 1px solid green; + } -.mykn-grid--debug[data-testid]:before { - content: attr(data-testid); - color: green; - display: block; - font-family: monospace; - grid-column: 1 / 12 span; - text-align: center; -} + &--debug[data-testid]:before { + content: attr(data-testid); + color: green; + display: block; + font-family: monospace; + grid-column: 1 / 12 span; + text-align: center; + } -.mykn-grid--debug[data-testid]:before { - content: attr(data-testid); -} + &--debug[data-testid]:before { + content: attr(data-testid); + } -@media screen and (min-width: $breakpoint-desktop) { - .mykn-grid { - grid-template-columns: repeat(12, auto); - gap: 32px; + @media screen and (min-width: style.$breakpoint-desktop) { + & { + grid-template-columns: repeat(12, auto); + gap: 32px; + } } } diff --git a/src/components/layout/grid/grid.tsx b/src/components/layout/grid/grid.tsx index 4e7e1681..3ab9363d 100644 --- a/src/components/layout/grid/grid.tsx +++ b/src/components/layout/grid/grid.tsx @@ -4,7 +4,7 @@ import React from "react"; import "./grid.scss"; export type GridProps = React.PropsWithChildren<{ - /** If set, show the outline of the grid. */ + /** If set, show the Outline of the grid. */ debug?: boolean; /** Gets passed as props. */ diff --git a/src/components/logo/logo.scss b/src/components/logo/logo.scss index 28e2236e..8c77a252 100644 --- a/src/components/logo/logo.scss +++ b/src/components/logo/logo.scss @@ -1,30 +1,30 @@ -@import '../../settings/style'; +.mykn-logo { + &__image { + width: 100%; + object-fit: contain; + max-width: 155px; + overflow: visible; + } -.mykn-logo .mykn-logo__image { - width: 100%; - object-fit: contain; - max-width: 155px; - overflow: visible; -} - -.mykn-logo .mykn-logo__handle { - transition: transform var(--animation-duration) var(--animation-timing-function); -} + & &__handle { + transition: transform var(--animation-duration) var(--animation-timing-function); + } -.mykn-logo[href]:hover .mykn-logo__handle--left, -.mykn-logo[href]:focus .mykn-logo__handle--left { - transform: translateX(-2px); -} + &[href]:hover &__handle--left, + &[href]:focus &__handle--left { + transform: translateX(-2px); + } -.mykn-logo[href]:active .mykn-logo__handle--left { - transform: translateX(2px); -} + &[href]:active &__handle--left { + transform: translateX(2px); + } -.mykn-logo[href]:hover .mykn-logo__handle--right, -.mykn-logo[href]:focus .mykn-logo__handle--right { - transform: translateX(2px); -} + &[href]:hover &__handle--right, + &[href]:focus &__handle--right { + transform: translateX(2px); + } -.mykn-logo[href]:active .mykn-logo__handle--right { - transform: translateX(-2px); + &[href]:active &__handle--right { + transform: translateX(-2px); + } } diff --git a/src/components/logo/logo.tsx b/src/components/logo/logo.tsx index d5ccf1c1..e4097969 100644 --- a/src/components/logo/logo.tsx +++ b/src/components/logo/logo.tsx @@ -12,6 +12,7 @@ export type LogoProps = { /** An aria-label describing the link action. */ hrefLabel?: string; + /** Gets passed as props. */ [index: string]: unknown; }; diff --git a/src/components/page/page.scss b/src/components/page/page.scss index a4b06ce9..8704c87a 100644 --- a/src/components/page/page.scss +++ b/src/components/page/page.scss @@ -1,5 +1,3 @@ -@import "../../settings/style"; - .mykn-page { background-color: var(--theme-color-primary-200); box-sizing: border-box; diff --git a/src/components/page/page.stories.tsx b/src/components/page/page.stories.tsx index 9cdf0fd0..6a0bc8a8 100644 --- a/src/components/page/page.stories.tsx +++ b/src/components/page/page.stories.tsx @@ -1,21 +1,28 @@ import type { Meta, StoryObj } from "@storybook/react"; import React from "react"; +import { Button, ButtonLink } from "../button"; +import { Outline } from "../icon"; import { Container, Grid } from "../layout"; import { Column } from "../layout/column"; import { Logo } from "../logo"; +import { Toolbar } from "../toolbar"; import { Page } from "./page"; +type PagePropsAndCustomArgs = React.ComponentProps & { + debug?: boolean; +}; + const meta = { title: "Building Blocks/Page", component: Page, parameters: { layout: "fullscreen", }, -} satisfies Meta; +} satisfies Meta; export default meta; -type Story = StoryObj; +type Story = StoryObj; export const PageComponent: Story = { args: { @@ -25,18 +32,49 @@ export const PageComponent: Story = { export const SamplePage: Story = { args: { - children: ( - - - + debug: false, + }, + render: ({ debug }) => ( + + + + + + + + + + + + + + Admin + + + + + - ), - }, + + ), }; diff --git a/src/components/toolbar/index.ts b/src/components/toolbar/index.ts new file mode 100644 index 00000000..cd2701db --- /dev/null +++ b/src/components/toolbar/index.ts @@ -0,0 +1 @@ +export * from "./toolbar"; diff --git a/src/components/toolbar/toolbar.scss b/src/components/toolbar/toolbar.scss new file mode 100644 index 00000000..879c0965 --- /dev/null +++ b/src/components/toolbar/toolbar.scss @@ -0,0 +1,50 @@ +@use '../../settings/style'; + +.mykn-toolbar { + $self: &; + column-gap: 24px; + display: flex; + flex-direction: column; + justify-content: flex-start; + row-gap: 12px; + text-align: start; + + &--align-center { + justify-content: center; + text-align: center; + } + + &--align-end { + justify-content: end; + text-align: end; + } + + &--align-center { + justify-content: center; + text-align: center; + } + + @media screen and (min-width: style.$breakpoint-desktop) { + &--direction-horizontal { + align-items: center; + flex-direction: row; + } + } + + &--pad-a .mykn-a { + padding: var(--spacing-v-s) var(--spacing-h-s); + } + + .mykn-a { + text-decoration: none; + color: var(--theme-color-body); + + &[aria-current] { + color: var(--theme-color-primary-800) + } + + &:hover { + text-decoration: underline; + } + } +} diff --git a/src/components/toolbar/toolbar.stories.tsx b/src/components/toolbar/toolbar.stories.tsx new file mode 100644 index 00000000..ec6dae02 --- /dev/null +++ b/src/components/toolbar/toolbar.stories.tsx @@ -0,0 +1,192 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; + +import { Button, ButtonLink } from "../button"; +import { Outline } from "../icon"; +import { A } from "../typography"; +import { Toolbar } from "./toolbar"; + +const meta = { + title: "Controls/Toolbar", + component: Toolbar, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const ToolbarComponent: Story = { + args: { + align: "end", + children: ( + <> + + + + + + + Admin + + + + + ), + }, +}; + +export const ToolbarOnMobile = { + args: { + align: "end", + children: ( + <> + + + + + + + Admin + + + + + ), + }, + parameters: { + viewport: { defaultViewport: "mobile1" }, + }, +}; + +export const VerticalToolbar: Story = { + args: { + direction: "vertical", + children: ( + <> + + + + + + + Admin + + + + + ), + }, +}; + +export const ToolbarWithLinks: Story = { + args: { + direction: "vertical", + children: ( + <> +
+ Structuur + + + + Basisinformatie + + + + Statussen + + + + Documenten + + + + Rollen + + + + Eigenshappen + + + + Resultaten + + + + Relaties + + + + Objecten + + + ), + }, +}; + +export const MixedToolbar: Story = { + args: { + align: "center", + direction: "vertical", + padA: true, + children: ( + <> + + + Relaties + + + + + + + Admin + + + ), + }, +}; diff --git a/src/components/toolbar/toolbar.tsx b/src/components/toolbar/toolbar.tsx new file mode 100644 index 00000000..a0334c75 --- /dev/null +++ b/src/components/toolbar/toolbar.tsx @@ -0,0 +1,50 @@ +import clsx from "clsx"; +import React from "react"; + +import "./toolbar.scss"; + +export type ToolbarProps = React.PropsWithChildren< + React.HTMLAttributes & { + /** Aligns the contents based on the current direction. */ + align?: "start" | "center" | "end"; + + /** Whether the toolbar shows items horizontally or vertically, mobile devices always use vertical. */ + direction?: "horizontal" | "vertical"; + + /** When set to true, padding is applied to A components to match Button component's height. */ + padA?: boolean; + } +>; + +/** + * A flexible and customizable toolbar component for arranging and aligning + * various interactive elements such as buttons, links, or other components. + * @param children + * @param align + * @param direction + * @param padA + * @param props + * @constructor + */ +export const Toolbar: React.FC = ({ + children, + align = "start", + direction = "horizontal", + padA = false, + ...props +}) => ( + +); diff --git a/src/components/typography/99-typography.stories.tsx b/src/components/typography/99-typography.stories.tsx new file mode 100644 index 00000000..b3bce3f2 --- /dev/null +++ b/src/components/typography/99-typography.stories.tsx @@ -0,0 +1,28 @@ +import type { Meta } from "@storybook/react"; +import React from "react"; + +import { H1 } from "./h1"; +import { H2 } from "./h2"; +import { H3 } from "./h3"; +import { P } from "./p"; + +const meta = { + title: "Typography/Reference", + render: (args) => ( + <> +

{args.children}

+

{args.children}

+

{args.children}

+

{args.children}

+

{args.children}

+ + ), +} satisfies Meta; + +export default meta; + +export const Sizes = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + }, +}; diff --git a/src/components/typography/a/a.scss b/src/components/typography/a/a.scss new file mode 100644 index 00000000..73c65d58 --- /dev/null +++ b/src/components/typography/a/a.scss @@ -0,0 +1,14 @@ +@use '../p/p'; + +.mykn-a { + @extend .mykn-p; + color: var(--theme-color-primary-800); + + &:hover { + text-decoration: none; + } + + &[aria-current] { + font-weight: var(--typography-font-weight-bold); + } +} diff --git a/src/components/typography/a/a.stories.tsx b/src/components/typography/a/a.stories.tsx new file mode 100644 index 00000000..316b0023 --- /dev/null +++ b/src/components/typography/a/a.stories.tsx @@ -0,0 +1,19 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { A } from "./a"; + +const meta = { + title: "Typography/A", + component: A, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const AComponent: Story = { + args: { + children: "Click me!", + href: "https://www.example.com", + target: "_blank", + }, +}; diff --git a/src/components/typography/a/a.tsx b/src/components/typography/a/a.tsx new file mode 100644 index 00000000..db20686a --- /dev/null +++ b/src/components/typography/a/a.tsx @@ -0,0 +1,24 @@ +import React, { AnchorHTMLAttributes } from "react"; + +import "./a.scss"; + +export type AProps = AnchorHTMLAttributes & { + /** + * This sets aria-current on the , (visually) indicating that this element represents the current item within a + * container or set of related elements. + */ + active?: boolean; +}; + +/** + * Anchor () component + * @param active + * @param children + * @param props + * @constructor + */ +export const A: React.FC = ({ active, children, ...props }) => ( + + {children} + +); diff --git a/src/components/typography/a/index.ts b/src/components/typography/a/index.ts new file mode 100644 index 00000000..378dcf84 --- /dev/null +++ b/src/components/typography/a/index.ts @@ -0,0 +1 @@ +export * from "./a"; diff --git a/src/components/typography/body/body.scss b/src/components/typography/body/body.scss new file mode 100644 index 00000000..86c648d5 --- /dev/null +++ b/src/components/typography/body/body.scss @@ -0,0 +1,14 @@ +@use "../../../settings/style"; + +.mykn-body { + .mykn-h1, + .mykn-h2, + .mykn-h3, + .mykn-p, + .mykn-ol, + .mykn-ul { + &:not(:last-child) { + margin-bottom: 16px; + } + } +} diff --git a/src/components/typography/body/body.stories.tsx b/src/components/typography/body/body.stories.tsx new file mode 100644 index 00000000..360ffbac --- /dev/null +++ b/src/components/typography/body/body.stories.tsx @@ -0,0 +1,87 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; + +import { A } from "../a"; +import { H1 } from "../h1"; +import { H2 } from "../h2"; +import { H3 } from "../h3"; +import { LI } from "../li"; +import { OL } from "../ol"; +import { P } from "../p"; +import { UL } from "../ul"; +import { Body } from "./body"; + +const meta = { + title: "Typography/Body", + component: Body, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const BodyComponent: Story = { + args: { + children: ( + <> +

Lorem ipsum dolor sit ament

+

+ + Lorem ipsum + {" "} + dolor sit amet, consectetur adipiscing elit. Nullam non faucibus + lorem, nec egestas ante. Donec in erat nec ligula pulvinar dictum in + at nunc. Ut placerat, metus nec condimentum tincidunt, mauris lectus + bibendum est, id sagittis leo orci tincidunt ligula. Suspendisse ut + nunc at diam commodo placerat. +

+ +

Lorem ipsum dolor sit ament

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam non + faucibus lorem, nec egestas ante. Donec in erat nec ligula pulvinar + dictum in at nunc. Ut placerat, metus nec condimentum tincidunt, + mauris lectus bibendum est, id sagittis leo orci tincidunt ligula. + Suspendisse ut nunc at diam commodo placerat. Sed a ligula nec felis + ornare feugiat. Praesent eu mauris in nunc pellentesque congue. Proin + vulputate non augue ac fermentum. Etiam placerat commodo maximus. + Class aptent taciti sociosqu ad litora torquent per conubia nostra, + per inceptos himenaeos. Praesent lobortis ultrices enim, ut dignissim + felis molestie ut. Sed urna quam, venenatis eu orci eget, iaculis + vehicula eros. Nam eget ornare nulla. Quisque aliquam ultrices elit et + viverra. +

+ +

Lorem ipsum dolor sit ament

+

Lorem ipsum dolor sit amet.

+ + + +
    +
  1. + + Lorem ipsum dolor sit amet. + +
  2. +
  3. Consectetur adipiscing elit.
  4. +
  5. Nullam non faucibus lorem, nec egestas ante.
  6. +
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam non + faucibus lorem, nec egestas ante. Donec in erat nec ligula pulvinar + dictum in at nunc. Ut placerat, metus nec condimentum tincidunt, + mauris lectus bibendum est, id sagittis leo orci tincidunt ligula. + Suspendisse ut nunc at diam commodo placerat. +

+ + ), + }, +}; diff --git a/src/components/typography/body/body.tsx b/src/components/typography/body/body.tsx new file mode 100644 index 00000000..c53322c9 --- /dev/null +++ b/src/components/typography/body/body.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +import "./body.scss"; + +export type BodyProps = React.PropsWithChildren<{ + // Props here. +}>; + +/** + * Provides styling (e.g. margins) for a group of typographic components. + * @param children + * @param props + * @constructor + */ +export const Body: React.FC = ({ children, ...props }) => ( +
+ {children} +
+); diff --git a/src/components/typography/body/index.ts b/src/components/typography/body/index.ts new file mode 100644 index 00000000..93f45293 --- /dev/null +++ b/src/components/typography/body/index.ts @@ -0,0 +1 @@ +export * from "./body"; diff --git a/src/components/typography/h1/h1.scss b/src/components/typography/h1/h1.scss new file mode 100644 index 00000000..971368dd --- /dev/null +++ b/src/components/typography/h1/h1.scss @@ -0,0 +1,11 @@ +@use "../../../settings/style"; + +.mykn-h1 { + color: var(--typography-color-h); + font-family: Inter, sans-serif; + font-size: var(--typography-font-size-h1); + font-weight: var(--typography-font-weight-bold); + line-height: var(--typography-line-height-h1); + margin-top: 0; + margin-bottom: 0; +} diff --git a/src/components/typography/h1/h1.stories.tsx b/src/components/typography/h1/h1.stories.tsx new file mode 100644 index 00000000..ffe6293b --- /dev/null +++ b/src/components/typography/h1/h1.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { H1 } from "./h1"; + +const meta = { + title: "Typography/H1", + component: H1, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const H1Component: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + }, +}; diff --git a/src/components/typography/h1/h1.tsx b/src/components/typography/h1/h1.tsx new file mode 100644 index 00000000..0fa8cfc0 --- /dev/null +++ b/src/components/typography/h1/h1.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +import "./h1.scss"; + +export type H1Props = React.PropsWithChildren<{ + // Props here. +}>; + +/** + * H1 component + * @param children + * @param props + * @constructor + */ +export const H1: React.FC = ({ children, ...props }) => ( +

+ {children} +

+); diff --git a/src/components/typography/h1/index.ts b/src/components/typography/h1/index.ts new file mode 100644 index 00000000..a9dd1272 --- /dev/null +++ b/src/components/typography/h1/index.ts @@ -0,0 +1 @@ +export * from "./h1"; diff --git a/src/components/typography/h2/h2.scss b/src/components/typography/h2/h2.scss new file mode 100644 index 00000000..24f068d8 --- /dev/null +++ b/src/components/typography/h2/h2.scss @@ -0,0 +1,11 @@ +@use "../../../settings/style"; + +.mykn-h2 { + color: var(--typography-color-h); + font-family: Inter, sans-serif; + font-size: var(--typography-font-size-h2); + font-weight: var(--typography-font-weight-bold); + line-height: var(--typography-line-height-h2); + margin-top: 0; + margin-bottom: 0; +} diff --git a/src/components/typography/h2/h2.stories.tsx b/src/components/typography/h2/h2.stories.tsx new file mode 100644 index 00000000..faa0eadc --- /dev/null +++ b/src/components/typography/h2/h2.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { H2 } from "./h2"; + +const meta = { + title: "Typography/H2", + component: H2, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const H2Component: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + }, +}; diff --git a/src/components/typography/h2/h2.tsx b/src/components/typography/h2/h2.tsx new file mode 100644 index 00000000..4ea9cca0 --- /dev/null +++ b/src/components/typography/h2/h2.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +import "./h2.scss"; + +export type H2Props = React.PropsWithChildren<{ + // Props here. +}>; + +/** + * H2 component + * @param children + * @param props + * @constructor + */ +export const H2: React.FC = ({ children, ...props }) => ( +

+ {children} +

+); diff --git a/src/components/typography/h2/index.ts b/src/components/typography/h2/index.ts new file mode 100644 index 00000000..e48baaaa --- /dev/null +++ b/src/components/typography/h2/index.ts @@ -0,0 +1 @@ +export * from "./h2"; diff --git a/src/components/typography/h3/h3.scss b/src/components/typography/h3/h3.scss new file mode 100644 index 00000000..212af7c0 --- /dev/null +++ b/src/components/typography/h3/h3.scss @@ -0,0 +1,11 @@ +@use "../../../settings/style"; + +.mykn-h3 { + color: var(--typography-color-h); + font-family: Inter, sans-serif; + font-size: var(--typography-font-size-h3); + font-weight: var(--typography-font-weight-bold); + line-height: var(--typography-line-height-h3); + margin-top: 0; + margin-bottom: 0; +} diff --git a/src/components/typography/h3/h3.stories.tsx b/src/components/typography/h3/h3.stories.tsx new file mode 100644 index 00000000..99cbe117 --- /dev/null +++ b/src/components/typography/h3/h3.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { H3 } from "./h3"; + +const meta = { + title: "Typography/H3", + component: H3, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const H3Component: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + }, +}; diff --git a/src/components/typography/h3/h3.tsx b/src/components/typography/h3/h3.tsx new file mode 100644 index 00000000..206871b7 --- /dev/null +++ b/src/components/typography/h3/h3.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +import "./h3.scss"; + +export type H3Props = React.PropsWithChildren<{ + // Props here. +}>; + +/** + * H3 component + * @param children + * @param props + * @constructor + */ +export const H3: React.FC = ({ children, ...props }) => ( +

+ {children} +

+); diff --git a/src/components/typography/h3/index.ts b/src/components/typography/h3/index.ts new file mode 100644 index 00000000..d95203c9 --- /dev/null +++ b/src/components/typography/h3/index.ts @@ -0,0 +1 @@ +export * from "./h3"; diff --git a/src/components/typography/index.ts b/src/components/typography/index.ts new file mode 100644 index 00000000..237670e9 --- /dev/null +++ b/src/components/typography/index.ts @@ -0,0 +1,6 @@ +export * from "./a"; +export * from "./body"; +export * from "./h1"; +export * from "./h2"; +export * from "./h3"; +export * from "./p"; diff --git a/src/components/typography/li/index.ts b/src/components/typography/li/index.ts new file mode 100644 index 00000000..2d17d5a9 --- /dev/null +++ b/src/components/typography/li/index.ts @@ -0,0 +1 @@ +export * from "./li"; diff --git a/src/components/typography/li/li.scss b/src/components/typography/li/li.scss new file mode 100644 index 00000000..b99004f0 --- /dev/null +++ b/src/components/typography/li/li.scss @@ -0,0 +1,6 @@ +@use "../../../settings/style"; +@use '../p/p'; + +.mykn-li { + @extend .mykn-p +} diff --git a/src/components/typography/li/li.stories.tsx b/src/components/typography/li/li.stories.tsx new file mode 100644 index 00000000..6d9862ab --- /dev/null +++ b/src/components/typography/li/li.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { LI } from "./li"; + +const meta = { + title: "Typography/LI", + component: LI, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const LIComponent: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + size: "s", + }, +}; diff --git a/src/components/typography/li/li.tsx b/src/components/typography/li/li.tsx new file mode 100644 index 00000000..b754fb2b --- /dev/null +++ b/src/components/typography/li/li.tsx @@ -0,0 +1,20 @@ +import clsx from "clsx"; +import React from "react"; + +import { PProps } from "../p"; +import "./li.scss"; + +export type LIProps = PProps; + +/** + * LI component + * @param children + * @param size + * @param props + * @constructor + */ +export const LI: React.FC = ({ children, size = "s", ...props }) => ( +
  • + {children} +
  • +); diff --git a/src/components/typography/ol/index.ts b/src/components/typography/ol/index.ts new file mode 100644 index 00000000..79aa32f1 --- /dev/null +++ b/src/components/typography/ol/index.ts @@ -0,0 +1 @@ +export * from "./ol"; diff --git a/src/components/typography/ol/ol.scss b/src/components/typography/ol/ol.scss new file mode 100644 index 00000000..4918bef2 --- /dev/null +++ b/src/components/typography/ol/ol.scss @@ -0,0 +1,6 @@ +@use "../../../settings/style"; +@use '../p/p'; + +.mykn-ol { + @extend .mykn-p +} diff --git a/src/components/typography/ol/ol.stories.tsx b/src/components/typography/ol/ol.stories.tsx new file mode 100644 index 00000000..d5f88ce7 --- /dev/null +++ b/src/components/typography/ol/ol.stories.tsx @@ -0,0 +1,30 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; + +import { A } from "../a"; +import { LI } from "../li"; +import { OL } from "./ol"; + +const meta = { + title: "Typography/OL", + component: OL, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const OLComponent: Story = { + args: { + children: ( + <> +
  • + + Lorem ipsum dolor sit amet. + +
  • +
  • Consectetur adipiscing elit.
  • +
  • Nullam non faucibus lorem, nec egestas ante.
  • + + ), + }, +}; diff --git a/src/components/typography/ol/ol.tsx b/src/components/typography/ol/ol.tsx new file mode 100644 index 00000000..0f6127e1 --- /dev/null +++ b/src/components/typography/ol/ol.tsx @@ -0,0 +1,20 @@ +import clsx from "clsx"; +import React from "react"; + +import { PProps } from "../p"; +import "./ol.scss"; + +export type OLProps = PProps; + +/** + * OL component + * @param children + * @param size + * @param props + * @constructor + */ +export const OL: React.FC = ({ children, size = "s", ...props }) => ( +
      + {children} +
    +); diff --git a/src/components/typography/p/index.ts b/src/components/typography/p/index.ts new file mode 100644 index 00000000..83015b57 --- /dev/null +++ b/src/components/typography/p/index.ts @@ -0,0 +1 @@ +export * from "./p"; diff --git a/src/components/typography/p/p.scss b/src/components/typography/p/p.scss new file mode 100644 index 00000000..ea630d15 --- /dev/null +++ b/src/components/typography/p/p.scss @@ -0,0 +1,20 @@ +@use "../../../settings/style"; + +.mykn-p { + color: var(--typography-color-body); + font-family: Inter, sans-serif; + font-size: var(--typography-font-size-body-s); + font-weight: var(--typography-font-weight-normal); + line-height: var(--typography-line-height-body-s); + margin-top: 0; + margin-bottom: 0; + + &--size-xs { + font-size: var(--typography-font-size-body-xs); + line-height: var(--typography-line-height-body-xs); + } + + &--muted { + color: var(--typography-color-muted); + } +} diff --git a/src/components/typography/p/p.stories.tsx b/src/components/typography/p/p.stories.tsx new file mode 100644 index 00000000..b0e16cc7 --- /dev/null +++ b/src/components/typography/p/p.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { P } from "./p"; + +const meta = { + title: "Typography/P", + component: P, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const PComponent: Story = { + args: { + children: "The quick brown fox jumps over the lazy dog.", + size: "s", + }, +}; diff --git a/src/components/typography/p/p.tsx b/src/components/typography/p/p.tsx new file mode 100644 index 00000000..bbddf8fc --- /dev/null +++ b/src/components/typography/p/p.tsx @@ -0,0 +1,35 @@ +import clsx from "clsx"; +import React from "react"; + +import "./p.scss"; + +export type PProps = React.PropsWithChildren<{ + /** Whether the text should be presented in a lighter color. */ + muted?: boolean; + + /** The size of the text. */ + size?: "s" | "xs"; +}>; + +/** + * UL component + * @param children + * @param size + * @param props + * @constructor + */ +export const P: React.FC = ({ + children, + muted, + size = "s", + ...props +}) => ( +

    + {children} +

    +); diff --git a/src/components/typography/ul/index.ts b/src/components/typography/ul/index.ts new file mode 100644 index 00000000..31bacf42 --- /dev/null +++ b/src/components/typography/ul/index.ts @@ -0,0 +1 @@ +export * from "./ul"; diff --git a/src/components/typography/ul/ul.scss b/src/components/typography/ul/ul.scss new file mode 100644 index 00000000..205739ad --- /dev/null +++ b/src/components/typography/ul/ul.scss @@ -0,0 +1,6 @@ +@use "../../../settings/style"; +@use '../p/p'; + +.mykn-ul { + @extend .mykn-p +} diff --git a/src/components/typography/ul/ul.stories.tsx b/src/components/typography/ul/ul.stories.tsx new file mode 100644 index 00000000..19015d3b --- /dev/null +++ b/src/components/typography/ul/ul.stories.tsx @@ -0,0 +1,30 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import React from "react"; + +import { A } from "../a"; +import { LI } from "../li"; +import { UL } from "./ul"; + +const meta = { + title: "Typography/UL", + component: UL, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const ULComponent: Story = { + args: { + children: ( + <> +
  • + + Lorem ipsum dolor sit amet. + +
  • +
  • Consectetur adipiscing elit.
  • +
  • Nullam non faucibus lorem, nec egestas ante.
  • + + ), + }, +}; diff --git a/src/components/typography/ul/ul.tsx b/src/components/typography/ul/ul.tsx new file mode 100644 index 00000000..df9c3e78 --- /dev/null +++ b/src/components/typography/ul/ul.tsx @@ -0,0 +1,20 @@ +import clsx from "clsx"; +import React from "react"; + +import { PProps } from "../p"; +import "./ul.scss"; + +export type ULProps = PProps; + +/** + * UL component + * @param children + * @param size + * @param props + * @constructor + */ +export const UL: React.FC = ({ children, size = "s", ...props }) => ( +
      + {children} +
    +); diff --git a/src/fonts/Inter-VariableFont_slnt,wght.ttf b/src/fonts/Inter-VariableFont_slnt,wght.ttf new file mode 100644 index 00000000..e7247087 Binary files /dev/null and b/src/fonts/Inter-VariableFont_slnt,wght.ttf differ diff --git a/src/settings/_style.scss b/src/settings/_style.scss new file mode 100644 index 00000000..68027c24 --- /dev/null +++ b/src/settings/_style.scss @@ -0,0 +1,61 @@ +/// USE CSS VARIABLES WHERE POSSIBLE +:root { + /// ANIMATION + --animation-timing-function: ease-in-out; + --animation-duration: 0.1s; + + /// THEME + --theme-color-primary-800: #341A90; + --theme-color-primary-700: #5422B9; + --theme-color-primary-600: #8D75E6; + --theme-color-primary-400: #BDB0ED; + --theme-color-primary-200: #ECF1FF; /* FIXME? */ + + --theme-color-tertiary-800: #0F172A; + --theme-color-tertiary-700: #1E293B; + --theme-color-tertiary-600: #334155; + --theme-color-tertiary-400: #475569; + + --theme-shade-1000: #000; + --theme-shade-900: #272727; + --theme-shade-700: #545454; + --theme-shade-400: #B3B3B3; + --theme-shade-0: #FFF; + + /// SPACING + --spacing-h-s: 12px; + --spacing-v-s: 6px; + + /// TYPOGRAPHY + --typography-color-background: var(--theme-shade-0); + --typography-color-h: var(--theme-shade-900); + --typography-color-body: var(--theme-shade-700); + --typography-color-muted: var(--theme-shade-400); + + --typography-font-size-h1: 24px; + --typography-font-size-h2: 20px; + --typography-font-size-h3: 16px; + --typography-font-size-body-s: 14px; + --typography-font-size-body-xs: 12px; + + --typography-font-weight-bold: 700; + --typography-font-weight-normal: 400; + + --typography-line-height-h1: 24px; + --typography-line-height-h2: 24px; + --typography-line-height-h3: 24px; + --typography-line-height-body-s: 24px; + --typography-line-height-body-xs: 24px; +} + +/// SASS CONSTANTS AS FALLBACK +$breakpoint-desktop: 768px; + +/// ASSETS +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('/src/fonts/Inter-VariableFont_slnt,wght.ttf') format('truetype'); +} diff --git a/src/settings/style.scss b/src/settings/style.scss deleted file mode 100644 index 8bb18eb8..00000000 --- a/src/settings/style.scss +++ /dev/null @@ -1,23 +0,0 @@ -$breakpoint-desktop: 768px; - -:root { - --animation-timing-function: ease-in-out; - --animation-duration: 0.2s; - - --theme-color-primary-800: #341A90; - --theme-color-primary-700: #5422B9; - --theme-color-primary-600: #8D75E6; - --theme-color-primary-400: #BDB0ED; - --theme-color-primary-200: #ECF1FF; /* FIXME? */ - - --theme-shade-800: #0F172A; - --theme-shade-700: #1E293B; - --theme-shade-600: #334155; - --theme-shade-400: #475569; - - --theme-shade-1000: #000; - --theme-shade-0: #FFF; - - --typography-color-background: var(--theme-shade-0); - --typography-color-text: var(--theme-shade-1000); -} diff --git a/tsconfig.json b/tsconfig.json index ae4fb748..c5f96197 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "module": "ESNext", "target": "ESNext", "outDir": "dist", "strict": true,