feat: create new identity (epic 4) (#41)

This commit is contained in:
Vojtech Simetka 2022-12-06 10:13:41 +01:00 committed by GitHub
parent 34961926dd
commit 90852893c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 305 additions and 7 deletions

View File

@ -6,9 +6,10 @@
export let variant: 'secondary' | 'primary' = 'secondary'
export let icon: ComponentConstructor<IconProps> | undefined = undefined
export let label: string | undefined = undefined
export let disabled: boolean | undefined = undefined
</script>
<button class={`root ${variant} ${!label ? 'icon-only' : ''} ${cls}`} on:click>
<button {disabled} class={`root ${variant} ${!label ? 'icon-only' : ''} ${cls}`} on:click>
{#if icon !== undefined}
<div class="wrapper">
<svelte:component this={icon} />
@ -34,6 +35,11 @@
font-family: var(--font-body);
font-weight: 600;
font-size: 16px;
&:disabled {
cursor: not-allowed;
opacity: 0.15;
}
}
.icon-only {
width: 44px;

View File

@ -0,0 +1,16 @@
<script lang="ts">
import type { IconProps } from '$lib/types'
type $$Props = IconProps
let cls: string | undefined = undefined
export { cls as class }
export let size = 20
</script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width={size} height={size} class={cls}>
<path d="M19,14a3,3,0,1,0-3-3A3,3,0,0,0,19,14Zm0-4a1,1,0,1,1-1,1A1,1,0,0,1,19,10Z" />
<path
d="M26,4H6A2,2,0,0,0,4,6V26a2,2,0,0,0,2,2H26a2,2,0,0,0,2-2V6A2,2,0,0,0,26,4Zm0,22H6V20l5-5,5.59,5.59a2,2,0,0,0,2.82,0L21,19l5,5Zm0-4.83-3.59-3.59a2,2,0,0,0-2.82,0L18,19.17l-5.59-5.59a2,2,0,0,0-2.82,0L6,17.17V6H26Z"
/>
</svg>

View File

@ -0,0 +1,14 @@
<script lang="ts">
import type { IconProps } from '$lib/types'
type $$Props = IconProps
let cls: string | undefined = undefined
export { cls as class }
export let size = 20
</script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width={size} height={size} class={cls}>
<path d="M12,10H6.78A11,11,0,0,1,27,16h2A13,13,0,0,0,6,7.68V4H4v8h8Z" />
<path d="M20,22h5.22A11,11,0,0,1,5,16H3a13,13,0,0,0,23,8.32V28h2V20H20Z" />
</svg>

View File

@ -0,0 +1,15 @@
<script lang="ts">
import type { IconProps } from '$lib/types'
type $$Props = IconProps
let cls: string | undefined = undefined
export { cls as class }
export let size = 20
</script>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width={size} height={size} class={cls}>
<path d="M12,4A5,5,0,1,1,7,9a5,5,0,0,1,5-5m0-2a7,7,0,1,0,7,7A7,7,0,0,0,12,2Z" />
<path d="M22,30H20V25a5,5,0,0,0-5-5H9a5,5,0,0,0-5,5v5H2V25a7,7,0,0,1,7-7h6a7,7,0,0,1,7,7Z" />
<polygon points="25 16.18 22.41 13.59 21 15 25 19 32 12 30.59 10.59 25 16.18" />
</svg>

View File

@ -0,0 +1,81 @@
<script lang="ts">
import type { ComponentConstructor, IconProps } from '$lib/types'
export let files: FileList | undefined = undefined
let cls: string | undefined = undefined
export { cls as class }
export let variant: 'secondary' | 'primary' = 'secondary'
export let icon: ComponentConstructor<IconProps> | undefined = undefined
export let label: string | undefined = undefined
export let disabled: boolean | undefined = undefined
</script>
<label class={`root ${variant} ${!label ? 'icon-only' : ''} ${disabled ? 'disabled' : ''} ${cls}`}>
{#if icon !== undefined}
<div class="wrapper">
<svelte:component this={icon} />
</div>
{/if}
{#if label !== undefined}
{label}
{/if}
<input type="file" bind:files {disabled} />
</label>
<style lang="scss">
.root {
input {
display: none;
}
padding-left: var(--spacing-15);
padding-right: var(--spacing-15);
height: 44px;
border: 1px solid var(--color-primary);
border-radius: 50px;
cursor: pointer;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-family: var(--font-body);
font-weight: 600;
font-size: 16px;
&.disabled {
cursor: not-allowed;
opacity: 0.15;
}
}
.icon-only {
width: 44px;
.wrapper {
margin-right: 0px;
}
}
.wrapper {
width: 20px;
height: 20px;
margin-right: var(--spacing-6);
}
.primary {
background-color: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-secondary);
& :global(svg) {
fill: var(--color-secondary);
}
}
.secondary {
background-color: var(--color-secondary);
border-color: var(--color-grey-border);
color: var(--color-primary);
& :global(svg) {
fill: var(--color-primary);
}
}
</style>

View File

@ -0,0 +1,22 @@
<script lang="ts">
let cls: string | undefined = undefined
export { cls as class }
export let value: string | undefined = undefined
export let disabled: boolean | undefined = undefined
export let placeholder: string | undefined = undefined
</script>
<input type="text" {placeholder} {disabled} bind:value class={`root ${cls}`} />
<style lang="scss">
.root {
border: none;
font-family: var(--font-body);
font-size: 18px;
&:disabled {
cursor: not-allowed;
opacity: 0.15;
}
}
</style>

View File

@ -0,0 +1,23 @@
<script lang="ts">
export let title: string | undefined = undefined
</script>
<div class="root">
<span class="title">{title}</span>
<slot />
</div>
<style lang="scss">
.root {
padding: var(--spacing-12);
display: flex;
flex-direction: column;
border-top: 1px solid var(--color-light-grey-background);
}
.title {
margin-bottom: var(--spacing-6);
font-family: var(--font-body);
font-size: 14px;
color: var(--color-grey-text);
}
</style>

View File

@ -2,6 +2,7 @@ import { writable, type Writable } from 'svelte/store'
import type { User } from './user'
export interface Profile {
key?: boolean // FIXME: this will need to change
profiles: User[]
active?: User
}

View File

@ -1,5 +1,5 @@
export function formatAddress(address: string) {
return `${address.substring(0, 6)}${address.substring(address.length - 5)}`
export function formatAddress(address: string, digits = 4) {
return `${address.substring(0, digits + 2)}${address.substring(address.length - digits - 1)}`
}
export function formatDateFromNow(timestamp: number) {

View File

@ -5,7 +5,9 @@
import Close from '$lib/components/icons/close.svelte'
import CodeSigningService from '$lib/components/icons/code-signing-service.svelte'
import GroupSecurity from '$lib/components/icons/group-security.svelte'
import Renew from '$lib/components/icons/renew.svelte'
import UpToTop from '$lib/components/icons/up-to-top.svelte'
import UserAdmin from '$lib/components/icons/user-admin.svelte'
import User from '$lib/components/icons/user.svelte'
import Wallet from '$lib/components/icons/wallet.svelte'
import img1 from '$lib/temp/assets/1.png'
@ -14,10 +16,16 @@
<h2>Buttons</h2>
<Button label="primary" variant="primary" />
<Button label="secondary" variant="secondary" />
<Button label="primary disabled" variant="primary" disabled />
<Button label="secondary disabled" variant="secondary" disabled />
<Button label="primary icon" variant="primary" icon={UpToTop} />
<Button label="secondary icon" variant="secondary" icon={UpToTop} />
<Button label="primary icon disabled" variant="primary" icon={UpToTop} disabled />
<Button label="secondary icon disabled" variant="secondary" icon={UpToTop} disabled />
<Button variant="primary" icon={UpToTop} />
<Button variant="secondary" icon={UpToTop} />
<Button variant="primary" icon={UpToTop} disabled />
<Button variant="secondary" icon={UpToTop} disabled />
<h2>Icons</h2>
@ -28,6 +36,8 @@
<ArrowRight />
<Close />
<CodeSigningService />
<Renew />
<UserAdmin />
<h2>Avatar</h2>

View File

@ -1,4 +1,5 @@
<script lang="ts">
import { goto } from '$app/navigation'
import Button from '$lib/components/button.svelte'
import Close from '$lib/components/icons/close.svelte'
import CodeSigningService from '$lib/components/icons/code-signing-service.svelte'
@ -14,22 +15,30 @@
</script>
<div class="header">
<h1>Choose identity</h1>
<h1>{$profile.key ? 'Choose' : 'Create'} identity</h1>
<Button icon={Close} on:click={() => history.back()} />
</div>
<div class="content">
{#if $profile.profiles.length > 0}
{#if $profile.key}
{#each $profile.profiles as p}
<Identity identity={p} click={onSelectIdentityClick} />
{/each}
<Button icon={GroupSecurity} label="Create new identity" />
<Button icon={GroupSecurity} label="Create new identity" on:click={() => goto('profile/new')} />
<span>You can create multiple identities under the same account.</span>
<a href="/">Learn more about identities.</a>
{:else}
<div class="icon">
<GroupSecurity size={200} />
</div>
<Button variant="primary" icon={CodeSigningService} label="Generate new keypair" />
<Button
variant="primary"
icon={CodeSigningService}
label="Generate new keypair"
on:click={() => {
$profile.key = true
goto('profile/new')
}}
/>
<span
>You need to generate a new address to be associated with your identity. This address will
different that your account address.</span

View File

@ -0,0 +1,100 @@
<script lang="ts">
import Button from '$lib/components/button.svelte'
import Close from '$lib/components/icons/close.svelte'
import UserAdmin from '$lib/components/icons/user-admin.svelte'
import Input from '$lib/components/input.svelte'
import InputFile from '$lib/components/input-file.svelte'
import Image from '$lib/components/icons/image.svelte'
import InputString from '$lib/components/input-string.svelte'
import { profile } from '$lib/stores/profile'
import { formatAddress } from '$lib/utils'
const generateRandomHex = (size: number) =>
`0x${[...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')}`
let address = generateRandomHex(40)
let name = ''
let files: FileList | undefined = undefined
let file: File | undefined = undefined
let image: string | undefined
let disabled = true
$: file = files && files[0]
$: image = file ? URL.createObjectURL(file) : undefined
$: disabled = name === '' || image === undefined
</script>
<div class="header">
<h1>Create identity</h1>
<Button icon={Close} on:click={() => history.back()} />
</div>
<div class="content">
<Input title="Public address">
<div>{formatAddress(address, 8)}</div>
</Input>
<Input title="Name">
<InputString bind:value={name} placeholder="Enter identity name…" />
</Input>
<Input title="Profile picture">
<div class="profile">
{#if image !== undefined}
<img src={image} alt={file?.name} />
{/if}
<InputFile bind:files label="Add image..." icon={Image} variant="secondary" />
</div>
{#if file !== undefined}
<span>{file.name}</span>
{/if}
</Input>
<div class="action">
<Button
icon={UserAdmin}
variant="primary"
{disabled}
label="Confirm and create"
on:click={() => {
const user = { address, name, avatar: image }
$profile.profiles = [...$profile.profiles, user]
profile.setActive(user)
history.back()
}}
/>
</div>
</div>
<style lang="scss">
.header {
left: 0;
right: 0;
top: 0;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.content {
display: flex;
flex-direction: column;
}
.action {
border-top: 1px solid var(--color-light-grey-background);
padding: var(--spacing-24);
display: flex;
justify-content: center;
}
.profile {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
img {
width: 200px;
height: 200px;
object-fit: contain;
}
}
</style>

View File

@ -7,6 +7,7 @@
--color-grey-border: #ddd;
--color-grey-background: #f0f0f0;
--color-light-grey-background: #ececec;
--color-grey-text: #999;
--color-text: #000;