mirror of
https://github.com/acid-info/Kurate.git
synced 2025-01-27 16:14:46 +00:00
feat: create new identity (epic 4) (#41)
This commit is contained in:
parent
34961926dd
commit
90852893c6
@ -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;
|
||||
|
16
src/lib/components/icons/image.svelte
Normal file
16
src/lib/components/icons/image.svelte
Normal 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>
|
14
src/lib/components/icons/renew.svelte
Normal file
14
src/lib/components/icons/renew.svelte
Normal 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>
|
15
src/lib/components/icons/user-admin.svelte
Normal file
15
src/lib/components/icons/user-admin.svelte
Normal 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>
|
81
src/lib/components/input-file.svelte
Normal file
81
src/lib/components/input-file.svelte
Normal 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>
|
22
src/lib/components/input-string.svelte
Normal file
22
src/lib/components/input-string.svelte
Normal 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>
|
23
src/lib/components/input.svelte
Normal file
23
src/lib/components/input.svelte
Normal 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>
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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
|
||||
|
100
src/routes/profile/new/+page.svelte
Normal file
100
src/routes/profile/new/+page.svelte
Normal 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>
|
@ -7,6 +7,7 @@
|
||||
--color-grey-border: #ddd;
|
||||
--color-grey-background: #f0f0f0;
|
||||
--color-light-grey-background: #ececec;
|
||||
--color-grey-text: #999;
|
||||
|
||||
--color-text: #000;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user