mirror of
https://github.com/acid-info/Kurate.git
synced 2025-02-18 18:56:55 +00:00
feat: added personas while still maintaining the ability to post (#154)
This commit is contained in:
parent
e24ab63af1
commit
9855038cac
@ -1,42 +0,0 @@
|
||||
<script lang="ts">
|
||||
let cls: string | undefined = undefined
|
||||
export { cls as class }
|
||||
</script>
|
||||
|
||||
<div class={`root header-description ${cls}`}>
|
||||
<div class="subtitle">Public timeline</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
padding: var(--spacing-12);
|
||||
transition: padding 0.2s, margin 0.2s;
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
padding-bottom: var(--spacing-12);
|
||||
margin: 0;
|
||||
transition: padding 0.2s, margin 0.2s;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
&.scrolled {
|
||||
box-shadow: 0 1px 5px 0 rgba(var(--color-body-bg-rgb), 0.75);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
padding: 0;
|
||||
width: 1280px;
|
||||
margin: 0 auto 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,21 +1,28 @@
|
||||
<script lang="ts">
|
||||
import UserIcon from '$lib/components/icons/user.svelte'
|
||||
import Button from './button.svelte'
|
||||
|
||||
import { goto } from '$app/navigation'
|
||||
import { ROUTES } from '$lib/routes'
|
||||
import Wallet from './icons/wallet.svelte'
|
||||
import Edit from './icons/edit.svelte'
|
||||
import UpToTop from './icons/up-to-top.svelte'
|
||||
import { formatAddress } from '$lib/utils'
|
||||
import { profile } from '$lib/stores/profile'
|
||||
import { connectWallet } from '$lib/services'
|
||||
|
||||
let cls: string | undefined = undefined
|
||||
export { cls as class }
|
||||
|
||||
let y: number
|
||||
export let loggedin: boolean | undefined = undefined
|
||||
export let address: string | undefined = undefined
|
||||
|
||||
function goTop() {
|
||||
document.body.scrollIntoView()
|
||||
const handleConnect = async () => {
|
||||
try {
|
||||
const signer = await connectWallet()
|
||||
const address = await signer.getAddress()
|
||||
|
||||
$profile = { signer, address }
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -25,26 +32,25 @@
|
||||
<div class="header-content">
|
||||
<div class="header">
|
||||
<div class="header-title-wrap">
|
||||
<div class="top-button">
|
||||
<Button icon={UpToTop} on:click={goTop} />
|
||||
</div>
|
||||
<span class={` ${y > 0 ? 'subtitle' : 'header-title'} ${cls}`}>
|
||||
{y > 0 ? 'Public Timeline' : 'The Outlet'}
|
||||
</span>
|
||||
<span class={`header-title ${cls}`}>Kurate</span>
|
||||
</div>
|
||||
|
||||
<div class="btns">
|
||||
<div class="btn wallet">
|
||||
{#if address}
|
||||
<Button
|
||||
icon={loggedin ? Edit : Wallet}
|
||||
variant="primary"
|
||||
on:click={() => goto(loggedin ? ROUTES.POST_NEW : ROUTES.PROFILE)}
|
||||
icon={Wallet}
|
||||
variant={'secondary'}
|
||||
label={formatAddress(address)}
|
||||
on:click={() => goto(ROUTES.PROFILE)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="btn user">
|
||||
<Button icon={UserIcon} variant="secondary" on:click={() => goto(ROUTES.PROFILE)} />
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
icon={Wallet}
|
||||
variant={'primary'}
|
||||
label={'Connect'}
|
||||
on:click={() => handleConnect()}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -122,13 +128,7 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--spacing-12);
|
||||
margin-left: -56px;
|
||||
transition: margin 0.2s ease-in-out;
|
||||
|
||||
.top-button {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
&.scrolled {
|
||||
|
@ -1,228 +0,0 @@
|
||||
<script lang="ts">
|
||||
import UserIcon from '$lib/components/icons/user.svelte'
|
||||
import Button from './button.svelte'
|
||||
|
||||
import { goto } from '$app/navigation'
|
||||
import { ROUTES } from '$lib/routes'
|
||||
import Wallet from './icons/wallet.svelte'
|
||||
import Edit from './icons/edit.svelte'
|
||||
import UpToTop from './icons/up-to-top.svelte'
|
||||
|
||||
let cls: string | undefined = undefined
|
||||
export { cls as class }
|
||||
|
||||
let y: number
|
||||
export let loggedin: boolean | undefined = undefined
|
||||
|
||||
function goTop() {
|
||||
document.body.scrollIntoView()
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window bind:scrollY={y} />
|
||||
|
||||
<div class={`root ${y > 0 ? 'scrolled' : ''} ${cls}`}>
|
||||
<div class="header-content">
|
||||
<div class="header">
|
||||
<div class="header-title-wrap">
|
||||
<div class="top-button">
|
||||
<Button icon={UpToTop} on:click={goTop} />
|
||||
</div>
|
||||
<span class={` ${y > 0 ? 'subtitle' : 'header-title'} ${cls}`}>
|
||||
{y > 0 ? 'Public Timeline' : 'The Outlet'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="btns">
|
||||
<div class="btn wallet">
|
||||
<Button
|
||||
icon={loggedin ? Edit : Wallet}
|
||||
variant="primary"
|
||||
on:click={() => goto(loggedin ? ROUTES.POST_NEW : ROUTES.PROFILE)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="btn user">
|
||||
<Button icon={UserIcon} variant="secondary" on:click={() => goto(ROUTES.PROFILE)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if y === 0}
|
||||
<div class="header-description">
|
||||
Milestone 1 shaman pitchfork typewriter single-origin coffee beard flannel, actually
|
||||
chillwave.
|
||||
</div>
|
||||
<div class={`subtitle ${y > 0 ? 'hide' : ''} ${cls}`}>Public timeline</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: var(--spacing-12);
|
||||
border-bottom: 1px solid var(--grey-200);
|
||||
background-color: rgba(var(--color-body-bg-rgb), 0.93);
|
||||
backdrop-filter: blur(3px);
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
padding-top: var(--spacing-48);
|
||||
transition: padding 0.2s;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto 0;
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
padding-bottom: var(--spacing-12);
|
||||
border-bottom: 1px solid var(--grey-200);
|
||||
transition: padding 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.btns {
|
||||
position: relative;
|
||||
height: 44px;
|
||||
|
||||
.btn {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
&.user {
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
&.wallet {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hide {
|
||||
opacity: 0;
|
||||
font-size: 0;
|
||||
transition: opacity 0.2s, font-size 0.2s;
|
||||
}
|
||||
|
||||
.show {
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s, font-size 0.2s;
|
||||
}
|
||||
|
||||
&.scrolled {
|
||||
box-shadow: 0 1px 5px 0 rgba(var(--color-body-text-rgb), 0.25);
|
||||
|
||||
@media (min-width: 1280px) {
|
||||
padding: var(--spacing-12);
|
||||
transition: padding 0.2s;
|
||||
|
||||
.header-content {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
transition: padding 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.btn.user {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.btn.wallet {
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding-bottom: 0;
|
||||
transition: padding 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.header-title-wrap {
|
||||
margin-left: 0;
|
||||
transition: margin 0.2s ease-in-out;
|
||||
|
||||
.top-button {
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.header-description,
|
||||
.subtitle.hide {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0;
|
||||
transition: height 0.2s, opacity 0.2s, padding 0.2s, margin 0.2s, font-size 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
border-bottom-color: var(--grey-500);
|
||||
&.scrolled {
|
||||
box-shadow: 0 1px 5px 0 rgba(var(--color-body-bg-rgb), 0.75);
|
||||
}
|
||||
}
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 0 var(--spacing-24);
|
||||
transition: padding 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-family: var(--font-body);
|
||||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.header-title-wrap {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--spacing-12);
|
||||
margin-left: -56px;
|
||||
transition: margin 0.2s ease-in-out;
|
||||
|
||||
.top-button {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.header-description {
|
||||
padding: 0 0 var(--spacing-24);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
}
|
||||
</style>
|
13
packages/ui/src/lib/components/icons/add.svelte
Normal file
13
packages/ui/src/lib/components/icons/add.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<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}>
|
||||
<polygon points="17,15 17,8 15,8 15,15 8,15 8,17 15,17 15,24 17,24 17,17 24,17 24,15 " />
|
||||
</svg>
|
15
packages/ui/src/lib/components/icons/search.svelte
Normal file
15
packages/ui/src/lib/components/icons/search.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="M29,27.5859l-7.5521-7.5521a11.0177,11.0177,0,1,0-1.4141,1.4141L27.5859,29ZM4,13a9,9,0,1,1,9,9A9.01,9.01,0,0,1,4,13Z"
|
||||
/>
|
||||
</svg>
|
@ -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="M27.71,4.29a1,1,0,0,0-1.05-.23l-22,8a1,1,0,0,0,0,1.87l8.59,3.43L19.59,11,21,12.41l-6.37,6.37,3.44,8.59A1,1,0,0,0,19,28h0a1,1,0,0,0,.92-.66l8-22A1,1,0,0,0,27.71,4.29Z"
|
||||
/>
|
||||
</svg>
|
20
packages/ui/src/lib/components/icons/settings-view.svelte
Normal file
20
packages/ui/src/lib/components/icons/settings-view.svelte
Normal file
@ -0,0 +1,20 @@
|
||||
<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}>
|
||||
<circle cx="23" cy="23.9999" r="2" />
|
||||
<path
|
||||
d="M30.7769,23.4785A8.64,8.64,0,0,0,23,18a8.64,8.64,0,0,0-7.7769,5.4785L15,24l.2231.5215A8.64,8.64,0,0,0,23,30a8.64,8.64,0,0,0,7.7769-5.4785L31,24ZM23,28a4,4,0,1,1,4-4A4.0045,4.0045,0,0,1,23,28Z"
|
||||
/>
|
||||
<path d="M12.3989,20.8A6,6,0,1,1,22,16H20a4,4,0,1,0-6.4,3.2Z" />
|
||||
<path
|
||||
d="M29.3047,11.0439,26.9441,6.9561a1.9977,1.9977,0,0,0-2.3728-.8946l-2.4341.8233a11.0419,11.0419,0,0,0-1.312-.7583l-.5037-2.5186A2,2,0,0,0,18.36,2H13.64a2,2,0,0,0-1.9611,1.6079l-.5037,2.5186A10.9666,10.9666,0,0,0,9.8481,6.88L7.4287,6.0615a1.9977,1.9977,0,0,0-2.3728.8946L2.6953,11.0439a2.0006,2.0006,0,0,0,.4119,2.5025l1.9309,1.6968C5.021,15.4946,5,15.7446,5,16c0,.2578.01.5127.0278.7656l-1.9206,1.688a2.0006,2.0006,0,0,0-.4119,2.5025l2.3606,4.0878a1.9977,1.9977,0,0,0,2.3728.8946l2.4341-.8233a10.9736,10.9736,0,0,0,1.312.7583l.5037,2.5186A2,2,0,0,0,13.64,30H15V28H13.64l-.71-3.5508a9.0953,9.0953,0,0,1-2.6948-1.5713l-3.4468,1.166-2.36-4.0878L7.1528,17.561a8.9263,8.9263,0,0,1-.007-3.1279L4.4275,12.0439,6.7886,7.9561l3.4267,1.1591a9.0305,9.0305,0,0,1,2.7141-1.5644L13.64,4H18.36l.71,3.5508a9.0978,9.0978,0,0,1,2.6948,1.5713l3.4468-1.166,2.36,4.0878-2.7978,2.4522L26.0923,16l2.8-2.4536A2.0006,2.0006,0,0,0,29.3047,11.0439Z"
|
||||
/>
|
||||
</svg>
|
18
packages/ui/src/lib/components/icons/user-multiple.svelte
Normal file
18
packages/ui/src/lib/components/icons/user-multiple.svelte
Normal file
@ -0,0 +1,18 @@
|
||||
<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="M30,30H28V25a5.0057,5.0057,0,0,0-5-5V18a7.0078,7.0078,0,0,1,7,7Z" />
|
||||
<path
|
||||
d="M22,30H20V25a5.0059,5.0059,0,0,0-5-5H9a5.0059,5.0059,0,0,0-5,5v5H2V25a7.0082,7.0082,0,0,1,7-7h6a7.0082,7.0082,0,0,1,7,7Z"
|
||||
/>
|
||||
<path d="M20,2V4a5,5,0,0,1,0,10v2A7,7,0,0,0,20,2Z" />
|
||||
<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" />
|
||||
</svg>
|
57
packages/ui/src/lib/components/persona.svelte
Normal file
57
packages/ui/src/lib/components/persona.svelte
Normal file
@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import UserMultiple from './icons/user-multiple.svelte'
|
||||
|
||||
let cls: string | undefined = undefined
|
||||
export { cls as class }
|
||||
export let name: string
|
||||
export let description: string
|
||||
export let postsCount: number
|
||||
export let picture: string | undefined
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class={`root ${cls}`} on:click>
|
||||
<div class="picture"><img src={picture} alt="persona" /></div>
|
||||
<div class="details">
|
||||
<div class="header">{name}</div>
|
||||
<div class="description">{description}</div>
|
||||
<div class="post-count"><UserMultiple size={18} /> {postsCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 24px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
|
||||
.picture {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
flex-basis: 100px;
|
||||
flex-shrink: 0;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding-left: 24px;
|
||||
}
|
||||
.post-count {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
@ -1,59 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation'
|
||||
import { ROUTES } from '$lib/routes'
|
||||
import Button from './button.svelte'
|
||||
import WalletIcon from './icons/wallet.svelte'
|
||||
|
||||
let cls: string | undefined = undefined
|
||||
let y: number
|
||||
export { cls as class }
|
||||
</script>
|
||||
|
||||
<svelte:window bind:scrollY={y} />
|
||||
<div class={`root ${y > 0 ? 'scrolled' : ''} ${cls}`}>
|
||||
<Button
|
||||
icon={WalletIcon}
|
||||
variant="primary"
|
||||
label="Connect wallet to post"
|
||||
on:click={() => goto(ROUTES.PROFILE)}
|
||||
/>
|
||||
<div class="description">Connect a wallet to access or create your account.</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: var(--spacing-24) var(--spacing-12);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--grey-200);
|
||||
border-bottom: 1px solid var(--grey-200);
|
||||
transition: height 0.2s, padding 0.2s, margin 0.2s, font-size 0.2s;
|
||||
|
||||
@media (min-width: 640px) {
|
||||
border-bottom: none;
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
border: none;
|
||||
outline: 1px solid var(--grey-200);
|
||||
outline-offset: -0.5px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
border-top-color: var(--grey-500);
|
||||
border-left-color: var(--grey-500);
|
||||
border-bottom-color: var(--grey-500);
|
||||
outline-color: var(--grey-500);
|
||||
}
|
||||
}
|
||||
.description {
|
||||
margin-top: var(--spacing-12);
|
||||
font-size: var(--font-size-sm);
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -1,5 +1,7 @@
|
||||
export const ROUTES = {
|
||||
HOME: '/',
|
||||
PROFILE: '/profile',
|
||||
POST_NEW: '/post/new',
|
||||
PERSONA: (slug: string) => `/persona/${slug}`,
|
||||
PERSONA_NEW: '/persona/new',
|
||||
POST_NEW: (slug: string) => `/persona/${slug}/post/new`,
|
||||
}
|
||||
|
15
packages/ui/src/lib/stores/chat.ts
Normal file
15
packages/ui/src/lib/stores/chat.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
|
||||
interface ChatData {
|
||||
unread: number
|
||||
}
|
||||
|
||||
export type ChatStore = Writable<ChatData>
|
||||
|
||||
function createChatStore(): ChatStore {
|
||||
const store = writable<ChatData>({ unread: 3 })
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
export const chats = createChatStore()
|
86
packages/ui/src/lib/stores/persona.ts
Normal file
86
packages/ui/src/lib/stores/persona.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
import type { Identity } from '@semaphore-protocol/identity'
|
||||
|
||||
interface Persona {
|
||||
identity?: Identity
|
||||
picture?: string
|
||||
name: string
|
||||
pitch: string
|
||||
description: string
|
||||
postsCount: number
|
||||
}
|
||||
|
||||
export type PersonaStore = Writable<{
|
||||
draft: Persona[]
|
||||
favorite: Map<string, Persona>
|
||||
all: Map<string, Persona>
|
||||
loading: boolean
|
||||
}>
|
||||
|
||||
function createPersonaStore(): PersonaStore {
|
||||
const store = writable({ all: new Map(), draft: [], favorite: new Map(), loading: true })
|
||||
|
||||
setTimeout(() => {
|
||||
const chitChat = {
|
||||
identity: undefined,
|
||||
name: 'Chit Chat',
|
||||
pitch: 'We pretty much just say gm all the time.',
|
||||
description: 'We pretty much just say gm all the time.',
|
||||
postsCount: 125,
|
||||
picture:
|
||||
'https://upload.wikimedia.org/wikipedia/commons/4/42/Chit_chat_%28256889331%29.jpg?20191121211426',
|
||||
}
|
||||
const expats = {
|
||||
identity: undefined,
|
||||
name: 'Expats',
|
||||
pitch: 'Different countries, same work...',
|
||||
description: 'Different countries, same work...',
|
||||
postsCount: 4,
|
||||
picture: 'https://upload.wikimedia.org/wikipedia/commons/8/88/British_expats_countrymap.svg',
|
||||
}
|
||||
const cats = {
|
||||
identity: undefined,
|
||||
name: 'Cats',
|
||||
pitch: "Yeah it's the internet, what did you expect?",
|
||||
description: "Yeah it's the internet, what did you expect?",
|
||||
postsCount: 5128,
|
||||
picture:
|
||||
'https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Adorable-animal-cat-20787.jpg/1599px-Adorable-animal-cat-20787.jpg?20180518085718',
|
||||
}
|
||||
const geoPolitics = {
|
||||
identity: undefined,
|
||||
name: 'Geo Politics',
|
||||
pitch: `Group full of "seen it all's"`,
|
||||
description: `Group full of "seen it all's"`,
|
||||
postsCount: 53,
|
||||
picture:
|
||||
'https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/World_geopolitical_chess.png/1600px-World_geopolitical_chess.png?20200226194321',
|
||||
}
|
||||
const controversy = {
|
||||
identity: undefined,
|
||||
name: 'Controversy',
|
||||
pitch: '...',
|
||||
description: '...',
|
||||
postsCount: 9999,
|
||||
picture:
|
||||
'https://upload.wikimedia.org/wikipedia/en/e/ea/Controversy_legend.gif?20060220215816',
|
||||
}
|
||||
|
||||
const all = new Map<string, Persona>()
|
||||
const favorite = new Map<string, Persona>()
|
||||
all.set('1', chitChat)
|
||||
all.set('2', expats)
|
||||
all.set('3', cats)
|
||||
all.set('4', geoPolitics)
|
||||
all.set('5', controversy)
|
||||
|
||||
favorite.set('3', cats)
|
||||
favorite.set('4', controversy)
|
||||
|
||||
store.set({ draft: [], all, favorite, loading: false })
|
||||
}, 1000)
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
export const personas = createPersonaStore()
|
@ -5,7 +5,6 @@ import { subscribeToPosts } from '$lib/services/posts'
|
||||
export interface Post {
|
||||
timestamp: number
|
||||
text: string
|
||||
tx: string
|
||||
}
|
||||
|
||||
interface PostData {
|
||||
@ -29,7 +28,6 @@ async function fetchPosts() {
|
||||
posts.add({
|
||||
text: post.text,
|
||||
timestamp: Date.now(),
|
||||
tx: '',
|
||||
})
|
||||
},
|
||||
undefined,
|
||||
|
@ -1,16 +1,15 @@
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
import type { Signer } from 'ethers'
|
||||
import type { Identity } from '@semaphore-protocol/identity'
|
||||
|
||||
export interface Profile {
|
||||
signer?: Signer
|
||||
identities: Record<string, Identity>
|
||||
address?: string
|
||||
}
|
||||
|
||||
export type ProfileStore = Writable<Profile>
|
||||
|
||||
function createProfileStore(): ProfileStore {
|
||||
return writable<Profile>({ identities: {} })
|
||||
return writable<Profile>({})
|
||||
}
|
||||
|
||||
export const profile = createProfileStore()
|
||||
|
@ -1,115 +1,104 @@
|
||||
<script lang="ts">
|
||||
// import Header from '$lib/components/header.svelte'
|
||||
import HeaderTop from '$lib/components/header-top.svelte'
|
||||
import HeaderDescription from '$lib/components/header-description.svelte'
|
||||
import Post from '$lib/components/post.svelte'
|
||||
import Button from '$lib/components/button.svelte'
|
||||
import WalletConnect from '$lib/components/wallet-connect.svelte'
|
||||
import Edit from '$lib/components/icons/edit.svelte'
|
||||
import Persona from '$lib/components/persona.svelte'
|
||||
|
||||
import { posts } from '$lib/stores/post'
|
||||
import { profile } from '$lib/stores/profile'
|
||||
import { personas } from '$lib/stores/persona'
|
||||
|
||||
import { goto } from '$app/navigation'
|
||||
import { browser } from '$app/environment'
|
||||
import Masonry from '$lib/masonry.svelte'
|
||||
import { ROUTES } from '$lib/routes'
|
||||
|
||||
let windowWidth: number = browser ? window.innerWidth : 0
|
||||
import Button from '$lib/components/button.svelte'
|
||||
import Search from '$lib/components/icons/search.svelte'
|
||||
import SettingsView from '$lib/components/icons/settings-view.svelte'
|
||||
import { chats } from '$lib/stores/chat'
|
||||
import Add from '$lib/components/icons/add.svelte'
|
||||
|
||||
function getMasonryColumnWidth(windowInnerWidth: number) {
|
||||
if (windowInnerWidth < 739) {
|
||||
return '100%'
|
||||
}
|
||||
|
||||
if (windowInnerWidth < 1060) {
|
||||
return 'minmax(min(100%/2, max(320px, 100%/2)), 1fr)'
|
||||
}
|
||||
|
||||
if (windowInnerWidth < 1381) {
|
||||
return 'minmax(min(100%/3, max(320px, 100%/3)), 1fr)'
|
||||
}
|
||||
|
||||
if (windowInnerWidth < 1702) {
|
||||
return 'minmax(min(100%/4, max(320px, 100%/4)), 1fr)'
|
||||
}
|
||||
|
||||
if (windowInnerWidth < 2023) {
|
||||
return 'minmax(min(100%/5, max(320px, 100%/5)), 1fr)'
|
||||
}
|
||||
|
||||
if (windowInnerWidth < 2560) {
|
||||
return 'minmax(min(100%/6, max(320px, 100%/6)), 1fr)'
|
||||
}
|
||||
|
||||
if (windowInnerWidth < 3009) {
|
||||
return 'minmax(min(100%/7, max(320px, 100%/7)), 1fr)'
|
||||
}
|
||||
|
||||
return 'minmax(323px, 1fr)'
|
||||
}
|
||||
let filterText = ''
|
||||
let showChat = false
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth={windowWidth} />
|
||||
|
||||
<div>
|
||||
<!-- <Header loggedin={$profile.signer !== undefined} /> -->
|
||||
|
||||
<HeaderTop loggedin={$profile.signer !== undefined} />
|
||||
<HeaderDescription />
|
||||
<HeaderTop address={$profile.address} />
|
||||
|
||||
<div class="wrapper">
|
||||
{#if $profile.signer !== undefined}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="new-post-button" on:click={() => goto('/post/new')}>
|
||||
Share freely...
|
||||
<Button variant="primary" label="Create post" icon={Edit} />
|
||||
<div class="nav">
|
||||
<div class={showChat ? '' : 'active'} on:click={() => (showChat = false)}>Personas</div>
|
||||
<div class={showChat ? 'active' : ''} on:click={() => (showChat = true)}>
|
||||
Chats
|
||||
{#if $chats.unread > 0}
|
||||
<div class="unread">{$chats.unread}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<WalletConnect />
|
||||
{/if}
|
||||
|
||||
{#if $posts.loading}
|
||||
<p>Loading posts...</p>
|
||||
{:else if $posts.posts.length == 0}
|
||||
<p>There are no posts yet</p>
|
||||
{#if showChat}
|
||||
<div>Chat not implemented yet</div>
|
||||
{:else if $personas.loading}
|
||||
<p>Loading personas...</p>
|
||||
{:else}
|
||||
<Masonry gridGap="0" colWidth={getMasonryColumnWidth(windowWidth)} items={$posts.posts}>
|
||||
{#each $posts.posts as post}
|
||||
<Post {post} />
|
||||
{#if $personas.draft.length !== 0 && $profile.signer !== undefined}
|
||||
<div class="subtitle">Draft personas</div>
|
||||
<Button icon={Add} label="Create persona" on:click={() => goto(ROUTES.PERSONA_NEW)} />
|
||||
<div class="grid">
|
||||
{#each $personas.draft as draftPersona, index}
|
||||
<Persona
|
||||
name={draftPersona.name}
|
||||
description={draftPersona.description}
|
||||
postsCount={draftPersona.postsCount}
|
||||
on:click={() => goto(ROUTES.PERSONA(index.toFixed()))}
|
||||
picture={draftPersona.picture}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $personas.favorite.size !== 0 && $profile.signer !== undefined}
|
||||
<div class="subtitle">Favorites</div>
|
||||
<div class="grid">
|
||||
{#each [...$personas.favorite] as [groupId, data]}
|
||||
<Persona
|
||||
name={data.name}
|
||||
description={data.description}
|
||||
postsCount={data.postsCount}
|
||||
on:click={() => goto(ROUTES.PERSONA(groupId))}
|
||||
picture={data.picture}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="subtitle">All personas</div>
|
||||
<Search />
|
||||
<input bind:value={filterText} placeholder="Search..." />
|
||||
{#if $profile.signer !== undefined}
|
||||
<Button icon={Add} label="Create persona" on:click={() => goto(ROUTES.PERSONA_NEW)} />
|
||||
{/if}
|
||||
<Button icon={SettingsView} />
|
||||
|
||||
<div class="grid">
|
||||
{#each [...$personas.all].filter(([, data]) => data.name
|
||||
.toLowerCase()
|
||||
.includes(filterText.toLowerCase())) as [groupId, data]}
|
||||
<Persona
|
||||
name={data.name}
|
||||
description={data.pitch}
|
||||
postsCount={data.postsCount}
|
||||
on:click={() => goto(ROUTES.PERSONA(groupId))}
|
||||
picture={data.picture}
|
||||
/>
|
||||
{:else}
|
||||
<p>There are no personas yet</p>
|
||||
{/each}
|
||||
</Masonry>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.new-post-button {
|
||||
font-family: var(--font-serif);
|
||||
padding: var(--spacing-24) var(--spacing-12);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-12);
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--grey-200);
|
||||
border-bottom: 1px solid var(--grey-200);
|
||||
cursor: pointer;
|
||||
|
||||
@media (min-width: 640px) {
|
||||
border-bottom: none;
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
border: none;
|
||||
outline: 1px solid var(--grey-200);
|
||||
outline-offset: -0.5px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
border-top-color: var(--grey-500);
|
||||
border-left-color: var(--grey-500);
|
||||
border-bottom-color: var(--grey-500);
|
||||
outline-color: var(--grey-500);
|
||||
}
|
||||
}
|
||||
.wrapper {
|
||||
margin-left: -1px;
|
||||
|
||||
@ -118,4 +107,49 @@
|
||||
margin: 0 auto 0;
|
||||
}
|
||||
}
|
||||
|
||||
.nav {
|
||||
width: 450px;
|
||||
height: 50px;
|
||||
margin: auto;
|
||||
border-radius: 25px;
|
||||
background-color: #ececec;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: solid 3px #ececec;
|
||||
font-family: var(--font-body);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
|
||||
div {
|
||||
padding: 10px;
|
||||
width: 50%;
|
||||
border-radius: 25px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.active {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.unread {
|
||||
background-color: black;
|
||||
color: white;
|
||||
width: min-content;
|
||||
margin-left: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-auto-columns: auto;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
grid-auto-rows: auto;
|
||||
}
|
||||
</style>
|
||||
|
98
packages/ui/src/routes/persona/[id]/+page.svelte
Normal file
98
packages/ui/src/routes/persona/[id]/+page.svelte
Normal file
@ -0,0 +1,98 @@
|
||||
<script lang="ts">
|
||||
import HeaderTop from '$lib/components/header-top.svelte'
|
||||
import Post from '$lib/components/post.svelte'
|
||||
import Button from '$lib/components/button.svelte'
|
||||
import Edit from '$lib/components/icons/edit.svelte'
|
||||
|
||||
import { posts } from '$lib/stores/post'
|
||||
import { profile } from '$lib/stores/profile'
|
||||
import { goto } from '$app/navigation'
|
||||
import { browser } from '$app/environment'
|
||||
import { page } from '$app/stores'
|
||||
import Masonry from '$lib/masonry.svelte'
|
||||
import { ROUTES } from '$lib/routes'
|
||||
|
||||
let windowWidth: number = browser ? window.innerWidth : 0
|
||||
|
||||
function getMasonryColumnWidth(windowInnerWidth: number) {
|
||||
if (windowInnerWidth < 739) return '100%'
|
||||
if (windowInnerWidth < 1060) return 'minmax(min(100%/2, max(320px, 100%/2)), 1fr)'
|
||||
if (windowInnerWidth < 1381) return 'minmax(min(100%/3, max(320px, 100%/3)), 1fr)'
|
||||
if (windowInnerWidth < 1702) return 'minmax(min(100%/4, max(320px, 100%/4)), 1fr)'
|
||||
if (windowInnerWidth < 2023) return 'minmax(min(100%/5, max(320px, 100%/5)), 1fr)'
|
||||
if (windowInnerWidth < 2560) return 'minmax(min(100%/6, max(320px, 100%/6)), 1fr)'
|
||||
if (windowInnerWidth < 3009) return 'minmax(min(100%/7, max(320px, 100%/7)), 1fr)'
|
||||
return 'minmax(323px, 1fr)'
|
||||
}
|
||||
|
||||
const isDraft = $page.url.searchParams.has('draft')
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth={windowWidth} />
|
||||
|
||||
<div>
|
||||
<HeaderTop address={$profile.address} />
|
||||
|
||||
<Button label="GO BACK" on:click={() => goto(ROUTES.HOME)} />
|
||||
|
||||
<div class="wrapper">
|
||||
{#if $profile.signer !== undefined}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="new-post-button" on:click={() => goto(ROUTES.POST_NEW($page.params.id))}>
|
||||
Share freely...
|
||||
<Button variant="primary" label="Create post" icon={Edit} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if $posts.loading}
|
||||
<p>Loading posts...</p>
|
||||
{:else if $posts.posts.length == 0}
|
||||
<p>There are no posts yet</p>
|
||||
{:else}
|
||||
<Masonry gridGap="0" colWidth={getMasonryColumnWidth(windowWidth)} items={$posts.posts}>
|
||||
{#each $posts.posts as post}
|
||||
<Post {post} />
|
||||
{/each}
|
||||
</Masonry>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.new-post-button {
|
||||
font-family: var(--font-serif);
|
||||
padding: var(--spacing-24) var(--spacing-12);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-12);
|
||||
align-items: center;
|
||||
border-top: 1px solid var(--grey-200);
|
||||
border-bottom: 1px solid var(--grey-200);
|
||||
cursor: pointer;
|
||||
|
||||
@media (min-width: 640px) {
|
||||
border-bottom: none;
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
border: none;
|
||||
outline: 1px solid var(--grey-200);
|
||||
outline-offset: -0.5px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
border-top-color: var(--grey-500);
|
||||
border-left-color: var(--grey-500);
|
||||
border-bottom-color: var(--grey-500);
|
||||
outline-color: var(--grey-500);
|
||||
}
|
||||
}
|
||||
.wrapper {
|
||||
margin-left: -1px;
|
||||
|
||||
@media (min-width: 739px) {
|
||||
padding: 0 var(--spacing-48);
|
||||
margin: 0 auto 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -7,10 +7,13 @@
|
||||
import { goto } from '$app/navigation'
|
||||
import { ROUTES } from '$lib/routes'
|
||||
import {
|
||||
createIdentity,
|
||||
generateGroupProof,
|
||||
getContractGroup,
|
||||
getGlobalAnonymousFeed,
|
||||
getRandomExternalNullifier,
|
||||
joinGroupOffChain,
|
||||
joinGroupOnChain,
|
||||
} from '$lib/services/index'
|
||||
import { posts } from '$lib/stores/post'
|
||||
import { hashPost, createPost } from '$lib/services/posts'
|
||||
@ -27,12 +30,21 @@
|
||||
const signer = $profile.signer
|
||||
if (!signer) throw new Error('no signer')
|
||||
|
||||
const identity = $profile.identities.anonymous
|
||||
if (!identity) throw new Error('no identity')
|
||||
const defaultIdentity = 'anonymous'
|
||||
|
||||
const identity = await createIdentity(signer, defaultIdentity)
|
||||
|
||||
const globalAnonymousFeed = getGlobalAnonymousFeed(signer)
|
||||
const group = await getContractGroup(globalAnonymousFeed)
|
||||
|
||||
const commitment = identity.commitment
|
||||
|
||||
if (!group.members.includes(commitment)) {
|
||||
joinGroupOffChain(group, commitment)
|
||||
const txres = await joinGroupOnChain(globalAnonymousFeed, commitment)
|
||||
console.log(txres)
|
||||
}
|
||||
|
||||
const post = { text: postText }
|
||||
const signal = hashPost(post)
|
||||
|
||||
@ -45,7 +57,6 @@
|
||||
posts.add({
|
||||
timestamp: Date.now(),
|
||||
text: postText,
|
||||
tx: '',
|
||||
})
|
||||
goto(ROUTES.HOME)
|
||||
} catch (error) {
|
35
packages/ui/src/routes/persona/new/+page.svelte
Normal file
35
packages/ui/src/routes/persona/new/+page.svelte
Normal file
@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import Undo from '$lib/components/icons/undo.svelte'
|
||||
import Button from '$lib/components/button.svelte'
|
||||
import { personas } from '$lib/stores/persona'
|
||||
|
||||
let name = ''
|
||||
let pitch = ''
|
||||
let description = ''
|
||||
</script>
|
||||
|
||||
<Button icon={Undo} on:click={() => history.back()} />
|
||||
<span>Create persona</span>
|
||||
|
||||
<label>
|
||||
Persona name
|
||||
<input type="text" bind:value={name} placeholder="Enter a short memorable name…" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Persona pitch
|
||||
<textarea bind:value={pitch} />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Persona description
|
||||
<textarea bind:value={description} />
|
||||
</label>
|
||||
|
||||
<Button label="Cancel" on:click={() => history.back()} />
|
||||
<Button
|
||||
label="Proceed"
|
||||
on:click={() => {
|
||||
$personas.draft
|
||||
}}
|
||||
/>
|
@ -6,15 +6,7 @@
|
||||
import Wallet from '$lib/components/icons/wallet.svelte'
|
||||
import WalletInfo from '$lib/components/wallet-info.svelte'
|
||||
import { formatAddress } from '$lib/utils'
|
||||
import {
|
||||
connectWallet,
|
||||
canConnectWallet,
|
||||
createIdentity,
|
||||
getGlobalAnonymousFeed,
|
||||
getContractGroup,
|
||||
joinGroupOffChain,
|
||||
joinGroupOnChain,
|
||||
} from '$lib/services'
|
||||
import { connectWallet, canConnectWallet } from '$lib/services'
|
||||
import { profile } from '$lib/stores/profile'
|
||||
|
||||
let y: number
|
||||
@ -25,24 +17,9 @@
|
||||
const handleConnect = async () => {
|
||||
try {
|
||||
const signer = await connectWallet()
|
||||
$profile.signer = signer
|
||||
const address = await signer.getAddress()
|
||||
|
||||
const defaultIdentity = 'anonymous'
|
||||
|
||||
const identity = await createIdentity(signer, defaultIdentity)
|
||||
|
||||
$profile.identities = { ...$profile.identities, [defaultIdentity]: identity }
|
||||
|
||||
const globalAnonymousFeed = getGlobalAnonymousFeed(signer)
|
||||
const group = await getContractGroup(globalAnonymousFeed)
|
||||
|
||||
const commitment = identity.commitment
|
||||
|
||||
if (!group.members.includes(commitment)) {
|
||||
joinGroupOffChain(group, commitment)
|
||||
const txres = await joinGroupOnChain(globalAnonymousFeed, commitment)
|
||||
console.log(txres)
|
||||
}
|
||||
$profile = { signer, address }
|
||||
} catch (err) {
|
||||
error = err as Error
|
||||
}
|
||||
@ -98,20 +75,11 @@
|
||||
variant="primary"
|
||||
icon={Logout}
|
||||
label="Logout"
|
||||
on:click={() => ($profile.signer = undefined)}
|
||||
on:click={() => ($profile = {})}
|
||||
disabled={!$profile.signer}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="info">
|
||||
{#each Object.entries($profile.identities) as [name, identity]}
|
||||
<div>{name}</div>
|
||||
<div>commitment: {identity.getCommitment().toString(16)}</div>
|
||||
<div>nullifier: {identity.getNullifier().toString(16)}</div>
|
||||
<div>trapdoor: {identity.getTrapdoor().toString(16)}</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
@ -192,13 +160,4 @@
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
padding: var(--spacing-12);
|
||||
max-width: 100%;
|
||||
word-wrap: break-word;
|
||||
|
||||
> div:not(:first-child) {
|
||||
margin-top: var(--spacing-12);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -3,5 +3,5 @@ import { expect, test } from '@playwright/test'
|
||||
|
||||
test('index page has expected header', async ({ page }) => {
|
||||
await page.goto(ROUTES.HOME)
|
||||
expect(await page.textContent('span')).toBe('The Outlet')
|
||||
expect(await page.textContent('span')).toBe('Kurate')
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user