Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Extract Button component
Rūdolfs Ošiņš committed 3 years ago
commit dc8a8f883c2798d4b651a984258ac10860aaebb6
parent b9a2e9d954f7df85bd0f5b242217a0dcf32bd581
29 files changed +352 -282
modified public/index.css
@@ -167,104 +167,11 @@ section {

body,
input,
-
textarea,
-
button {
+
textarea {
  font-family: var(--font-family-sans-serif);
  font-feature-settings: "ss01", "ss02", "cv01", "cv03";
}

-
button {
-
  color: var(--color-foreground-6);
-
  background: transparent;
-
  font-size: 1rem;
-
  padding: 0rem 1.5rem;
-
  border: 1px solid var(--color-foreground-6);
-
  border-radius: var(--border-radius-round);
-
  cursor: pointer;
-
  min-width: 6rem;
-
  height: var(--button-regular-height);
-
  display: inline-flex;
-
  align-items: center;
-
  justify-content: center;
-
}
-
button:not([disabled]):hover {
-
  color: var(--color-background);
-
  background-color: var(--color-foreground);
-
  border-color: transparent;
-
}
-
button.waiting {
-
  cursor: wait;
-
}
-
button.secondary {
-
  color: var(--color-secondary);
-
  border-color: var(--color-secondary);
-
}
-
button.secondary[disabled] {
-
  color: var(--color-secondary-faded);
-
  border-color: var(--color-secondary-faded);
-
}
-
button.secondary:not([disabled]):hover {
-
  background-color: var(--color-secondary);
-
}
-
button.primary {
-
  color: var(--color-primary);
-
  border-color: var(--color-primary);
-
}
-
button.primary:hover,
-
button.primary.active {
-
  color: var(--color-background);
-
  background-color: var(--color-primary);
-
}
-
button.primary[disabled] {
-
  color: var(--color-primary-faded) !important;
-
  border-color: var(--color-primary-faded) !important;
-
  background-color: transparent;
-
}
-
button.faded {
-
  color: var(--color-foreground-90);
-
  border-color: var(--color-foreground-90);
-
}
-
button[disabled] {
-
  cursor: not-allowed !important;
-
  color: var(--color-foreground-faded);
-
  border-color: var(--color-foreground-faded);
-
}
-
button[data-waiting] {
-
  cursor: wait !important;
-
}
-
button.unstyled,
-
button.unstyled:hover,
-
button.unstyled:focus {
-
  padding: 0;
-
  margin: 0;
-
  min-width: 0;
-
  border: none;
-
  color: var(--color-foreground);
-
  background: transparent;
-
}
-

-
button.text {
-
  color: var(--color-foreground-6);
-
  background-color: transparent;
-
  border: none;
-
  min-width: 3rem;
-
}
-
button.text:hover {
-
  background-color: var(--color-foreground);
-
}
-

-
button.regular {
-
  padding-top: 0.5rem;
-
  padding-bottom: 0.5rem;
-
  min-width: 6rem;
-
  height: var(--button-regular-height);
-
}
-
button.small {
-
  min-width: auto;
-
  padding: 0 0.75rem;
-
  height: 2rem;
-
}
-

a {
  color: inherit;
  text-decoration: none;
@@ -290,8 +197,7 @@ a.address {
  border-bottom-color: transparent;
}

-
input[type="text"],
-
button {
+
input[type="text"] {
  line-height: 1.6;
}
input[type="text"] {
added src/Button.svelte
@@ -0,0 +1,134 @@
+
<script lang="ts">
+
  export let title: string | undefined = undefined;
+
  export let variant:
+
    | "foreground"
+
    | "negative"
+
    | "primary"
+
    | "secondary"
+
    | "text";
+
  export let size: "tiny" | "small" | "regular" = "regular";
+

+
  export let disabled: boolean = false;
+
  export let waiting: boolean = false;
+
  export let style: string | undefined = undefined;
+
</script>
+

+
<style>
+
  button {
+
    background: transparent;
+
    border-radius: var(--border-radius-round);
+
    border: 1px solid var(--color-foreground-6);
+
    cursor: pointer;
+
    font-family: var(--font-family-sans-serif);
+
    font-feature-settings: "ss01", "ss02", "cv01", "cv03";
+
    font-size: 1rem;
+
    line-height: 1.6rem;
+
    display: inline-flex;
+
    justify-content: center;
+
    align-items: center;
+
  }
+
  button[disabled] {
+
    cursor: not-allowed;
+
  }
+
  button:not([disabled]):hover {
+
    color: var(--color-background);
+
  }
+
  .foreground {
+
    color: var(--color-foreground-6);
+
  }
+
  .foreground[disabled] {
+
    color: var(--color-foreground-faded);
+
    border-color: var(--color-foreground-faded);
+
  }
+
  .foreground:not([disabled]):hover {
+
    background-color: var(--color-foreground);
+
  }
+

+
  .primary {
+
    color: var(--color-primary);
+
    border-color: var(--color-primary);
+
  }
+
  .primary[disabled] {
+
    color: var(--color-primary-faded);
+
    border-color: var(--color-primary-faded);
+
  }
+
  .primary:not([disabled]):hover {
+
    background-color: var(--color-primary);
+
  }
+

+
  .secondary {
+
    color: var(--color-secondary);
+
    border-color: var(--color-secondary);
+
  }
+
  .secondary[disabled] {
+
    color: var(--color-secondary-faded);
+
    border-color: var(--color-secondary-faded);
+
  }
+
  .secondary:not([disabled]):hover {
+
    background-color: var(--color-secondary);
+
  }
+

+
  .negative {
+
    color: var(--color-negative);
+
    border-color: var(--color-negative);
+
  }
+
  .negative[disabled] {
+
    color: var(--color-negative-faded);
+
    border-color: var(--color-negative-faded);
+
  }
+
  .negative:not([disabled]):hover {
+
    background-color: var(--color-negative);
+
  }
+

+
  .text {
+
    color: var(--color-foreground-6);
+
    border: none;
+
  }
+
  .text[disabled] {
+
    color: var(--color-foreground-4);
+
  }
+
  .text:not([disabled]):hover {
+
    background-color: var(--color-foreground);
+
  }
+

+
  .tiny {
+
    font-size: 0.75rem;
+
    height: var(--button-small-tiny);
+
    padding: 0 0.6rem;
+
  }
+
  .small {
+
    font-size: 0.875rem;
+
    height: var(--button-small-height);
+
    padding: 0 0.75rem;
+
  }
+
  .regular {
+
    height: var(--button-regular-height);
+
    padding: 0 1.5rem;
+
    min-width: 6rem;
+
  }
+

+
  .waiting {
+
    cursor: waiting;
+
  }
+
</style>
+

+
<button
+
  {title}
+
  {disabled}
+
  {style}
+
  on:click|stopPropagation
+
  on:focus
+
  on:blur
+
  on:mouseout
+
  on:mouseover
+
  class:foreground={variant === "foreground"}
+
  class:negative={variant === "negative"}
+
  class:primary={variant === "primary"}
+
  class:secondary={variant === "secondary"}
+
  class:text={variant === "text"}
+
  class:tiny={size === "tiny"}
+
  class:small={size === "small"}
+
  class:regular={size === "regular"}
+
  class:waiting>
+
  <slot />
+
</button>
modified src/Connect.svelte
@@ -5,11 +5,11 @@
  import Error from "@app/Error.svelte";
  import type { Config } from "@app/config";
  import ConnectWallet from "@app/components/Modal/ConnectWallet.svelte";
+
  import Button from "@app/Button.svelte";

  export let caption = "Connect";
-
  export let className = "";
-
  export let style = "";
  export let config: Config;
+
  export let buttonVariant: "foreground" | "primary";

  let error: Err | null = null;

@@ -34,18 +34,17 @@
  $: walletConnectState = config.walletConnect.state;
</script>

-
<button
-
  on:click|stopPropagation={onConnect}
-
  {style}
-
  class="connect {className}"
+
<Button
+
  on:click={onConnect}
+
  variant={buttonVariant}
  disabled={connecting}
-
  data-waiting={connecting || null}>
+
  waiting={connecting}>
  {#if connecting}
    Connecting...
  {:else}
    {caption}
  {/if}
-
</button>
+
</Button>

{#if $walletConnectState.state === "open"}
  <ConnectWallet
modified src/Error.svelte
@@ -1,7 +1,9 @@
<script lang="ts">
+
  import type { Err } from "@app/error";
+

  import { createEventDispatcher } from "svelte";
  import Modal from "@app/Modal.svelte";
-
  import type { Err } from "@app/error";
+
  import Button from "@app/Button.svelte";

  const dispatch = createEventDispatcher();

@@ -38,9 +40,9 @@

  <span slot="actions">
    <slot name="actions">
-
      <button on:click={() => dispatch("close")}>
+
      <Button variant="negative" on:click={() => dispatch("close")}>
        {action}
-
      </button>
+
      </Button>
    </slot>
  </span>
</Modal>
modified src/Form.svelte
@@ -1,4 +1,5 @@
<script context="module" lang="ts">
+
  import Button from "@app/Button.svelte";
  export interface Field {
    name: string;
    value?: string;
@@ -167,9 +168,9 @@
    margin-top: 2rem;
    text-align: center;
    visibility: hidden;
-
  }
-
  .actions button {
-
    margin-left: 1rem;
+
    gap: 1.5rem;
+
    display: flex;
+
    justify-content: center;
  }
  .actions.editable {
    visibility: visible;
@@ -258,11 +259,8 @@
</div>

<div class="actions" class:editable>
-
  <button on:click={cancel} {disabled} class="regular">Cancel</button>
-
  <button
-
    on:click={save}
-
    disabled={hasErrors || disabled}
-
    class="regular primary">
+
  <Button on:click={cancel} {disabled} variant="foreground">Cancel</Button>
+
  <Button on:click={save} disabled={hasErrors || disabled} variant="primary">
    Save
-
  </button>
+
  </Button>
</div>
modified src/Header.svelte
@@ -15,6 +15,7 @@
  import Icon from "./Icon.svelte";
  import MobileNavbar from "./MobileNavbar.svelte";
  import SeedDropdown from "./SeedDropdown.svelte";
+
  import Button from "@app/Button.svelte";

  export let session: Session | null;
  export let config: Config;
@@ -92,16 +93,6 @@
    margin-left: 1.5rem;
    display: inline-block;
  }
-
  .address {
-
    display: flex;
-
    flex-direction: row;
-
    align-items: center;
-
    justify-content: center;
-
    margin-left: 2rem;
-
    width: 10rem;
-
    padding-left: 0;
-
    padding-right: 0;
-
  }
  .connect {
    display: inline-block;
    margin-left: 2rem;
@@ -125,7 +116,7 @@
  }

  .balance {
-
    margin-left: 2rem;
+
    margin: 0 2rem;
    white-space: nowrap;
  }

@@ -209,8 +200,9 @@
        {/if}
      </span>

-
      <button
-
        class="address outline regular"
+
      <Button
+
        style="width: 10rem; white-space: nowrap;"
+
        variant="foreground"
        on:click={() => disconnectWallet(config)}
        on:mouseover={() => (sessionButtonHover = true)}
        on:focus={() => (sessionButtonHover = true)}
@@ -228,10 +220,10 @@
              inline />{formatAddress(address)}
          {/if}
        {/await}
-
      </button>
+
      </Button>
    {:else if config}
      <span class="connect">
-
        <Connect className="regular" {config} />
+
        <Connect buttonVariant="foreground" {config} />
      </span>
    {/if}
    <div class="toggle" on:click={toggleNavbar}>
modified src/NotFound.svelte
@@ -1,4 +1,5 @@
<script lang="ts">
+
  import Button from "@app/Button.svelte";
  import Modal from "@app/Modal.svelte";

  export let title = "";
@@ -14,6 +15,6 @@
    <p>{subtitle}</p>
  </span>
  <span slot="actions">
-
    <button on:click={back}>Back</button>
+
    <Button variant="foreground" on:click={back}>Back</Button>
  </span>
</Modal>
modified src/Profile.svelte
@@ -21,6 +21,7 @@
  import NotFound from "@app/NotFound.svelte";
  import RadicleUrn from "@app/RadicleUrn.svelte";
  import Badge from "@app/Badge.svelte";
+
  import Button from "@app/Button.svelte";

  export let config: Config;
  export let addressOrName: string;
@@ -271,9 +272,12 @@
        <div class="desktop">
          {#await account && profile.org.isMember(account, config) then isMember}
            {#if isOwner(profile.org) || isMember}
-
              <button class="small secondary" on:click={transferOwnership}>
+
              <Button
+
                variant="secondary"
+
                size="small"
+
                on:click={transferOwnership}>
                Transfer
-
              </button>
+
              </Button>
            {/if}
          {/await}
        </div>
@@ -320,7 +324,9 @@
              <!-- Loading -->
            {:then authorized}
              {#if authorized}
-
                <button class="small secondary" on:click={setName}>Set</button>
+
                <Button variant="secondary" size="small" on:click={setName}>
+
                  Set
+
                </Button>
              {/if}
            {/await}
          </div>
@@ -348,7 +354,9 @@
        </div>
        <div class="desktop">
          {#if isUserAuthorized(profile.address)}
-
            <button class="small secondary" on:click={setName}>Set</button>
+
            <Button variant="secondary" size="small" on:click={setName}>
+
              Set
+
            </Button>
          {/if}
        </div>
      {/if}
modified src/RadicleUrn.svelte
@@ -1,19 +1,19 @@
<script lang="ts">
  import { parseRadicleId, toClipboard } from "@app/utils";
+
  import Button from "@app/Button.svelte";

  export let urn: string;

  let copied = false;

-
  const copy = () => {
-
    return () =>
-
      toClipboard(urn).then(() => {
-
        copied = true;
-
        setTimeout(() => {
-
          copied = false;
-
        }, 3000);
-
      });
-
  };
+
  function copy() {
+
    toClipboard(urn).then(() => {
+
      copied = true;
+
      setTimeout(() => {
+
        copied = false;
+
      }, 1000);
+
    });
+
  }
</script>

<style>
@@ -41,11 +41,11 @@
  </div>
</div>
<div>
-
  <button class="small faded" disabled={copied} on:click={copy()}>
+
  <Button variant="foreground" size="small" disabled={copied} on:click={copy}>
    {#if copied}
      Copy ✓
    {:else}
      Copy
    {/if}
-
  </button>
+
  </Button>
</div>
modified src/Reactions.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
  import { createEventDispatcher } from "svelte";
+
  import Button from "@app/Button.svelte";

  export let reactions: Record<string, number> | null = null;

@@ -7,11 +8,9 @@
</script>

<style>
-
  .reaction {
-
    margin-right: 0.6rem;
-
    padding: 0 0.6rem;
-
    height: 26px;
-
    min-width: unset; /* Resets min-width from button in public.css */
+
  .reactions {
+
    display: flex;
+
    gap: 0.5rem;
  }
</style>

@@ -19,13 +18,13 @@
  <div class="reactions">
    {#each Object.entries(reactions) as [reaction, count]}
      <!-- TODO: Remove the disabled attribute once we are able to increment reactions -->
-
      <button
-
        disabled
-
        class="reaction text-xsmall"
+
      <Button
+
        variant="foreground"
+
        size="tiny"
        on:click={() => dispatch("click", reaction)}>
        {reaction}
        {count}
-
      </button>
+
      </Button>
    {/each}
  </div>
{/if}
modified src/SiweConnect.svelte
@@ -5,6 +5,7 @@
  import { signInWithEthereum } from "@app/siwe";
  import Loading from "@app/Loading.svelte";
  import { Connection } from "@app/session";
+
  import Button from "@app/Button.svelte";

  export let seed: Seed;
  export let config: Config;
@@ -16,14 +17,9 @@
  let connection: Connection = Connection.Disconnected;
</script>

-
<style>
-
  button {
-
    min-height: 32px;
-
  }
-
</style>
-

-
<button
-
  class="small secondary"
+
<Button
+
  variant="secondary"
+
  size="small"
  title={tooltip}
  disabled={disabled || connection === Connection.Connecting}
  on:click={async () => {
@@ -45,4 +41,4 @@
      {caption}
    {/if}
  </span>
-
</button>
+
</Button>
modified src/ToggleButton.svelte
@@ -40,6 +40,7 @@
    padding: 0.25rem 0.5rem;
    border: none;
    min-width: 0;
+
    background-color: var(--color-background);
  }
  button:hover,
  button.active {
modified src/base/faucet/Index.svelte
@@ -10,6 +10,7 @@
    lastWithdrawalByUser,
    calculateTimeLock,
  } from "./lib";
+
  import Button from "@app/Button.svelte";

  export let config: Config;

@@ -142,9 +143,7 @@
            placeholder="Set amount to withdraw"
            bind:value={amount}
            on:input={() => (error = "")} />
-
          <button disabled={false} class="primary" on:click={withdraw}>
-
            Withdraw
-
          </button>
+
          <Button variant="primary" on:click={withdraw}>Withdraw</Button>
        </div>
        {#if error}
          <div class="error description invalid text-small faded">
modified src/base/faucet/Withdraw.svelte
@@ -8,6 +8,7 @@
  import { Status, State } from "@app/utils";
  import { withdraw } from "./lib";
  import { session } from "@app/session";
+
  import Button from "@app/Button.svelte";

  export let config: Config;

@@ -80,7 +81,7 @@

    <span slot="actions">
      {#if state.status === Status.Success}
-
        <button on:click={back}>Back</button>
+
        <Button variant="foreground" on:click={back}>Back</Button>
      {/if}
    </span>
  </Modal>
modified src/base/orgs/Create.svelte
@@ -9,6 +9,7 @@
  import Loading from "@app/Loading.svelte";
  import Options from "@app/Options.svelte";
  import Address from "@app/Address.svelte";
+
  import Button from "@app/Button.svelte";

  export let config: Config;
  export let owner: string;
@@ -149,7 +150,11 @@
    </span>

    <span slot="actions">
-
      <button on:click={() => navigate(`/${org?.address}`)}>Done</button>
+
      <Button
+
        variant="foreground"
+
        on:click={() => navigate(`/${org?.address}`)}>
+
        Done
+
      </Button>
    </span>
  </Modal>
{:else}
@@ -205,17 +210,15 @@

    <span slot="actions">
      {#if state === State.Idle}
-
        <button
+
        <Button
          on:click={createOrg}
-
          class="primary regular"
-
          data-waiting={[State.Signing, State.Pending].includes(state) || null}
+
          variant="primary"
+
          waiting={[State.Signing, State.Pending].includes(state)}
          disabled={state !== State.Idle}>
          Create
-
        </button>
+
        </Button>

-
        <button on:click={() => dispatch("close")} class="text regular">
-
          Close
-
        </button>
+
        <Button on:click={() => dispatch("close")} variant="text">Close</Button>
      {/if}
    </span>
  </Modal>
modified src/base/orgs/Index.svelte
@@ -8,6 +8,7 @@
  import Message from "@app/Message.svelte";
  import Cards from "@app/Cards.svelte";
  import { setOpenGraphMetaTag } from "@app/utils";
+
  import Button from "@app/Button.svelte";

  export let config: Config;

@@ -37,6 +38,7 @@
    display: flex;
    align-items: center;
    padding: 1rem 0;
+
    gap: 1.5rem;
  }

  .my-orgs {
@@ -48,10 +50,6 @@
    color: var(--color-foreground-faded);
  }

-
  button.create {
-
    margin-left: 1.5rem;
-
  }
-

  .loading {
    padding: 2rem 0;
  }
@@ -68,12 +66,9 @@
        <span>
          My <strong>Orgs</strong>
        </span>
-
        <button
-
          class="create regular secondary"
-
          on:click={onCreate}
-
          disabled={!account}>
+
        <Button variant="secondary" on:click={onCreate} disabled={!account}>
          Create
-
        </button>
+
        </Button>
      </header>

      {#await Org.getOrgsByMember(account, config)}
modified src/base/orgs/TransferOwnership.svelte
@@ -7,6 +7,7 @@
  import { assert } from "@app/error";
  import * as utils from "@app/utils";
  import Address from "@app/Address.svelte";
+
  import Button from "@app/Button.svelte";

  import type { Org } from "./Org";

@@ -84,7 +85,9 @@
    </div>

    <div slot="actions">
-
      <button class="regular" on:click={() => dispatch("close")}>Done</button>
+
      <Button variant="secondary" on:click={() => dispatch("close")}>
+
        Done
+
      </Button>
    </div>
  </Modal>
{:else if state === State.Proposed && org}
@@ -104,7 +107,9 @@
    </div>

    <div slot="actions">
-
      <button class="regular" on:click={() => dispatch("close")}>Done</button>
+
      <Button variant="secondary" on:click={() => dispatch("close")}>
+
        Done
+
      </Button>
    </div>
  </Modal>
{:else}
@@ -152,24 +157,24 @@

    <div slot="actions">
      {#if state === State.Signing}
-
        <button class="regular" on:click={() => dispatch("close")}>
+
        <Button variant="text" on:click={() => dispatch("close")}>
          Cancel
-
        </button>
+
        </Button>
      {:else if state === State.Pending}
-
        <button class="regular" on:click={() => dispatch("close")}>
-
          Close
-
        </button>
+
        <Button variant="text" on:click={() => dispatch("close")}>Close</Button>
      {:else if state === State.Failed}
-
        <button class="regular" on:click={resetForm}>Back</button>
+
        <Button variant="negative" on:click={resetForm}>Back</Button>
      {:else}
-
        <button
-
          class="primary"
+
        <Button
+
          variant="primary"
          on:click={onSubmit}
          disabled={!newOwner || state !== State.Idle}>
          Submit
-
        </button>
+
        </Button>

-
        <button class="text" on:click={() => dispatch("close")}>Cancel</button>
+
        <Button variant="text" on:click={() => dispatch("close")}>
+
          Cancel
+
        </Button>
      {/if}
    </div>
  </Modal>
modified src/base/profiles/AnchorActions.svelte
@@ -8,6 +8,7 @@
  import Avatar from "@app/Avatar.svelte";
  import { createEventDispatcher } from "svelte";
  import Badge from "@app/Badge.svelte";
+
  import Button from "@app/Button.svelte";

  export let safe: Safe;
  export let anchor: PendingAnchor;
@@ -109,11 +110,6 @@
    display: flex;
    margin-right: 0.75rem;
  }
-
  button.execute {
-
    display: flex;
-
    align-items: center;
-
    justify-content: center;
-
  }
</style>

<span class="confirmations">
@@ -131,26 +127,28 @@

<!-- Check whether the threshold has been matched or passed -->
{#if pending <= 0}
-
  <button
-
    on:click|stopPropagation={() => {
+
  <Button
+
    on:click={() => {
      action = Action.Execute;
      state = State.Confirm;
    }}
-
    class="small execute">
+
    variant="foreground"
+
    size="small">
    <Avatar inline source={account} title={account} /> Execute
-
  </button>
+
  </Button>
  <!-- Check whether or not we've signed this proposal -->
{:else if isSigned}
  <Badge variant="caution">✓ signed</Badge>
{:else}
-
  <button
-
    on:click|stopPropagation={() => {
+
  <Button
+
    on:click={() => {
      action = Action.Sign;
      state = State.Confirm;
    }}
-
    class="small">
+
    variant="foreground"
+
    size="small">
    Confirm
-
  </button>
+
  </Button>
{/if}

<!-- We've initiated an action -->
@@ -190,20 +188,21 @@

    <span slot="actions">
      {#if state === State.Confirm}
-
        <button
-
          class="primary"
+
        <Button
+
          variant="primary"
          on:click={() => confirmAnchor(anchor.safeTxHash)}>
          Confirm
-
        </button>
-
        <button class="text" on:click={close}>Cancel</button>
+
        </Button>
+
        <Button variant="text" on:click={close}>Cancel</Button>
      {:else if state === State.Success || state === State.Failed}
-
        <button
+
        <Button
+
          variant="foreground"
          on:click={() => {
            close();
            dispatch("success");
          }}>
          Done
-
        </button>
+
        </Button>
      {/if}
    </span>
  </Modal>
@@ -243,20 +242,21 @@

    <span slot="actions">
      {#if state === State.Confirm}
-
        <button
-
          class="primary"
+
        <Button
+
          variant="primary"
          on:click={() => executeTransaction(anchor.safeTxHash)}>
          Confirm
-
        </button>
-
        <button class="text" on:click={close}>Cancel</button>
+
        </Button>
+
        <Button variant="text" on:click={close}>Cancel</Button>
      {:else if state === State.Success || state === State.Failed}
-
        <button
+
        <Button
+
          variant="foreground"
          on:click={() => {
            close();
            dispatch("success");
          }}>
          Done
-
        </button>
+
        </Button>
      {/if}
    </span>
  </Modal>
modified src/base/projects/Browser.svelte
@@ -4,6 +4,7 @@
  import Loading from "@app/Loading.svelte";
  import Placeholder from "@app/Placeholder.svelte";
  import * as utils from "@app/utils";
+
  import Button from "@app/Button.svelte";

  import Tree from "./Tree.svelte";
  import Blob from "./Blob.svelte";
@@ -128,10 +129,6 @@
  }

  @media (max-width: 720px) {
-
    button.browse {
-
      width: 100%;
-
      border-color: var(--color-secondary-faded);
-
    }
    .column-right {
      padding: 1.5rem 0;
      min-width: 0;
@@ -161,11 +158,12 @@
  <!-- Mobile navigation -->
  {#if tree.entries.length > 0}
    <nav class="mobile">
-
      <button
-
        class="regular browse secondary center-content"
+
      <Button
+
        style="width: 100%;"
+
        variant="secondary"
        on:click={toggleMobileFileTree}>
        Browse
-
      </button>
+
      </Button>
    </nav>
  {/if}

modified src/base/projects/Patch/PatchTabBar.svelte
@@ -60,6 +60,7 @@
    font-size: 0.75rem;
    height: var(--button-tiny-height);
    padding: 0.25rem 0.5rem;
+
    background-color: var(--color-background);
  }
  .revision-toggle:hover {
    background-color: var(--color-foreground-background);
modified src/base/registrations/Index.svelte
@@ -3,6 +3,7 @@
  import type { Config } from "@app/config";

  import DomainInput from "@app/ens/DomainInput.svelte";
+
  import Button from "@app/Button.svelte";

  export let config: Config;

@@ -94,12 +95,13 @@
        {/if}
      </span>

-
      <button
+
      <Button
        disabled={!label || errors.length !== 0}
-
        class="primary register regular"
+
        variant="primary"
+
        size="regular"
        on:click={register}>
        Check
-
      </button>
+
      </Button>
    </div>
  </div>
</main>
modified src/base/registrations/New.svelte
@@ -9,6 +9,7 @@
  import Modal from "@app/Modal.svelte";
  import Loading from "@app/Loading.svelte";
  import Message from "@app/Message.svelte";
+
  import Button from "@app/Button.svelte";

  import { registrar } from "./registrar";

@@ -97,18 +98,23 @@
  <span slot="actions">
    {#if state === State.NameAvailable}
      {#if $session}
-
        <button on:click={begin} class="primary register">
+
        <Button on:click={begin} variant="primary">
          Begin registration &rarr;
-
        </button>
+
        </Button>
      {:else}
-
        <Connect caption="Connect to register" className="primary" {config} />
+
        <Connect
+
          caption="Connect to register"
+
          buttonVariant="primary"
+
          {config} />
      {/if}

-
      <button on:click={() => navigate("/registrations")} class="text">
+
      <Button on:click={() => navigate("/registrations")} variant="text">
        Cancel
-
      </button>
+
      </Button>
    {:else if state === State.NameUnavailable || state === State.CheckingFailed}
-
      <button on:click={() => navigate("/registrations")} class="">Back</button>
+
      <Button variant="foreground" on:click={() => navigate("/registrations")}>
+
        Back
+
      </Button>
    {/if}
  </span>
</Modal>
modified src/base/registrations/Submit.svelte
@@ -9,6 +9,7 @@
  import Modal from "@app/Modal.svelte";
  import Err from "@app/Error.svelte";
  import BlockTimer from "@app/BlockTimer.svelte";
+
  import Button from "@app/Button.svelte";

  import { registerName, State, state } from "./registrar";

@@ -100,7 +101,7 @@

    <span slot="actions">
      {#if $state.connection === State.Registered}
-
        <button on:click={view} class="register">View</button>
+
        <Button on:click={view} variant="foreground">View</Button>
      {/if}
    </span>
  </Modal>
modified src/base/registrations/Update.svelte
@@ -7,6 +7,7 @@
  import Loading from "@app/Loading.svelte";
  import Modal from "@app/Modal.svelte";
  import { Status, State } from "@app/utils";
+
  import Button from "@app/Button.svelte";

  export let domain: string;
  export let config: Config;
@@ -71,9 +72,9 @@
    {#if [Status.Signing, Status.Pending].includes(state.status)}
      <Loading center small />
    {:else if state.status === Status.Success}
-
      <button on:click={onDone}>Done</button>
+
      <Button variant="foreground" on:click={onDone}>Done</Button>
    {:else if state.status === Status.Failed}
-
      <button on:click={onClose}>Close</button>
+
      <Button variant="foreground" on:click={onClose}>Close</Button>
    {/if}
  </span>
</Modal>
modified src/base/registrations/View.svelte
@@ -12,6 +12,7 @@
  import { assert } from "@app/error";
  import Error from "@app/Error.svelte";
  import { isAddressEqual, isReverseRecordSet } from "@app/utils";
+
  import Button from "@app/Button.svelte";

  import { getRegistration, getOwner } from "./registrar";
  import type { EnsRecord } from "./resolver";
@@ -261,15 +262,20 @@
  <main>
    <header>
      <h1 class="bold">{domain}</h1>
-
      <button
-
        style="min-width: 60px;"
-
        class="small primary"
-
        class:active={editable}
-
        disabled={!isOwner(state.owner)}
-
        title={!isOwner(state.owner) ? "Only owner can edit this profile" : ""}
-
        on:click={() => (editable = !editable)}>
-
        Edit
-
      </button>
+
      <div style="width: 4rem;">
+
        {#if !editable}
+
          <Button
+
            size="small"
+
            variant="primary"
+
            disabled={!isOwner(state.owner)}
+
            title={!isOwner(state.owner)
+
              ? "Only owner can edit this profile"
+
              : ""}
+
            on:click={() => (editable = !editable)}>
+
            Edit
+
          </Button>
+
        {/if}
+
      </div>
    </header>
    <Form
      {config}
modified src/base/resolver/List.svelte
@@ -4,6 +4,7 @@
  import type { Config } from "@app/config";
  import { Profile } from "@app/profile";
  import Loading from "@app/Loading.svelte";
+
  import Button from "@app/Button.svelte";

  export let config: Config;

@@ -40,6 +41,6 @@
    </div>
  </span>
  <span slot="actions">
-
    <button on:click={back}>Back</button>
+
    <Button variant="foreground" on:click={back}>Back</Button>
  </span>
</Modal>
modified src/base/vesting/Index.svelte
@@ -8,6 +8,7 @@
  import Modal from "@app/Modal.svelte";
  import Address from "@app/Address.svelte";
  import { formatAddress, isAddressEqual } from "@app/utils";
+
  import Button from "@app/Button.svelte";

  let input: HTMLElement;

@@ -107,22 +108,22 @@
        <span slot="actions">
          {#if isBeneficiary}
            {#if $state === State.WithdrawingSign}
-
              <button disabled data-waiting class="primary regular">
+
              <Button disabled waiting={true} variant="primary">
                Waiting for signature...
-
              </button>
+
              </Button>
            {:else if $state === State.Withdrawing}
-
              <button disabled data-waiting class="primary regular">
+
              <Button disabled waiting={true} variant="primary">
                Withdrawing...
-
              </button>
+
              </Button>
            {:else if $state === State.Idle}
-
              <button
+
              <Button
                on:click={() => withdrawVested(contractAddress, config)}
-
                class="primary regular">
+
                variant="primary">
                Withdraw
-
              </button>
+
              </Button>
            {/if}
          {/if}
-
          <button on:click={reset} class="regular">Back</button>
+
          <Button on:click={reset} variant="primary">Back</Button>
        </span>
      </Modal>
    {:else}
@@ -143,13 +144,13 @@
              bind:value={contractAddress} />
          </div>
        </span>
-
        <button
+
        <Button
          on:click={() => loadContract(config)}
-
          class="primary"
-
          data-waiting={$state === State.Loading || null}
+
          variant="primary"
+
          waiting={$state === State.Loading}
          disabled={$state === State.Loading}>
          Load
-
        </button>
+
        </Button>
      </div>
    {/if}
  </div>
modified src/components/Modal/ConnectWallet.svelte
@@ -1,10 +1,12 @@
<script lang="ts">
+
  import type { Config } from "@app/config";
+

  import { createEventDispatcher } from "svelte";
  import { qrcode } from "pure-svg-code";

  import Modal from "@app/Modal.svelte";
  import { state } from "@app/session";
-
  import type { Config } from "@app/config";
+
  import Button from "@app/Button.svelte";

  export let uri: string;
  export let config: Config;
@@ -72,13 +74,14 @@
    </div>

    <div slot="actions">
-
      <button
-
        class="secondary small text-small"
+
      <Button
+
        variant="secondary"
+
        size="small"
        on:click={onClickConnect}
        disabled={!config.metamask.signer}>
        Connect with Metamask
-
      </button>
-
      <button class="text small text-small" on:click={onClose}>Close</button>
+
      </Button>
+
      <Button variant="text" size="small" on:click={onClose}>Close</Button>
    </div>
  </Modal>
</div>
modified src/ens/SetName.svelte
@@ -11,6 +11,7 @@
  import Error from "@app/Error.svelte";
  import Address from "@app/Address.svelte";
  import * as utils from "@app/utils";
+
  import Button from "@app/Button.svelte";

  const dispatch = createEventDispatcher();

@@ -83,7 +84,9 @@
    </div>

    <div slot="actions">
-
      <button class="regular" on:click={() => dispatch("close")}>Done</button>
+
      <Button variant="secondary" on:click={() => dispatch("close")}>
+
        Done
+
      </Button>
    </div>
  </Modal>
{:else if state === State.Proposed && org}
@@ -103,7 +106,9 @@
    </div>

    <div slot="actions">
-
      <button class="regular" on:click={() => dispatch("close")}>Done</button>
+
      <Button variant="secondary" on:click={() => dispatch("close")}>
+
        Done
+
      </Button>
    </div>
  </Modal>
{:else if state === State.Mismatch}
@@ -115,10 +120,14 @@
    to the correct address and try again.

    <div slot="actions">
-
      <button on:click={() => navigate(`/registrations/${name}`)}>
+
      <Button
+
        variant="negative"
+
        on:click={() => navigate(`/registrations/${name}`)}>
        Go to registration &rarr;
-
      </button>
-
      <button on:click={() => dispatch("close")} class="text">Close</button>
+
      </Button>
+
      <Button variant="negative" on:click={() => dispatch("close")}>
+
        Close
+
      </Button>
    </div>
  </Error>
{:else if state === State.Failed && error}
@@ -161,16 +170,16 @@

    <div slot="actions">
      {#if state === State.Signing}
-
        <button class="regular" on:click={() => dispatch("close")}>
+
        <Button variant="secondary" on:click={() => dispatch("close")}>
          Cancel
-
        </button>
+
        </Button>
      {:else if state === State.Pending}
-
        <button class="regular" on:click={() => dispatch("close")}>
+
        <Button variant="secondary" on:click={() => dispatch("close")}>
          Close
-
        </button>
+
        </Button>
      {:else}
-
        <button
-
          class="primary"
+
        <Button
+
          variant="primary"
          on:click={onSubmit}
          disabled={!name || state !== State.Idle}>
          {#if state === State.Checking}
@@ -178,9 +187,11 @@
          {:else}
            Submit
          {/if}
-
        </button>
+
        </Button>

-
        <button class="text" on:click={() => dispatch("close")}>Cancel</button>
+
        <Button variant="text" on:click={() => dispatch("close")}>
+
          Cancel
+
        </Button>
      {/if}
    </div>
  </Modal>