mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-30 00:41:12 +00:00
Add cypress tests
This commit is contained in:
parent
744f42a65f
commit
bc88d341d4
7
cypress.config.ts
Normal file
7
cypress.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import {defineConfig} from "cypress"
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
e2e: {
|
||||||
|
baseUrl: "http://localhost:5173",
|
||||||
|
},
|
||||||
|
})
|
21
cypress/e2e/feed.cy.ts
Normal file
21
cypress/e2e/feed.cy.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
describe("feed interaction", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit("/")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("clicking a card works", () => {
|
||||||
|
cy.get(".cy-note-click-target:first").click()
|
||||||
|
cy.get(".modal .fa-heart")
|
||||||
|
cy.get(".modal .cy-modal-close").click()
|
||||||
|
|
||||||
|
cy.get(".modal").should("not.exist")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("feed controls works", () => {
|
||||||
|
cy.get(".fa-sliders").click()
|
||||||
|
cy.get(".modal .cy-chip:first .fa-times").click()
|
||||||
|
cy.get(".modal").contains("Apply Filters").click()
|
||||||
|
cy.contains("Kinds 30023,")
|
||||||
|
cy.get(".card", {timeout: 30000})
|
||||||
|
})
|
||||||
|
})
|
12
cypress/e2e/login.cy.ts
Normal file
12
cypress/e2e/login.cy.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
describe("authenticated usage", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.login()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("works", () => {
|
||||||
|
cy.visit("/")
|
||||||
|
cy.get("svg.logo").click()
|
||||||
|
cy.get(".card").contains("Profile").click()
|
||||||
|
cy.get(".cy-person-name").contains("test account 12938740")
|
||||||
|
})
|
||||||
|
})
|
10
cypress/e2e/search.cy.ts
Normal file
10
cypress/e2e/search.cy.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
describe("search", () => {
|
||||||
|
it("works", () => {
|
||||||
|
cy.visit("/")
|
||||||
|
cy.get(".cy-top-nav .fa-search").click()
|
||||||
|
cy.get(".cy-top-nav input").type("hodlbod")
|
||||||
|
cy.get(".modal").contains("hodlbod").click()
|
||||||
|
cy.get(".modal").contains("following")
|
||||||
|
cy.get(".modal").contains("followers")
|
||||||
|
})
|
||||||
|
})
|
23
cypress/e2e/signup.cy.ts
Normal file
23
cypress/e2e/signup.cy.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
describe("signup", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit("/")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("works", () => {
|
||||||
|
cy.get(".cy-top-nav").contains("Log In").click()
|
||||||
|
cy.get(".modal").contains("Sign Up").click()
|
||||||
|
cy.get(".modal").contains("Let's go!").click()
|
||||||
|
cy.get(".modal [name=name]").type("9sd2j3e0sd")
|
||||||
|
cy.get(".modal").contains("Continue").click()
|
||||||
|
cy.get(".modal").contains("Got it").click()
|
||||||
|
cy.get(".modal").contains("Continue").click()
|
||||||
|
cy.get(".modal").contains("Continue").click()
|
||||||
|
cy.wait(1000)
|
||||||
|
cy.get(".modal").contains("Skip and see your feed").click()
|
||||||
|
cy.get(".modal").should("not.exist")
|
||||||
|
cy.contains("From follows")
|
||||||
|
cy.get("svg.logo").click()
|
||||||
|
cy.get(".card").contains("Profile").click()
|
||||||
|
cy.get(".cy-person-name").contains("9sd2j3e0sd")
|
||||||
|
})
|
||||||
|
})
|
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
29
cypress/support/commands.ts
Normal file
29
cypress/support/commands.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const nsec = "nsec1er8narhat3xjypf46pksxlr6k4jrmv2e9psazjk0adynly0l4ltsepvmy5"
|
||||||
|
|
||||||
|
Cypress.Commands.add("login", () => {
|
||||||
|
cy.session(
|
||||||
|
nsec,
|
||||||
|
() => {
|
||||||
|
cy.visit("/login/privkey")
|
||||||
|
cy.get("input[type=password]").type(nsec, {log: false})
|
||||||
|
cy.get(".cy-login-submit").click()
|
||||||
|
cy.get(".modal", {timeout: 10_000}).should("not.exist")
|
||||||
|
cy.contains("Don't have an account?").should("not.exist")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validate: () => {
|
||||||
|
let pubkey
|
||||||
|
|
||||||
|
cy.window()
|
||||||
|
.then(w => {
|
||||||
|
pubkey = w.pubkey.get()
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
expect(pubkey).to.equal(
|
||||||
|
"c853d879b7376dab1cdcd4faf235a05f680aae42ba620abdd95d619542a5a379"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
20
cypress/support/e2e.ts
Normal file
20
cypress/support/e2e.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example support/e2e.ts is processed and
|
||||||
|
// loaded automatically before your test files.
|
||||||
|
//
|
||||||
|
// This is a great place to put global configuration and
|
||||||
|
// behavior that modifies Cypress.
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off
|
||||||
|
// automatically serving support files with the
|
||||||
|
// 'supportFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/configuration
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// Import commands.js using ES2015 syntax:
|
||||||
|
import "./commands"
|
||||||
|
|
||||||
|
// Alternatively you can use CommonJS syntax:
|
||||||
|
// require('./commands')
|
@ -23,6 +23,7 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^5.50.0",
|
"@typescript-eslint/eslint-plugin": "^5.50.0",
|
||||||
"@typescript-eslint/parser": "^5.50.0",
|
"@typescript-eslint/parser": "^5.50.0",
|
||||||
"autoprefixer": "^10.4.13",
|
"autoprefixer": "^10.4.13",
|
||||||
|
"cypress": "^13.3.1",
|
||||||
"eslint": "^8.33.0",
|
"eslint": "^8.33.0",
|
||||||
"eslint-plugin-svelte3": "^4.0.0",
|
"eslint-plugin-svelte3": "^4.0.0",
|
||||||
"postcss": "^8.4.19",
|
"postcss": "^8.4.19",
|
||||||
@ -55,6 +56,7 @@
|
|||||||
"insane": "^2.6.2",
|
"insane": "^2.6.2",
|
||||||
"lru-cache": "^7.18.3",
|
"lru-cache": "^7.18.3",
|
||||||
"marked": "^5.1.0",
|
"marked": "^5.1.0",
|
||||||
|
"normalize-url": "^8.0.0",
|
||||||
"nostr-tools": "^1.12.1",
|
"nostr-tools": "^1.12.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"paravel": "^0.3.7",
|
"paravel": "^0.3.7",
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import "@fortawesome/fontawesome-free/css/fontawesome.css"
|
import "@fortawesome/fontawesome-free/css/fontawesome.css"
|
||||||
import "@fortawesome/fontawesome-free/css/solid.css"
|
import "@fortawesome/fontawesome-free/css/solid.css"
|
||||||
|
|
||||||
import {nip19} from "nostr-tools"
|
import {nip19, getPublicKey, generatePrivateKey} from "nostr-tools"
|
||||||
import {pluck} from "ramda"
|
import {pluck} from "ramda"
|
||||||
import {seconds, Fetch} from "hurdak"
|
import {seconds, Fetch} from "hurdak"
|
||||||
import {tryFetch, hexToBech32, bech32ToHex, now} from "src/util/misc"
|
import {tryFetch, hexToBech32, bech32ToHex, now} from "src/util/misc"
|
||||||
@ -223,7 +223,15 @@
|
|||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
|
|
||||||
Object.assign(window, {...engine, nip19, bech32ToHex, hexToBech32, router})
|
Object.assign(window, {
|
||||||
|
...engine,
|
||||||
|
nip19,
|
||||||
|
bech32ToHex,
|
||||||
|
hexToBech32,
|
||||||
|
router,
|
||||||
|
getPublicKey,
|
||||||
|
generatePrivateKey,
|
||||||
|
})
|
||||||
|
|
||||||
// Theme
|
// Theme
|
||||||
|
|
||||||
|
@ -156,8 +156,8 @@
|
|||||||
}} />
|
}} />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="fixed top-0 z-10 flex h-16 w-full items-center justify-between border-b
|
class="cy-top-nav fixed top-0 z-10 flex h-16 w-full items-center justify-between
|
||||||
border-gray-6 bg-gray-7 px-2 text-gray-2">
|
border-b border-gray-6 bg-gray-7 px-2 text-gray-2">
|
||||||
<div>
|
<div>
|
||||||
<div class="app-logo flex cursor-pointer items-center gap-2" on:click={toggleMenu}>
|
<div class="app-logo flex cursor-pointer items-center gap-2" on:click={toggleMenu}>
|
||||||
<!-- <img alt="App Logo" src={logoUrl} class="w-10" /> -->
|
<!-- <img alt="App Logo" src={logoUrl} class="w-10" /> -->
|
||||||
@ -183,7 +183,7 @@
|
|||||||
<div
|
<div
|
||||||
class={cx(
|
class={cx(
|
||||||
"search-input pointer-events-none fixed top-0 z-10 w-full px-2 text-gray-1",
|
"search-input pointer-events-none fixed top-0 z-10 w-full px-2 text-gray-1",
|
||||||
"flex h-16 items-center justify-end gap-4",
|
"cy-top-nav flex h-16 items-center justify-end gap-4",
|
||||||
{
|
{
|
||||||
"pr-16": $session,
|
"pr-16": $session,
|
||||||
"pr-28": !$session,
|
"pr-28": !$session,
|
||||||
|
@ -223,7 +223,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{#if muted}
|
{#if muted}
|
||||||
<p class="border-l-2 border-solid border-gray-6 pl-4 text-gray-1">
|
<p class="border-l-2 border-solid border-gray-6 pl-4 text-gray-1">
|
||||||
You have muted this note.
|
You have hidden this note.
|
||||||
<Anchor
|
<Anchor
|
||||||
theme="anchor"
|
theme="anchor"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
@ -233,10 +233,12 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<NoteContent {anchorId} note={event} {showEntire} />
|
<NoteContent {anchorId} note={event} {showEntire} />
|
||||||
{/if}
|
{/if}
|
||||||
|
<div class="cy-note-click-target h-px" />
|
||||||
<NoteActions
|
<NoteActions
|
||||||
note={event}
|
note={event}
|
||||||
bind:this={actions}
|
bind:this={actions}
|
||||||
{removeFromContext}
|
{removeFromContext}
|
||||||
|
{showMuted}
|
||||||
{replies}
|
{replies}
|
||||||
{likes}
|
{likes}
|
||||||
{zaps}
|
{zaps}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
export let note: Event
|
export let note: Event
|
||||||
export let reply
|
export let reply
|
||||||
|
export let showMuted
|
||||||
export let showEntire
|
export let showEntire
|
||||||
export let removeFromContext
|
export let removeFromContext
|
||||||
export let replies
|
export let replies
|
||||||
@ -102,7 +103,7 @@
|
|||||||
let showDetails = false
|
let showDetails = false
|
||||||
let actions = []
|
let actions = []
|
||||||
|
|
||||||
$: disableActions = !$canSign || $muted
|
$: disableActions = !$canSign || ($muted && !showMuted)
|
||||||
$: like = like || find(propEq("pubkey", $session?.pubkey), likes)
|
$: like = like || find(propEq("pubkey", $session?.pubkey), likes)
|
||||||
$: allLikes = like ? likes.filter(n => n.id !== like?.id).concat(like) : likes
|
$: allLikes = like ? likes.filter(n => n.id !== like?.id).concat(like) : likes
|
||||||
$: $likesCount = allLikes.length
|
$: $likesCount = allLikes.length
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
{:else if quote}
|
{:else if quote}
|
||||||
{#if muted}
|
{#if muted}
|
||||||
<p class="mb-1 py-24 text-center text-gray-5">
|
<p class="mb-1 py-24 text-center text-gray-5">
|
||||||
You have muted this note.
|
You have hidden this note.
|
||||||
<Anchor class="underline" on:click={unmute}>Show</Anchor>
|
<Anchor class="underline" on:click={unmute}>Show</Anchor>
|
||||||
</p>
|
</p>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={cx("flex items-center gap-1", $$props.class)}>
|
<div class={cx("flex items-center gap-1", $$props.class)}>
|
||||||
<span>{displayPerson($person)}</span>
|
<span class="cy-person-name">{displayPerson($person)}</span>
|
||||||
<div class="flex items-center gap-1 font-normal">
|
<div class="flex items-center gap-1 font-normal">
|
||||||
{#if $following}
|
{#if $following}
|
||||||
<span class="px-2 py-1 text-xs">
|
<span class="px-2 py-1 text-xs">
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
loginWithExtension(await ext.getPublicKey())
|
loginWithExtension(await ext.getPublicKey())
|
||||||
boot()
|
boot()
|
||||||
} else {
|
} else {
|
||||||
router.at("login/privkey").open()
|
router.at("login/privkey").replaceModal()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const signUp = () => router.at("onboarding").open()
|
const signUp = () => router.at("onboarding").replaceModal()
|
||||||
|
|
||||||
const advancedLogIn = () => router.at("login/advanced").open()
|
const advancedLogIn = () => router.at("login/advanced").replaceModal()
|
||||||
|
|
||||||
document.title = "Log In"
|
document.title = "Log In"
|
||||||
</script>
|
</script>
|
||||||
|
@ -131,13 +131,15 @@
|
|||||||
<Spinner />
|
<Spinner />
|
||||||
{:else if Object.values(currentRelays).length > 0}
|
{:else if Object.values(currentRelays).length > 0}
|
||||||
<p>Currently searching:</p>
|
<p>Currently searching:</p>
|
||||||
{#each Object.values(currentRelays) as relay}
|
<Content gap="gap-4" size="inherit">
|
||||||
<div class="h-12">
|
{#each Object.values(currentRelays) as relay}
|
||||||
{#if relay}
|
<div class="h-12">
|
||||||
<RelayCard hideActions relay={{...relay, description: null}} />
|
{#if relay}
|
||||||
{/if}
|
<RelayCard hideActions relay={{...relay, description: null}} />
|
||||||
</div>
|
{/if}
|
||||||
{/each}
|
</div>
|
||||||
|
{/each}
|
||||||
|
</Content>
|
||||||
{/if}
|
{/if}
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
<i slot="before" class="fa fa-key" />
|
<i slot="before" class="fa fa-key" />
|
||||||
</Input>
|
</Input>
|
||||||
</div>
|
</div>
|
||||||
<Anchor theme="button" on:click={logIn}>Log In</Anchor>
|
<Anchor theme="button" class="cy-login-submit" on:click={logIn}>Log In</Anchor>
|
||||||
</div>
|
</div>
|
||||||
{#if !Capacitor.isNativePlatform()}
|
{#if !Capacitor.isNativePlatform()}
|
||||||
<p class="rounded border-2 border-solid border-warning bg-gray-8 px-6 py-3">
|
<p class="rounded border-2 border-solid border-warning bg-gray-8 px-6 py-3">
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {generatePrivateKey} from "nostr-tools"
|
import {generatePrivateKey} from "nostr-tools"
|
||||||
import {closure} from "hurdak"
|
import {closure, sleep} from "hurdak"
|
||||||
import {fly} from "src/util/transition"
|
import {fly} from "src/util/transition"
|
||||||
|
import Content from "src/partials/Content.svelte"
|
||||||
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 OnboardingProfile from "src/app/views/OnboardingProfile.svelte"
|
||||||
import OnboardingKey from "src/app/views/OnboardingKey.svelte"
|
import OnboardingKey from "src/app/views/OnboardingKey.svelte"
|
||||||
@ -62,6 +63,13 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
const signup = async noteContent => {
|
const signup = async noteContent => {
|
||||||
|
// Go to our home page
|
||||||
|
router.at("notes").push()
|
||||||
|
|
||||||
|
// Make things async since the `key` change in App.svelte prevents the modal
|
||||||
|
// animation from completing, and it gets stuck. This is a svelte bug
|
||||||
|
await sleep(10)
|
||||||
|
|
||||||
loginWithPrivateKey(privkey)
|
loginWithPrivateKey(privkey)
|
||||||
|
|
||||||
// Do this first so we know where to publish everything else
|
// Do this first so we know where to publish everything else
|
||||||
@ -78,12 +86,6 @@
|
|||||||
|
|
||||||
// Start our notifications listener
|
// Start our notifications listener
|
||||||
listenForNotifications()
|
listenForNotifications()
|
||||||
|
|
||||||
// Close all modals
|
|
||||||
router.clearModals()
|
|
||||||
|
|
||||||
// Go to our home page
|
|
||||||
router.at("notes").push()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -94,18 +96,20 @@
|
|||||||
|
|
||||||
{#key stage}
|
{#key stage}
|
||||||
<div in:fly={{y: 20}}>
|
<div in:fly={{y: 20}}>
|
||||||
{#if stage === "intro"}
|
<Content size="lg">
|
||||||
<OnboardingIntro {setStage} />
|
{#if stage === "intro"}
|
||||||
{:else if stage === "profile"}
|
<OnboardingIntro {setStage} />
|
||||||
<OnboardingProfile {setStage} {profile} />
|
{:else if stage === "profile"}
|
||||||
{:else if stage === "key"}
|
<OnboardingProfile {setStage} {profile} />
|
||||||
<OnboardingKey {setStage} {privkey} />
|
{:else if stage === "key"}
|
||||||
{:else if stage === "relays"}
|
<OnboardingKey {setStage} {privkey} />
|
||||||
<OnboardingRelays {setStage} bind:relays />
|
{:else if stage === "relays"}
|
||||||
{:else if stage === "follows"}
|
<OnboardingRelays {setStage} bind:relays />
|
||||||
<OnboardingFollows {setStage} bind:petnames />
|
{:else if stage === "follows"}
|
||||||
{:else if stage === "note"}
|
<OnboardingFollows {setStage} bind:petnames />
|
||||||
<OnboardingNote {setStage} {signup} />
|
{:else if stage === "note"}
|
||||||
{/if}
|
<OnboardingNote {setStage} {signup} />
|
||||||
|
{/if}
|
||||||
|
</Content>
|
||||||
</div>
|
</div>
|
||||||
{/key}
|
{/key}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
import Input from "src/partials/Input.svelte"
|
import Input from "src/partials/Input.svelte"
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
import Heading from "src/partials/Heading.svelte"
|
import Heading from "src/partials/Heading.svelte"
|
||||||
import Content from "src/partials/Content.svelte"
|
|
||||||
import PersonSummary from "src/app/shared/PersonSummary.svelte"
|
import PersonSummary from "src/app/shared/PersonSummary.svelte"
|
||||||
import type {Person} from "src/engine"
|
import type {Person} from "src/engine"
|
||||||
import {env, mention, loadPeople, searchPeople} from "src/engine"
|
import {env, mention, loadPeople, searchPeople} from "src/engine"
|
||||||
@ -29,58 +28,54 @@
|
|||||||
$: results = reject((p: Person) => pubkeys.includes(p.pubkey), $searchPeople(q))
|
$: results = reject((p: Person) => pubkeys.includes(p.pubkey), $searchPeople(q))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Content>
|
<Heading class="text-center">Find Your People</Heading>
|
||||||
<Content class="text-center">
|
<p>
|
||||||
<Heading>Find Your People</Heading>
|
To get you started, we’ve added some interesting people to your follow list. You can update your
|
||||||
<p>
|
follows list at any time.
|
||||||
To get you started, we’ve added some interesting people to your follow list. You can update
|
</p>
|
||||||
your follows list at any time.
|
<div class="flex gap-2">
|
||||||
</p>
|
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
||||||
<div class="flex gap-2">
|
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Continue</Anchor>
|
||||||
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
</div>
|
||||||
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Continue</Anchor>
|
<div class="flex items-center gap-2">
|
||||||
</div>
|
<i class="fa fa-user-astronaut fa-lg" />
|
||||||
</Content>
|
<h2 class="staatliches text-2xl">Your follows</h2>
|
||||||
<div class="flex items-center gap-2">
|
</div>
|
||||||
<i class="fa fa-user-astronaut fa-lg" />
|
{#if pubkeys.length === 0}
|
||||||
<h2 class="staatliches text-2xl">Your follows</h2>
|
<div class="mt-8 flex items-center justify-center gap-2 text-center">
|
||||||
|
<i class="fa fa-triangle-exclamation" />
|
||||||
|
<span>No follows selected</span>
|
||||||
</div>
|
</div>
|
||||||
{#if pubkeys.length === 0}
|
{:else}
|
||||||
<div class="mt-8 flex items-center justify-center gap-2 text-center">
|
{#each pubkeys as pubkey (pubkey)}
|
||||||
<i class="fa fa-triangle-exclamation" />
|
<PersonSummary {pubkey}>
|
||||||
<span>No follows selected</span>
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
{#each pubkeys as pubkey (pubkey)}
|
|
||||||
<PersonSummary {pubkey}>
|
|
||||||
<div slot="actions" class="flex items-start justify-end">
|
|
||||||
<Anchor
|
|
||||||
theme="button"
|
|
||||||
class="flex items-center gap-2"
|
|
||||||
on:click={() => removeFollow(pubkey)}>
|
|
||||||
<i class="fa fa-user-slash" /> Unfollow
|
|
||||||
</Anchor>
|
|
||||||
</div>
|
|
||||||
</PersonSummary>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<i class="fa fa-earth-asia fa-lg" />
|
|
||||||
<h2 class="staatliches text-2xl">Other people</h2>
|
|
||||||
</div>
|
|
||||||
<Input bind:value={q} type="text" wrapperClass="flex-grow" placeholder="Type to search">
|
|
||||||
<i slot="before" class="fa-solid fa-search" />
|
|
||||||
</Input>
|
|
||||||
{#each results.slice(0, 50) as profile (profile.pubkey)}
|
|
||||||
<PersonSummary pubkey={profile.pubkey}>
|
|
||||||
<div slot="actions" class="flex items-start justify-end">
|
<div slot="actions" class="flex items-start justify-end">
|
||||||
<Anchor
|
<Anchor
|
||||||
theme="button-accent"
|
theme="button"
|
||||||
class="flex items-center gap-2"
|
class="flex items-center gap-2"
|
||||||
on:click={() => addFollow(profile.pubkey)}>
|
on:click={() => removeFollow(pubkey)}>
|
||||||
<i class="fa fa-user-plus" /> Follow
|
<i class="fa fa-user-slash" /> Unfollow
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</div>
|
</div>
|
||||||
</PersonSummary>
|
</PersonSummary>
|
||||||
{/each}
|
{/each}
|
||||||
</Content>
|
{/if}
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<i class="fa fa-earth-asia fa-lg" />
|
||||||
|
<h2 class="staatliches text-2xl">Other people</h2>
|
||||||
|
</div>
|
||||||
|
<Input bind:value={q} type="text" wrapperClass="flex-grow" placeholder="Type to search">
|
||||||
|
<i slot="before" class="fa-solid fa-search" />
|
||||||
|
</Input>
|
||||||
|
{#each results.slice(0, 50) as profile (profile.pubkey)}
|
||||||
|
<PersonSummary pubkey={profile.pubkey}>
|
||||||
|
<div slot="actions" class="flex items-start justify-end">
|
||||||
|
<Anchor
|
||||||
|
theme="button-accent"
|
||||||
|
class="flex items-center gap-2"
|
||||||
|
on:click={() => addFollow(profile.pubkey)}>
|
||||||
|
<i class="fa fa-user-plus" /> Follow
|
||||||
|
</Anchor>
|
||||||
|
</div>
|
||||||
|
</PersonSummary>
|
||||||
|
{/each}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
import Heading from "src/partials/Heading.svelte"
|
import Heading from "src/partials/Heading.svelte"
|
||||||
import Content from "src/partials/Content.svelte"
|
|
||||||
|
|
||||||
export let setStage
|
export let setStage
|
||||||
|
|
||||||
@ -10,16 +9,14 @@
|
|||||||
const next = () => setStage("profile")
|
const next = () => setStage("profile")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Content size="lg" class="text-center">
|
<Heading class="text-center">Create an Account</Heading>
|
||||||
<Heading>Create an Account</Heading>
|
<p>
|
||||||
<p>
|
New to Nostr? Click <Anchor class="underline" external href={tutorialUrl}>here</Anchor> or watch the
|
||||||
New to Nostr? Click <Anchor class="underline" external href={tutorialUrl}>here</Anchor> or watch
|
video below for a crash course on what it is, and how to use it.
|
||||||
the video below for a crash course on what it is, and how to use it.
|
</p>
|
||||||
</p>
|
<video controls src={videoUrl} class="object-contain object-center" />
|
||||||
<video controls src={videoUrl} class="object-contain object-center" />
|
<p>
|
||||||
<p>
|
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 theme="button-accent" class="text-center" on:click={next}>Let's go!</Anchor>
|
||||||
<Anchor theme="button-accent" on:click={next}>Let's go!</Anchor>
|
|
||||||
</Content>
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
import Input from "src/partials/Input.svelte"
|
import Input from "src/partials/Input.svelte"
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
import Heading from "src/partials/Heading.svelte"
|
import Heading from "src/partials/Heading.svelte"
|
||||||
import Content from "src/partials/Content.svelte"
|
|
||||||
import {env} from "src/engine"
|
import {env} from "src/engine"
|
||||||
|
|
||||||
export let privkey
|
export let privkey
|
||||||
@ -21,19 +20,17 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Content size="lg" class="text-center">
|
<Heading class="text-center">Generate a Key</Heading>
|
||||||
<Heading>Generate a Key</Heading>
|
<p>
|
||||||
<p>
|
Your private key is your password, and gives you total control over your Nostr account. We've
|
||||||
Your private key is your password, and gives you total control over your Nostr account. We've
|
generated a fresh one for you below – store it somewhere safe!
|
||||||
generated a fresh one for you below – store it somewhere safe!
|
</p>
|
||||||
</p>
|
<Input disabled placeholder={"•".repeat(53)} wrapperClass="flex-grow">
|
||||||
<Input disabled placeholder={"•".repeat(53)} wrapperClass="flex-grow">
|
<i slot="before" class="fa fa-lock" />
|
||||||
<i slot="before" class="fa fa-lock" />
|
<button slot="after" class="fa fa-copy cursor-pointer" on:click={copyKey} />
|
||||||
<button slot="after" class="fa fa-copy cursor-pointer" on:click={copyKey} />
|
</Input>
|
||||||
</Input>
|
<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>
|
<div class="flex gap-2">
|
||||||
<div class="flex gap-2">
|
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
||||||
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Got it</Anchor>
|
||||||
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Got it</Anchor>
|
</div>
|
||||||
</div>
|
|
||||||
</Content>
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
import Compose from "src/app/shared/Compose.svelte"
|
import Compose from "src/app/shared/Compose.svelte"
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
import Heading from "src/partials/Heading.svelte"
|
import Heading from "src/partials/Heading.svelte"
|
||||||
import Content from "src/partials/Content.svelte"
|
|
||||||
|
|
||||||
export let signup
|
export let signup
|
||||||
export let setStage
|
export let setStage
|
||||||
@ -19,20 +18,18 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Content size="lg">
|
<Heading class="text-center">Welcome to Nostr</Heading>
|
||||||
<Heading class="text-center">Welcome to Nostr</Heading>
|
<p>
|
||||||
<p class="text-center">
|
Your're all set! If have any questions, just ask! People around these parts are always ready to
|
||||||
Your're all set! If have any questions, just ask! People around these parts are always ready to
|
lend a hand.
|
||||||
lend a hand.
|
</p>
|
||||||
</p>
|
<div class="border-l-2 border-solid border-gray-6 pl-4">
|
||||||
<div class="border-l-2 border-solid border-gray-6 pl-4">
|
<Compose bind:this={compose} onSubmit={next} />
|
||||||
<Compose bind:this={compose} onSubmit={next} />
|
</div>
|
||||||
</div>
|
<div class="flex gap-2">
|
||||||
<div class="flex gap-2">
|
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
||||||
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Say Hello!</Anchor>
|
||||||
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Say Hello!</Anchor>
|
</div>
|
||||||
</div>
|
<Anchor class="text-center" on:click={skip}>
|
||||||
<Anchor class="text-center" on:click={skip}>
|
Skip and see your feed <i class="fa fa-arrow-right" />
|
||||||
Skip and see your feed <i class="fa fa-arrow-right" />
|
</Anchor>
|
||||||
</Anchor>
|
|
||||||
</Content>
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
import ImageInput from "src/partials/ImageInput.svelte"
|
import ImageInput from "src/partials/ImageInput.svelte"
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
import Heading from "src/partials/Heading.svelte"
|
import Heading from "src/partials/Heading.svelte"
|
||||||
import Content from "src/partials/Content.svelte"
|
|
||||||
|
|
||||||
export let profile
|
export let profile
|
||||||
export let setStage
|
export let setStage
|
||||||
@ -13,35 +12,28 @@
|
|||||||
const next = () => setStage("key")
|
const next = () => setStage("key")
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Content size="lg">
|
<Heading class="text-center">Introduce Yourself</Heading>
|
||||||
<Heading class="text-center">Introduce Yourself</Heading>
|
<p>
|
||||||
<p class="text-center">
|
Give other people something to go on. Remember that "privacy is the power to selectively reveal
|
||||||
Give other people something to go on. Remember that "privacy is the power to selectively reveal
|
oneself to the world".
|
||||||
oneself to the world".
|
</p>
|
||||||
</p>
|
<div class="flex flex-col gap-2">
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-1">
|
||||||
<div class="flex flex-col gap-1">
|
<strong>Your Name</strong>
|
||||||
<strong>Your Name</strong>
|
<Input type="text" name="name" wrapperClass="flex-grow" bind:value={profile.name}>
|
||||||
<Input type="text" name="name" wrapperClass="flex-grow" bind:value={profile.name}>
|
<i slot="before" class="fa-solid fa-user-astronaut" />
|
||||||
<i slot="before" class="fa-solid fa-user-astronaut" />
|
</Input>
|
||||||
</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>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-col gap-1">
|
||||||
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
<strong>About You</strong>
|
||||||
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Continue</Anchor>
|
<Textarea name="about" bind:value={profile.about} />
|
||||||
</div>
|
</div>
|
||||||
</Content>
|
<div class="flex flex-col gap-1">
|
||||||
|
<strong>Profile Picture</strong>
|
||||||
|
<ImageInput bind:value={profile.picture} icon="image-portrait" maxWidth={480} maxHeight={480} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
||||||
|
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Continue</Anchor>
|
||||||
|
</div>
|
||||||
|
@ -34,52 +34,50 @@
|
|||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Content>
|
<Heading class="text-center">Get Connected</Heading>
|
||||||
<div class="text-center">
|
<p>
|
||||||
<Heading>Get Connected</Heading>
|
Nostr is a protocol, not a platform. This means that <i>you</i> choose where to store your data.
|
||||||
<p>
|
</p>
|
||||||
Nostr is a protocol, not a platform. This means that <i>you</i> choose where to store your data.
|
<p>
|
||||||
Select your preferred storage relays below, or click "continue" to use some reasonable defaults.
|
Select your preferred storage relays below, or click "continue" to use some reasonable defaults.
|
||||||
You can change your selection any time.
|
You can change your selection any time.
|
||||||
</p>
|
</p>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
||||||
|
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Continue</Anchor>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<i class="fa fa-server fa-lg" />
|
||||||
|
<h2 class="staatliches text-2xl">Your relays</h2>
|
||||||
|
</div>
|
||||||
|
{#if relays.length === 0}
|
||||||
|
<div class="mt-8 flex items-center justify-center gap-2 text-center">
|
||||||
|
<i class="fa fa-triangle-exclamation" />
|
||||||
|
<span>No relays connected</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
{:else}
|
||||||
<Anchor theme="button" on:click={prev}><i class="fa fa-arrow-left" /></Anchor>
|
<Content gap="gap-4" size="inherit">
|
||||||
<Anchor theme="button-accent" class="flex-grow text-center" on:click={next}>Continue</Anchor>
|
{#each relays as relay (relay.url)}
|
||||||
</div>
|
<RelayCard {relay}>
|
||||||
<div class="flex items-center gap-2">
|
<div slot="actions">
|
||||||
<i class="fa fa-server fa-lg" />
|
{#if relays.length > 1}
|
||||||
<h2 class="staatliches text-2xl">Your relays</h2>
|
<button class="flex items-center gap-3 text-gray-1" on:click={() => removeRelay(relay)}>
|
||||||
</div>
|
<i class="fa fa-right-from-bracket" /> Leave
|
||||||
{#if relays.length === 0}
|
</button>
|
||||||
<div class="mt-8 flex items-center justify-center gap-2 text-center">
|
{/if}
|
||||||
<i class="fa fa-triangle-exclamation" />
|
</div>
|
||||||
<span>No relays connected</span>
|
</RelayCard>
|
||||||
</div>
|
{/each}
|
||||||
{:else}
|
</Content>
|
||||||
<div class="grid grid-cols-1 gap-4">
|
{/if}
|
||||||
{#each relays as relay (relay.url)}
|
<div class="flex items-center gap-2">
|
||||||
<RelayCard {relay}>
|
<i class="fa fa-earth-asia fa-lg" />
|
||||||
<div slot="actions">
|
<h2 class="staatliches text-2xl">Other relays</h2>
|
||||||
{#if relays.length > 1}
|
</div>
|
||||||
<button
|
<Input bind:value={q} type="text" wrapperClass="flex-grow" placeholder="Type to search">
|
||||||
class="flex items-center gap-3 text-gray-1"
|
<i slot="before" class="fa-solid fa-search" />
|
||||||
on:click={() => removeRelay(relay)}>
|
</Input>
|
||||||
<i class="fa fa-right-from-bracket" /> Leave
|
<Content gap="gap-4" size="inherit">
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</RelayCard>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<i class="fa fa-earth-asia fa-lg" />
|
|
||||||
<h2 class="staatliches text-2xl">Other relays</h2>
|
|
||||||
</div>
|
|
||||||
<Input bind:value={q} type="text" wrapperClass="flex-grow" placeholder="Type to search">
|
|
||||||
<i slot="before" class="fa-solid fa-search" />
|
|
||||||
</Input>
|
|
||||||
{#each (search(q) || []).slice(0, 50) as relay (relay.url)}
|
{#each (search(q) || []).slice(0, 50) as relay (relay.url)}
|
||||||
<RelayCard {relay}>
|
<RelayCard {relay}>
|
||||||
<div slot="actions">
|
<div slot="actions">
|
||||||
@ -89,8 +87,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</RelayCard>
|
</RelayCard>
|
||||||
{/each}
|
{/each}
|
||||||
<small class="text-center">
|
|
||||||
Showing {Math.min($knownRelays.length - relays.length, 50)}
|
|
||||||
of {$knownRelays.length - relays.length} known relays
|
|
||||||
</small>
|
|
||||||
</Content>
|
</Content>
|
||||||
|
<small class="text-center">
|
||||||
|
Showing {Math.min($knownRelays.length - relays.length, 50)}
|
||||||
|
of {$knownRelays.length - relays.length} known relays
|
||||||
|
</small>
|
||||||
|
@ -4,10 +4,14 @@
|
|||||||
export let theme = "dark"
|
export let theme = "dark"
|
||||||
export let onRemove = null
|
export let onRemove = null
|
||||||
|
|
||||||
const className = cx($$props.class, "inline-block rounded-full border border-solid py-1 px-2", {
|
const className = cx(
|
||||||
"border-gray-1": theme === "dark",
|
$$props.class,
|
||||||
"border-gray-8": theme === "light",
|
"inline-block rounded-full border border-solid py-1 px-2 cy-chip",
|
||||||
})
|
{
|
||||||
|
"border-gray-1": theme === "dark",
|
||||||
|
"border-gray-8": theme === "light",
|
||||||
|
}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={className}>
|
<div class={className}>
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
<div
|
<div
|
||||||
class="pointer-events-auto flex h-10 w-10 cursor-pointer items-center justify-center rounded-full
|
class="pointer-events-auto flex h-10 w-10 cursor-pointer items-center justify-center rounded-full
|
||||||
border border-solid border-accent-light bg-accent text-white transition-colors hover:bg-accent-light">
|
border border-solid border-accent-light bg-accent text-white transition-colors hover:bg-accent-light">
|
||||||
<i class="fa fa-times fa-lg" />
|
<i class="fa fa-times fa-lg cy-modal-close" />
|
||||||
</div>
|
</div>
|
||||||
{#if $modals.length > 1 && index > 0}
|
{#if $modals.length > 1 && index > 0}
|
||||||
<div
|
<div
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"include": ["src/**/*"],
|
"include": ["src/**/*"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
|
"module": "esnext",
|
||||||
"paths": {
|
"paths": {
|
||||||
"src/*": ["src/*"]
|
"src/*": ["src/*"]
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user