From 09efae17c283d0b96efff2135dcf7e86a63d9258 Mon Sep 17 00:00:00 2001 From: puria Date: Sun, 28 Jan 2024 04:45:27 +0100 Subject: [PATCH 1/2] feat(button): Initial implementation --- .storybook/preview-head.html | 5 ++ src/components.d.ts | 23 ++++++- src/components/avatar/avatar.stories.ts | 2 +- src/components/avatar/avatar.tsx | 7 ++- src/components/avatar/test/avatar.spec.tsx | 6 +- src/components/button/button.stories.ts | 62 +++++++++++++++++++ src/components/button/d-button.scss | 31 ++++++++++ src/components/button/d-button.tsx | 34 ++++++++++ src/components/button/readme.md | 19 ++++++ src/components/button/test/d-button.e2e.ts | 11 ++++ src/components/button/test/d-button.spec.tsx | 20 ++++++ .../credential-card/d-credential-card.tsx | 14 ++--- .../d-credential-service.tsx | 2 +- src/components/types.ts | 10 +++ src/global/global.css | 4 ++ vscode-data.json | 21 +++++++ 16 files changed, 254 insertions(+), 17 deletions(-) create mode 100644 src/components/button/button.stories.ts create mode 100644 src/components/button/d-button.scss create mode 100644 src/components/button/d-button.tsx create mode 100644 src/components/button/readme.md create mode 100644 src/components/button/test/d-button.e2e.ts create mode 100644 src/components/button/test/d-button.spec.tsx diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index 0fecfc6..8ccd966 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -1,3 +1,8 @@ + diff --git a/src/components.d.ts b/src/components.d.ts index 295363b..298f1cd 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -5,8 +5,8 @@ * It contains typing information for all components that exist in this project. */ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal"; -import { Shape, Size } from "./components/types"; -export { Shape, Size } from "./components/types"; +import { Color, Shape, Size } from "./components/types"; +export { Color, Shape, Size } from "./components/types"; export namespace Components { interface DAvatar { "name"?: string; @@ -14,6 +14,11 @@ export namespace Components { "size"?: Size; "src"?: string; } + interface DButton { + "color"?: Color; + "disabled"?: boolean; + "href"?: string; + } interface DCredentialCard { "description"?: string; "expirationDate"?: string; @@ -37,6 +42,12 @@ declare global { prototype: HTMLDAvatarElement; new (): HTMLDAvatarElement; }; + interface HTMLDButtonElement extends Components.DButton, HTMLStencilElement { + } + var HTMLDButtonElement: { + prototype: HTMLDButtonElement; + new (): HTMLDButtonElement; + }; interface HTMLDCredentialCardElement extends Components.DCredentialCard, HTMLStencilElement { } var HTMLDCredentialCardElement: { @@ -51,6 +62,7 @@ declare global { }; interface HTMLElementTagNameMap { "d-avatar": HTMLDAvatarElement; + "d-button": HTMLDButtonElement; "d-credential-card": HTMLDCredentialCardElement; "d-credential-service": HTMLDCredentialServiceElement; } @@ -62,6 +74,11 @@ declare namespace LocalJSX { "size"?: Size; "src"?: string; } + interface DButton { + "color"?: Color; + "disabled"?: boolean; + "href"?: string; + } interface DCredentialCard { "description"?: string; "expirationDate"?: string; @@ -79,6 +96,7 @@ declare namespace LocalJSX { } interface IntrinsicElements { "d-avatar": DAvatar; + "d-button": DButton; "d-credential-card": DCredentialCard; "d-credential-service": DCredentialService; } @@ -88,6 +106,7 @@ declare module "@stencil/core" { export namespace JSX { interface IntrinsicElements { "d-avatar": LocalJSX.DAvatar & JSXBase.HTMLAttributes; + "d-button": LocalJSX.DButton & JSXBase.HTMLAttributes; "d-credential-card": LocalJSX.DCredentialCard & JSXBase.HTMLAttributes; "d-credential-service": LocalJSX.DCredentialService & JSXBase.HTMLAttributes; } diff --git a/src/components/avatar/avatar.stories.ts b/src/components/avatar/avatar.stories.ts index 8208a9b..83cab53 100644 --- a/src/components/avatar/avatar.stories.ts +++ b/src/components/avatar/avatar.stories.ts @@ -23,7 +23,7 @@ export const Rounded: Story = { parameters: { design: { type: 'figma', - url: 'https://www.figma.com/file/Klm6pxIZSaJFiOMX5FpTul9F/@storybook/addon-designs-sample', + url: 'https://www.figma.com/file/pdwfO3dMKtaCAQakht0JE6/DIDRoom-%2B-Signroom---WF-and-GUI---Dyne.org?type=design&node-id=2005-930&mode=dev', }, }, }; diff --git a/src/components/avatar/avatar.tsx b/src/components/avatar/avatar.tsx index 24f7ca4..3a21405 100644 --- a/src/components/avatar/avatar.tsx +++ b/src/components/avatar/avatar.tsx @@ -7,10 +7,11 @@ import { Shape, Size } from '../types'; shadow: true, }) export class Avatar { + @Prop() name?: string; + @Prop() size?: Size = 'm'; + @Prop() shape?: Shape = 'round'; @Prop({ reflect: true }) src?: string; - @Prop({ reflect: true }) name?: string; - @Prop({ reflect: true }) size?: Size = 'm'; - @Prop({ reflect: true }) shape?: Shape = 'round'; + @State() error: boolean = false; render() { diff --git a/src/components/avatar/test/avatar.spec.tsx b/src/components/avatar/test/avatar.spec.tsx index c28ec04..88fb50d 100644 --- a/src/components/avatar/test/avatar.spec.tsx +++ b/src/components/avatar/test/avatar.spec.tsx @@ -8,7 +8,7 @@ describe('d-avatar', () => { html: ``, }); expect(page.root).toEqualHtml(` - + @@ -24,7 +24,7 @@ describe('d-avatar', () => { html: ``, }); expect(root).toEqualHtml(` - + MC @@ -40,7 +40,7 @@ describe('d-avatar', () => { html: ``, }); expect(root).toEqualHtml(` - + diff --git a/src/components/button/button.stories.ts b/src/components/button/button.stories.ts new file mode 100644 index 0000000..4e10089 --- /dev/null +++ b/src/components/button/button.stories.ts @@ -0,0 +1,62 @@ +import { Meta, StoryObj } from '@storybook/html'; +import type { Components } from '../../components.js'; +import { ColorArgTypes } from '../types.js'; + +const meta = { + title: 'Design System/Atoms/Button', + render: args => `BUTTON`, + argTypes: { + disabled: { control: 'boolean', description: 'Disable the button' }, + color: ColorArgTypes, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + color: 'primary', + href: '#', + disabled: false, + }, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/pdwfO3dMKtaCAQakht0JE6/DIDRoom-%2B-Signroom---WF-and-GUI---Dyne.org?type=design&node-id=2584-15529&mode=design&t=7gAir6gIxMq07ebE-0', + }, + }, +}; + +export const Primary: Story = { + args: { + ...Default.args, + color: 'primary', + }, +}; +export const Accent: Story = { + args: { + ...Default.args, + color: 'accent', + }, +}; +export const AccentDisabled: Story = { + args: { + ...Default.args, + color: 'accent', + disabled: true, + }, +}; +export const PrimaryDisabled: Story = { + args: { + ...Default.args, + color: 'primary', + disabled: true, + }, +}; +export const Link: Story = { + args: { + ...Default.args, + href: '/', + }, +}; diff --git a/src/components/button/d-button.scss b/src/components/button/d-button.scss new file mode 100644 index 0000000..a5e51ca --- /dev/null +++ b/src/components/button/d-button.scss @@ -0,0 +1,31 @@ +:host > a, +:host > button { + @apply flex w-full justify-center items-center shrink-0 rounded px-0 py-2 text-center text-base not-italic font-semibold leading-8 tracking-[0.16px] uppercase; +} + +:host([disabled]:not([disabled='false'])) > a, +:host([disabled]:not([disabled='false'])) > button { + pointer-events: none; + cursor: not-allowed; + &.accent { + @apply opacity-30 text-opacity-30; + } + + &.primary { + @apply opacity-60 text-opacity-60; + } +} + +.accent { + @apply bg-accent text-on-accent; + &:active { + background: linear-gradient(0deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%), var(--accent); + } +} + +.primary { + @apply bg-primary text-on; + &:active { + background: linear-gradient(0deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.1) 100%), var(--primary); + } +} diff --git a/src/components/button/d-button.tsx b/src/components/button/d-button.tsx new file mode 100644 index 0000000..0ccb330 --- /dev/null +++ b/src/components/button/d-button.tsx @@ -0,0 +1,34 @@ +import { Component, Host, Prop, h } from '@stencil/core'; +import { Color } from '../types'; + +@Component({ + tag: 'd-button', + styleUrl: 'd-button.scss', + shadow: true, +}) +export class DButton { + @Prop() color?: Color = 'primary'; + // @Prop() outline?: boolean = false; + @Prop({ reflect: true }) href?: string; + @Prop({ reflect: true }) disabled?: boolean = false; + + render() { + if (this.href) { + return ( + + + + + + ); + } else { + return ( + + + + ); + } + } +} diff --git a/src/components/button/readme.md b/src/components/button/readme.md new file mode 100644 index 0000000..1467e82 --- /dev/null +++ b/src/components/button/readme.md @@ -0,0 +1,19 @@ +# d-button + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ---------- | ---------- | ----------- | --------- | ----------- | +| `color` | `color` | | `string` | `'primary'` | +| `disabled` | `disabled` | | `boolean` | `false` | +| `href` | `href` | | `string` | `undefined` | + + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/src/components/button/test/d-button.e2e.ts b/src/components/button/test/d-button.e2e.ts new file mode 100644 index 0000000..eee0ad3 --- /dev/null +++ b/src/components/button/test/d-button.e2e.ts @@ -0,0 +1,11 @@ +import { newE2EPage } from '@stencil/core/testing'; + +describe('d-button', () => { + it('renders', async () => { + const page = await newE2EPage(); + await page.setContent(''); + + const element = await page.find('d-button'); + expect(element).toHaveClass('hydrated'); + }); +}); diff --git a/src/components/button/test/d-button.spec.tsx b/src/components/button/test/d-button.spec.tsx new file mode 100644 index 0000000..b2d954f --- /dev/null +++ b/src/components/button/test/d-button.spec.tsx @@ -0,0 +1,20 @@ +import { newSpecPage } from '@stencil/core/testing'; +import { DButton } from '../d-button'; + +describe('d-button', () => { + it('renders', async () => { + const page = await newSpecPage({ + components: [DButton], + html: ``, + }); + expect(page.root).toEqualHtml(` + + + + + + `); + }); +}); diff --git a/src/components/credential-card/d-credential-card.tsx b/src/components/credential-card/d-credential-card.tsx index cd746be..e578bdd 100644 --- a/src/components/credential-card/d-credential-card.tsx +++ b/src/components/credential-card/d-credential-card.tsx @@ -32,15 +32,15 @@ const verifiedUser = ( tag: 'd-credential-card', styleUrl: 'd-credential-card.css', shadow: true, - assetsDirs: ['assets'] + assetsDirs: ['assets'], }) export class DCredentialCard { - @Prop({ reflect: true }) name: string; - @Prop({ reflect: true }) issuer: string; - @Prop({ reflect: true }) logoSrc?: string; - @Prop({ reflect: true }) description?: string; - @Prop({ reflect: true }) expirationDate?: string; - @Prop({ reflect: true }) verified?: boolean = false; + @Prop() name: string; + @Prop() issuer: string; + @Prop() logoSrc?: string; + @Prop() verified?: boolean = false; + @Prop() description?: string; + @Prop() expirationDate?: string; render() { // const imageSrc = getAssetPath(`./assets/Rectangle.png`); diff --git a/src/components/credential-service/d-credential-service.tsx b/src/components/credential-service/d-credential-service.tsx index a1fcbe1..b41f68a 100644 --- a/src/components/credential-service/d-credential-service.tsx +++ b/src/components/credential-service/d-credential-service.tsx @@ -10,7 +10,7 @@ export class DCredentialService { @Prop() issuer: string; @Prop() logoSrc?: string; @Prop() description?: string; - @Prop() href?: string; + @Prop({ reflect: true }) href?: string; render() { const content = ( diff --git a/src/components/types.ts b/src/components/types.ts index aef9f41..a0eb1f2 100644 --- a/src/components/types.ts +++ b/src/components/types.ts @@ -12,3 +12,13 @@ export const ShapeArgTypes = { control: { type: 'inline-radio' }, }; export type Shape = (typeof ShapeOptions)[number]; + +const ColorOptions = 'primary accent'.split(' '); +export const ColorArgTypes = { + options: ColorOptions, + description: 'Color of the button', + defaultValue: 'primary', + default: 'primary', + control: { type: 'inline-radio' }, +}; +export type Color = (typeof ColorOptions)[number]; diff --git a/src/global/global.css b/src/global/global.css index 9bd2ab8..b16e78f 100644 --- a/src/global/global.css +++ b/src/global/global.css @@ -68,3 +68,7 @@ * { @apply text-on; } + +body { + @apply bg-surface; +} diff --git a/vscode-data.json b/vscode-data.json index 81de16c..f6efd16 100644 --- a/vscode-data.json +++ b/vscode-data.json @@ -26,6 +26,27 @@ } ] }, + { + "name": "d-button", + "description": { + "kind": "markdown", + "value": "" + }, + "attributes": [ + { + "name": "color", + "description": "" + }, + { + "name": "disabled", + "description": "" + }, + { + "name": "href", + "description": "" + } + ] + }, { "name": "d-credential-card", "description": { From 00f5814f252b96a356a1163486cfd7edcbf9cbc7 Mon Sep 17 00:00:00 2001 From: puria Date: Sun, 28 Jan 2024 04:53:56 +0100 Subject: [PATCH 2/2] fix(button): force colors on buttons --- src/components/button/d-button.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/button/d-button.scss b/src/components/button/d-button.scss index a5e51ca..3853b9e 100644 --- a/src/components/button/d-button.scss +++ b/src/components/button/d-button.scss @@ -18,6 +18,9 @@ .accent { @apply bg-accent text-on-accent; + * { + @apply text-on-accent; + } &:active { background: linear-gradient(0deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%), var(--accent); } @@ -25,6 +28,9 @@ .primary { @apply bg-primary text-on; + * { + @apply text-on; + } &:active { background: linear-gradient(0deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.1) 100%), var(--primary); }