mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-18 19:23:40 +00:00
Add relay reviews
This commit is contained in:
parent
a83a5d25be
commit
dd07b0480a
@ -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
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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"}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
48
src/app/views/RelayReview.svelte
Normal file
48
src/app/views/RelayReview.svelte
Normal 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>
|
16
src/partials/Rating.svelte
Normal file
16
src/partials/Rating.svelte
Normal 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>
|
8
src/partials/Subheading.svelte
Normal file
8
src/partials/Subheading.svelte
Normal 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>
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user