mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-18 19:23:40 +00:00
Fix a few bugs
This commit is contained in:
parent
eaa517d71a
commit
dfb1916b02
2
.env
2
.env
@ -1,3 +1,3 @@
|
||||
VITE_THEME_DARK=transparent:transparent,black:#0f0f0e,white:#FFFFFF,accent:#EB5E28,accent-light:#FB652C,gray-1:#FFFFFF,gray-2:#FAF6F1,gray-3:#F2EBE1,gray-4:#E9E0D3,gray-5:#B3AA98,gray-6:#565249,gray-7:#393530,gray-8:#252422,danger:#ff0000,warning:#ebd112,success:#37ab51,input:#FAF6F1,input-hover:#F2EBE1
|
||||
VITE_THEME_LIGHT=transparent:transparent,black:#0f0f0e,white:#FFFFFF,accent:#EB5E28,accent-light:#FB652C,gray-8:#FFFFFF,gray-7:#FAF6F1,gray-6:#F2EBE1,gray-5:#E9E0D3,gray-4:#B3AA98,gray-3:#565249,gray-2:#393530,gray-1:#252422,danger:#ff0000,warning:#ebd112,success:#37ab51,input:#FAF6F1,input-hover:#F2EBE1
|
||||
VITE_THEME_LIGHT=transparent:transparent,black:#0f0f0e,white:#FFFFFF,accent:#EB5E28,accent-light:#FB652C,gray-8:#FFFFFF,gray-7:#FAF6F1,gray-6:#F2EBE1,gray-5:#B3AA98,gray-4:#B3AA98,gray-3:#565249,gray-2:#393530,gray-1:#252422,danger:#ff0000,warning:#ebd112,success:#37ab51,input:#FAF6F1,input-hover:#F2EBE1
|
||||
VITE_DUFFLEPUD_URL=https://dufflepud.onrender.com
|
||||
|
@ -1,10 +1,11 @@
|
||||
# Current
|
||||
|
||||
- [ ] Claim relays bounty
|
||||
- [ ] Add real search, it's a big hurdle for first-timers/anons
|
||||
- [ ] Remember message/chat status
|
||||
- [ ] Fix note nesting
|
||||
- [ ] Image classification
|
||||
- https://github.com/bhky/opennsfw2
|
||||
- [ ] Claim relays bounty
|
||||
|
||||
# Core
|
||||
|
||||
@ -71,6 +72,7 @@
|
||||
- [ ] Share button for notes, shows qr code and nevent
|
||||
- [ ] open web+nostr links like snort
|
||||
- [ ] Pinned posts ala snort
|
||||
- [ ] Scroll to top button that appears after scrolling a bit
|
||||
- [ ] Likes list on note detail. Maybe a sidebar or header for note detail page?
|
||||
- [ ] Add keyword mutes
|
||||
- [ ] Show options on note detail for retrieving replies
|
||||
|
@ -2,6 +2,7 @@
|
||||
import {nip19} from "nostr-tools"
|
||||
import {find, last} from "ramda"
|
||||
import {onMount} from "svelte"
|
||||
import {get} from "svelte/store"
|
||||
import {quantify} from "hurdak/lib/hurdak"
|
||||
import {findRootId, findReplyId, displayPerson} from "src/util/nostr"
|
||||
import {formatTimestamp} from "src/util/misc"
|
||||
@ -55,24 +56,34 @@
|
||||
return showContext ? true : !r.isContext
|
||||
})
|
||||
|
||||
// If we're already in a note detail modal, don't infinitely nest. But if we're in
|
||||
// some other modal, make it possible to go back.
|
||||
const goToNote = data => {
|
||||
if (modal.getCurrent()?.type === "note/detail") {
|
||||
modal.replace({type: "note/detail", ...data})
|
||||
} else {
|
||||
modal.push({type: "note/detail", ...data})
|
||||
}
|
||||
}
|
||||
|
||||
const onClick = e => {
|
||||
const target = e.target as HTMLElement
|
||||
|
||||
if (interactive && !["I"].includes(target.tagName) && !target.closest("a")) {
|
||||
modal.push({type: "note/detail", note})
|
||||
goToNote({note})
|
||||
}
|
||||
}
|
||||
|
||||
const goToParent = async () => {
|
||||
const relays = getRelaysForEventParent(note)
|
||||
|
||||
modal.push({type: "note/detail", note: {id: findReplyId(note)}, relays})
|
||||
goToNote({note: {id: findReplyId(note)}, relays})
|
||||
}
|
||||
|
||||
const goToRoot = async () => {
|
||||
const relays = getRelaysForEventParent(note)
|
||||
|
||||
modal.push({type: "note/detail", note: {id: findRootId(note)}, relays})
|
||||
goToNote({note: {id: findRootId(note)}, relays})
|
||||
}
|
||||
|
||||
const setBorderHeight = () => {
|
||||
|
@ -176,19 +176,19 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex justify-between text-gray-1">
|
||||
<div class="flex justify-between text-gray-1" on:click|stopPropagation>
|
||||
<div
|
||||
class={cx("flex", {
|
||||
"pointer-events-none opacity-75": !$canPublish || muted,
|
||||
})}>
|
||||
<button class="w-16 text-left" on:click|stopPropagation={reply.start}>
|
||||
<button class="w-16 text-left" on:click={reply.start}>
|
||||
<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("+"))}>
|
||||
on:click={() => (like ? deleteReaction(like) : react("+"))}>
|
||||
<i
|
||||
class={cx("fa fa-heart cursor-pointer", {
|
||||
"fa-beat fa-beat-custom": like,
|
||||
@ -200,12 +200,12 @@
|
||||
"pointer-events-none opacity-50": !canZap,
|
||||
})}
|
||||
class:text-accent={zap}
|
||||
on:click|stopPropagation={startZap}>
|
||||
on:click={startZap}>
|
||||
<i class="fa fa-bolt cursor-pointer" />
|
||||
{formatSats($zapsTotal)}
|
||||
</button>
|
||||
</div>
|
||||
<div on:click|stopPropagation class="flex items-center">
|
||||
<div class="flex items-center">
|
||||
{#if pool.forceUrls.length === 0}
|
||||
<!-- Mobile version -->
|
||||
<div
|
||||
|
@ -6,7 +6,7 @@
|
||||
import {modal} from "src/partials/state"
|
||||
import Popover from "src/partials/Popover.svelte"
|
||||
import OverflowMenu from "src/partials/OverflowMenu.svelte"
|
||||
import {getPubkeyWriteRelays} from "src/agent/relays"
|
||||
import {sampleRelays, getPubkeyWriteRelays} from "src/agent/relays"
|
||||
import user from "src/agent/user"
|
||||
import pool from "src/agent/pool"
|
||||
import {addToList} from "src/app/state"
|
||||
@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
const follow = async () => {
|
||||
const [{url}] = getPubkeyWriteRelays(person.pubkey)
|
||||
const [{url}] = sampleRelays(getPubkeyWriteRelays(person.pubkey))
|
||||
|
||||
user.addPetname(person.pubkey, url, displayPerson(person))
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
<script lang="ts">
|
||||
import {last, nth} from "ramda"
|
||||
import {displayPerson} from "src/util/nostr"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import user from "src/agent/user"
|
||||
import {sampleRelays, getPubkeyWriteRelays} from "src/agent/relays"
|
||||
import {getPersonWithFallback} from "src/agent/db"
|
||||
import {watch} from "src/agent/db"
|
||||
import PersonCircle from "src/app/shared/PersonCircle.svelte"
|
||||
import PersonAbout from "src/app/shared/PersonAbout.svelte"
|
||||
import {routes} from "src/app/state"
|
||||
|
||||
export let pubkey
|
||||
|
||||
@ -32,16 +34,18 @@
|
||||
|
||||
<div class="relative flex flex-col gap-4 py-2 px-3">
|
||||
<div class="flex gap-4">
|
||||
<PersonCircle size={14} person={$person} />
|
||||
<div class="flex flex-grow flex-col gap-2">
|
||||
<h2 class="text-lg">{displayPerson($person)}</h2>
|
||||
{#if $person.verified_as}
|
||||
<div class="flex gap-1 text-sm">
|
||||
<i class="fa fa-user-check text-accent" />
|
||||
<span class="text-gray-1">{last($person.verified_as.split("@"))}</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<Anchor type="unstyled" href={routes.person($person.pubkey)} class="flex gap-4">
|
||||
<PersonCircle size={14} person={$person} />
|
||||
<div class="flex flex-grow flex-col gap-2">
|
||||
<h2 class="text-lg">{displayPerson($person)}</h2>
|
||||
{#if $person.verified_as}
|
||||
<div class="flex gap-1 text-sm">
|
||||
<i class="fa fa-user-check text-accent" />
|
||||
<span class="opacity-75">{last($person.verified_as.split("@"))}</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Anchor>
|
||||
<div class="flex gap-4 py-2 text-lg">
|
||||
{#if $canPublish}
|
||||
{#if muted}
|
||||
|
@ -90,6 +90,10 @@ export const logUsage = async name => {
|
||||
}
|
||||
}
|
||||
|
||||
// Feed
|
||||
|
||||
export const feedsTab = writable("Follows")
|
||||
|
||||
// State
|
||||
|
||||
export const lastChecked = synced("app/alerts/lastChecked", {})
|
||||
@ -150,7 +154,7 @@ const processChats = async (pubkey, events) => {
|
||||
|
||||
lastChecked.update($lastChecked => {
|
||||
for (const message of messages) {
|
||||
const id = Tags.from(message).type("e").values().first()
|
||||
const id = Tags.from(message).getMeta("e")
|
||||
|
||||
if (message.pubkey === pubkey) {
|
||||
$lastChecked[id] = Math.max($lastChecked[id] || 0, message.created_at)
|
||||
|
@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import cx from "classnames"
|
||||
import {prop, uniq, indexBy, objOf, filter as _filter} from "ramda"
|
||||
import {shuffle, synced} from "src/util/misc"
|
||||
import {prop, indexBy, objOf, filter as _filter} from "ramda"
|
||||
import {shuffle} from "src/util/misc"
|
||||
import {Tags} from "src/util/nostr"
|
||||
import {modal, theme} from "src/partials/state"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
@ -12,38 +12,31 @@
|
||||
import {getUserFollows, getUserNetwork} from "src/agent/social"
|
||||
import {sampleRelays, getAllPubkeyWriteRelays, getUserReadRelays} from "src/agent/relays"
|
||||
import user from "src/agent/user"
|
||||
import {feedsTab} from "src/app/state"
|
||||
|
||||
const {lists, canPublish} = user
|
||||
const activeTab = synced("views/Feeds/activeTab", "Follows")
|
||||
const defaultTabs = ["Follows", "Network"]
|
||||
|
||||
let relays, filter, tabs
|
||||
let relays, filter
|
||||
|
||||
$: listsByName = indexBy(l => Tags.from(l).getMeta("d"), $lists)
|
||||
$: {
|
||||
const defaultTabs = ["Follows", "Network"]
|
||||
const customTabs = Object.keys(listsByName)
|
||||
const validTabs = defaultTabs.concat(customTabs)
|
||||
|
||||
if (!validTabs.includes($activeTab)) {
|
||||
$activeTab = validTabs[0]
|
||||
}
|
||||
|
||||
tabs = uniq(defaultTabs.concat($activeTab).concat(customTabs)).slice(0, 3)
|
||||
}
|
||||
$: allTabs = defaultTabs.concat(Object.keys(listsByName))
|
||||
$: $feedsTab = allTabs.includes($feedsTab) ? $feedsTab : defaultTabs[0]
|
||||
$: visibleTabs = defaultTabs.includes($feedsTab) ? defaultTabs : [defaultTabs[0], $feedsTab]
|
||||
|
||||
$: {
|
||||
if ($activeTab === "Follows") {
|
||||
if ($feedsTab === "Follows") {
|
||||
const authors = shuffle(getUserFollows()).slice(0, 256)
|
||||
|
||||
filter = {authors}
|
||||
relays = sampleRelays(getAllPubkeyWriteRelays(authors))
|
||||
} else if ($activeTab === "Network") {
|
||||
} else if ($feedsTab === "Network") {
|
||||
const authors = shuffle(getUserNetwork()).slice(0, 256)
|
||||
|
||||
filter = {authors}
|
||||
relays = sampleRelays(getAllPubkeyWriteRelays(authors))
|
||||
} else {
|
||||
const list = listsByName[$activeTab]
|
||||
const list = listsByName[$feedsTab]
|
||||
const tags = Tags.from(list)
|
||||
const authors = tags.type("p").values().all()
|
||||
const topics = tags.type("t").values().all()
|
||||
@ -59,14 +52,14 @@
|
||||
}
|
||||
|
||||
const setActiveTab = tab => {
|
||||
$activeTab = tab
|
||||
$feedsTab = tab
|
||||
}
|
||||
|
||||
const showLists = () => {
|
||||
modal.push({type: "list/list"})
|
||||
}
|
||||
|
||||
document.title = $activeTab
|
||||
document.title = $feedsTab
|
||||
</script>
|
||||
|
||||
<Content>
|
||||
@ -79,7 +72,7 @@
|
||||
</Content>
|
||||
{/if}
|
||||
<div>
|
||||
<Tabs {tabs} activeTab={$activeTab} {setActiveTab}>
|
||||
<Tabs tabs={visibleTabs} activeTab={$feedsTab} {setActiveTab}>
|
||||
{#if $canPublish}
|
||||
{#if $lists.length > 1}
|
||||
<Popover placement="bottom" opts={{hideOnClick: true}} theme="transparent">
|
||||
@ -89,19 +82,17 @@
|
||||
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()}
|
||||
{#if meta.d !== $activeTab}
|
||||
<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={() => {
|
||||
$activeTab = meta.d
|
||||
}}>
|
||||
<i class="fa fa-scroll fa-sm mr-1" />
|
||||
{meta.d}
|
||||
</button>
|
||||
{/if}
|
||||
<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}
|
||||
<button
|
||||
on:click={showLists}
|
||||
@ -118,7 +109,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</Tabs>
|
||||
{#key $activeTab}
|
||||
{#key $feedsTab}
|
||||
<Feed {relays} {filter} />
|
||||
{/key}
|
||||
</div>
|
||||
|
@ -16,6 +16,7 @@
|
||||
const topics = t
|
||||
.all()
|
||||
.map(topic => ({type: "topic", id: topic.name, topic, text: "#" + topic.name}))
|
||||
|
||||
const people = p
|
||||
.all({"kind0.name": {$type: "string"}, pubkey: {$ne: user.getPubkey()}})
|
||||
.map(person => ({
|
||||
|
@ -24,7 +24,9 @@
|
||||
}} />
|
||||
|
||||
<div class="modal fixed inset-0 z-30" bind:this={root} transition:fade>
|
||||
<div class="fixed inset-0 cursor-pointer bg-black opacity-50" on:click={onEscape} />
|
||||
<div
|
||||
class="fixed inset-0 cursor-pointer bg-black opacity-50"
|
||||
on:click|stopPropagation={onEscape} />
|
||||
<div
|
||||
class="modal-content h-full overflow-auto"
|
||||
bind:this={content}
|
||||
|
@ -48,10 +48,18 @@ export const openModals = writable(0)
|
||||
|
||||
export const modal = {
|
||||
stack: new WritableList([]) as WritableList<any>,
|
||||
sync: ($stack, opts = {}) => {
|
||||
getCurrent() {
|
||||
const $stack = get(modal.stack)
|
||||
const $openModals = get(openModals)
|
||||
|
||||
return $stack[$openModals - 1]
|
||||
},
|
||||
sync($stack, opts = {}) {
|
||||
const hash = $stack.length > 0 ? `#m=${$stack.length}` : ""
|
||||
|
||||
navigate(window.location.pathname + hash, opts)
|
||||
if (hash !== window.location.hash) {
|
||||
navigate(window.location.pathname + hash, opts)
|
||||
}
|
||||
|
||||
return $stack
|
||||
},
|
||||
@ -63,8 +71,7 @@ export const modal = {
|
||||
await sleep(100)
|
||||
},
|
||||
async replace(data) {
|
||||
await modal.pop()
|
||||
modal.push(data)
|
||||
modal.stack.update($stack => $stack.slice(0, -1).concat(data))
|
||||
},
|
||||
async clear() {
|
||||
const stackSize = (get(modal.stack) as any).length
|
||||
|
Loading…
Reference in New Issue
Block a user