mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-05 21:03:46 +00:00
Add mutes
This commit is contained in:
parent
bfc011551a
commit
c4c72abddc
@ -4,6 +4,8 @@
|
||||
|
||||
- [x] Make "show new notes" button fixed position
|
||||
- [x] Gray out buttons that don't work when logged in with pubkey
|
||||
- [x] Clean up popovers, re-design notes on small screens
|
||||
- [x] Migrate muffle to mute, add thread muting
|
||||
|
||||
## 0.2.16
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
# Current
|
||||
|
||||
- [ ] Check mention interpolation indexes nevent1qqsx27cspgfcj93kryt2zpzzt5ua60rtucckvcmsrqc949e6t83jaxspzemhxue69uhhyetvv9ujumn0wd68ytnzv9hxg46e8sv
|
||||
- [ ] Muffle -> mute
|
||||
- Add mute button on profile
|
||||
- [ ] Show loading/success on zap invoice screen
|
||||
- [ ] Fix iOS/safari/firefox
|
||||
- [ ] Update https://nostr.com/clients/coracle
|
||||
|
@ -60,7 +60,6 @@
|
||||
import NoteDetail from "src/views/notes/NoteDetail.svelte"
|
||||
import PersonList from "src/views/person/PersonList.svelte"
|
||||
import PersonProfileInfo from "src/views/person/PersonProfileInfo.svelte"
|
||||
import PersonSettings from "src/views/person/PersonSettings.svelte"
|
||||
import PersonShare from "src/views/person/PersonShare.svelte"
|
||||
import AddRelay from "src/views/relays/AddRelay.svelte"
|
||||
import RelayCard from "src/views/relays/RelayCard.svelte"
|
||||
@ -250,8 +249,6 @@
|
||||
<PubKeyLogin />
|
||||
{:else if $modal.type === "login/connect"}
|
||||
<ConnectUser />
|
||||
{:else if $modal.type === "person/settings"}
|
||||
<PersonSettings person={$modal.person} />
|
||||
{:else if $modal.type === "person/info"}
|
||||
<PersonProfileInfo person={$modal.person} />
|
||||
{:else if $modal.type === "person/share"}
|
||||
|
@ -26,8 +26,8 @@ const setRelays = newRelays =>
|
||||
const setPetnames = petnames =>
|
||||
new PublishableEvent(3, {tags: petnames})
|
||||
|
||||
const muffle = muffle =>
|
||||
new PublishableEvent(12165, {tags: muffle})
|
||||
const setMutes = mutes =>
|
||||
new PublishableEvent(10000, {tags: mutes})
|
||||
|
||||
const createRoom = room =>
|
||||
new PublishableEvent(40, {content: JSON.stringify(pick(roomAttrs, room))})
|
||||
@ -132,7 +132,7 @@ class PublishableEvent {
|
||||
}
|
||||
|
||||
export default {
|
||||
updateUser, setRelays, setPetnames, muffle, createRoom, updateRoom,
|
||||
updateUser, setRelays, setPetnames, setMutes, createRoom, updateRoom,
|
||||
createChatMessage, createDirectMessage, createNote, createReaction,
|
||||
createReply, requestZap, deleteEvent, PublishableEvent,
|
||||
}
|
||||
|
@ -96,7 +96,23 @@ const processProfileEvents = async events => {
|
||||
|
||||
return data
|
||||
},
|
||||
12165: () => ({muffle: e.tags}),
|
||||
10000: () => {
|
||||
if (e.created_at > (person.mutes_updated_at || 0)) {
|
||||
return {
|
||||
mutes_updated_at: e.created_at,
|
||||
mutes: e.tags,
|
||||
}
|
||||
}
|
||||
},
|
||||
// DEPRECATED
|
||||
12165: () => {
|
||||
if (e.created_at > (person.mutes_updated_at || 0)) {
|
||||
return {
|
||||
mutes_updated_at: e.created_at,
|
||||
mutes: e.tags,
|
||||
}
|
||||
}
|
||||
},
|
||||
// DEPRECATED
|
||||
10001: () => {
|
||||
if (e.created_at > (person.relays_updated_at || 0)) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import type {Person} from 'src/util/types'
|
||||
import type {Readable} from 'svelte/store'
|
||||
import {last, prop, find, pipe, assoc, whereEq, when, concat, reject, nth, map} from 'ramda'
|
||||
import {slice, identity, prop, find, pipe, assoc, whereEq, when, concat, reject, nth, map} from 'ramda'
|
||||
import {findReplyId, findRootId} from 'src/util/nostr'
|
||||
import {synced} from 'src/util/misc'
|
||||
import {Tags} from 'src/util/nostr'
|
||||
import {derived} from 'svelte/store'
|
||||
import database from 'src/agent/database'
|
||||
import keys from 'src/agent/keys'
|
||||
@ -19,9 +19,11 @@ let settingsCopy = null
|
||||
let profileCopy = null
|
||||
let petnamesCopy = []
|
||||
let relaysCopy = []
|
||||
let mutesCopy = []
|
||||
|
||||
const anonPetnames = synced('agent/user/anonPetnames', [])
|
||||
const anonRelays = synced('agent/user/anonRelays', [])
|
||||
const anonMutes = synced('agent/user/anonMutes', [])
|
||||
|
||||
const settings = synced("agent/user/settings", {
|
||||
relayLimit: 20,
|
||||
@ -42,17 +44,17 @@ const profile = derived(
|
||||
}
|
||||
) as Readable<Person>
|
||||
|
||||
const petnames = derived(
|
||||
[profile, anonPetnames],
|
||||
([$profile, $anonPetnames]) =>
|
||||
$profile?.petnames || $anonPetnames
|
||||
const profileKeyWithDefault = (key, stores) => derived(
|
||||
[profile, ...stores],
|
||||
([$profile, ...values]) =>
|
||||
$profile?.[key] || find(identity, values)
|
||||
)
|
||||
|
||||
const relays = derived(
|
||||
[profile, anonRelays],
|
||||
([$profile, $anonRelays]) =>
|
||||
$profile?.relays || $anonRelays
|
||||
)
|
||||
const petnames = profileKeyWithDefault('petnames', [anonPetnames])
|
||||
const relays = profileKeyWithDefault('relays', [anonRelays])
|
||||
|
||||
// Backwards compat, migrate muffle to mute temporarily
|
||||
const mutes = profileKeyWithDefault('mutes', [anonMutes, derived(profile, prop('muffle'))])
|
||||
|
||||
const canPublish = derived(
|
||||
[keys.pubkey, relays],
|
||||
@ -74,6 +76,10 @@ petnames.subscribe($petnames => {
|
||||
petnamesCopy = $petnames
|
||||
})
|
||||
|
||||
mutes.subscribe($mutes => {
|
||||
mutesCopy = $mutes
|
||||
})
|
||||
|
||||
relays.subscribe($relays => {
|
||||
relaysCopy = $relays
|
||||
})
|
||||
@ -92,34 +98,6 @@ const user = {
|
||||
canPublish,
|
||||
getProfile: () => profileCopy,
|
||||
getPubkey: () => profileCopy?.pubkey,
|
||||
muffle: events => {
|
||||
const muffle = user.getMuffle()
|
||||
|
||||
return events.filter(e => !muffle.has(e.pubkey))
|
||||
},
|
||||
getMuffle: () => {
|
||||
return new Set(
|
||||
Tags
|
||||
.wrap((profileCopy?.muffle || []))
|
||||
.filter(t => Math.random() > parseFloat(last(t)))
|
||||
.values()
|
||||
.all()
|
||||
)
|
||||
},
|
||||
mute: events => {
|
||||
const mutes = user.getMutes()
|
||||
|
||||
return events.filter(e => !mutes.has(e.pubkey))
|
||||
},
|
||||
getMutes: () => {
|
||||
return new Set(
|
||||
Tags
|
||||
.wrap((profileCopy?.muffle || []))
|
||||
.filter(t => parseFloat(last(t)) === 0)
|
||||
.values()
|
||||
.all()
|
||||
)
|
||||
},
|
||||
|
||||
// Petnames
|
||||
|
||||
@ -166,6 +144,39 @@ const user = {
|
||||
setRelayWriteCondition(url, write) {
|
||||
return this.updateRelays(map(when(whereEq({url}), assoc('write', write))))
|
||||
},
|
||||
|
||||
// Mutes
|
||||
|
||||
mutes,
|
||||
getMutes: () => mutesCopy,
|
||||
applyMutes: events => {
|
||||
const m = new Set(mutesCopy.map(m => m[1]))
|
||||
|
||||
return events.filter(e =>
|
||||
!(m.has(e.id) || m.has(e.pubkey) || m.has(findReplyId(e)) || m.has(findRootId(e)))
|
||||
)
|
||||
},
|
||||
updateMutes(f) {
|
||||
const $mutes = f(mutesCopy)
|
||||
console.log(mutesCopy, $mutes)
|
||||
|
||||
anonMutes.set($mutes)
|
||||
|
||||
if (profileCopy) {
|
||||
return cmd.setMutes($mutes.map(slice(0, 2))).publish(relaysCopy)
|
||||
}
|
||||
},
|
||||
addMute(type, value) {
|
||||
return this.updateMutes(
|
||||
pipe(
|
||||
reject(t => t[1] === value),
|
||||
concat([[type, value]])
|
||||
)
|
||||
)
|
||||
},
|
||||
removeMute(pubkey) {
|
||||
return this.updateMutes(reject(t => t[1] === pubkey))
|
||||
},
|
||||
}
|
||||
|
||||
export default user
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import {sortBy, assoc} from "ramda"
|
||||
import {sortBy, any, assoc} from "ramda"
|
||||
import {onMount} from "svelte"
|
||||
import {fly} from "svelte/transition"
|
||||
import {now, createScroller} from "src/util/misc"
|
||||
@ -22,13 +22,11 @@
|
||||
return createScroller(async () => {
|
||||
limit += 10
|
||||
|
||||
// Filter out alerts for which we failed to find the required context. The bug
|
||||
// Filter out mutes, and alerts for which we failed to find the required context. The bug
|
||||
// is really upstream of this, but it's an easy fix
|
||||
const events = user
|
||||
.mute(database.alerts.all())
|
||||
.filter(
|
||||
e => e.replies.length > 0 || e.likedBy.length > 0 || e.zappedBy?.length > 0 || e.isMention
|
||||
)
|
||||
.applyMutes(database.alerts.all())
|
||||
.filter(e => any(k => e[k].length > 0, ["replies", "likedBy", "zappedBy"]) || e.isMention)
|
||||
|
||||
notes = sortBy(e => -e.created_at, events).slice(0, limit)
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {last} from "ramda"
|
||||
import {last, find} from "ramda"
|
||||
import {onMount} from "svelte"
|
||||
import {tweened} from "svelte/motion"
|
||||
import {fly, fade} from "svelte/transition"
|
||||
@ -26,11 +26,12 @@
|
||||
export let relays = []
|
||||
|
||||
const interpolate = (a, b) => t => a + Math.round((b - a) * t)
|
||||
const {petnamePubkeys, canPublish} = user
|
||||
const {petnamePubkeys, canPublish, mutes} = user
|
||||
const getRelays = () => sampleRelays(relays.concat(getPubkeyWriteRelays(pubkey)))
|
||||
|
||||
let pubkey = toHex(npub)
|
||||
let following = false
|
||||
let muted = false
|
||||
let followers = new Set()
|
||||
let followersCount = tweened(0, {interpolate, duration: 1000})
|
||||
let person = database.getPersonWithFallback(pubkey)
|
||||
@ -39,6 +40,7 @@
|
||||
let actions = []
|
||||
|
||||
$: following = $petnamePubkeys.includes(pubkey)
|
||||
$: muted = find(m => m[1] === pubkey, $mutes)
|
||||
|
||||
$: {
|
||||
actions = []
|
||||
@ -53,12 +55,17 @@
|
||||
actions.push({onClick: follow, label: "Follow", icon: "user-plus"})
|
||||
}
|
||||
|
||||
if (muted) {
|
||||
actions.push({onClick: unmute, label: "Muted", icon: "microphone-slash"})
|
||||
} else if (user.getPubkey() !== pubkey) {
|
||||
actions.push({onClick: mute, label: "Mute", icon: "microphone"})
|
||||
}
|
||||
|
||||
actions.push({
|
||||
onClick: () => navigate(`/messages/${npub}`),
|
||||
label: "Message",
|
||||
icon: "envelope",
|
||||
})
|
||||
actions.push({onClick: openAdvanced, label: "Advanced", icon: "sliders"})
|
||||
}
|
||||
|
||||
actions.push({onClick: openProfileInfo, label: "Profile", icon: "info"})
|
||||
@ -133,8 +140,12 @@
|
||||
user.removePetname(pubkey)
|
||||
}
|
||||
|
||||
const openAdvanced = () => {
|
||||
modal.set({type: "person/settings", person})
|
||||
const mute = async () => {
|
||||
user.addMute("p", pubkey)
|
||||
}
|
||||
|
||||
const unmute = async () => {
|
||||
user.removeMute(pubkey)
|
||||
}
|
||||
|
||||
const openProfileInfo = () => {
|
||||
|
@ -3,7 +3,7 @@ import {is, fromPairs, mergeLeft, last, identity, objOf, prop, flatten, uniq} fr
|
||||
import {nip19} from 'nostr-tools'
|
||||
import {ensurePlural, ellipsize, first} from 'hurdak/lib/hurdak'
|
||||
|
||||
export const personKinds = [0, 2, 3, 10001, 10002, 12165]
|
||||
export const personKinds = [0, 2, 3, 10000, 10001, 10002, 12165]
|
||||
|
||||
export class Tags {
|
||||
tags: Array<any>
|
||||
|
@ -9,9 +9,9 @@ export type Relay = {
|
||||
|
||||
export type Person = {
|
||||
pubkey: string
|
||||
relays?: Array<Relay>
|
||||
muffle?: Array<Array<string>>
|
||||
petnames?: Array<Array<string>>
|
||||
relays?: Array<Relay>
|
||||
mutes?: Array<Array<string>>
|
||||
kind0?: {
|
||||
name?: string
|
||||
about?: string
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
const onChunk = async newNotes => {
|
||||
// Deduplicate and filter out stuff we don't want, apply user preferences
|
||||
const filtered = user.muffle(newNotes.filter(n => !seen.has(n.id) && shouldDisplay(n)))
|
||||
const filtered = user.applyMutes(newNotes.filter(n => !seen.has(n.id) && shouldDisplay(n)))
|
||||
|
||||
// Drop the oldest 20% of notes. We sometimes get pretty old stuff since we don't
|
||||
// use a since on our filter
|
||||
@ -68,7 +68,7 @@
|
||||
depth: 2,
|
||||
notes: combined,
|
||||
onChunk: context => {
|
||||
context = user.muffle(context)
|
||||
context = user.applyMutes(context)
|
||||
|
||||
notesBuffer = network.applyContext(notesBuffer, context)
|
||||
notes = network.applyContext(notes, context)
|
||||
@ -118,10 +118,11 @@
|
||||
|
||||
<Content size="inherit" class="pt-6">
|
||||
{#if notesBuffer.length > 0}
|
||||
<div class="fixed left-0 top-0 z-10 mt-20 flex w-full justify-center">
|
||||
<div class="pointer-events-none fixed left-0 top-0 z-10 mt-20 flex w-full justify-center">
|
||||
<button
|
||||
in:fly={{y: 20}}
|
||||
class="cursor-pointer rounded-full border border-solid border-accentl bg-accent py-2 px-4 text-center shadow-lg transition-colors hover:bg-accentl"
|
||||
class="pointer-events-auto cursor-pointer rounded-full border border-solid border-accentl
|
||||
bg-accent py-2 px-4 text-center shadow-lg transition-colors hover:bg-accentl"
|
||||
on:click={loadBufferedNotes}>
|
||||
Load {quantify(notesBuffer.length, "new note")}
|
||||
</button>
|
||||
|
@ -5,7 +5,6 @@
|
||||
import {onMount} from "svelte"
|
||||
import {tweened} from "svelte/motion"
|
||||
import {slide} from "svelte/transition"
|
||||
import {navigate} from "svelte-routing"
|
||||
import {quantify} from "hurdak/lib/hurdak"
|
||||
import {Tags, findRootId, findReplyId, displayPerson, isLike} from "src/util/nostr"
|
||||
import {formatTimestamp, now, tryJson, formatSats, fetchJson} from "src/util/misc"
|
||||
@ -54,7 +53,7 @@
|
||||
let visibleNotes = []
|
||||
let showRelays = false
|
||||
|
||||
const {profile, canPublish} = user
|
||||
const {profile, canPublish, mutes} = user
|
||||
const timestamp = formatTimestamp(note.created_at)
|
||||
const borderColor = invertColors ? "medium" : "dark"
|
||||
const links = extractUrls(note.content)
|
||||
@ -63,6 +62,7 @@
|
||||
const person = database.watch("people", () => database.getPersonWithFallback(note.pubkey))
|
||||
|
||||
let likes, flags, zaps, like, flag, border, childrenContainer, noteContainer, canZap
|
||||
let muted = false
|
||||
|
||||
const interpolate = (a, b) => t => a + Math.round((b - a) * t)
|
||||
const likesCount = tweened(0, {interpolate})
|
||||
@ -70,6 +70,7 @@
|
||||
const zapsTotal = tweened(0, {interpolate})
|
||||
const repliesCount = tweened(0, {interpolate})
|
||||
|
||||
$: muted = find(m => m[1] === note.id, $mutes)
|
||||
$: likes = note.reactions.filter(n => isLike(n.content))
|
||||
$: flags = note.reactions.filter(whereEq({content: "-"}))
|
||||
$: zaps = note.zaps
|
||||
@ -143,11 +144,15 @@
|
||||
modal.set({type: "note/detail", note: {id: findRootId(note)}, relays})
|
||||
}
|
||||
|
||||
const react = async content => {
|
||||
if (!$profile) {
|
||||
return navigate("/login")
|
||||
}
|
||||
const mute = async () => {
|
||||
user.addMute("e", note.id)
|
||||
}
|
||||
|
||||
const unmute = async () => {
|
||||
user.removeMute(note.id)
|
||||
}
|
||||
|
||||
const react = async content => {
|
||||
const relays = getEventPublishRelays(note)
|
||||
const [event] = await cmd.createReaction(note, content).publish(relays)
|
||||
|
||||
@ -173,11 +178,7 @@
|
||||
}
|
||||
|
||||
const startReply = () => {
|
||||
if ($profile) {
|
||||
reply = reply || true
|
||||
} else {
|
||||
navigate("/login")
|
||||
}
|
||||
reply = reply || true
|
||||
}
|
||||
|
||||
const removeMention = pubkey => {
|
||||
@ -385,6 +386,10 @@
|
||||
You have flagged this content as offensive.
|
||||
<Anchor on:click={() => deleteReaction(flag)}>Unflag</Anchor>
|
||||
</p>
|
||||
{:else if muted}
|
||||
<p class="border-l-2 border-solid border-medium pl-4 text-light">
|
||||
You have muted this note.
|
||||
</p>
|
||||
{:else}
|
||||
<div class="flex flex-col gap-2 overflow-hidden text-ellipsis">
|
||||
<p>{@html renderNote(note, {showEntire})}</p>
|
||||
@ -394,60 +399,69 @@
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex justify-between text-light">
|
||||
<div
|
||||
class={cx("flex", {
|
||||
"pointer-events-none opacity-75": !$canPublish,
|
||||
})}>
|
||||
<button class="w-16 text-left" on:click|stopPropagation={startReply}>
|
||||
<i class="fa fa-reply cursor-pointer" />
|
||||
{$repliesCount}
|
||||
</button>
|
||||
<button
|
||||
class="w-16 text-left"
|
||||
class:text-accent={like}
|
||||
on:click|stopPropagation={() => (like ? deleteReaction(like) : react("+"))}>
|
||||
<i
|
||||
class={cx("fa fa-heart cursor-pointer", {
|
||||
"fa-beat fa-beat-custom": like,
|
||||
})} />
|
||||
{$likesCount}
|
||||
</button>
|
||||
<button
|
||||
class={cx("w-20 text-left", {
|
||||
"pointer-events-none opacity-50": !canZap,
|
||||
})}
|
||||
class:text-accent={zapped}
|
||||
on:click|stopPropagation={startZap}>
|
||||
<i class="fa fa-bolt cursor-pointer" />
|
||||
{formatSats($zapsTotal)}
|
||||
</button>
|
||||
</div>
|
||||
<div on:click|stopPropagation>
|
||||
<Popover theme="transparent">
|
||||
<div slot="trigger" class="cursor-pointer px-2">
|
||||
<i class="fa fa-ellipsis-v" />
|
||||
</div>
|
||||
<div
|
||||
slot="tooltip"
|
||||
let:instance
|
||||
class="flex flex-col gap-2"
|
||||
on:click={() => instance.hide()}>
|
||||
<Anchor
|
||||
type="button-circle"
|
||||
on:click={() => {
|
||||
showRelays = true
|
||||
}}>
|
||||
<i class="fa fa-server" />
|
||||
</Anchor>
|
||||
<Anchor type="button-circle" on:click={() => react("-")}>
|
||||
<i class="fa fa-flag" />
|
||||
</Anchor>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex justify-between text-light">
|
||||
<div
|
||||
class={cx("flex", {
|
||||
"pointer-events-none opacity-75": !$canPublish || flag || muted,
|
||||
})}>
|
||||
<button class="w-16 text-left" on:click|stopPropagation={startReply}>
|
||||
<i class="fa fa-reply cursor-pointer" />
|
||||
{$repliesCount}
|
||||
</button>
|
||||
<button
|
||||
class="w-16 text-left"
|
||||
class:text-accent={like}
|
||||
on:click|stopPropagation={() => (like ? deleteReaction(like) : react("+"))}>
|
||||
<i
|
||||
class={cx("fa fa-heart cursor-pointer", {
|
||||
"fa-beat fa-beat-custom": like,
|
||||
})} />
|
||||
{$likesCount}
|
||||
</button>
|
||||
<button
|
||||
class={cx("w-20 text-left", {
|
||||
"pointer-events-none opacity-50": !canZap,
|
||||
})}
|
||||
class:text-accent={zapped}
|
||||
on:click|stopPropagation={startZap}>
|
||||
<i class="fa fa-bolt cursor-pointer" />
|
||||
{formatSats($zapsTotal)}
|
||||
</button>
|
||||
</div>
|
||||
<div on:click|stopPropagation>
|
||||
<Popover theme="transparent">
|
||||
<div slot="trigger" class="cursor-pointer px-2">
|
||||
<i class="fa fa-ellipsis-v" />
|
||||
</div>
|
||||
<div
|
||||
slot="tooltip"
|
||||
let:instance
|
||||
class="flex flex-col gap-2"
|
||||
on:click={() => instance.hide()}>
|
||||
<Anchor
|
||||
type="button-circle"
|
||||
on:click={() => {
|
||||
showRelays = true
|
||||
}}>
|
||||
<i class="fa fa-server" />
|
||||
</Anchor>
|
||||
{#if muted}
|
||||
<Anchor type="button-circle" on:click={unmute}>
|
||||
<i class="fa fa-microphone" />
|
||||
</Anchor>
|
||||
{:else}
|
||||
<Anchor type="button-circle" on:click={mute}>
|
||||
<i class="fa fa-microphone-slash" />
|
||||
</Anchor>
|
||||
{/if}
|
||||
<Anchor type="button-circle" on:click={() => react("-")}>
|
||||
<i class="fa fa-flag" />
|
||||
</Anchor>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@ -503,7 +517,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if visibleNotes.length > 0 && depth > 0}
|
||||
{#if visibleNotes.length > 0 && depth > 0 && !muted}
|
||||
<div class="relative">
|
||||
<div class={`absolute w-px bg-${borderColor} z-10 -mt-4 ml-4 h-0`} bind:this={border} />
|
||||
<div class="note-children relative ml-8 flex flex-col gap-4" bind:this={childrenContainer}>
|
||||
|
@ -40,7 +40,7 @@
|
||||
depth: 6,
|
||||
notes: [note],
|
||||
onChunk: context => {
|
||||
note = first(network.applyContext([note], user.muffle(context)))
|
||||
note = first(network.applyContext([note], user.applyMutes(context)))
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -54,7 +54,7 @@
|
||||
<Content size="lg" class="text-center">Sorry, we weren't able to find this note.</Content>
|
||||
</div>
|
||||
{:else if note.pubkey}
|
||||
<div in:fly={{y: 20}} class="m-auto flex max-w-2xl flex-col gap-4 p-4">
|
||||
<div in:fly={{y: 20}} class="m-auto flex w-full max-w-2xl flex-col gap-4 p-4">
|
||||
<Note showContext depth={6} anchorId={note.id} note={asDisplayEvent(note)} {invertColors} />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -1,56 +0,0 @@
|
||||
<script>
|
||||
import {last} from "ramda"
|
||||
import {switcher, first} from "hurdak/lib/hurdak"
|
||||
import {fly} from "svelte/transition"
|
||||
import Button from "src/partials/Button.svelte"
|
||||
import Content from "src/partials/Content.svelte"
|
||||
import SelectButton from "src/partials/SelectButton.svelte"
|
||||
import user from "src/agent/user"
|
||||
import {getUserWriteRelays} from "src/agent/relays"
|
||||
import cmd from "src/agent/cmd"
|
||||
import {publishWithToast} from "src/app"
|
||||
|
||||
export let person
|
||||
|
||||
const muffle = user.getProfile().muffle || []
|
||||
const muffleOptions = ["Never", "Sometimes", "Often", "Always"]
|
||||
const muffleValue = parseFloat(first(muffle.filter(t => t[1] === person.pubkey).map(last)) || 1)
|
||||
|
||||
const values = {
|
||||
// Scale up to integers for each choice we have
|
||||
muffle: switcher(Math.round(muffleValue * 3), muffleOptions),
|
||||
}
|
||||
|
||||
const save = async e => {
|
||||
e.preventDefault()
|
||||
|
||||
// Scale back down to a decimal based on string value
|
||||
const muffleValue = muffleOptions.indexOf(values.muffle) / 3
|
||||
const muffleTags = muffle
|
||||
.filter(t => t[1] !== person.pubkey)
|
||||
.concat([["p", person.pubkey, muffleValue.toString()]])
|
||||
.filter(t => last(t) !== "1")
|
||||
|
||||
publishWithToast(getUserWriteRelays(), cmd.muffle(muffleTags))
|
||||
|
||||
history.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<form in:fly={{y: 20}} on:submit={save}>
|
||||
<Content class="text-white">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h1 class="text-3xl">Advanced Follow</h1>
|
||||
<p>Fine grained controls for interacting with other people.</p>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<strong>How often do you want to see notes from this person?</strong>
|
||||
<SelectButton bind:value={values.muffle} options={muffleOptions} />
|
||||
<p class="text-sm text-light">
|
||||
"Never" is effectively a mute, while "Always" will show posts whenever available. If you
|
||||
want a middle ground, choose "Sometimes" or "Often".
|
||||
</p>
|
||||
</div>
|
||||
<Button type="submit" class="text-center">Done</Button>
|
||||
</Content>
|
||||
</form>
|
Loading…
Reference in New Issue
Block a user