Refactor button styles and update usage

This commit refactors the button component styles by introducing a new `kind` prop to replace the `filled` and `outlined` props. The `kind` prop takes values "filled", "outlined", or "plain". It also updates the usage of the button component in other components, using the new `kind` prop. Additionally, the button stories have been updated to remove redundancy and use the new `kind` prop.

Changes:
- Introduce `kind` prop in Button component
- Remove `filled` and `outlined` props
- Update button usage in BackForwardButtons and Breadcrumbs components
- Update Button.stories to use new `kind` prop
This commit is contained in:
Nikita Galaiko 2023-05-08 08:27:27 +02:00
parent 5dd48b69ab
commit 2969c24dfa
16 changed files with 226 additions and 230 deletions

View File

@ -44,11 +44,6 @@
</script>
<div class="flex items-center justify-center space-x-3 text-zinc-600">
<Button filled={false} on:click={onBackClicked} disabled={!canGoBack} icon={IconArrowLeft} />
<Button
filled={false}
on:click={onForwardClicked}
icon={IconArrowRight}
disabled={!canGoForward}
/>
<Button kind="plain" on:click={onBackClicked} disabled={!canGoBack} icon={IconArrowLeft} />
<Button kind="plain" on:click={onForwardClicked} icon={IconArrowRight} disabled={!canGoForward} />
</div>

View File

@ -8,10 +8,10 @@
</script>
<div class="flex flex-row items-center gap-1 text-zinc-400">
<Button icon={IconHome} filled={false} on:click={() => goto('/')} />
<Button icon={IconHome} kind="plain" on:click={() => goto('/')} />
{#if project}
<Tooltip label="{project.title} home">
<Button filled={false} on:click={() => project && goto(`/projects/${project.id}`)}>
<Button kind="plain" on:click={() => project && goto(`/projects/${project.id}`)}>
{project.title}
</Button>
</Tooltip>

View File

@ -5,6 +5,7 @@
import Button from './Button.svelte';
const heights = ['basic', 'small'] as const;
const kinds = ['filled', 'outlined', 'plain'] as const;
</script>
<Meta title="GitButler/Button" component={Button} />
@ -13,48 +14,43 @@
<div class="flex flex-col gap-4">
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
{#each [true, false] as outlined}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
role="basic"
{filled}
{disabled}
{outlined}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
role="basic"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
role="basic"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
{#each kinds as kind}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
color="basic"
{disabled}
{kind}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
color="basic"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
color="basic"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
</div>
{/each}
{/each}
</div>
{/each}
</div>
{/each}
@ -65,48 +61,43 @@
<div class="flex flex-col gap-4">
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
{#each [true, false] as outlined}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
role="primary"
{filled}
{disabled}
{outlined}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
role="primary"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
role="primary"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
{#each kinds as kind}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
color="primary"
{disabled}
{kind}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
color="primary"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
color="primary"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
</div>
{/each}
{/each}
</div>
{/each}
</div>
{/each}
@ -117,48 +108,43 @@
<div class="flex flex-col gap-4">
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
{#each [true, false] as outlined}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
role="destructive"
{filled}
{disabled}
{outlined}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
role="destructive"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
role="destructive"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
{#each kinds as kind}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
color="destructive"
{disabled}
{kind}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
color="destructive"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
color="destructive"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
</div>
{/each}
{/each}
</div>
{/each}
</div>
{/each}
@ -169,48 +155,43 @@
<div class="flex flex-col gap-4">
{#each heights as height}
<div class="flex flex-col gap-2">
{#each [true, false] as filled}
{#each [true, false] as outlined}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
role="purple"
{filled}
{disabled}
{outlined}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
role="purple"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
role="purple"
{filled}
{disabled}
{outlined}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
{#each kinds as kind}
<div class="flex gap-2">
{#each [false, true] as loading}
{#each [false, true] as disabled}
<Button
color="purple"
{disabled}
{kind}
{height}
{loading}
on:click={() => alert('Clicked!')}
>
Button
</Button>
<Button
color="purple"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
>
Button with icon
</Button>
<Button
color="purple"
{disabled}
{kind}
{height}
{loading}
icon={IconHome}
on:click={() => alert('Clicked!')}
/>
{/each}
</div>
{/each}
{/each}
</div>
{/each}
</div>
{/each}

View File

@ -2,9 +2,8 @@
import { onMount, type ComponentType } from 'svelte';
import { IconLoading } from '../icons';
export let role: 'basic' | 'primary' | 'destructive' | 'purple' = 'basic';
export let filled = true;
export let outlined = false;
export let color: 'basic' | 'primary' | 'destructive' | 'purple' = 'basic';
export let kind: 'plain' | 'filled' | 'outlined' = 'filled';
export let disabled = false;
export let height: 'basic' | 'small' = 'basic';
export let width: 'basic' | 'full-width' = 'basic';
@ -12,6 +11,9 @@
export let icon: ComponentType | undefined = undefined;
export let loading = false;
let filled = kind === 'filled';
let outlined = kind === 'outlined';
let element: HTMLAnchorElement | HTMLButtonElement;
onMount(() => {
@ -20,7 +22,7 @@
</script>
<button
class={role}
class={color}
class:small={height === 'small'}
class:full-width={width === 'full-width'}
class:pointer-events-none={loading}
@ -54,7 +56,7 @@
<style lang="postcss">
button {
@apply relative flex h-[36px] w-fit cursor-pointer items-center justify-center gap-[10px] whitespace-nowrap rounded py-2 text-base font-medium transition transition duration-150 ease-in-out ease-out hover:ease-in;
@apply relative flex h-[36px] w-fit cursor-pointer items-center justify-center gap-[10px] whitespace-nowrap rounded py-2 text-base font-medium underline transition transition duration-150 ease-in-out ease-out hover:ease-in;
}
button:focus {
@ -65,70 +67,85 @@
@apply text-zinc-300;
}
.basic:hover {
@apply bg-[#D4D4D8]/20;
@apply bg-[#D4D4D833]/20 no-underline;
}
.basic:active {
@apply bg-transparent no-underline;
}
.basic.outlined {
@apply border-zinc-500;
@apply border-[#3F3F46] no-underline;
}
.basic.outlined:hover {
@apply bg-[#FFFFFF1A]/10;
@apply bg-[#3F3F46]/20;
}
.basic.filled {
@apply bg-zinc-500;
@apply bg-[#3F3F46] no-underline;
}
.basic.filled:hover {
@apply bg-zinc-600;
@apply bg-[#35353B];
}
.primary {
@apply text-blue-500;
}
.primary:hover {
@apply bg-[#3B82F6]/20;
@apply bg-[#3B82F6]/20 no-underline;
}
.primary:disabled {
@apply text-[#BDC1CC] no-underline opacity-100;
}
.primary:active {
@apply bg-transparent text-blue-700 underline;
}
.primary.outlined {
@apply border-[#3662E3];
@apply border-[#3662E3] no-underline;
}
.primary.outlined:hover {
@apply bg-[#1C48C94D]/20;
}
.primary.filled {
@apply bg-blue-600;
@apply bg-blue-600 no-underline;
}
.primary.filled:hover {
@apply bg-[#1C48C9];
}
.destructive {
@apply text-red-600;
@apply text-red-600 no-underline;
}
.destructive:hover {
@apply bg-[#DC2626]/20;
}
.destructive.outlined {
@apply border-[#E33636];
}
.destructive.outlined:hover {
@apply bg-[#E336364D]/30;
.destructive:active {
@apply bg-transparent text-red-400;
}
.destructive.filled {
@apply bg-[#E33636];
@apply bg-[#BF4545] text-zinc-50 no-underline;
}
.destructive.filled:disabled {
@apply bg-[#EB2525];
}
.destructive.filled:hover {
@apply bg-[#C91C1C];
}
.destructive.outlined {
@apply border-[#BF4545] text-[#BF4545] no-underline;
}
.destructive.outlined:hover {
@apply bg-[#E3363633]/20;
}
.purple {
@apply text-[#5852A0];
}
.purple.outlined {
@apply border-[#524C93];
@apply border-[#524C93] no-underline;
}
.purple.outlined:hover {
@apply bg-[#524C93]/20;
}
.purple.filled {
@apply bg-[#5852A0];
@apply bg-[#5852A0] no-underline;
}
.purple.filled:hover {
@apply bg-[#423E7A];

View File

@ -15,7 +15,7 @@
<Button on:click={leftAction} {width}>
{leftLabel}
</Button>
<Button on:click={rightAction} role="primary" {width}>
<Button on:click={rightAction} color="primary" {width}>
{rightLabel}
</Button>
</div>

View File

@ -16,7 +16,7 @@
<slot name="title">Title</slot>
</h2>
<Button filled={false} on:click={close} icon={IconClose} />
<Button kind="plain" on:click={close} icon={IconClose} />
</header>
{#if $$slots.default}
@ -27,8 +27,8 @@
<footer class="flex w-full justify-end gap-4 p-4">
<slot name="controls" {close}>
<Button filled={false} outlined={true} on:click={close}>Secondary action</Button>
<Button role="primary" on:click={close}>Primary action</Button>
<Button kind="outlined" on:click={close}>Secondary action</Button>
<Button color="primary" on:click={close}>Primary action</Button>
</slot>
</footer>
</div>

View File

@ -3,7 +3,6 @@
import { Status, type Project, git } from '$lib/api';
import type { CloudApi, User } from '$lib/api';
import { Button, Modal, Link } from '$lib/components';
import Tooltip from './Tooltip/Tooltip.svelte';
import { IconGitBranch, IconSparkle } from './icons';
export const show = () => modal.show();
@ -151,9 +150,8 @@
/>
<Button
role="purple"
filled={false}
outlined={true}
color="purple"
kind="outlined"
disabled={isCommitting || !project.api?.sync}
loading={isAutowriting}
on:click={onAutowrite}
@ -202,8 +200,8 @@
</div>
<div class="flex gap-2">
<Button filled={false} outlined={true} on:click={close}>Cancel</Button>
<Button type="submit" disabled={isAutowriting} role="primary" loading={isCommitting}>
<Button kind="outlined" on:click={close}>Cancel</Button>
<Button type="submit" disabled={isAutowriting} color="primary" loading={isCommitting}>
Commit
</Button>
</div>

View File

@ -142,7 +142,7 @@
<h3 class="mt-2 text-lg font-semibold text-zinc-300">No projects</h3>
<p class="mt-1 text-gray-500">Get started by tracking a project you're working on.</p>
<div class="mt-6">
<Button role="primary" on:click={onAddLocalRepositoryClick}>
<Button color="primary" on:click={onAddLocalRepositoryClick}>
Start Tracking a Project
</Button>
</div>
@ -160,7 +160,7 @@
</div>
<div>
<Tooltip label="Adds a git repository on your computer to GitButler">
<Button role="primary" on:click={onAddLocalRepositoryClick}>
<Button color="primary" on:click={onAddLocalRepositoryClick}>
Track a New Project
</Button>
</Tooltip>

View File

@ -94,7 +94,7 @@
<Tooltip label="Terminal">
<Button
on:click={() => goto(`/projects/${$project.id}/terminal`)}
filled={false}
kind="plain"
height="small"
icon={IconTerminal}
/>
@ -104,7 +104,7 @@
<Tooltip label="Project settings">
<Button
on:click={() => goto(`/projects/${$project.id}/settings`)}
filled={false}
kind="plain"
height="small"
icon={IconSettings}
/>

View File

@ -81,11 +81,11 @@
</div>
</Tooltip>
{#await statuses.load()}
<Button disabled role="primary">Commit changes</Button>
<Button disabled color="primary">Commit changes</Button>
{:then}
<Button
disabled={Object.keys($statuses).length === 0}
role="primary"
color="primary"
on:click={() => goto(`/projects/${$project?.id}/commit`)}
>
Commit changes

View File

@ -137,7 +137,7 @@
<div class="flex gap-2 text-xl">Chat GitButler</div>
<div class="flex items-center gap-2">
<Button role="basic" height="small" on:click={setupChat}>Reset chat</Button>
<Button color="basic" height="small" on:click={setupChat}>Reset chat</Button>
</div>
</div>
@ -282,7 +282,7 @@
/>
<Button
disabled={chatInput.length == 0 || !chatId}
role="primary"
color="primary"
on:click={() => {
newChatMessage(chatId, chatInput).then((data) => {
requestedSeq = +data;
@ -303,7 +303,7 @@
</div>
</div>
<style>
<style lang="postcss">
.chat-user-avatar {
@apply relative flex h-[40px] w-[40px] items-center justify-center rounded-full p-2;
}

View File

@ -237,8 +237,8 @@
</p>
</div>
<svelte:fragment slot="controls" let:close>
<Button filled={false} outlined={true} on:click={close}>Cancel</Button>
<Button role="primary" on:click={() => enableProjectSync().finally(close)}>Connect</Button>
<Button kind="outlined" on:click={close}>Cancel</Button>
<Button color="primary" on:click={() => enableProjectSync().finally(close)}>Connect</Button>
</svelte:fragment>
</Dialog>
@ -366,7 +366,7 @@
<div class="flex justify-between">
<Button
role="purple"
color="purple"
disabled={!isGenerateCommitEnabled}
on:click={onGenerateCommitMessage}
loading={isGeneratingCommitMessage}
@ -377,7 +377,7 @@
<Button
loading={isCommitting}
disabled={!isCommitEnabled || isGeneratingCommitMessage}
role="primary"
color="primary"
type="submit"
>
Commit changes

View File

@ -218,11 +218,15 @@
</fieldset>
<footer class="flex justify-between">
<Button role="destructive" filled={false} on:click={() => deleteConfirmationDialog.show()}
>Delete project</Button
<Button
color="destructive"
kind="outlined"
on:click={() => deleteConfirmationDialog.show()}
>
Delete project
</Button>
<Button disabled={!canTriggerUpdate} loading={saving} role="primary" type="submit">
<Button disabled={!canTriggerUpdate} loading={saving} color="primary" type="submit">
Update project
</Button>
</footer>
@ -238,13 +242,13 @@
<p>
Are you sure you want to delete the project,
<span class="font-bold text-white">hugo-ianthedesigner</span>? This cant be undone.
<span class="font-bold text-white">{$project.title}</span>? This cant be undone.
</p>
<svelte:fragment slot="controls" let:close>
<Button filled={false} outlined={true} on:click={close}>Cancel</Button>
<Button role="destructive" loading={isDeleting} on:click={onDeleteClicked}
>Delete project</Button
>
<Button kind="outlined" on:click={close}>Cancel</Button>
<Button color="destructive" loading={isDeleting} on:click={onDeleteClicked}>
Delete project
</Button>
</svelte:fragment>
</Dialog>

View File

@ -39,7 +39,7 @@
{/await}
<div class="mt-4 font-bold">Commands</div>
<ul class="py-2">
<Button role="primary" width="full-width" on:click={() => runCommand('git push')}>
<Button color="primary" width="full-width" on:click={() => runCommand('git push')}>
Push Commit
</Button>
</ul>

View File

@ -138,9 +138,9 @@
</div>
<footer class="flex justify-end pt-4">
<Button disabled={!canTriggerUpdate} loading={saving} role="primary" type="submit"
>Update profile</Button
>
<Button disabled={!canTriggerUpdate} loading={saving} color="primary" type="submit">
Update profile
</Button>
</footer>
</fields>
</form>

View File

@ -60,6 +60,7 @@ const config = {
900: '#713f12'
},
red: {
400: '#F87171',
500: '#ef4444',
600: '#dc2626',
700: '#b91c1c',