mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-29 08:21:20 +00:00
remove profile popover and add mute button to profile feed
This commit is contained in:
parent
2a0780e55b
commit
fd29fb82f9
@ -13,6 +13,7 @@
|
||||
- [x] Emphasize follow status instead of nip05 addresses
|
||||
- [x] Add image uploads to chat
|
||||
- [x] Add new thread view
|
||||
- [x] Removed profile popover, click on a person's name to find mute and follow buttons
|
||||
|
||||
# 0.2.35
|
||||
|
||||
|
@ -1,9 +1,7 @@
|
||||
# Current
|
||||
|
||||
- [ ] Refactor
|
||||
- [ ] Add thread view
|
||||
- [ ] Use image and fetch proxies for user-provided content (especially profile data: nip05, picture, banner) to avoid security warnings
|
||||
- [ ] Remove profile popover
|
||||
- [ ] Re-work note media
|
||||
- [ ] Add webcam image/video capture
|
||||
- [ ] Show list of media that can be viewed/removed below post
|
||||
@ -12,7 +10,6 @@
|
||||
- [ ] Support bigger files, or at least handle errors. Monetize, or use nip 95
|
||||
- [ ] Fork and white label blowater
|
||||
- [ ] Add word/char count to compose
|
||||
- [ ] Show full nip05 unless it starts with an underscore, change icon to non-verified
|
||||
- [ ] Add relayset support with kind 30022
|
||||
- [ ] White-labeled
|
||||
- [ ] Add invite code registration for relay
|
||||
@ -26,12 +23,6 @@
|
||||
- [ ] Add imgproxy https://github.com/imgproxy/imgproxy
|
||||
- Protects metadata, saves bandwidth, fixes void.cat?
|
||||
- [ ] Put search icon in header or hover button, open in modal
|
||||
- [ ] Centralize relays
|
||||
- This is ok, relays are the source of decentralization
|
||||
- clients can help with discoverability
|
||||
- Add agent to dufflepud database that scrapes relays and reviews
|
||||
- Serve relays from dufflepud
|
||||
- Or maybe set up a special purpose relay for relay recs?
|
||||
|
||||
# Core
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
import Popover from "src/partials/Popover.svelte"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import PersonCircle from "src/app/shared/PersonCircle.svelte"
|
||||
import PersonSummary from "src/app/shared/PersonSummary.svelte"
|
||||
import PersonName from "src/app/shared/PersonName.svelte"
|
||||
import NoteReply from "src/app/shared/NoteReply.svelte"
|
||||
import NoteActions from "src/app/shared/NoteActions.svelte"
|
||||
import Card from "src/partials/Card.svelte"
|
||||
@ -37,7 +37,6 @@
|
||||
const interactive = !anchorId || !showEntire
|
||||
const author = Directory.profiles.key(note.pubkey).derived(defaultTo({pubkey: note.pubkey}))
|
||||
const muted = Nip02.graph.key(Keys.pubkey.get()).derived(() => user.isIgnoring(note.id))
|
||||
const following = user.followsSet.derived(s => s.has(note.pubkey))
|
||||
|
||||
let border, childrenContainer, noteContainer
|
||||
|
||||
@ -119,22 +118,12 @@
|
||||
</div>
|
||||
<div class="flex min-w-0 flex-grow flex-col gap-2">
|
||||
<div class="flex flex-col items-start justify-between sm:flex-row sm:items-center">
|
||||
<Popover triggerType="mouseenter">
|
||||
<div slot="trigger">
|
||||
<Anchor
|
||||
type="unstyled"
|
||||
class="flex items-center gap-2 pr-16 text-lg font-bold"
|
||||
on:click={() => modal.push({type: "person/feed", pubkey: note.pubkey})}>
|
||||
<span>{Directory.displayProfile($author)}</span>
|
||||
{#if $following}
|
||||
<i class="fa fa-user-check text-sm text-accent" />
|
||||
{/if}
|
||||
</Anchor>
|
||||
</div>
|
||||
<div slot="tooltip">
|
||||
<PersonSummary pubkey={note.pubkey} />
|
||||
</div>
|
||||
</Popover>
|
||||
<Anchor
|
||||
type="unstyled"
|
||||
class="pr-16 text-lg font-bold"
|
||||
on:click={() => modal.push({type: "person/feed", pubkey: note.pubkey})}>
|
||||
<PersonName pubkey={$author.pubkey} />
|
||||
</Anchor>
|
||||
<Anchor
|
||||
href={"/" + nip19.neventEncode({id: note.id, relays: note.seen_on})}
|
||||
class="text-sm text-gray-1"
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
export let pubkey
|
||||
|
||||
const canSign = Keys.canSign.get()
|
||||
const isSelf = Keys.pubkey.get() === pubkey
|
||||
const npub = nip19.npubEncode(pubkey)
|
||||
const graphEntry = Nip02.graph.key(Keys.pubkey.get())
|
||||
const following = graphEntry.derived(() => user.isFollowing(pubkey))
|
||||
@ -19,7 +21,7 @@
|
||||
$: {
|
||||
actions = []
|
||||
|
||||
if (Keys.canSign.get()) {
|
||||
if (canSign) {
|
||||
actions.push({
|
||||
onClick: () => addToList("p", pubkey),
|
||||
label: "Add to list",
|
||||
@ -29,25 +31,19 @@
|
||||
|
||||
actions.push({onClick: share, label: "Share", icon: "share-nodes"})
|
||||
|
||||
if (Keys.pubkey.get() !== pubkey && Keys.canSign.get()) {
|
||||
if (!isSelf && canSign) {
|
||||
actions.push({
|
||||
onClick: () => navigate(`/messages/${npub}`),
|
||||
label: "Message",
|
||||
icon: "envelope",
|
||||
})
|
||||
|
||||
if ($muted) {
|
||||
actions.push({onClick: unmute, label: "Unmute", icon: "microphone"})
|
||||
} else if (Keys.pubkey.get() !== pubkey) {
|
||||
actions.push({onClick: mute, label: "Mute", icon: "microphone-slash"})
|
||||
}
|
||||
}
|
||||
|
||||
if (Env.FORCE_RELAYS.length === 0) {
|
||||
actions.push({onClick: openProfileInfo, label: "Details", icon: "info"})
|
||||
}
|
||||
|
||||
if (Keys.pubkey.get() === pubkey && Keys.canSign.get()) {
|
||||
if (isSelf && canSign) {
|
||||
actions.push({
|
||||
onClick: () => navigate("/profile"),
|
||||
label: "Edit",
|
||||
@ -70,12 +66,22 @@
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
{#if Keys.canSign.get()}
|
||||
{#if canSign && !isSelf}
|
||||
<Popover triggerType="mouseenter">
|
||||
<div slot="trigger">
|
||||
<div slot="trigger" class="w-6 text-center">
|
||||
{#if $muted}
|
||||
<i class="fa fa-microphone-slash cursor-pointer" on:click={unmute} />
|
||||
{:else}
|
||||
<i class="fa fa-microphone cursor-pointer" on:click={mute} />
|
||||
{/if}
|
||||
</div>
|
||||
<div slot="tooltip">{$muted ? "Unmute" : "Mute"}</div>
|
||||
</Popover>
|
||||
<Popover triggerType="mouseenter">
|
||||
<div slot="trigger" class="w-6 text-center">
|
||||
{#if $following}
|
||||
<i class="fa fa-user-minus cursor-pointer" on:click={unfollow} />
|
||||
{:else if Keys.pubkey.get() !== pubkey}
|
||||
{:else}
|
||||
<i class="fa fa-user-plus cursor-pointer" on:click={follow} />
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -4,13 +4,19 @@
|
||||
import {Directory, user} from "src/app/engine"
|
||||
|
||||
export let pubkey
|
||||
export let inert = false
|
||||
|
||||
const profile = Directory.profiles.key(pubkey).derived(defaultTo({pubkey}))
|
||||
const following = user.followsSet.derived(s => s.has(pubkey))
|
||||
</script>
|
||||
|
||||
<div class={cx("flex items-center gap-2", $$props.class)}>
|
||||
<span>{Directory.displayProfile($profile)}</span>
|
||||
<div
|
||||
class={cx("flex items-center gap-2 group/PersonName", $$props.class)}>
|
||||
<span class={cx({
|
||||
"duration-600 transition-all border-b border-solid border-transparent group-hover/PersonName:border-gray-3": !inert,
|
||||
})}>
|
||||
{Directory.displayProfile($profile)}
|
||||
</span>
|
||||
{#if $following}
|
||||
<i class="fa fa-user-check text-xs text-accent" />
|
||||
{/if}
|
||||
|
@ -8,6 +8,7 @@
|
||||
import {Keys, user} from "src/app/engine"
|
||||
|
||||
export let pubkey
|
||||
export let inert = false
|
||||
export let hideActions = false
|
||||
|
||||
const following = user.followsSet.derived(s => s.has(pubkey))
|
||||
@ -20,10 +21,10 @@
|
||||
</script>
|
||||
|
||||
<div class="relative flex flex-grow flex-col gap-4 px-3 py-2">
|
||||
<Anchor on:click={showDetail} class="flex gap-4">
|
||||
<Anchor on:click={inert ? null : showDetail} class="flex gap-4">
|
||||
<PersonCircle size={14} {pubkey} />
|
||||
<div class="mr-16 flex flex-grow flex-col gap-1">
|
||||
<PersonName class="text-lg" {pubkey} />
|
||||
<PersonName inert class="text-lg" {pubkey} />
|
||||
<PersonHandle {pubkey} />
|
||||
</div>
|
||||
</Anchor>
|
||||
|
@ -16,7 +16,7 @@
|
||||
import NoteContent from "src/app/shared/NoteContent.svelte"
|
||||
import RelaySearch from "src/app/shared/RelaySearch.svelte"
|
||||
import {Directory, user, Builder, Nip65, Keys} from "src/app/engine"
|
||||
import {toast, modal} from "src/partials/state"
|
||||
import {modal} from "src/partials/state"
|
||||
import {publishWithToast} from "src/app/state"
|
||||
|
||||
export let quote = null
|
||||
@ -43,27 +43,7 @@
|
||||
}
|
||||
|
||||
if (content) {
|
||||
const rawEvent = Builder.createNote(content.trim(), tags)
|
||||
const [event, promise] = await publishWithToast(rawEvent, $relays)
|
||||
|
||||
promise.then(() =>
|
||||
setTimeout(
|
||||
() =>
|
||||
toast.show("info", {
|
||||
text: `Your note has been created!`,
|
||||
link: {
|
||||
text: "View",
|
||||
href:
|
||||
"/" +
|
||||
nip19.neventEncode({
|
||||
id: event.id,
|
||||
relays: $relays.slice(0, 3),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
3000
|
||||
)
|
||||
)
|
||||
await publishWithToast(Builder.createNote(content.trim(), tags), $relays)
|
||||
|
||||
modal.clear()
|
||||
}
|
||||
|
@ -56,7 +56,7 @@
|
||||
<div class="flex flex-grow flex-col gap-4">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex flex-grow flex-col gap-2">
|
||||
<PersonName class="text-2xl" {pubkey} />
|
||||
<PersonName inert class="text-2xl" {pubkey} />
|
||||
<PersonHandle {pubkey} />
|
||||
</div>
|
||||
<PersonActions {pubkey} />
|
||||
|
@ -40,12 +40,12 @@
|
||||
|
||||
<Content>
|
||||
<div class="z-10 flex gap-4 text-gray-1">
|
||||
<PersonCircle pubkey={$profile.pubkey} size={16} class="sm:h-32 sm:w-32" />
|
||||
<PersonCircle {pubkey} size={16} class="sm:h-32 sm:w-32" />
|
||||
<div class="flex flex-grow flex-col gap-4">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex flex-grow flex-col gap-2">
|
||||
<Anchor href={routes.person(pubkey)}>
|
||||
<PersonName {pubkey} />
|
||||
<PersonName inert class="text-2xl" {pubkey} />
|
||||
</Anchor>
|
||||
<PersonHandle {pubkey} />
|
||||
</div>
|
||||
|
@ -118,7 +118,6 @@
|
||||
class="fa-solid fa-camera cursor-pointer text-accent"
|
||||
on:click={() => scanner.start()} />
|
||||
</Input>
|
||||
|
||||
{#each search(q).slice(0, 50) as result (result.type + result.id)}
|
||||
{#if result.type === "topic"}
|
||||
<BorderLeft on:click={() => openTopic(result.topic.name)}>
|
||||
@ -126,7 +125,7 @@
|
||||
</BorderLeft>
|
||||
{:else if result.type === "profile"}
|
||||
<BorderLeft on:click={() => modal.push({type: "person/feed", pubkey: result.id})}>
|
||||
<PersonSummary hideActions pubkey={result.id} />
|
||||
<PersonSummary inert hideActions pubkey={result.id} />
|
||||
</BorderLeft>
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -107,13 +107,16 @@ export class FeedLoader {
|
||||
this.feed.update($feed => {
|
||||
// Avoid showing the same note twice, even if it's once as
|
||||
// a parent and once as a child
|
||||
const ids = new Set(pluck('id', $feed))
|
||||
const ids = new Set(pluck("id", $feed))
|
||||
|
||||
return uniqBy(
|
||||
prop("id"),
|
||||
$feed.concat(
|
||||
this.context.applyContext(
|
||||
sortBy(e => -e.created_at, notes.filter(e => !ids.has(e))),
|
||||
sortBy(
|
||||
e => -e.created_at,
|
||||
notes.filter(e => !ids.has(e.id))
|
||||
),
|
||||
true
|
||||
)
|
||||
)
|
||||
|
@ -5,7 +5,7 @@
|
||||
<Anchor
|
||||
type="unstyled"
|
||||
class="flex gap-4 border-l-2 border-solid border-gray-6 py-2 px-4 transition-all
|
||||
hover:border-accent hover:bg-gray-8"
|
||||
hover:border-accent hover:bg-gray-8 hover:pl-5"
|
||||
on:click>
|
||||
<slot />
|
||||
</Anchor>
|
||||
|
@ -15,8 +15,11 @@
|
||||
const id = randomId()
|
||||
const {stack} = modal
|
||||
|
||||
$: _isOnTop = virtual || isOnTop
|
||||
$: _onEscape = _isOnTop ? onEscape : null
|
||||
const escapeIfOnTop = () => {
|
||||
if (virtual || isOnTop) {
|
||||
onEscape()
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
if (virtual) {
|
||||
@ -34,28 +37,25 @@
|
||||
<svelte:body
|
||||
on:keydown={e => {
|
||||
if (e.key === "Escape" && !root.querySelector(".modal")) {
|
||||
_onEscape?.()
|
||||
escapeIfOnTop?.()
|
||||
}
|
||||
}} />
|
||||
|
||||
<div
|
||||
bind:this={root}
|
||||
transition:fade
|
||||
class="modal fixed inset-0 z-30"
|
||||
class:pointer-events-none={mini}>
|
||||
{#if !mini}
|
||||
<div
|
||||
class="fixed inset-0 cursor-pointer bg-black opacity-50"
|
||||
on:click|stopPropagation={_onEscape} />
|
||||
{/if}
|
||||
class="modal fixed inset-0 z-30">
|
||||
<div
|
||||
class="fixed inset-0 cursor-pointer bg-black opacity-50"
|
||||
on:click|stopPropagation={escapeIfOnTop} />
|
||||
<div
|
||||
class="modal-content h-full overflow-auto"
|
||||
class:overflow-hidden={mini}
|
||||
class:pointer-events-none={mini}
|
||||
class:cursor-pointer={_onEscape}
|
||||
class:cursor-pointer={escapeIfOnTop}
|
||||
transition:fly={{y: 1000}}
|
||||
bind:this={content}
|
||||
on:click={_onEscape}>
|
||||
on:click={escapeIfOnTop}>
|
||||
<div
|
||||
class="pointer-events-auto mt-12 min-h-full transition transition-all duration-500"
|
||||
style={mini ? "margin-top: 55vh" : ""}>
|
||||
|
Loading…
Reference in New Issue
Block a user