redo buttons component

This commit is contained in:
Nikita Galaiko 2023-03-31 17:03:16 +02:00
parent 7f9d53822d
commit de015d2f8c
9 changed files with 204 additions and 205 deletions

View File

@ -1,112 +1,139 @@
<script lang="ts">
import { Meta, Story } from '@storybook/addon-svelte-csf';
import { IconHome } from '../icons';
import Button from './Button.svelte';
let count = 0;
const heights = ['basic', 'small'] as const;
const widths = ['basic', 'long'] as const;
</script>
<Meta title="GitButler/Button" component={Button} />
<Story name="Basic">
<Button on:click={() => count++}>
You clicked: {count}
</Button>
<Story name="Basic Button">
<div class="flex gap-6">
{#each widths as width}
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
<div class="flex gap-2">
{#each [false, true] as disabled}
<Button role="basic" {filled} {disabled} {height} {width}>Label</Button>
{/each}
</div>
{/each}
</div>
{/each}
{/each}
</div>
</Story>
<Story name="Basic With Icon">
<Button on:click={() => count++}>
<svelte:fragment slot="icon">
<IconHome />
</svelte:fragment>
You clicked: {count}
</Button>
<Story name="Primary Button">
<div class="flex gap-6">
{#each widths as width}
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
<div class="flex gap-2">
{#each [false, true] as disabled}
<Button role="primary" {filled} {disabled} {height} {width}>Label</Button>
{/each}
</div>
{/each}
</div>
{/each}
{/each}
</div>
</Story>
<Story name="Small With Icon">
<Button on:click={() => count++} small>
<svelte:fragment slot="icon">
<IconHome />
</svelte:fragment>
You clicked: {count}
</Button>
<Story name="Destructive Button">
<div class="flex gap-6">
{#each widths as width}
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
<div class="flex gap-2">
{#each [false, true] as disabled}
<Button role="destructive" {filled} {disabled} {height} {width}>Label</Button>
{/each}
</div>
{/each}
</div>
{/each}
{/each}
</div>
</Story>
<Story name="Outlined icon">
<Button on:click={() => count++} outlined>
<svelte:fragment slot="icon">
<IconHome />
</svelte:fragment>
</Button>
<Story name="Basic Link">
<div class="flex gap-6">
{#each widths as width}
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
<div class="flex gap-2">
{#each [false, true] as disabled}
<Button
href="https://gitbutler.com"
role="basic"
{filled}
{disabled}
{height}
{width}>Label</Button
>
{/each}
</div>
{/each}
</div>
{/each}
{/each}
</div>
</Story>
<Story name="Wide With Icon">
<Button on:click={() => count++} wide>
<svelte:fragment slot="icon">
<IconHome />
</svelte:fragment>
You clicked: {count}
</Button>
<Story name="Primary Link">
<div class="flex gap-6">
{#each widths as width}
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
<div class="flex gap-2">
{#each [false, true] as disabled}
<Button
href="https://gitbutler.com"
role="primary"
{filled}
{disabled}
{height}
{width}>Label</Button
>
{/each}
</div>
{/each}
</div>
{/each}
{/each}
</div>
</Story>
<Story name="Basic Outlined">
<Button on:click={() => count++} outlined>
You clicked: {count}
</Button>
</Story>
<Story name="Basic Small">
<Button on:click={() => count++} small>
You clicked: {count}
</Button>
</Story>
<Story name="Basic Outlined Small">
<Button on:click={() => count++} small outlined>
You clicked: {count}
</Button>
</Story>
<Story name="Primary">
<Button on:click={() => count++} primary>
You clicked: {count}
</Button>
</Story>
<Story name="Primary Small">
<Button on:click={() => count++} primary small>
You clicked: {count}
</Button>
</Story>
<Story name="Primary Wide">
<Button on:click={() => count++} primary wide>
You clicked: {count}
</Button>
</Story>
<Story name="Primary Small Wide">
<Button on:click={() => count++} primary wide small>
You clicked: {count}
</Button>
</Story>
<Story name="Primary Outlined Small">
<Button on:click={() => count++} primary outlined small>
You clicked: {count}
</Button>
</Story>
<Story name="Link">
<Button href="https://gitbutler.com">Go to https://gitbutler.com</Button>
</Story>
<Story name="Link with icon">
<Button href="https://gitbutler.com">
<svelte:fragment slot="icon">
<IconHome />
</svelte:fragment>
Go to https://gitbutler.com
</Button>
<Story name="Destructive Link">
<div class="flex gap-6">
{#each widths as width}
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
<div class="flex gap-2">
{#each [false, true] as disabled}
<Button
href="https://gitbutler.com"
role="destructive"
{filled}
{disabled}
{height}
{width}>Label</Button
>
{/each}
</div>
{/each}
</div>
{/each}
{/each}
</div>
</Story>

View File

@ -1,49 +1,25 @@
<script lang="ts">
export let primary = false;
export let outlined = false;
export let role: 'basic' | 'primary' | 'destructive' = 'basic';
export let filled = true;
const outlined = true;
export let disabled = false;
export let small = false;
export let wide = false;
export let height: 'basic' | 'small' = 'basic';
export let width: 'basic' | 'long' = 'basic';
export let type: 'button' | 'submit' = 'button';
export let href: string | undefined = undefined;
</script>
<!--
@component
This is the only button we should be using in the app.
It emits a click event like any self respecting button should.
It takes the following required props:
And the following optional props:
- `primary` - boolean - whether the button should be primary or not
- `outlined` - boolean - whether the button should be outlined or not
- `small` - boolean - whether the button should be small or not
- `href` - string - if this is set, the button will be a link instead of a button
- `type` - string - the type of button, defaults to `button`
- `disabled` - boolean - whether the button is disabled or not
- Usage:
```tsx
<Button {...props} on:click={yourFunction} >
label
</Button>
```
-->
{#if href}
<a
{href}
class="btn-base"
class:btn-disabled={disabled}
class:btn-primary-outline={primary && outlined}
class:btn-primary={primary && !outlined}
class:btn-basic-outline={!primary && outlined}
class:btn-basic={!primary && !outlined}
class:btn-height-small={small}
class:btn-height-normal={!small}
class:btn-width-normal={wide}
class:btn-width-small={!wide}
class="{role} flex w-fit items-center justify-center gap-2 whitespace-nowrap rounded border text-base font-medium text-zinc-50 transition ease-in-out"
class:small={height === 'small'}
class:long={width === 'long'}
class:filled
class:outlined
{type}
on:click
class:disabled
>
{#if $$slots.icon}
<div class="icon">
@ -54,18 +30,15 @@ And the following optional props:
</a>
{:else}
<button
class="{role} flex w-fit items-center justify-center gap-2 whitespace-nowrap rounded border text-base font-medium text-zinc-50 transition ease-in-out"
class:small={height === 'small'}
class:long={width === 'long'}
class:filled
class:outlined
{disabled}
{type}
on:click
class="btn-base"
class:btn-disabled={disabled}
class:btn-primary-outline={primary && outlined}
class:btn-primary={primary && !outlined}
class:btn-basic-outline={!primary && outlined}
class:btn-basic={!primary && !outlined}
class:btn-height-small={small}
class:btn-height-normal={!small}
class:btn-width-normal={wide}
class:btn-width-small={!wide}
class:disabled
>
{#if $$slots.icon}
<div class="icon">
@ -77,74 +50,61 @@ And the following optional props:
{/if}
<style lang="postcss">
.icon {
@apply h-4 w-4 text-zinc-50;
.disabled {
@apply pointer-events-none opacity-40;
}
.btn-base {
@apply flex w-fit items-center justify-center gap-2 whitespace-nowrap rounded text-base text-zinc-50 shadow transition ease-in-out;
border-top: 1px solid rgba(255, 255, 255, 0.2);
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
border-left: 1px solid rgba(255, 255, 255, 0);
border-right: 1px solid rgba(255, 255, 255, 0);
text-shadow: 0px 2px #00000021;
.filled,
.outlined {
@apply px-[16px] py-[10px];
}
.btn-disabled {
@apply opacity-40;
pointer-events: none;
.filled.small,
.outlined.small {
@apply py-[4px];
}
/* Primary */
.btn-primary {
background: #3662e3;
}
.btn-primary:hover {
background: #1c48c9;
@apply transition ease-in-out;
}
.btn-primary-outline {
background: rgba(28, 72, 201, 0);
border: 1px solid #3662e3;
@apply transition ease-in-out;
}
.btn-primary-outline:hover {
background: rgba(28, 72, 201, 0.3);
border: 1px solid #3662e3;
@apply transition ease-in-out;
.filled.long,
.outlined.long {
@apply px-[42px];
}
/* Basic */
.btn-basic {
background: #71717a;
@apply transition ease-in-out;
.basic {
@apply border-zinc-500;
}
.btn-basic:hover {
@apply border-zinc-600 bg-zinc-600;
.basic:hover {
@apply bg-[#FFFFFF1A]/10;
}
.btn-basic-outline {
background: rgba(113, 113, 122, 0);
border: 1px solid #71717a;
@apply transition ease-in-out;
.basic.filled {
@apply border-transparent bg-zinc-500;
}
.btn-basic-outline:hover {
background: rgba(113, 113, 122, 0.4);
border: 1px solid #71717a;
@apply transition ease-in-out;
.basic.filled:hover {
@apply bg-zinc-600;
}
/* Size */
.btn-height-normal {
@apply py-2;
.primary {
@apply border-[#3662E3];
}
.btn-height-small {
@apply py-1;
.primary:hover {
@apply bg-[#1C48C94D]/30;
}
.btn-width-normal {
@apply px-[42.75px];
.primary.filled {
@apply border-transparent bg-blue-600;
}
.btn-width-small {
@apply px-[16px];
.primary.filled:hover {
@apply bg-[#1C48C9];
}
.destructive {
@apply border-[#E33636];
}
.destructive:hover {
@apply bg-[#E336364D]/30;
}
.destructive.filled {
@apply border-transparent bg-[#E33636];
}
.destructive.filled:hover {
@apply bg-[#C91C1C];
}
</style>

View File

@ -13,7 +13,13 @@
</Story>
<Story name="Two buttons wide">
<ButtonGroup leftLabel="Cancel" rightLabel="Submit" wide leftAction={noop} rightAction={noop} />
<ButtonGroup
leftLabel="Cancel"
rightLabel="Submit"
width="long"
leftAction={noop}
rightAction={noop}
/>
</Story>
<Story name="Three buttons">
@ -31,7 +37,7 @@
leftLabel="Cancel"
rightLabel="Submit"
middleLabel="Middle"
wide
width="long"
leftAction={noop}
rightAction={noop}
/>

View File

@ -7,28 +7,28 @@
export let rightAction: () => void;
export let middleLabel: string | undefined = undefined;
export let middleAction: (() => void) | undefined = undefined;
export let wide = false;
export let width: 'basic' | 'long' = 'basic';
</script>
{#if !middleLabel}
<div class="btn-group">
<Button on:click={leftAction} outlined={true} {wide}>
<Button on:click={leftAction} {width}>
{leftLabel}
</Button>
<Button on:click={rightAction} primary={true} outlined={false} {wide}>
<Button on:click={rightAction} role="primary" {width}>
{rightLabel}
</Button>
</div>
{:else}
<div class="btn-group btn-group--segmented">
<button class="joined-base rounded-l-lg border-l border-t border-b" on:click={leftAction}>
<span class="my-2 {wide ? 'mx-[31.5px]' : 'mx-[16px]'}">{leftLabel}</span>
<span class="my-2 {width === 'long' ? 'mx-[31.5px]' : 'mx-[16px]'}">{leftLabel}</span>
</button>
<button class="joined-base border" on:click={middleAction}>
<span class="my-2 {wide ? 'mx-[31.5px]' : 'mx-[16px]'}">{middleLabel}</span>
<span class="my-2 {width === 'long' ? 'mx-[31.5px]' : 'mx-[16px]'}">{middleLabel}</span>
</button>
<button class="joined-base rounded-r-lg border-r border-t border-b" on:click={rightAction}>
<span class="my-2 {wide ? 'mx-[31.5px]' : 'mx-[16px]'}">{rightLabel}</span>
<span class="my-2 {width === 'long' ? 'mx-[31.5px]' : 'mx-[16px]'}">{rightLabel}</span>
</button>
</div>
{/if}

View File

@ -160,7 +160,9 @@
</div>
<div>
<Tooltip label="Adds a git repository on your computer to GitButler">
<Button primary on:click={onAddLocalRepositoryClick}>Track a New Project</Button>
<Button role="primary" on:click={onAddLocalRepositoryClick}
>Track a New Project</Button
>
</Tooltip>
</div>
</div>

View File

@ -152,7 +152,7 @@
</span>
</div>
</Tooltip>
<Button primary href="/projects/{$project?.id}/commit">Commit changes</Button>
<Button role="primary" href="/projects/{$project?.id}/commit">Commit changes</Button>
</div>
{#if $statuses.length === 0}

View File

@ -195,7 +195,11 @@
<span>Comitting...</span>
</div>
{:else}
<Button disabled={!isCommitEnabled || isGeneratingCommitMessage} primary type="submit">
<Button
disabled={!isCommitEnabled || isGeneratingCommitMessage}
role="primary"
type="submit"
>
Commit changes
</Button>
{/if}

View File

@ -193,7 +193,7 @@
<span>Updating...</span>
</div>
{:else}
<Button primary type="submit">Update profile</Button>
<Button role="primary" type="submit">Update profile</Button>
{/if}
</footer>
</form>

View File

@ -104,7 +104,7 @@
<span>Updating...</span>
</div>
{:else}
<Button primary type="submit">Update profile</Button>
<Button role="primary" type="submit">Update profile</Button>
{/if}
</footer>
</fields>