mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-19 19:46:42 +00:00
Add profile and note to onboarding
This commit is contained in:
parent
dcdac88b75
commit
97d37eaca0
@ -1,5 +1,7 @@
|
|||||||
# Current
|
# Current
|
||||||
|
|
||||||
|
- [ ] Enable global view via env var
|
||||||
|
- [ ] Ask for name/image, first post on signup
|
||||||
- [ ] Image classification
|
- [ ] Image classification
|
||||||
- https://github.com/bhky/opennsfw2
|
- https://github.com/bhky/opennsfw2
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ export const defaultFollows = (import.meta.env.VITE_DEFAULT_FOLLOWS || "")
|
|||||||
.split(",")
|
.split(",")
|
||||||
.filter(identity)
|
.filter(identity)
|
||||||
|
|
||||||
|
console.log(defaultFollows)
|
||||||
|
|
||||||
export const getFollows = pubkey =>
|
export const getFollows = pubkey =>
|
||||||
Tags.wrap(getPersonWithFallback(pubkey).petnames).type("p").values().all()
|
Tags.wrap(getPersonWithFallback(pubkey).petnames).type("p").values().all()
|
||||||
|
|
||||||
|
@ -7,10 +7,11 @@
|
|||||||
import {shuffle} from "src/util/misc"
|
import {shuffle} from "src/util/misc"
|
||||||
import {displayPerson} from "src/util/nostr"
|
import {displayPerson} from "src/util/nostr"
|
||||||
import OnboardingIntro from "src/app/views/OnboardingIntro.svelte"
|
import OnboardingIntro from "src/app/views/OnboardingIntro.svelte"
|
||||||
|
import OnboardingProfile from "src/app/views/OnboardingProfile.svelte"
|
||||||
import OnboardingKey from "src/app/views/OnboardingKey.svelte"
|
import OnboardingKey from "src/app/views/OnboardingKey.svelte"
|
||||||
import OnboardingRelays from "src/app/views/OnboardingRelays.svelte"
|
import OnboardingRelays from "src/app/views/OnboardingRelays.svelte"
|
||||||
import OnboardingFollows from "src/app/views/OnboardingFollows.svelte"
|
import OnboardingFollows from "src/app/views/OnboardingFollows.svelte"
|
||||||
import OnboardingComplete from "src/app/views/OnboardingComplete.svelte"
|
import OnboardingNote from "src/app/views/OnboardingNote.svelte"
|
||||||
import {getFollows, defaultFollows} from "src/agent/social"
|
import {getFollows, defaultFollows} from "src/agent/social"
|
||||||
import {getPubkeyWriteRelays, sampleRelays} from "src/agent/relays"
|
import {getPubkeyWriteRelays, sampleRelays} from "src/agent/relays"
|
||||||
import {getPersonWithFallback} from "src/agent/db"
|
import {getPersonWithFallback} from "src/agent/db"
|
||||||
@ -18,13 +19,14 @@
|
|||||||
import user from "src/agent/user"
|
import user from "src/agent/user"
|
||||||
import pool from "src/agent/pool"
|
import pool from "src/agent/pool"
|
||||||
import keys from "src/agent/keys"
|
import keys from "src/agent/keys"
|
||||||
|
import cmd from "src/agent/cmd"
|
||||||
import {loadAppData} from "src/app/state"
|
import {loadAppData} from "src/app/state"
|
||||||
import {modal} from "src/partials/state"
|
import {modal} from "src/partials/state"
|
||||||
|
|
||||||
export let stage
|
export let stage
|
||||||
|
|
||||||
const privkey = generatePrivateKey()
|
const privkey = generatePrivateKey()
|
||||||
|
const profile = {}
|
||||||
const {relays} = user
|
const {relays} = user
|
||||||
|
|
||||||
if ($relays.length === 0) {
|
if ($relays.length === 0) {
|
||||||
@ -36,19 +38,23 @@
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const signup = async () => {
|
const signup = async note => {
|
||||||
await keys.login("privkey", privkey)
|
await keys.login("privkey", privkey)
|
||||||
|
|
||||||
// Re-save preferences now that we have a key
|
// Re-save preferences now that we have a key
|
||||||
await user.updateRelays(() => user.getRelays())
|
await Promise.all([
|
||||||
await user.updatePetnames(() =>
|
user.updateRelays(() => user.getRelays()),
|
||||||
user.getPetnamePubkeys().map(pubkey => {
|
cmd.updateUser(profile).publish(user.getRelays()),
|
||||||
const [{url}] = sampleRelays(getPubkeyWriteRelays(pubkey))
|
note && cmd.createNote(note.content, note.mentions, note.topics).publish(user.getRelays()),
|
||||||
const name = displayPerson(getPersonWithFallback(pubkey))
|
user.updatePetnames(() =>
|
||||||
|
user.getPetnamePubkeys().map(pubkey => {
|
||||||
|
const [{url}] = sampleRelays(getPubkeyWriteRelays(pubkey))
|
||||||
|
const name = displayPerson(getPersonWithFallback(pubkey))
|
||||||
|
|
||||||
return ["p", pubkey, url, name]
|
return ["p", pubkey, url, name]
|
||||||
})
|
})
|
||||||
)
|
),
|
||||||
|
])
|
||||||
|
|
||||||
loadAppData(user.getPubkey())
|
loadAppData(user.getPubkey())
|
||||||
|
|
||||||
@ -73,14 +79,16 @@
|
|||||||
<div in:fly={{y: 20}}>
|
<div in:fly={{y: 20}}>
|
||||||
{#if stage === "intro"}
|
{#if stage === "intro"}
|
||||||
<OnboardingIntro />
|
<OnboardingIntro />
|
||||||
|
{:else if stage === "profile"}
|
||||||
|
<OnboardingProfile {profile} />
|
||||||
{:else if stage === "key"}
|
{:else if stage === "key"}
|
||||||
<OnboardingKey {privkey} />
|
<OnboardingKey {privkey} />
|
||||||
{:else if stage === "relays"}
|
{:else if stage === "relays"}
|
||||||
<OnboardingRelays />
|
<OnboardingRelays />
|
||||||
{:else if stage === "follows"}
|
{:else if stage === "follows"}
|
||||||
<OnboardingFollows />
|
<OnboardingFollows />
|
||||||
{:else}
|
{:else if stage === "note"}
|
||||||
<OnboardingComplete {signup} />
|
<OnboardingNote {signup} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/key}
|
{/key}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
|
||||||
import Heading from "src/partials/Heading.svelte"
|
|
||||||
import Content from "src/partials/Content.svelte"
|
|
||||||
import Spinner from "src/partials/Spinner.svelte"
|
|
||||||
|
|
||||||
export let signup
|
|
||||||
|
|
||||||
let loading = false
|
|
||||||
|
|
||||||
const startSignup = () => {
|
|
||||||
loading = true
|
|
||||||
signup()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Content size="lg" class="text-center">
|
|
||||||
<Heading>Welcome to Nostr</Heading>
|
|
||||||
<p>
|
|
||||||
You’re all set! If have any questions, or need any help, just ask. Your fellow nostriches are
|
|
||||||
always happy to lend a hand.
|
|
||||||
</p>
|
|
||||||
<Anchor {loading} type="button-accent" on:click={startSignup}>Get on Nostr</Anchor>
|
|
||||||
{#if loading}
|
|
||||||
<Spinner />
|
|
||||||
{/if}
|
|
||||||
</Content>
|
|
@ -39,7 +39,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<Anchor
|
<Anchor
|
||||||
type="button-accent"
|
type="button-accent"
|
||||||
on:click={() => modal.replace({type: "onboarding", stage: "complete"})}>
|
on:click={() => modal.replace({type: "onboarding", stage: "note"})}>
|
||||||
Continue
|
Continue
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
When you’re ready to dive in, click below and we’ll guide you through the process of creating an
|
When you’re ready to dive in, click below and we’ll guide you through the process of creating an
|
||||||
account.
|
account.
|
||||||
</p>
|
</p>
|
||||||
<Anchor type="button-accent" on:click={() => modal.replace({type: "onboarding", stage: "key"})}>
|
<Anchor
|
||||||
|
type="button-accent"
|
||||||
|
on:click={() => modal.replace({type: "onboarding", stage: "profile"})}>
|
||||||
Let's go!
|
Let's go!
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
<Anchor
|
<Anchor
|
||||||
type="button-accent"
|
type="button-accent"
|
||||||
on:click={() => modal.replace({type: "onboarding", stage: nextStage})}>
|
on:click={() => modal.replace({type: "onboarding", stage: nextStage})}>
|
||||||
Log in
|
Got it
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</div>
|
</div>
|
||||||
<p>If you don't want to save your keys now, you can find them later in {appName}'s settings.</p>
|
<p>If you don't want to save your keys now, you can find them later in {appName}'s settings.</p>
|
||||||
|
36
src/app/views/OnboardingNote.svelte
Normal file
36
src/app/views/OnboardingNote.svelte
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {onMount} from "svelte"
|
||||||
|
import Compose from "src/partials/Compose.svelte"
|
||||||
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
|
import Heading from "src/partials/Heading.svelte"
|
||||||
|
import Content from "src/partials/Content.svelte"
|
||||||
|
|
||||||
|
export let signup
|
||||||
|
|
||||||
|
let compose = null
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
signup(compose.parse())
|
||||||
|
}
|
||||||
|
|
||||||
|
const skip = () => signup()
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
compose.write("Hello world! #introductions")
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Content size="lg">
|
||||||
|
<Heading class="text-center">Welcome to Nostr</Heading>
|
||||||
|
<p class="text-center">
|
||||||
|
Your're all set! If have any questions, just ask! People around these parts are always ready to
|
||||||
|
lend a hand.
|
||||||
|
</p>
|
||||||
|
<div class="border-l-2 border-solid border-gray-6 pl-4">
|
||||||
|
<Compose bind:this={compose} {onSubmit} />
|
||||||
|
</div>
|
||||||
|
<Anchor type="button-accent" class="flex-grow text-center" on:click={onSubmit}>Say Hello!</Anchor>
|
||||||
|
<Anchor type="unstyled" class="text-center" on:click={skip}>
|
||||||
|
Skip and see your feed <i class="fa fa-arrow-right" />
|
||||||
|
</Anchor>
|
||||||
|
</Content>
|
46
src/app/views/OnboardingProfile.svelte
Normal file
46
src/app/views/OnboardingProfile.svelte
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {modal} from "src/partials/state"
|
||||||
|
import Input from "src/partials/Input.svelte"
|
||||||
|
import Textarea from "src/partials/Textarea.svelte"
|
||||||
|
import ImageInput from "src/partials/ImageInput.svelte"
|
||||||
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
|
import Heading from "src/partials/Heading.svelte"
|
||||||
|
import Content from "src/partials/Content.svelte"
|
||||||
|
|
||||||
|
export let profile
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Content size="lg">
|
||||||
|
<Heading class="text-center">Introduce Yourself</Heading>
|
||||||
|
<p class="text-center">
|
||||||
|
Give other people something to go on. Remember that "privacy is the power to selectively reveal
|
||||||
|
oneself to the world".
|
||||||
|
</p>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<strong>Your Name</strong>
|
||||||
|
<Input type="text" name="name" wrapperClass="flex-grow" bind:value={profile.name}>
|
||||||
|
<i slot="before" class="fa-solid fa-user-astronaut" />
|
||||||
|
</Input>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<strong>About You</strong>
|
||||||
|
<Textarea name="about" bind:value={profile.about} />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<strong>Profile Picture</strong>
|
||||||
|
<ImageInput
|
||||||
|
bind:value={profile.picture}
|
||||||
|
icon="image-portrait"
|
||||||
|
maxWidth={480}
|
||||||
|
maxHeight={480} />
|
||||||
|
<p class="text-sm text-gray-1">Please be mindful of others and only use small images.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Anchor
|
||||||
|
type="button-accent"
|
||||||
|
class="text-center"
|
||||||
|
on:click={() => modal.replace({type: "onboarding", stage: "key"})}>
|
||||||
|
Continue
|
||||||
|
</Anchor>
|
||||||
|
</Content>
|
@ -170,6 +170,24 @@
|
|||||||
selection.collapse(input, 0)
|
selection.collapse(input, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const write = text => {
|
||||||
|
const selection = window.getSelection()
|
||||||
|
const textNode = document.createTextNode(text)
|
||||||
|
|
||||||
|
selection.getRangeAt(0).insertNode(textNode)
|
||||||
|
selection.collapse(textNode, text.length)
|
||||||
|
|
||||||
|
autocomplete()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const newlines = n => {
|
||||||
|
const selection = window.getSelection()
|
||||||
|
const newLines = createNewLines(2)
|
||||||
|
|
||||||
|
selection.getRangeAt(0).insertNode(newLines)
|
||||||
|
selection.collapse(newLines, 2)
|
||||||
|
}
|
||||||
|
|
||||||
export const parse = () => {
|
export const parse = () => {
|
||||||
let {content, annotations} = contenteditable.parse()
|
let {content, annotations} = contenteditable.parse()
|
||||||
const topics = pluck("value", annotations.filter(propEq("prefix", "#")))
|
const topics = pluck("value", annotations.filter(propEq("prefix", "#")))
|
||||||
|
Loading…
Reference in New Issue
Block a user