Fix a few bugs

This commit is contained in:
Jonathan Staab 2023-04-17 16:47:54 -05:00
parent 5b548cccab
commit 879ece60a9
20 changed files with 171 additions and 134 deletions

1
.env
View File

@ -1,4 +1,3 @@
VITE_THEME_DARK=transparent:transparent,black:#0f0f0e,white:#FFFFFF,accent:#EB5E28,accent-light:#FB652C,gray-1:#FFFFFF,gray-2:#FAF6F1,gray-3:#F2EBE1,gray-4:#E9E0D3,gray-5:#B3AA98,gray-6:#565249,gray-7:#393530,gray-8:#252422,danger:#ff0000,warning:#ebd112,success:#37ab51,input:#FAF6F1,input-hover:#F2EBE1
VITE_THEME_LIGHT=transparent:transparent,black:#0f0f0e,white:#FFFFFF,accent:#EB5E28,accent-light:#FB652C,gray-8:#FFFFFF,gray-7:#FAF6F1,gray-6:#F2EBE1,gray-5:#E9E0D3,gray-4:#B3AA98,gray-3:#565249,gray-2:#393530,gray-1:#252422,danger:#ff0000,warning:#ebd112,success:#37ab51,input:#FAF6F1,input-hover:#F2EBE1
VITE_DUFFLEPUD_URL=https://dufflepud.onrender.com
VITE_SHOW_DEBUG_ROUTE=false

View File

@ -1,14 +1,7 @@
# Current
- [ ] Topics
- [x] Improve topic suggestions and rendering
- [x] Add topic search, keep cache of topics
- [x] Ability to create custom feeds
- [x] Bookmark icon opens "create feed" dialog with form pre-filled
- [ ] Replace some modals instead of pushing
- [ ] Test anonymous with lists
- [ ] Test hardcoded relay, currently you get asked to pick a relay if not logged in
- [ ] Claim relays bounty
- [ ] Claim relays bounty
- [ ] Add real search, it's a big hurdle for first-timers/anons
- [ ] Fix notifications
- [ ] Queue context requests to avoid having too many concurrent subscriptions
- [ ] Advanced search

View File

@ -41,7 +41,7 @@ const profile = synced("agent/user/profile", {
})
const settings = derived(profile, prop("settings"))
const petnames = derived(profile, prop("petnames"))
const petnames = derived(profile, prop("petnames")) as Readable<Array<Array<string>>>
const relays = derived(profile, prop("relays")) as Readable<Array<Relay>>
const mutes = derived(profile, prop("mutes")) as Readable<Array<[string, string]>>
const lists = derived(profile, prop("lists")) as Readable<Array<MyEvent>>

View File

@ -8,8 +8,9 @@
import PersonSearch from "src/app/shared/PersonSearch.svelte"
import {getPersonWithFallback} from "src/agent/db"
import user from "src/agent/user"
import pool from "src/agent/pool"
export let enforceRelays = true
export let enforceRelays = pool.forceUrls.length === 0
export let enforcePeople = true
const {petnamePubkeys, relays} = user
@ -29,18 +30,24 @@
{#if $relays.length > 0}
<h1 class="text-2xl">Your Relays</h1>
{/if}
{#each $relays as relay (relay.url)}
<RelayCard showControls {relay} />
{:else}
<div class="flex flex-col items-center gap-4 my-8">
<div class="text-xl flex gap-2 items-center">
<i class="fa fa-triangle-exclamation fa-light" />
You aren't yet connected to any relays.
<div class="flex flex-col gap-2">
{#each $relays as relay (relay.url)}
<RelayCard showActions {relay} />
{:else}
<div class="flex flex-col items-center gap-4 my-8">
<div class="text-xl flex gap-2 items-center">
<i class="fa fa-triangle-exclamation fa-light" />
You aren't yet connected to any relays.
</div>
<div>Search below to find one to join.</div>
</div>
<div>Search below to find one to join.</div>
{/each}
</div>
<RelaySearch>
<div slot="item" let:relay>
<RelayCard showActions {relay} />
</div>
{/each}
<RelaySearch />
</RelaySearch>
</Content>
</Modal>
{:else if needsRelays()}
@ -72,7 +79,7 @@
<div>Search below to find some interesting people.</div>
</div>
{/each}
<PersonSearch />
<PersonSearch hideFollows />
</Content>
</Modal>
{:else if needsPeople()}
@ -83,7 +90,7 @@
You aren't yet following anyone.
</div>
<div>
Click <Anchor href="/search/people">here</Anchor> to find some interesting people.
Click <Anchor href="/search">here</Anchor> to find some interesting people.
</div>
</div>
</Content>

View File

@ -121,13 +121,6 @@
</a>
</li>
{/if}
{#if import.meta.env.VITE_SHOW_DEBUG_ROUTE === "true"}
<li class="cursor-pointer">
<a class="block px-4 py-2 transition-all hover:bg-accent hover:text-white" href="/debug">
<i class="fa fa-bug mr-2" /> Debug
</a>
</li>
{/if}
{#if $installPrompt}
<li
class="cursor-pointer px-4 py-2 transition-all hover:bg-accent hover:text-white"

View File

@ -23,11 +23,13 @@
$: {
actions = []
actions.push({
onClick: () => addToList("p", person.pubkey),
label: "Add to list",
icon: "scroll",
})
if ($canPublish) {
actions.push({
onClick: () => addToList("p", person.pubkey),
label: "Add to list",
icon: "scroll",
})
}
actions.push({onClick: share, label: "Share", icon: "share-nodes"})

View File

@ -19,7 +19,7 @@
class={cx(
$$props.class,
`relative overflow-hidden w-${size} h-${size} inline-block shrink-0 rounded-full border border-solid
border-white bg-cover bg-center`
border-gray-1 bg-cover bg-center`
)}
style="--logo-color: {primary}; --logo-bg-color: {secondary}; background-color: var(--logo-bg-color);">
<LogoSvg

View File

@ -1,7 +1,6 @@
<script lang="ts">
import {last, nth} from "ramda"
import {fly} from "svelte/transition"
import {noEvent} from "src/util/html"
import {displayPerson} from "src/util/nostr"
import Anchor from "src/partials/Anchor.svelte"
import PersonCircle from "src/app/shared/PersonCircle.svelte"
@ -10,9 +9,10 @@
import user from "src/agent/user"
import {routes} from "src/app/state"
export let person
const {petnames} = user
export let hasPetname = pubkey => user.getPetnames().map(nth(1)).includes(pubkey)
export let person
export let hasPetname = null
export let removePetname = ({pubkey}) => user.removePetname(pubkey)
@ -21,35 +21,41 @@
user.addPetname(pubkey, url, displayPerson(person))
}
$: isFollowing = hasPetname
? hasPetname(person.pubkey)
: $petnames.map(nth(1)).includes(person.pubkey)
</script>
<a
in:fly={{y: 20}}
href={routes.person(person.pubkey)}
class="flex gap-4 overflow-hidden border-l-2 border-solid border-gray-7 py-3 px-4
transition-all hover:border-accent hover:bg-gray-8">
<PersonCircle {person} size={12} />
<div class="flex min-w-0 flex-grow flex-col gap-4">
<div class="flex items-start justify-between gap-2">
<div class="flex flex-col gap-2">
<h1 class="text-xl">{displayPerson(person)}</h1>
{#if person.verified_as}
<div class="flex gap-1 text-sm">
<i class="fa fa-user-check text-accent" />
<span class="text-gray-1">{last(person.verified_as.split("@"))}</span>
</div>
<div in:fly={{y: 20}}>
<Anchor
type="unstyled"
href={routes.person(person.pubkey)}
class="flex gap-4 overflow-hidden border-l-2 border-solid border-gray-7 py-3 px-4
transition-all hover:border-accent hover:bg-gray-8">
<PersonCircle {person} size={12} />
<div class="flex min-w-0 flex-grow flex-col gap-4">
<div class="flex items-start justify-between gap-2">
<div class="flex flex-col gap-2">
<h1 class="text-xl">{displayPerson(person)}</h1>
{#if person.verified_as}
<div class="flex gap-1 text-sm">
<i class="fa fa-user-check text-accent" />
<span class="text-gray-1">{last(person.verified_as.split("@"))}</span>
</div>
{/if}
</div>
{#if isFollowing}
<Anchor type="button-accent" stopPropagation on:click={() => removePetname(person)}>
Following
</Anchor>
{:else}
<Anchor type="button" stopPropagation on:click={() => addPetname(person)}>Follow</Anchor>
{/if}
</div>
{#if hasPetname(person.pubkey)}
<Anchor type="button-accent" on:click={noEvent(() => removePetname(person))}>
Following
</Anchor>
{:else}
<Anchor type="button" on:click={noEvent(() => addPetname(person))}>Follow</Anchor>
{/if}
<p class="overflow-hidden text-ellipsis">
<PersonAbout truncate {person} />
</p>
</div>
<p class="overflow-hidden text-ellipsis">
<PersonAbout truncate {person} />
</p>
</div>
</a>
</Anchor>
</div>

View File

@ -1,4 +1,5 @@
<script>
import {nth} from "ramda"
import Input from "src/partials/Input.svelte"
import Spinner from "src/partials/Spinner.svelte"
import PersonInfo from "src/app/shared/PersonInfo.svelte"
@ -7,9 +8,25 @@
import network from "src/agent/network"
import user from "src/agent/user"
export let hideFollows = false
let q
$: results = $searchPeople(q).slice(0, 50)
$: results = $searchPeople(q)
.filter(person => {
if (person.pubkey === user.getPubkey()) {
return false
}
if (hideFollows && $petnames.map(nth(1)).includes(person.pubkey)) {
return false
}
return true
})
.slice(0, 50)
const {petnames} = user
// Prime our database, in case we don't have any people stored yet
network.load({
@ -22,9 +39,7 @@
<i slot="before" class="fa-solid fa-search" />
</Input>
{#each results as person (person.pubkey)}
{#if person.pubkey !== user.getPubkey()}
<PersonInfo {person} />
{/if}
<PersonInfo {person} />
{:else}
<Spinner />
{/each}

View File

@ -9,7 +9,7 @@
relay = getRelayWithFallback(relay.url)
const {relays: userRelays} = user
const {relays: userRelays, canPublish} = user
let actions = []
@ -31,11 +31,13 @@
})
}
actions.push({
onClick: () => addToList("r", relay.url),
label: "Add to list",
icon: "scroll",
})
if ($canPublish) {
actions.push({
onClick: () => addToList("r", relay.url),
label: "Add to list",
icon: "scroll",
})
}
if (relay.contact) {
actions.push({

View File

@ -28,14 +28,14 @@
export let removeRelay = r => user.removeRelay(r.url)
export let addRelay = r => {
user.addRelay(r.url).then(() => {
const pubkey = user.getPubkey()
const profile = user.getProfile()
user.addRelay(r.url)
if (pubkey && !profile?.kind0) {
loadAppData(pubkey)
}
})
const pubkey = user.getPubkey()
const profile = user.getProfile()
if (pubkey && !profile?.kind0) {
loadAppData(pubkey)
}
}
onMount(() => {
@ -79,7 +79,7 @@
</p>
{/if}
</div>
{#if $canPublish && showActions}
{#if showActions}
<slot name="actions">
{#if hasRelay(relay) && $relays.length > 1}
<button class="flex items-center gap-3 text-gray-1" on:click={() => removeRelay(relay)}>

View File

@ -1,17 +1,24 @@
<script lang="ts">
import OverflowMenu from "src/partials/OverflowMenu.svelte"
import {addToList} from "src/app/state"
import user from "src/agent/user"
export let topic
const {canPublish} = user
let actions = []
$: {
actions.push({
onClick: () => addToList("t", topic),
label: "Add to list",
icon: "scroll",
})
actions = []
if ($canPublish) {
actions.push({
onClick: () => addToList("t", topic),
label: "Add to list",
icon: "scroll",
})
}
}
</script>

View File

@ -1,8 +1,9 @@
<script lang="ts">
import cx from "classnames"
import {prop, uniq, indexBy, objOf, filter as _filter} from "ramda"
import {shuffle, synced} from "src/util/misc"
import {Tags} from "src/util/nostr"
import {modal} from "src/partials/state"
import {modal, theme} from "src/partials/state"
import Anchor from "src/partials/Anchor.svelte"
import Content from "src/partials/Content.svelte"
import Tabs from "src/partials/Tabs.svelte"
@ -12,7 +13,7 @@
import {sampleRelays, getAllPubkeyWriteRelays, getUserReadRelays} from "src/agent/relays"
import user from "src/agent/user"
const {lists} = user
const {lists, canPublish} = user
const activeTab = synced("views/Feeds/activeTab", "Follows")
let relays, filter, tabs
@ -79,32 +80,42 @@
{/if}
<div>
<Tabs {tabs} activeTab={$activeTab} {setActiveTab}>
{#if $lists.length > 1}
<Popover placement="bottom" opts={{hideOnClick: true}} theme="transparent">
<i slot="trigger" class="fa fa-ellipsis-v cursor-pointer p-2" />
<div
slot="tooltip"
class="flex flex-col items-start rounded border border-solid border-gray-8 bg-black">
{#each $lists as e (e.id)}
{@const meta = Tags.from(e).asMeta()}
{#if meta.d !== $activeTab}
<button
class="w-full py-2 px-3 text-left hover:bg-gray-7"
on:click={() => {
$activeTab = meta.d
}}>
<i class="fa fa-scroll fa-sm mr-1" />
{meta.d}
</button>
{/if}
{/each}
<button on:click={showLists} class="w-full py-2 px-3 text-left hover:bg-gray-7">
<i class="fa fa-cog fa-sm mr-1" /> Customize
</button>
</div>
</Popover>
{:else}
<i class="fa fa-ellipsis-v cursor-pointer p-1" on:click={showLists} />
{#if $canPublish}
{#if $lists.length > 1}
<Popover placement="bottom" opts={{hideOnClick: true}} theme="transparent">
<i slot="trigger" class="fa fa-ellipsis-v cursor-pointer p-2" />
<div
slot="tooltip"
class="flex flex-col items-start overflow-hidden rounded border border-solid border-gray-8 bg-black">
{#each $lists as e (e.id)}
{@const meta = Tags.from(e).asMeta()}
{#if meta.d !== $activeTab}
<button
class={cx("w-full py-2 px-3 text-left transition-colors", {
"hover:bg-gray-7": $theme === "dark",
"hover:bg-gray-1": $theme === "light",
})}
on:click={() => {
$activeTab = meta.d
}}>
<i class="fa fa-scroll fa-sm mr-1" />
{meta.d}
</button>
{/if}
{/each}
<button
on:click={showLists}
class={cx("w-full py-2 px-3 text-left transition-colors", {
"hover:bg-gray-7": $theme === "dark",
"hover:bg-gray-1": $theme === "light",
})}>
<i class="fa fa-cog fa-sm mr-1" /> Customize
</button>
</div>
</Popover>
{:else}
<i class="fa fa-ellipsis-v cursor-pointer p-1" on:click={showLists} />
{/if}
{/if}
</Tabs>
{#key $activeTab}

View File

@ -3,5 +3,5 @@
import {navigate} from "svelte-routing"
import user from "src/agent/user"
onMount(() => navigate(user.getProfile() ? "/notes" : "/login"))
onMount(() => navigate(user.getPubkey() ? "/notes" : "/login"))
</script>

View File

@ -1,5 +1,7 @@
<script>
import cx from "classnames"
import {omit} from "ramda"
import {navigate} from "svelte-routing"
import {switcher} from "hurdak/lib/hurdak"
import {createEventDispatcher} from "svelte"
@ -35,10 +37,19 @@
e.stopPropagation()
}
if (href && !external) {
navigate(href)
}
dispatch("click", e)
}
</script>
<a on:click={onClick} {...$$props} {href} class={className} target={external ? "_blank" : null}>
<a
on:click={onClick}
{...omit(["href"], $$props)}
href={external ? $$props.href : null}
class={className}
target={external ? "_blank" : null}>
<slot />
</a>

View File

@ -9,7 +9,7 @@
class={cx(
$$props.class,
`overflow-hidden w-${size} h-${size} inline-block shrink-0 rounded-full border border-solid
border-white bg-cover bg-center`
border-gray-1 bg-cover bg-center`
)}
style="background-image: url({src}); {$$props.style || ''}">
<slot />

View File

@ -24,7 +24,7 @@
}} />
<div class="modal fixed inset-0 z-30" bind:this={root} transition:fade>
<div class="fixed inset-0 cursor-pointer bg-black opacity-75" on:click={onEscape} />
<div class="fixed inset-0 cursor-pointer bg-black opacity-50" on:click={onEscape} />
<div
class="modal-content h-full overflow-auto"
bind:this={content}

View File

@ -26,11 +26,10 @@
class="relative flex flex-col gap-2"
on:click={() => instance.hide()}>
<div
class="absolute top-0 right-0 bottom-0 w-32 rounded-full bg-gray-8"
class="absolute top-0 right-0 bottom-0 w-32 rounded-3xl bg-gray-8"
style="filter: blur(15px) opacity(0.75)" />
{#each actions as { label, icon, onClick }}
<div class="relative z-10 cursor-pointer" on:click={onClick}>
<div class="relative z-10 cursor-pointer text-gray-3" on:click={onClick}>
<span class="absolute right-0 mr-12 mt-2 whitespace-nowrap">{label}</span>
<Anchor type="button-circle"><i class={`fa fa-${icon}`} /></Anchor>
</div>

View File

@ -48,7 +48,7 @@ export const openModals = writable(0)
export const modal = {
stack: new WritableList([]) as WritableList<any>,
sync: ($stack, opts) => {
sync: ($stack, opts = null) => {
const hash = $stack.length > 0 ? `#m=${$stack.length}` : ""
navigate(window.location.pathname + hash, opts)

View File

@ -92,14 +92,6 @@ export const killEvent = e => {
e.stopImmediatePropagation()
}
export const noEvent = f => e => {
e.preventDefault()
e.stopPropagation()
e.stopImmediatePropagation()
f()
}
export const isMobile = localStorage.mobile || window.navigator.maxTouchPoints > 1
export const parseHex = hex => {