feat: reduced scope to just global timeline and without avatars (#77)

This commit is contained in:
Vojtech Simetka 2022-12-15 15:01:33 +01:00 committed by GitHub
parent bcbf373e07
commit 2aa2c2d81b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 16 additions and 471 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,22 +0,0 @@
<script lang="ts">
import defaultAvatar from '$lib/assets/default-avatar.png'
let cls: string | undefined = undefined
export { cls as class }
export let src: string = defaultAvatar
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<img class={`root ${cls}`} {src} alt="Avatar" on:click />
<style>
.root {
width: 44px;
height: 44px;
border-radius: 22px;
background-color: var(--color-light-grey-background);
object-fit: cover;
overflow: hidden;
cursor: pointer;
}
</style>

View File

@ -2,19 +2,17 @@
import UserIcon from '$lib/components/icons/user.svelte'
import Button from './button.svelte'
import WalletConnect from '$lib/components/wallet-connect.svelte'
import Avatar from '$lib/components/avatar.svelte'
import Edit from '$lib/components/icons/edit.svelte'
import { profile } from '$lib/stores/profile'
import type { User } from '$lib/stores/user'
import { goto } from '$app/navigation'
import { ROUTES } from '$lib/routes'
import Wallet from './icons/wallet.svelte'
let cls: string | undefined = undefined
export { cls as class }
export let user: User | undefined = undefined
let y: number
export let loggedin: boolean | undefined = undefined
</script>
<svelte:window bind:scrollY={y} />
@ -22,11 +20,7 @@
<div class={`root ${y > 0 ? 'scrolled' : ''} ${cls}`}>
<div class="header">
<span class="header-title">The Outlet</span>
{#if user !== undefined}
<Avatar src={user.avatar} on:click={() => goto(ROUTES.PROFILE)} />
{:else}
<Button icon={UserIcon} on:click={() => goto(ROUTES.PROFILE)} />
{/if}
<Button icon={loggedin ? UserIcon : Wallet} on:click={() => goto(ROUTES.PROFILE)} />
</div>
<div class="header-description">
Milestone 1 shaman pitchfork typewriter single-origin coffee beard flannel, actually chillwave.
@ -34,9 +28,8 @@
<div class="subtitle">Public timeline</div>
{#if $profile.active !== undefined}
{#if $profile.key?.publicKey !== undefined}
<div>
<Avatar src={$profile.active.avatar} />
Share freely...
<Button
variant="primary"
@ -45,16 +38,6 @@
on:click={() => goto('/post/new')}
/>
</div>
{:else if $profile.key?.publicKey !== undefined}
<div>
<Button
variant="primary"
label="Select identity"
icon={UserIcon}
on:click={() => goto('/profile')}
/>
Select an identity to use with your account.
</div>
{:else}
<WalletConnect />
{/if}

View File

@ -1,32 +0,0 @@
<script lang="ts">
import type { User } from '$lib/stores/user'
import Avatar from './avatar.svelte'
import ArrowRight from './icons/arrow-right.svelte'
export let identity: User
export let click: undefined | ((id: User) => void) = undefined
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="root" on:click|preventDefault|stopPropagation={() => click && click(identity)}>
<Avatar src={identity.avatar} />
<div class="description">
<div>{identity.name}</div>
<div />
</div>
<ArrowRight />
</div>
<style lang="scss">
.root {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.description {
display: flex;
flex-direction: column;
flex-grow: 1;
}
</style>

View File

@ -1,81 +0,0 @@
<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

@ -1,30 +1,19 @@
<script lang="ts">
import Avatar from './avatar.svelte'
import { formatAddress, formatDateFromNow } from '$lib/utils'
import type { Post } from '$lib/stores/post'
import type { User } from '$lib/stores/user'
let cls: string | undefined = undefined
export { cls as class }
export let post: Post
export let onUserClick: ((user: User) => void) | undefined = undefined
</script>
<div class={`root ${cls}`}>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="user-img" on:click={() => onUserClick && onUserClick(post.user)}>
<Avatar src={post.user.avatar} />
</div>
<div class="content-wrapper">
<div class="user-info">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="username" on:click={() => onUserClick && onUserClick(post.user)}>
<div class="username">
{post.user.name ?? 'Anonymous'}
</div>
{#if post.user.address !== undefined}
<div>{formatAddress(post.user.address)}</div>
{/if}
<div class="faded"></div>
<div class="faded">{formatDateFromNow(post.timestamp)}</div>
</div>

View File

@ -1,8 +1,5 @@
export const ROUTES = {
HOME: '/',
PROFILE: '/profile',
PROFILE_ADDRESS: (address: string) => `/profile/${address}`,
IDENTITY: '/identity',
IDENTITY_NEW: '/identity/new',
POST_NEW: '/post/new',
}

View File

@ -3,7 +3,6 @@ import { writable, type Writable } from 'svelte/store'
export interface User {
name?: string
address: string
avatar?: string
}
export interface UserStore extends Writable<User[]> {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -3,9 +3,6 @@
import { users, type User } from '$lib/stores/user'
import { posts } from '$lib/stores/post'
import Button from '$lib/components/button.svelte'
import image1 from '$lib/temp/assets/1.png'
import image2 from '$lib/temp/assets/2.png'
import image3 from '$lib/temp/assets/3.png'
const testPosts: Post[] = [
{
@ -13,7 +10,6 @@
text: 'Decision making by awkward silence.',
user: {
name: 'CoyoteRide',
avatar: image1,
address: '0x2d37a46fad14c4fcaba66660da6a5d99af88bf71',
},
},
@ -22,7 +18,6 @@
text: "It's an amazing trigger within human nature: the minute someone acknowledges their flaws, not only do we tend to forgive them, but we actually come to admire them.",
user: {
name: 'Lemur',
avatar: image2,
address: '0x032b3c7a6af9bbf38838f582acc8e4074932f2b8',
},
},
@ -45,7 +40,6 @@
text: "Y'all should go check this amazing online magazine https://two.compost.digital/",
user: {
name: 'Cryptocowboy',
avatar: image3,
address: '0x0554369c1f47B130104fC8A6aa5a94fF3b06b0e1',
},
},
@ -61,7 +55,6 @@
text: 'Decision making by awkward silence.',
user: {
name: 'CoyoteRide',
avatar: image1,
address: '0x2d37a46fad14c4fcaba66660da6a5d99af88bf71',
},
},
@ -70,7 +63,6 @@
text: "It's an amazing trigger within human nature: the minute someone acknowledges their flaws, not only do we tend to forgive them, but we actually come to admire them.",
user: {
name: 'Lemur',
avatar: image2,
address: '0x032b3c7a6af9bbf38838f582acc8e4074932f2b8',
},
},
@ -93,7 +85,6 @@
text: "Y'all should go check this amazing online magazine https://two.compost.digital/",
user: {
name: 'Cryptocowboy',
avatar: image3,
address: '0x0554369c1f47B130104fC8A6aa5a94fF3b06b0e1',
},
},
@ -109,7 +100,6 @@
text: 'Decision making by awkward silence.',
user: {
name: 'CoyoteRide',
avatar: image1,
address: '0x2d37a46fad14c4fcaba66660da6a5d99af88bf71',
},
},

View File

@ -1,28 +1,18 @@
<script lang="ts">
import { goto } from '$app/navigation'
import Header from '$lib/components/header.svelte'
import Post from '$lib/components/post.svelte'
import Populate from '$lib/temp/index.svelte'
import { posts } from '$lib/stores/post'
import { profile } from '$lib/stores/profile'
import { ROUTES } from '$lib/routes'
</script>
<div>
<Header user={$profile.active} />
<Header loggedin={$profile.key !== undefined} />
{#each $posts as post}
<Post
{post}
onUserClick={(user) => {
goto(ROUTES.PROFILE_ADDRESS(user.address))
}}
/>
<Post {post} />
{:else}
<Populate />
{/each}
</div>
<style>
</style>

View File

@ -1,5 +1,4 @@
<script lang="ts">
import Avatar from '$lib/components/avatar.svelte'
import Button from '$lib/components/button.svelte'
import ArrowRight from '$lib/components/icons/arrow-right.svelte'
import Close from '$lib/components/icons/close.svelte'
@ -11,7 +10,6 @@
import User from '$lib/components/icons/user.svelte'
import Wallet from '$lib/components/icons/wallet.svelte'
import Edit from '$lib/components/icons/edit.svelte'
import img1 from '$lib/temp/assets/1.png'
</script>
<h2>Buttons</h2>
@ -40,8 +38,3 @@
<Renew />
<UserAdmin />
<Edit />
<h2>Avatar</h2>
<Avatar />
<Avatar src={img1} />

View File

@ -1,71 +0,0 @@
<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'
import GroupSecurity from '$lib/components/icons/group-security.svelte'
import Identity from '$lib/components/identity.svelte'
import { ROUTES } from '$lib/routes'
import { profile } from '$lib/stores/profile'
import type { User } from '$lib/stores/user'
const onSelectIdentityClick = (id: User) => {
$profile.active = id
history.back()
}
</script>
<div class="header">
<h1>{$profile.key ? 'Choose' : 'Create'} identity</h1>
<Button icon={Close} on:click={() => history.back()} />
</div>
<div class="content">
{#if $profile.key}
{#each $profile.profiles as p}
<Identity identity={p} click={onSelectIdentityClick} />
{/each}
<Button
icon={GroupSecurity}
label="Create new identity"
on:click={() => goto(ROUTES.IDENTITY_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"
on:click={() => {
$profile.key = { publicKey: '0x90b1c0A1EeF1fe519AeE75D2Ee04855219923f26' }
}}
/>
<span
>You need to generate a new address to be associated with your identity. This address will
different that your account address.</span
>
{/if}
</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;
align-items: center;
}
.icon :global(svg) {
fill: grey;
}
</style>

View File

@ -1,102 +0,0 @@
<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 Renew from '$lib/components/icons/renew.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} />
<InputFile bind:files label="Change" icon={Renew} variant="secondary" />
{:else}
<InputFile bind:files label="Add image..." icon={Image} variant="secondary" />
{/if}
</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]
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

@ -1,5 +1,4 @@
<script lang="ts">
import Avatar from '$lib/components/avatar.svelte'
import Button from '$lib/components/button.svelte'
import Close from '$lib/components/icons/close.svelte'
import SendAltFilled from '$lib/components/icons/send-alt-filled.svelte'
@ -7,18 +6,17 @@
import { profile } from '$lib/stores/profile'
import { posts } from '$lib/stores/post'
import { goto } from '$app/navigation'
import Collaborate from '$lib/components/icons/collaborate.svelte'
import { ROUTES } from '$lib/routes'
let postText = ''
function submit() {
if (!$profile.active) return
if (!$profile.key?.publicKey) return
posts.add({
timestamp: Date.now(),
text: postText,
user: $profile.active,
user: { address: $profile.key.publicKey },
})
goto(ROUTES.HOME)
}
@ -28,17 +26,16 @@
<div>Create post</div>
<div>
<Button variant="secondary" label="Cancel" icon={Close} on:click={() => history.back()} />
<Button variant="primary" label="Post" icon={SendAltFilled} on:click={submit} />
<Button
variant="primary"
label="Post"
icon={SendAltFilled}
on:click={submit}
disabled={!$profile.key?.publicKey}
/>
</div>
</div>
<div>
<Avatar src={$profile.active?.avatar} on:click={() => goto(ROUTES.PROFILE)} />
<div>{$profile.active?.name}</div>
<div>{$profile.active?.address}</div>
<Button variant="secondary" icon={Collaborate} on:click={() => goto(ROUTES.IDENTITY)} />
</div>
<InputString bind:value={postText} placeholder="Write here..." />
<style lang="scss">

View File

@ -1,24 +1,10 @@
<script lang="ts">
import { goto } from '$app/navigation'
import Avatar from '$lib/components/avatar.svelte'
import Button from '$lib/components/button.svelte'
import Collaborate from '$lib/components/icons/collaborate.svelte'
import Logout from '$lib/components/icons/logout.svelte'
import Image from '$lib/components/icons/image.svelte'
import Undo from '$lib/components/icons/undo.svelte'
import Wallet from '$lib/components/icons/wallet.svelte'
import InputFile from '$lib/components/input-file.svelte'
import InputString from '$lib/components/input-string.svelte'
import Input from '$lib/components/input.svelte'
import { ROUTES } from '$lib/routes'
import { profile } from '$lib/stores/profile'
import Renew from '$lib/components/icons/renew.svelte'
let files: FileList | undefined = undefined
let file: File | undefined = undefined
$: file = files && files[0]
$: if ($profile.active && file) $profile.active.avatar = URL.createObjectURL(file)
</script>
<div class="header">
@ -48,38 +34,6 @@
<Input title="Connected wallet">
<span>{$profile.key.publicKey}</span>
</Input>
{#if $profile.active === undefined}
<Button
variant="primary"
icon={Collaborate}
label="Select identity"
on:click={() => goto(ROUTES.IDENTITY)}
/>
<span>Select an identity to use with your account.</span>
{:else}
<div>
<span>Selected identity</span>
<Avatar src={$profile.active.avatar} />
<span>{$profile.active.name}</span>
<span>{$profile.active.address}</span>
<Button icon={Collaborate} on:click={() => goto(ROUTES.IDENTITY)} />
</div>
<Input title="Name">
<InputString bind:value={$profile.active.name} placeholder="Enter identity name…" />
</Input>
<Input title="Profile picture">
<div class="profile">
{#if $profile.active.avatar !== undefined}
<img src={$profile.active.avatar} alt={file?.name} />
<InputFile bind:files label="Change" icon={Renew} variant="secondary" />
{:else}
<InputFile bind:files label="Add image..." icon={Image} variant="secondary" />
{/if}
</div>
</Input>
{/if}
{/if}
</div>

View File

@ -1,5 +0,0 @@
<script>
import { page } from '$app/stores'
</script>
<h1>{$page.status}: {$page.error?.message}</h1>

View File

@ -1,19 +0,0 @@
<script lang="ts">
import Avatar from '$lib/components/avatar.svelte'
import type { PageData } from './$types'
export let data: PageData
</script>
<div class="root">
<div><Avatar src={data.avatar} /></div>
<div>{data.name}</div>
<div>{data.address}</div>
</div>
<style>
.root {
display: flex;
flex-direction: column;
}
</style>

View File

@ -1,15 +0,0 @@
import { error } from '@sveltejs/kit'
import type { PageLoad } from './$types'
import { users } from '$lib/stores/user'
export const load: PageLoad = async ({ params }) => {
if (!/0x[a-z0-9]{40}/i.test(params.address)) {
throw error(404, `Incorrect user address format ${params.address}`)
}
const user = await users.find(params.address)
if (!user) throw error(404, `Could not find user with address ${params.address}`)
return user
}