Add relay reviews

This commit is contained in:
Jonathan Staab 2023-06-08 18:03:57 -07:00
parent a83a5d25be
commit dd07b0480a
12 changed files with 155 additions and 51 deletions

View File

@ -4,9 +4,8 @@
- [ ] Use vida to stream development
- [ ] Fix connection management stuff. Have GPT help
- [ ] Relay reviews
- New kind, d as url? Combine with labeling?
- Show reviews in relay detail rather than events. Warn about events tab
- Add curated relay list, and an easy way to view content on the relays
- Deploy ontology.coracle.social
- [ ] Add preview proxy thing
- [ ] White-labeled
- [ ] Add invite code registration for relay
@ -71,6 +70,10 @@
- [ ] NIP 39 Support https://github.com/nostr-protocol/nips/pull/201/files
- [ ] Integrate plephy https://plebhy.com/
- [ ] Add support for website kind0
- [ ] Schedule notes for x seconds in the future with a queue
- In the queue, add send now and cancel buttons
- maybe put all user events here too - keep track of what relays they were published to
- Add un-delete using event log
# UI/Features

View File

@ -84,6 +84,8 @@ const requestZap = (relays, content, pubkey, eventId, amount, lnurl) => {
const deleteEvent = ids => new PublishableEvent(5, {tags: ids.map(id => ["e", id])})
const createLabel = payload => new PublishableEvent(1985, payload)
// Utils
const tagsFromContent = (content, tags) => {
@ -158,7 +160,6 @@ class PublishableEvent {
}
async publish(relays, onProgress = null, verb = "EVENT") {
const event = await this.getSignedEvent()
// console.log(event); return
const promise = pool.publish({relays, event, onProgress, verb})
// Copy the event since loki mutates it to add metadata
@ -186,5 +187,6 @@ export default {
createReply,
requestZap,
deleteEvent,
createLabel,
PublishableEvent,
}

View File

@ -21,6 +21,7 @@
import ListEdit from "src/app/views/ListEdit.svelte"
import RelayAdd from "src/app/views/RelayAdd.svelte"
import RelayDetail from "src/app/views/RelayDetail.svelte"
import RelayReview from "src/app/views/RelayReview.svelte"
export let m
</script>
@ -41,6 +42,8 @@
<RelayAdd url={m.url} />
{:else if m.type === "relay/detail"}
<RelayDetail url={m.url} />
{:else if m.type === "relay/review"}
<RelayReview url={m.url} />
{:else if m.type === "onboarding"}
<Onboarding stage={m.stage} />
{:else if m.type === "room/edit"}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import {onMount} from "svelte"
import {last, partition, always, propEq, uniqBy, sortBy, prop} from "ramda"
import {last, partition, always, uniqBy, sortBy, prop} from "ramda"
import {fly} from "svelte/transition"
import {quantify} from "hurdak/lib/hurdak"
import {createScroller, now, timedelta} from "src/util/misc"
@ -12,10 +12,11 @@
import Note from "src/app/shared/Note.svelte"
import user from "src/agent/user"
import network from "src/agent/network"
import {getUserReadRelays} from "src/agent/relays"
import {mergeParents} from "src/app/state"
export let filter
export let relays = []
export let relays = getUserReadRelays()
export let delta = timedelta(6, "hours")
export let shouldDisplay = always(true)
export let parentsTimeout = 500
@ -26,12 +27,12 @@
let feedRelay = null
let feedScroller = null
// Add a short buffer so we can get the most possible results for recent notes
const since = now()
const maxNotes = 100
const seen = new Set()
const cursor = new network.Cursor({relays, delta})
const getModal = () => last(document.querySelectorAll(".modal-content"))
const canDisplay = e => [1, 1985].includes(e.kind)
const setFeedRelay = relay => {
feedRelay = relay
@ -71,13 +72,13 @@
// Combine notes and parents into a single collection
const combined = uniqBy(
prop("id"),
filtered.filter(propEq("kind", 1)).concat(parents).map(asDisplayEvent)
filtered.filter(canDisplay).concat(parents).map(asDisplayEvent)
)
// Stream in additional data and merge it in
network.streamContext({
maxDepth: 2,
notes: combined.filter(propEq("kind", 1)),
notes: combined.filter(canDisplay),
onChunk: context => {
context = user.applyMutes(context)
@ -129,7 +130,7 @@
})
</script>
<Content size="inherit" class="pt-6">
<Content size="inherit">
{#if notesBuffer.length > 0}
<div class="pointer-events-none fixed left-0 top-0 z-10 mt-20 flex w-full justify-center">
<button

View File

@ -1,5 +1,6 @@
<script lang="ts">
import {find, last, propEq} from "ramda"
import {modal} from "src/partials/state"
import OverflowMenu from "src/partials/OverflowMenu.svelte"
import user from "src/agent/user"
import {getRelayWithFallback} from "src/agent/db"
@ -37,6 +38,12 @@
label: "Add to list",
icon: "scroll",
})
actions.push({
onClick: () => modal.push({type: "relay/review", url: relay.url}),
label: "Review",
icon: "feather",
})
}
if (relay.contact) {

View File

@ -20,9 +20,10 @@
["https://nostr.watch", "Nostr Watch", "A directory of nostr relays."],
["https://nostr.directory", "Nostr Directory", "Validate your nostr pubkey with Twitter."],
["https://getalby.com", "Alby", "Sign in to nostr apps without sharing your private key."],
["https://nak.nostr.com", "NAK", "A Nostr Army Knife, for advanced users."],
["https://nostrplebs.com", "NostrPlebs", "Get verified at nostrplebs.com."],
["https://nadar.tigerville.no", "Nadar", "Find out what relays know about your post."],
["https://pinstr.app", "Pinstr", "Create and manage collections of notes."],
["https://advancednostrsearch.vercel.app", "Advanced Search", "Find what you're looking for."],
]
document.title = "Apps"

View File

@ -69,46 +69,44 @@
</p>
</Content>
{/if}
<div>
<Tabs tabs={visibleTabs} activeTab={$feedsTab} {setActiveTab}>
{#if $canPublish}
{#if $lists.length > 0}
<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()}
<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={() => {
$feedsTab = meta.d
}}>
<i class="fa fa-scroll fa-sm mr-1" />
{meta.d}
</button>
{/each}
<Tabs tabs={visibleTabs} activeTab={$feedsTab} {setActiveTab}>
{#if $canPublish}
{#if $lists.length > 0}
<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()}
<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
})}
on:click={() => {
$feedsTab = meta.d
}}>
<i class="fa fa-scroll fa-sm mr-1" />
{meta.d}
</button>
</div>
</Popover>
{:else}
<i class="fa fa-ellipsis-v cursor-pointer p-1" on:click={showLists} />
{/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}
</Tabs>
{#key $feedsTab}
<Feed {relays} {filter} />
{/key}
</div>
{/if}
</Tabs>
{#key $feedsTab}
<Feed {relays} {filter} />
{/key}
</Content>

View File

@ -2,15 +2,22 @@
import {displayRelay, normalizeRelayUrl} from "src/util/nostr"
import Content from "src/partials/Content.svelte"
import Feed from "src/app/shared/Feed.svelte"
import Tabs from "src/partials/Tabs.svelte"
import RelayTitle from "src/app/shared/RelayTitle.svelte"
import RelayActions from "src/app/shared/RelayActions.svelte"
import {relays} from "src/agent/db"
export let url
let activeTab = "reviews"
url = normalizeRelayUrl(url)
const relay = relays.get(url) || {url}
const tabs = ["reviews", "notes"]
const setActiveTab = tab => {
activeTab = tab
}
document.title = displayRelay(relay)
</script>
@ -23,8 +30,17 @@
{#if relay.description}
<p>{relay.description}</p>
{/if}
</Content>
<div class="border-b border-solid border-gray-6" />
<Content>
<Feed relays={[relay]} filter={{kinds: [1]}} />
<Tabs borderClass="border-gray-6" {tabs} {activeTab} {setActiveTab} />
{#if activeTab === "reviews"}
<Feed
invertColors
filter={{
kinds: [1985],
"#l": ["review"],
"#L": ["social.coracle.ontology"],
"#r": [relay.url],
}} />
{:else}
<Feed invertColors relays={[relay]} filter={{kinds: [1]}} />
{/if}
</Content>

View File

@ -0,0 +1,48 @@
<script lang="ts">
import {fly} from "svelte/transition"
import {modal} from "src/partials/state"
import Button from "src/partials/Button.svelte"
import Content from "src/partials/Content.svelte"
import Heading from "src/partials/Heading.svelte"
import Textarea from "src/partials/Textarea.svelte"
import Rating from "src/partials/Rating.svelte"
import user from "src/agent/user"
import cmd from "src/agent/cmd"
export let url
let review
let rating
const onSubmit = () => {
cmd
.createLabel({
content: review,
tagClient: false,
tags: [
["L", "social.coracle.ontology"],
["l", "review", "social.coracle.ontology"],
["r", url],
],
})
.publish(user.getRelays())
modal.pop()
}
</script>
<form on:submit|preventDefault={onSubmit} in:fly={{y: 20}}>
<Content size="lg">
<Heading class="text-center">Leave a review</Heading>
<div class="flex w-full flex-col gap-4">
<div class="flex flex-col gap-1">
<div class="flex items-center justify-between gap-2">
<strong>Your rating:</strong>
<Rating bind:value={rating} />
</div>
</div>
<Textarea bind:value={review} placeholder="Share your thoughts..." />
<Button type="submit" class="flex-grow text-center">Send</Button>
</div>
</Content>
</form>

View File

@ -0,0 +1,16 @@
<script lang="ts">
import {range} from "hurdak/lib/hurdak"
export let value = 1
</script>
<div class="flex gap-1">
{#each range(0, 5) as x}
<i
class="fa fa-star cursor-pointer text-gray-5 hover:text-warning hover:opacity-75"
class:text-warning={value >= x / 5}
on:click={() => {
value = x / 5
}} />
{/each}
</div>

View File

@ -0,0 +1,8 @@
<script>
export let icon
</script>
<div class="flex items-center gap-2">
<i class={`fa {icon} fa-lg`} />
<h2 class="staatliches text-2xl"><slot /></h2>
</div>

View File

@ -6,10 +6,11 @@
export let activeTab
export let setActiveTab
export let getDisplay = tab => ({title: toTitle(tab), badge: null})
export let borderClass = "border-gray-7"
</script>
<div
class="flex items-center justify-between overflow-auto border-b border-solid border-gray-7 pt-2"
class={`flex items-center justify-between overflow-auto border-b border-solid pt-2 ${borderClass}`}
in:fly={{y: 20}}>
<div class="flex">
{#each tabs as tab}