feat: button component with icons (#5)

This commit is contained in:
Vojtech Simetka 2022-11-24 17:22:37 +01:00 committed by GitHub
parent b60baf462f
commit 814229ef90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 131 additions and 29 deletions

View File

@ -17,4 +17,7 @@ module.exports = {
es2017: true,
node: true,
},
globals: {
svelte: true,
},
}

26
package-lock.json generated
View File

@ -8,6 +8,8 @@
"name": "theoutlet",
"version": "0.0.1",
"devDependencies": {
"@fontsource/source-code-pro": "^4.5.12",
"@fontsource/source-sans-pro": "^4.5.11",
"@playwright/test": "1.28.1",
"@sveltejs/adapter-static": "^1.0.0-next.48",
"@sveltejs/kit": "next",
@ -81,6 +83,18 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@fontsource/source-code-pro": {
"version": "4.5.12",
"resolved": "https://registry.npmjs.org/@fontsource/source-code-pro/-/source-code-pro-4.5.12.tgz",
"integrity": "sha512-6r1dykX7SH1Orm7xUh4sA8pjM1uNPKo9fV+y9/wxS+y/fwN+sMf6b1jHDUTmfEtw1OxlTaHGrr2I7dGeNqxdPA==",
"dev": true
},
"node_modules/@fontsource/source-sans-pro": {
"version": "4.5.11",
"resolved": "https://registry.npmjs.org/@fontsource/source-sans-pro/-/source-sans-pro-4.5.11.tgz",
"integrity": "sha512-f7iw44q1EjBv3MNcHCGAgrW/QVyweaEouFsJzykPhTOGnZFSwFJRISToXornOmuAy7xUUGiVdqOLiykgZoYB8A==",
"dev": true
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.7",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
@ -2945,6 +2959,18 @@
"strip-json-comments": "^3.1.1"
}
},
"@fontsource/source-code-pro": {
"version": "4.5.12",
"resolved": "https://registry.npmjs.org/@fontsource/source-code-pro/-/source-code-pro-4.5.12.tgz",
"integrity": "sha512-6r1dykX7SH1Orm7xUh4sA8pjM1uNPKo9fV+y9/wxS+y/fwN+sMf6b1jHDUTmfEtw1OxlTaHGrr2I7dGeNqxdPA==",
"dev": true
},
"@fontsource/source-sans-pro": {
"version": "4.5.11",
"resolved": "https://registry.npmjs.org/@fontsource/source-sans-pro/-/source-sans-pro-4.5.11.tgz",
"integrity": "sha512-f7iw44q1EjBv3MNcHCGAgrW/QVyweaEouFsJzykPhTOGnZFSwFJRISToXornOmuAy7xUUGiVdqOLiykgZoYB8A==",
"dev": true
},
"@humanwhocodes/config-array": {
"version": "0.11.7",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",

View File

@ -13,6 +13,8 @@
"format": "prettier --plugin-search-dir . --write . && eslint . --fix"
},
"devDependencies": {
"@fontsource/source-code-pro": "^4.5.12",
"@fontsource/source-sans-pro": "^4.5.11",
"@playwright/test": "1.28.1",
"@sveltejs/adapter-static": "^1.0.0-next.48",
"@sveltejs/kit": "next",

View File

@ -1,18 +1,57 @@
<script lang="ts">
import type { ComponentConstructor, IconProps } from '$lib/types'
export let variant: 'light' | 'dark' = 'light'
export let icon: ComponentConstructor<IconProps> | undefined = undefined
export let click: svelte.JSX.MouseEventHandler<HTMLButtonElement> | null | undefined = undefined
export let label: string | undefined = undefined
let hovered = false
$: fill = (variant === 'dark' && hovered) || (variant === 'light' && !hovered) ? 'black' : 'white'
</script>
<button class={`${variant} root`}>
<slot />
<button
class={`root ${variant} ${!label ? 'icon-only' : ''}`}
on:mouseenter={() => (hovered = true)}
on:click={click}
on:mouseleave={() => (hovered = false)}
>
{#if icon !== undefined}
<div class="wrapper">
<svelte:component this={icon} size={20} {fill} />
</div>
{/if}
{#if label !== undefined}
{label}
{/if}
</button>
<style>
.root {
padding: 15px;
padding-left: 15px;
padding-right: 15px;
height: 44px;
border: 1px solid var(--color-black);
border-radius: 50px;
cursor: pointer;
transition: 1s;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-family: var(--font-body);
font-weight: 600;
font-size: 16px;
}
.icon-only {
width: 44px;
}
.wrapper {
width: 20px;
height: 20px;
margin-right: 10px;
}
.icon-only .wrapper {
margin-right: 0px;
}
.light,
.dark:hover {
@ -20,11 +59,10 @@
background-color: var(--color-white);
border-color: var(--color-light-grey);
}
.dark,
.light:hover {
color: var(--color-white);
background-color: var(--color-black);
border-color: var(--color-light-black);
border-color: var(--color-black);
}
</style>

View File

@ -1,12 +1,11 @@
<script lang="ts">
import UserIcon from '$lib/components/icons/user.svelte'
import Button from './button.svelte'
</script>
<div class="root">
<span class="title">The Outlet</span>
<div class="user-icon">
<UserIcon size={18} />
</div>
<Button icon={UserIcon} />
</div>
<style>
@ -17,21 +16,10 @@
padding: 15px;
}
.title {
font-family: 'SourceSansPro-Semibold';
font-size: 18px;
font-family: var(--font-body);
font-weight: 600;
font-size: 18px;
font-style: normal;
text-align: left;
}
.user-icon {
width: 38px;
height: 38px;
border-radius: 19px;
border-color: #dddddd;
border-style: solid;
border-width: 1px;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@ -1,8 +1,16 @@
<script lang="ts">
import type { IconProps } from '$lib/types'
type $$Props = IconProps
export let size = 32
export let fill = 'black'
</script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width={size} height={size}>
<path d="M16,4a5,5,0,1,1-5,5,5,5,0,0,1,5-5m0-2a7,7,0,1,0,7,7A7,7,0,0,0,16,2Z" />
<path d="M26,30H24V25a5,5,0,0,0-5-5H13a5,5,0,0,0-5,5v5H6V25a7,7,0,0,1,7-7h6a7,7,0,0,1,7,7Z" />
<path {fill} d="M16,4a5,5,0,1,1-5,5,5,5,0,0,1,5-5m0-2a7,7,0,1,0,7,7A7,7,0,0,0,16,2Z" />
<path
{fill}
d="M26,30H24V25a5,5,0,0,0-5-5H13a5,5,0,0,0-5,5v5H6V25a7,7,0,0,1,7-7h6a7,7,0,0,1,7,7Z"
/>
</svg>

View File

@ -0,0 +1,16 @@
<script lang="ts">
import type { IconProps } from '$lib/types'
type $$Props = IconProps
export let size = 32
export let fill = 'black'
</script>
<svg id="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width={size} height={size}>
<rect x="22" y="17" width="2" height="2" {fill} />
<path
{fill}
d="M28,8H4V5H26V3H4A2,2,0,0,0,2,5V26a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10A2,2,0,0,0,28,8ZM4,26V10H28v3H20a2,2,0,0,0-2,2v6a2,2,0,0,0,2,2h8v3ZM28,15v6H20V15Z"
/>
</svg>

12
src/lib/types.ts Normal file
View File

@ -0,0 +1,12 @@
import type { SvelteComponentTyped } from 'svelte'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ComponentConstructor<T extends Record<string, any>> = new (args: {
target: Element | ShadowRoot
props?: T
}) => SvelteComponentTyped<T>
export interface IconProps {
fill?: string
size?: number
}

View File

@ -0,0 +1,7 @@
<script lang="ts">
import '@fontsource/source-code-pro'
import '@fontsource/source-sans-pro'
import './styles.css'
</script>
<slot />

View File

@ -1,11 +1,11 @@
<script lang="ts">
import './styles.css'
import Header from '$lib/components/header.svelte'
import Button from '$lib/components/button.svelte'
import WalletIcon from '$lib/components/icons/wallet.svelte'
</script>
<div>
<Header />
<Button>Light Button</Button>
<Button variant="dark">Dark Button</Button>
<Button label="Light Button" />
<Button variant="dark" label="Dark Button" icon={WalletIcon} />
</div>

View File

@ -1,6 +1,6 @@
:root {
--font-body: ' SourceSansPro-Semibold';
--font-mono: monospace;
--font-body: 'Source Sans Pro';
--font-mono: 'Source Code Pro';
--color-light-grey: #ddd;
--color-white: #fff;
@ -15,4 +15,6 @@ body {
padding: 0;
color: var(--color-black);
background-color: var(--color-white);
font-family: 'Source Sans Pro';
font-weight: 400;
}