mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-29 00:10:52 +00:00
Use new wot score indicator, revert to one-off style, show loading when searching profiles
This commit is contained in:
parent
6fd36ccecc
commit
dde8e47f34
@ -8,6 +8,8 @@
|
||||
- [x] Add zap splits
|
||||
- [x] Add default platform split amount
|
||||
- [x] Add invite link generation
|
||||
- [x] Use new web of trust display
|
||||
- [x] Show loading when searching profiles
|
||||
|
||||
# 0.4.2
|
||||
|
||||
|
@ -55,7 +55,7 @@
|
||||
external
|
||||
href="https://info.coracle.social">
|
||||
<img alt="App Logo" src={import.meta.env.VITE_LOGO_URL || "/images/logo.png"} class="w-12" />
|
||||
<h1 class="staatliches text-4xl leading-none">{appName}</h1>
|
||||
<h1 class="staatliches text-[2.6em] leading-none -mb-[0.1em]">{appName}</h1>
|
||||
</Anchor>
|
||||
<MenuDesktopItem path="/notes">Feed</MenuDesktopItem>
|
||||
{#if !$env.FORCE_GROUP && $env.FORCE_RELAYS.length === 0}
|
||||
|
@ -65,7 +65,7 @@
|
||||
{#if $searchTerm}
|
||||
<div
|
||||
class="absolute right-0 top-10 max-h-[70vh] w-96 overflow-auto rounded bg-cocoa shadow-2xl">
|
||||
<SearchResults term={searchTerm}>
|
||||
<SearchResults showLoading term={searchTerm}>
|
||||
<div slot="result" let:result class="px-4 py-2 transition-colors hover:bg-dark">
|
||||
{#if result.type === "topic"}
|
||||
#{result.topic.name}
|
||||
|
@ -1,19 +1,19 @@
|
||||
<script lang="ts">
|
||||
import {nip19} from "nostr-tools"
|
||||
import {debounce, throttle} from "throttle-debounce"
|
||||
import {throttle} from "throttle-debounce"
|
||||
import {createEventDispatcher} from "svelte"
|
||||
import {last, partition, whereEq} from "ramda"
|
||||
import PersonBadge from "src/app/shared/PersonBadge.svelte"
|
||||
import ContentEditable from "src/partials/ContentEditable.svelte"
|
||||
import Suggestions from "src/partials/Suggestions.svelte"
|
||||
import {
|
||||
load,
|
||||
follows,
|
||||
derivePerson,
|
||||
displayPerson,
|
||||
searchableRelays,
|
||||
getPubkeyHints,
|
||||
searchPeople,
|
||||
createPeopleLoader,
|
||||
} from "src/engine"
|
||||
|
||||
export let onSubmit
|
||||
@ -24,6 +24,11 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const {loading: loadingPeople, load: loadPeople} = createPeopleLoader({
|
||||
shouldLoad: (term: string) => term.startsWith("@"),
|
||||
onEvent: () => applySearch(getInfo().word),
|
||||
})
|
||||
|
||||
const pubkeyEncoder = {
|
||||
encode: pubkey => {
|
||||
const relays = getPubkeyHints.limit(3).getHints(pubkey, "write")
|
||||
@ -37,16 +42,6 @@
|
||||
},
|
||||
}
|
||||
|
||||
const loadPeople = debounce(500, search => {
|
||||
if (search.length > 2 && search.startsWith("@")) {
|
||||
load({
|
||||
relays: $searchableRelays,
|
||||
filters: [{kinds: [0], search, limit: 10}],
|
||||
onEvent: () => applySearch(getInfo().word),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const applySearch = throttle(300, word => {
|
||||
let results = []
|
||||
if (word.length > 1 && word.startsWith("@")) {
|
||||
@ -273,7 +268,10 @@
|
||||
<slot name="addon" />
|
||||
</div>
|
||||
|
||||
<Suggestions bind:this={suggestions} select={person => autocomplete({person})}>
|
||||
<Suggestions
|
||||
bind:this={suggestions}
|
||||
select={person => autocomplete({person})}
|
||||
loading={$loadingPeople}>
|
||||
<div slot="item" let:item>
|
||||
<PersonBadge inert pubkey={item.pubkey} />
|
||||
</div>
|
||||
|
@ -14,7 +14,6 @@
|
||||
deriveAdminKeyForGroup,
|
||||
publishGroupExitRequest,
|
||||
publishGroupEntryRequest,
|
||||
deriveGroup,
|
||||
deriveGroupStatus,
|
||||
resetGroupAccess,
|
||||
} from "src/engine"
|
||||
|
@ -254,7 +254,7 @@
|
||||
</div>
|
||||
<div class="flex min-w-0 flex-grow flex-col gap-2">
|
||||
<div class="flex min-w-0 flex-col items-start justify-between sm:flex-row">
|
||||
<Anchor type="unstyled" class="mr-4 min-w-0 text-lg font-bold" on:click={showPerson}>
|
||||
<Anchor type="unstyled" class="mr-4 min-w-0" on:click={showPerson}>
|
||||
<PersonName pubkey={event.pubkey} />
|
||||
</Anchor>
|
||||
<Anchor
|
||||
|
@ -1,29 +1,76 @@
|
||||
<style>
|
||||
.wot-background {
|
||||
fill: transparent;
|
||||
stroke: var(--mid);
|
||||
}
|
||||
|
||||
.wot-highlight {
|
||||
fill: transparent;
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 100 100;
|
||||
transform-origin: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script context="module">
|
||||
import {writable} from "src/engine"
|
||||
|
||||
const maxWot = writable(10)
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import cx from "classnames"
|
||||
import {themeColors} from "src/partials/state"
|
||||
import Popover from "src/partials/Popover.svelte"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import {deriveFollowing, derivePerson, displayPerson, session, getWotScore} from "src/engine"
|
||||
import {
|
||||
deriveFollowing,
|
||||
derivePerson,
|
||||
displayPerson,
|
||||
displayNpub,
|
||||
session,
|
||||
getWotScore,
|
||||
} from "src/engine"
|
||||
|
||||
export let pubkey
|
||||
|
||||
const person = derivePerson(pubkey)
|
||||
const following = deriveFollowing(pubkey)
|
||||
const wotScore = getWotScore($session?.pubkey, pubkey)
|
||||
const npubDisplay = displayNpub(pubkey)
|
||||
|
||||
maxWot.update(x => Math.max(x, wotScore + 10))
|
||||
|
||||
$: dashOffset = 100 - (Math.max(0, wotScore) / $maxWot) * 100
|
||||
$: style = `transform: rotate(${dashOffset * 1.8 - 4}deg)`
|
||||
$: stroke = $themeColors[$following || pubkey === $session?.pubkey ? "accent" : "white"]
|
||||
$: personDisplay = displayPerson($person)
|
||||
</script>
|
||||
|
||||
<div class={cx("flex gap-1", $$props.class)}>
|
||||
<span class="cy-person-name overflow-hidden text-ellipsis">
|
||||
{displayPerson($person)}
|
||||
</span>
|
||||
<div class="flex flex-col overflow-hidden text-ellipsis">
|
||||
<span class="cy-person-name">{personDisplay}</span>
|
||||
{#if personDisplay != npubDisplay}
|
||||
<small class="text-xs">{npubDisplay}</small>
|
||||
{/if}
|
||||
</div>
|
||||
{#if $session}
|
||||
<div class="flex gap-1 font-normal">
|
||||
<Popover triggerType="mouseenter">
|
||||
<span slot="trigger" class="whitespace-nowrap px-2 py-1 text-xs">
|
||||
{#if $following}
|
||||
<i class="fa fa-check-circle text-accent" />
|
||||
{:else}
|
||||
<i class="fa fa-diagram-project text-accent" />
|
||||
{/if}
|
||||
<span
|
||||
slot="trigger"
|
||||
class="relative flex h-10 w-10 items-center justify-center whitespace-nowrap px-4 text-xs">
|
||||
<svg height="32" width="32" class="absolute">
|
||||
<circle class="wot-background" cx="16" cy="16" r="15" />
|
||||
<circle
|
||||
cx="16"
|
||||
cy="16"
|
||||
r="15"
|
||||
class="wot-highlight"
|
||||
stroke-dashoffset={dashOffset}
|
||||
{style}
|
||||
{stroke} />
|
||||
</svg>
|
||||
{wotScore}
|
||||
</span>
|
||||
<Anchor modal slot="tooltip" class="flex items-center gap-1" href="/help/web-of-trust">
|
||||
|
@ -1,13 +1,15 @@
|
||||
<script lang="ts">
|
||||
import {throttle} from "throttle-debounce"
|
||||
import {slide} from "src/util/transition"
|
||||
import {fuzzy} from "src/util/misc"
|
||||
import {parseAnything} from "src/util/nostr"
|
||||
import {router} from "src/app/router"
|
||||
import type {Person, Topic} from "src/engine"
|
||||
import {topics, derived, searchPeople, loadPeople} from "src/engine"
|
||||
import {topics, derived, searchPeople, createPeopleLoader} from "src/engine"
|
||||
|
||||
export let term
|
||||
export let replace = false
|
||||
export let showLoading = false
|
||||
|
||||
const openTopic = topic => router.at("topics").of(topic).open({replace})
|
||||
|
||||
@ -39,6 +41,8 @@
|
||||
},
|
||||
)
|
||||
|
||||
const {loading: loadingPeople, load: loadPeople} = createPeopleLoader()
|
||||
|
||||
const searchTopics = topics
|
||||
.throttle(1000)
|
||||
.derived($topics => fuzzy($topics, {keys: ["name"], threshold: 0.5, shouldSort: true}))
|
||||
@ -72,3 +76,11 @@
|
||||
{:else}
|
||||
<p class="text-center py-12">No results found.</p>
|
||||
{/each}
|
||||
{#if showLoading && $loadingPeople}
|
||||
<div transition:slide|local class="flex gap-2 bg-cocoa px-4 py-2 text-lighter absolute bottom-0 left-0 right-0">
|
||||
<div>
|
||||
<i class="fa fa-circle-notch fa-spin" />
|
||||
</div>
|
||||
Loading more options...
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -11,7 +11,15 @@
|
||||
import PersonSummary from "src/app/shared/PersonSummary.svelte"
|
||||
import RelayCard from "src/app/shared/RelayCard.svelte"
|
||||
import type {Relay} from "src/engine"
|
||||
import {env, lists, urlToRelay, mention, loadPeople, searchPeople, searchRelays} from "src/engine"
|
||||
import {
|
||||
env,
|
||||
lists,
|
||||
urlToRelay,
|
||||
mention,
|
||||
createPeopleLoader,
|
||||
searchPeople,
|
||||
searchRelays,
|
||||
} from "src/engine"
|
||||
|
||||
export let relays
|
||||
export let petnames
|
||||
@ -24,6 +32,8 @@
|
||||
let showPersonSearch
|
||||
let showRelaySearch
|
||||
|
||||
const {load: loadPeople} = createPeopleLoader()
|
||||
|
||||
const prev = () => setStage("profile")
|
||||
const next = () => setStage("note")
|
||||
|
||||
@ -138,8 +148,7 @@
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Anchor button on:click={prev}><i class="fa fa-arrow-left" /> Back</Anchor>
|
||||
<Anchor button accent class="flex-grow" on:click={() => next()}
|
||||
>Continue</Anchor>
|
||||
<Anchor button accent class="flex-grow" on:click={() => next()}>Continue</Anchor>
|
||||
</div>
|
||||
|
||||
{#if showList}
|
||||
|
@ -78,17 +78,19 @@
|
||||
<i slot="before" class="fa fa-search" />
|
||||
<i slot="after" class="fa fa-qrcode cursor-pointer" on:click={startScanner} />
|
||||
</Input>
|
||||
<SearchResults replace term={searchTerm}>
|
||||
<div slot="result" let:result>
|
||||
{#if result.type === "topic"}
|
||||
<Card interactive>
|
||||
#{result.topic.name}
|
||||
</Card>
|
||||
{:else if result.type === "profile"}
|
||||
<Card interactive>
|
||||
<PersonSummary inert hideActions pubkey={result.id} />
|
||||
</Card>
|
||||
{/if}
|
||||
</div>
|
||||
</SearchResults>
|
||||
<div class="relative max-h-full">
|
||||
<SearchResults replace term={searchTerm}>
|
||||
<div slot="result" let:result>
|
||||
{#if result.type === "topic"}
|
||||
<Card interactive>
|
||||
#{result.topic.name}
|
||||
</Card>
|
||||
{:else if result.type === "profile"}
|
||||
<Card interactive>
|
||||
<PersonSummary inert hideActions pubkey={result.id} />
|
||||
</Card>
|
||||
{/if}
|
||||
</div>
|
||||
</SearchResults>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -1,13 +1,41 @@
|
||||
import {debounce} from "throttle-debounce"
|
||||
import {always} from "ramda"
|
||||
import {noop, sleep} from "hurdak"
|
||||
import {writable} from "src/engine/core/utils"
|
||||
import {load} from "src/engine/network/utils"
|
||||
import {searchableRelays} from "src/engine/relays/derived"
|
||||
import type {Event} from "src/engine/events/model"
|
||||
|
||||
export const loadPeople = debounce(500, search => {
|
||||
// Only search if we have a query
|
||||
if (search.length > 2) {
|
||||
load({
|
||||
relays: searchableRelays.get(),
|
||||
filters: [{kinds: [0], search, limit: 100}],
|
||||
})
|
||||
type PeopleLoaderOpts = {
|
||||
shouldLoad?: (term: string) => boolean
|
||||
onEvent?: (e: Event) => void
|
||||
}
|
||||
|
||||
export const createPeopleLoader = ({
|
||||
shouldLoad = always(true),
|
||||
onEvent = noop,
|
||||
}: PeopleLoaderOpts = {}) => {
|
||||
const loading = writable(false)
|
||||
|
||||
return {
|
||||
loading,
|
||||
load: debounce(500, term => {
|
||||
if (term.length > 2 && shouldLoad(term)) {
|
||||
const now = Date.now()
|
||||
|
||||
loading.set(true)
|
||||
|
||||
load({
|
||||
onEvent,
|
||||
relays: searchableRelays.get(),
|
||||
filters: [{kinds: [0], search: term, limit: 100}],
|
||||
onClose: async () => {
|
||||
await sleep(Math.min(1000, Date.now() - now))
|
||||
|
||||
loading.set(false)
|
||||
},
|
||||
})
|
||||
}
|
||||
}),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -34,6 +34,12 @@ export const personHasName = ({profile: p}: Person) => Boolean(p?.name || p?.dis
|
||||
|
||||
export const getPersonWithDefault = pubkey => ({pubkey, ...people.key(pubkey).get()})
|
||||
|
||||
export const displayNpub = pubkey => {
|
||||
const d = nip19.npubEncode(pubkey)
|
||||
|
||||
return d.slice(0, 8) + "..." + d.slice(-5)
|
||||
}
|
||||
|
||||
export const displayPerson = ({pubkey, profile}: Person) => {
|
||||
if (profile) {
|
||||
const {display_name, name} = profile
|
||||
@ -48,7 +54,7 @@ export const displayPerson = ({pubkey, profile}: Person) => {
|
||||
}
|
||||
|
||||
try {
|
||||
return nip19.npubEncode(pubkey).slice(-8)
|
||||
return displayNpub(pubkey)
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import {whereEq, when, reject, uniqBy, prop, inc} from "ramda"
|
||||
import {now, normalizeRelayUrl, isShareableRelay} from "paravel"
|
||||
import {now, normalizeRelayUrl, isShareableRelay, createEvent} from "paravel"
|
||||
import {people} from "src/engine/people/state"
|
||||
import {canSign, stateKey} from "src/engine/session/derived"
|
||||
import {canSign, signer, stateKey} from "src/engine/session/derived"
|
||||
import {updateStore} from "src/engine/core/commands"
|
||||
import {pool} from "src/engine/network/state"
|
||||
import {createAndPublish, getClientTags} from "src/engine/network/utils"
|
||||
import {createAndPublish, getClientTags, Publisher} from "src/engine/network/utils"
|
||||
import type {RelayPolicy} from "./model"
|
||||
import {relays} from "./state"
|
||||
import {relayPolicies} from "./derived"
|
||||
@ -58,16 +57,16 @@ export const publishRelays = ($relays: RelayPolicy[]) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const joinRelay = (url: string, claim?: string) => {
|
||||
export const joinRelay = async (url: string, claim?: string) => {
|
||||
// Fire off the claim to join the relay
|
||||
if (claim) {
|
||||
Publisher.publish({
|
||||
relays: [url],
|
||||
event: createEvent(28934, {
|
||||
"tags": [
|
||||
["claim", claim],
|
||||
],
|
||||
})
|
||||
event: await signer.get().signAsUser(
|
||||
createEvent(28934, {
|
||||
tags: [["claim", claim]],
|
||||
})
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,11 @@
|
||||
className = cx({
|
||||
"border-r-4 border-transparent": border,
|
||||
"cursor-pointer transition-colors": interactive,
|
||||
"hover:border-cocoa": border && interactive && isAlt,
|
||||
"hover:border-dark-l": border && interactive && !isAlt,
|
||||
"hover:border-accent": border && interactive,
|
||||
"bg-cocoa": isAlt,
|
||||
"hover:bg-cocoa-d": isAlt && interactive,
|
||||
// "hover:bg-cocoa-d": isAlt && interactive && !border,
|
||||
"bg-dark": !isAlt,
|
||||
"hover:bg-dark-d": !isAlt && interactive,
|
||||
// "hover:bg-dark-d": !isAlt && interactive && !border,
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
@ -44,7 +44,7 @@
|
||||
<AlternatingBackground
|
||||
border
|
||||
{interactive}
|
||||
class={cx($$props.class, "rounded p-3 text-lightest")}>
|
||||
class={cx($$props.class, "rounded py-5 px-7 text-lightest")}>
|
||||
<slot />
|
||||
</AlternatingBackground>
|
||||
</div>
|
||||
|
@ -18,6 +18,7 @@
|
||||
export let displayItem = getKey
|
||||
export let autofocus = false
|
||||
export let multiple = false
|
||||
export let loading = false
|
||||
export let defaultOptions = []
|
||||
export let term = multiple ? "" : displayItem(value)
|
||||
|
||||
@ -134,6 +135,7 @@
|
||||
<Suggestions
|
||||
bind:this={suggestions}
|
||||
create={termToItem ? create : null}
|
||||
{loading}
|
||||
{select}
|
||||
{term}
|
||||
{getKey}>
|
||||
|
@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import {identity} from "ramda"
|
||||
import {slide} from "src/util/transition"
|
||||
|
||||
export let select
|
||||
export let term = null
|
||||
export let create = null
|
||||
export let loading = false
|
||||
export let getKey = identity
|
||||
|
||||
let data = []
|
||||
@ -37,7 +39,7 @@
|
||||
|
||||
{#if data.length > 0 || (create && term)}
|
||||
<div
|
||||
class="mt-2 flex max-h-[350px] flex-col overflow-y-auto overflow-x-hidden rounded border border-solid border-mid">
|
||||
class="mt-2 flex max-h-[350px] flex-col overflow-y-auto overflow-x-hidden border border-solid border-mid">
|
||||
{#if create && term}
|
||||
{@const i = data.length}
|
||||
<button
|
||||
@ -65,3 +67,11 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if loading}
|
||||
<div transition:slide|local class="flex gap-2 bg-cocoa px-4 py-2 text-lighter">
|
||||
<div>
|
||||
<i class="fa fa-circle-notch fa-spin" />
|
||||
</div>
|
||||
Loading more options...
|
||||
</div>
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user