mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-18 19:23:40 +00:00
Stack modals explicitly
This commit is contained in:
parent
82da83f5e1
commit
f019b64695
@ -7,6 +7,7 @@
|
||||
- [ ] Ability to create custom feeds
|
||||
- [ ] Add global/following/network tabs to relay detail
|
||||
- [ ] Some lnurls aren't working npub1y3k2nheva29y9ej8a22e07epuxrn04rvgy28wvs54y57j7vsxxuq0gvp4j
|
||||
- [ ] Global search modal that searches within current feed
|
||||
- [ ] Fix force relays on login: http://localhost:5173/messages/npub1l66wvfm7dxhd6wmvpukpjpyhvwtlxzu0qqajqxjfpr4rlfa8hl5qlkfr3q
|
||||
- [ ] Image classification
|
||||
- https://github.com/bhky/opennsfw2
|
||||
|
@ -5,8 +5,8 @@
|
||||
import {onMount} from "svelte"
|
||||
import {Router, links} from "svelte-routing"
|
||||
import {globalHistory} from "svelte-routing/src/history"
|
||||
import {identity, last} from "ramda"
|
||||
import {first} from "hurdak/lib/hurdak"
|
||||
import {identity} from "ramda"
|
||||
import {warn} from "src/util/logger"
|
||||
import {timedelta, hexToBech32, bech32ToHex, shuffle, now} from "src/util/misc"
|
||||
import cmd from "src/agent/cmd"
|
||||
@ -55,9 +55,9 @@
|
||||
let scrollY
|
||||
|
||||
// Log modals
|
||||
const unsubModal = modal.subscribe($modal => {
|
||||
if ($modal) {
|
||||
logUsage(btoa(["modal", $modal.type].join(":")))
|
||||
const unsubModal = modal.stack.subscribe($stack => {
|
||||
if ($stack.length > 0) {
|
||||
logUsage(btoa(["modal", last($stack).type].join(":")))
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
const matches = $location.pathname.match(/people\/(npub1[0-9a-z]+)/)
|
||||
const pubkey = matches ? nip19.decode(matches[1]).data : null
|
||||
|
||||
modal.set({type: "note/create", pubkey})
|
||||
modal.push({type: "note/create", pubkey})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {last} from "ramda"
|
||||
import {menuIsOpen} from "src/app/state"
|
||||
import {modal} from "src/partials/state"
|
||||
import Modal from "src/partials/Modal.svelte"
|
||||
@ -15,53 +16,55 @@
|
||||
import PersonProfileInfo from "src/app/views/PersonProfileInfo.svelte"
|
||||
import PersonShare from "src/app/views/PersonShare.svelte"
|
||||
import TopicFeed from "src/app/views/TopicFeed.svelte"
|
||||
import AddRelay from "src/app/views/RelayAdd.svelte"
|
||||
import RelayAdd from "src/app/views/RelayAdd.svelte"
|
||||
|
||||
const {stack} = modal
|
||||
|
||||
const closeModal = async () => {
|
||||
modal.clear()
|
||||
modal.pop()
|
||||
menuIsOpen.set(false)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $modal}
|
||||
<Modal onEscape={$modal.noEscape ? null : closeModal}>
|
||||
{#if $modal.type === "note/detail"}
|
||||
{#key $modal.note.id}
|
||||
<NoteDetail {...$modal} invertColors />
|
||||
{#each $stack as m}
|
||||
<Modal onEscape={m.noEscape || m !== last($stack) ? null : closeModal}>
|
||||
{#if m.type === "note/detail"}
|
||||
{#key m.note.id}
|
||||
<NoteDetail {...m} invertColors />
|
||||
{/key}
|
||||
{:else if $modal.type === "note/create"}
|
||||
<NoteCreate pubkey={$modal.pubkey} nevent={$modal.nevent} />
|
||||
{:else if $modal.type === "relay/add"}
|
||||
<AddRelay />
|
||||
{:else if $modal.type === "onboarding"}
|
||||
<Onboarding stage={$modal.stage} />
|
||||
{:else if $modal.type === "room/edit"}
|
||||
<ChatEdit {...$modal} />
|
||||
{:else if $modal.type === "login/privkey"}
|
||||
{:else if m.type === "note/create"}
|
||||
<NoteCreate pubkey={m.pubkey} nevent={m.nevent} />
|
||||
{:else if m.type === "relay/add"}
|
||||
<RelayAdd url={m.url} />
|
||||
{:else if m.type === "onboarding"}
|
||||
<Onboarding stage={m.stage} />
|
||||
{:else if m.type === "room/edit"}
|
||||
<ChatEdit {...m} />
|
||||
{:else if m.type === "login/privkey"}
|
||||
<LoginPrivKey />
|
||||
{:else if $modal.type === "login/pubkey"}
|
||||
{:else if m.type === "login/pubkey"}
|
||||
<LoginPubKey />
|
||||
{:else if $modal.type === "login/connect"}
|
||||
{:else if m.type === "login/connect"}
|
||||
<LoginConnect />
|
||||
{:else if $modal.type === "person/info"}
|
||||
<PersonProfileInfo person={$modal.person} />
|
||||
{:else if $modal.type === "person/share"}
|
||||
<PersonShare person={$modal.person} />
|
||||
{:else if $modal.type === "person/follows"}
|
||||
<PersonList type="follows" pubkey={$modal.pubkey} />
|
||||
{:else if $modal.type === "person/followers"}
|
||||
<PersonList type="followers" pubkey={$modal.pubkey} />
|
||||
{:else if $modal.type === "topic/feed"}
|
||||
{#key $modal.topic}
|
||||
<TopicFeed topic={$modal.topic} />
|
||||
{:else if m.type === "person/info"}
|
||||
<PersonProfileInfo person={m.person} />
|
||||
{:else if m.type === "person/share"}
|
||||
<PersonShare person={m.person} />
|
||||
{:else if m.type === "person/follows"}
|
||||
<PersonList type="follows" pubkey={m.pubkey} />
|
||||
{:else if m.type === "person/followers"}
|
||||
<PersonList type="followers" pubkey={m.pubkey} />
|
||||
{:else if m.type === "topic/feed"}
|
||||
{#key m.topic}
|
||||
<TopicFeed topic={m.topic} />
|
||||
{/key}
|
||||
{:else if $modal.type === "message"}
|
||||
{:else if m.type === "message"}
|
||||
<Content size="lg">
|
||||
<div class="text-center">{$modal.message}</div>
|
||||
{#if $modal.spinner}
|
||||
<div class="text-center">{m.message}</div>
|
||||
{#if m.spinner}
|
||||
<Spinner delay={0} />
|
||||
{/if}
|
||||
</Content>
|
||||
{/if}
|
||||
</Modal>
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -1,11 +1,10 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {partition, always, propEq, uniqBy, sortBy, prop} from "ramda"
|
||||
import {last, partition, always, propEq, uniqBy, sortBy, prop} from "ramda"
|
||||
import {fly} from "svelte/transition"
|
||||
import {quantify} from "hurdak/lib/hurdak"
|
||||
import {createScroller, now, timedelta, Cursor} from "src/util/misc"
|
||||
import {asDisplayEvent, mergeFilter} from "src/util/nostr"
|
||||
import {modal} from "src/partials/state"
|
||||
import Spinner from "src/partials/Spinner.svelte"
|
||||
import Modal from "src/partials/Modal.svelte"
|
||||
import Content from "src/partials/Content.svelte"
|
||||
@ -17,7 +16,6 @@
|
||||
|
||||
export let filter
|
||||
export let relays = []
|
||||
export let inModal = false
|
||||
export let delta = timedelta(6, "hours")
|
||||
export let shouldDisplay = always(true)
|
||||
export let parentsTimeout = 500
|
||||
@ -32,17 +30,14 @@
|
||||
const maxNotes = 100
|
||||
const cursor = new Cursor({delta})
|
||||
const seen = new Set()
|
||||
const getModal = () => last(document.querySelectorAll(".modal-content"))
|
||||
|
||||
const setFeedRelay = relay => {
|
||||
feedRelay = relay
|
||||
|
||||
setTimeout(() => {
|
||||
feedScroller?.stop()
|
||||
feedScroller = !relay
|
||||
? null
|
||||
: createScroller(loadMore, {
|
||||
element: document.querySelector(".modal-content"),
|
||||
})
|
||||
feedScroller = !relay ? null : createScroller(loadMore, {element: getModal()})
|
||||
}, 300)
|
||||
}
|
||||
|
||||
@ -106,11 +101,6 @@
|
||||
}
|
||||
|
||||
const loadMore = async () => {
|
||||
console.log("here")
|
||||
if ($modal && !inModal) {
|
||||
return
|
||||
}
|
||||
|
||||
// Wait for this page to load before trying again
|
||||
await network.load({
|
||||
relays: feedRelay ? [feedRelay] : relays,
|
||||
@ -129,9 +119,7 @@
|
||||
onChunk,
|
||||
})
|
||||
|
||||
const scroller = createScroller(loadMore, {
|
||||
element: inModal ? document.querySelector(".modal-content") : null,
|
||||
})
|
||||
const scroller = createScroller(loadMore, {element: getModal()})
|
||||
|
||||
return () => {
|
||||
scroller.stop()
|
||||
|
@ -59,20 +59,20 @@
|
||||
const target = e.target as HTMLElement
|
||||
|
||||
if (interactive && !["I"].includes(target.tagName) && !target.closest("a")) {
|
||||
modal.set({type: "note/detail", note})
|
||||
modal.push({type: "note/detail", note})
|
||||
}
|
||||
}
|
||||
|
||||
const goToParent = async () => {
|
||||
const relays = getRelaysForEventParent(note)
|
||||
|
||||
modal.set({type: "note/detail", note: {id: findReplyId(note)}, relays})
|
||||
modal.push({type: "note/detail", note: {id: findReplyId(note)}, relays})
|
||||
}
|
||||
|
||||
const goToRoot = async () => {
|
||||
const relays = getRelaysForEventParent(note)
|
||||
|
||||
modal.set({type: "note/detail", note: {id: findRootId(note)}, relays})
|
||||
modal.push({type: "note/detail", note: {id: findRootId(note)}, relays})
|
||||
}
|
||||
|
||||
const setBorderHeight = () => {
|
||||
|
@ -50,7 +50,7 @@
|
||||
toast.show("info", "Note link copied to clipboard!")
|
||||
}
|
||||
|
||||
const quote = () => modal.set({type: "note/create", nevent})
|
||||
const quote = () => modal.push({type: "note/create", nevent})
|
||||
const mute = () => user.addMute("e", note.id)
|
||||
const unmute = () => user.removeMute(note.id)
|
||||
|
||||
|
@ -106,11 +106,11 @@
|
||||
}
|
||||
|
||||
const openQuote = id => {
|
||||
modal.set({type: "note/detail", note: {id}})
|
||||
modal.push({type: "note/detail", note: {id}})
|
||||
}
|
||||
|
||||
const openTopic = topic => {
|
||||
modal.set({type: "topic/feed", topic})
|
||||
modal.push({type: "topic/feed", topic})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -219,7 +219,7 @@ export const loadAppData = async pubkey => {
|
||||
export const login = (method, key) => {
|
||||
keys.login(method, key)
|
||||
|
||||
modal.set({type: "login/connect", noEscape: true})
|
||||
modal.push({type: "login/connect", noEscape: true})
|
||||
}
|
||||
|
||||
export const mergeParents = (notes: Array<DisplayEvent>) => {
|
||||
|
@ -36,7 +36,7 @@
|
||||
})
|
||||
|
||||
const edit = () => {
|
||||
modal.set({type: "room/edit", room: $room})
|
||||
modal.push({type: "room/edit", room: $room})
|
||||
}
|
||||
|
||||
const sendMessage = async content => {
|
||||
|
@ -48,7 +48,7 @@
|
||||
rooms.patch({id: event.id, joined: true})
|
||||
}
|
||||
|
||||
modal.set(null)
|
||||
modal.pop()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -40,7 +40,7 @@
|
||||
<i class="fa fa-server fa-lg" />
|
||||
<h2 class="staatliches text-2xl">Your rooms</h2>
|
||||
</div>
|
||||
<Anchor type="button-accent" on:click={() => modal.set({type: "room/edit"})}>
|
||||
<Anchor type="button-accent" on:click={() => modal.push({type: "room/edit"})}>
|
||||
<i class="fa-solid fa-plus" /> Create Room
|
||||
</Anchor>
|
||||
</div>
|
||||
|
@ -16,16 +16,16 @@
|
||||
if (nostr) {
|
||||
login("extension", await nostr.getPublicKey())
|
||||
} else {
|
||||
modal.set({type: "login/privkey"})
|
||||
modal.push({type: "login/privkey"})
|
||||
}
|
||||
}
|
||||
|
||||
const signUp = () => {
|
||||
modal.set({type: "onboarding", stage: "intro"})
|
||||
modal.push({type: "onboarding", stage: "intro"})
|
||||
}
|
||||
|
||||
const pubkeyLogIn = () => {
|
||||
modal.set({type: "login/pubkey"})
|
||||
modal.push({type: "login/pubkey"})
|
||||
}
|
||||
|
||||
if (user.getPubkey()) {
|
||||
|
@ -43,7 +43,7 @@
|
||||
<Card
|
||||
interactive
|
||||
class="flex flex-col gap-2 text-left"
|
||||
on:click={() => modal.set({type: "note/detail", note})}>
|
||||
on:click={() => modal.push({type: "note/detail", note})}>
|
||||
<div class="relative flex w-full items-center justify-between gap-2" on:click|stopPropagation>
|
||||
{#if !event.ref}
|
||||
<div class="flex items-center gap-2">
|
||||
|
@ -65,7 +65,7 @@
|
||||
|
||||
loadAppData(user.getPubkey())
|
||||
|
||||
modal.set(null)
|
||||
modal.pop()
|
||||
navigate("/notes/follows")
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
</p>
|
||||
<Anchor
|
||||
type="button-accent"
|
||||
on:click={() => modal.set({type: "onboarding", stage: "complete"})}>
|
||||
on:click={() => modal.push({type: "onboarding", stage: "complete"})}>
|
||||
Continue
|
||||
</Anchor>
|
||||
</Content>
|
||||
|
@ -19,7 +19,7 @@
|
||||
When you’re ready to dive in, click below and we’ll guide you through the process of creating an
|
||||
account.
|
||||
</p>
|
||||
<Anchor type="button-accent" on:click={() => modal.set({type: "onboarding", stage: "key"})}>
|
||||
<Anchor type="button-accent" on:click={() => modal.push({type: "onboarding", stage: "key"})}>
|
||||
Let's go!
|
||||
</Anchor>
|
||||
</Content>
|
||||
|
@ -30,7 +30,9 @@
|
||||
<i slot="before" class="fa fa-lock" />
|
||||
<button slot="after" class="fa fa-copy cursor-pointer" on:click={copyKey} />
|
||||
</Input>
|
||||
<Anchor type="button-accent" on:click={() => modal.set({type: "onboarding", stage: nextStage})}>
|
||||
<Anchor
|
||||
type="button-accent"
|
||||
on:click={() => modal.push({type: "onboarding", stage: nextStage})}>
|
||||
Log in
|
||||
</Anchor>
|
||||
</div>
|
||||
|
@ -39,7 +39,9 @@
|
||||
Select your preferred storage relays below, or click "continue" to use some reasonable defaults.
|
||||
You can change your selection any time.
|
||||
</p>
|
||||
<Anchor type="button-accent" on:click={() => modal.set({type: "onboarding", stage: "follows"})}>
|
||||
<Anchor
|
||||
type="button-accent"
|
||||
on:click={() => modal.push({type: "onboarding", stage: "follows"})}>
|
||||
Continue
|
||||
</Anchor>
|
||||
</Content>
|
||||
|
@ -132,11 +132,11 @@
|
||||
const setActiveTab = tab => navigate(routes.person(pubkey, tab))
|
||||
|
||||
const showFollows = () => {
|
||||
modal.set({type: "person/follows", pubkey})
|
||||
modal.push({type: "person/follows", pubkey})
|
||||
}
|
||||
|
||||
const showFollowers = () => {
|
||||
modal.set({type: "person/followers", pubkey})
|
||||
modal.push({type: "person/followers", pubkey})
|
||||
}
|
||||
|
||||
const follow = async () => {
|
||||
@ -158,11 +158,11 @@
|
||||
}
|
||||
|
||||
const openProfileInfo = () => {
|
||||
modal.set({type: "person/info", $person})
|
||||
modal.push({type: "person/info", $person})
|
||||
}
|
||||
|
||||
const share = () => {
|
||||
modal.set({type: "person/share", $person})
|
||||
modal.push({type: "person/share", $person})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
import {toast, modal} from "src/partials/state"
|
||||
import {loadAppData} from "src/app/state"
|
||||
|
||||
let url = $modal.url
|
||||
export let url
|
||||
|
||||
const submit = async e => {
|
||||
e.preventDefault()
|
||||
@ -28,7 +28,7 @@
|
||||
return toast.show("error", "That isn't a valid websocket url")
|
||||
}
|
||||
|
||||
modal.set(null)
|
||||
modal.pop()
|
||||
|
||||
await user.addRelay(url)
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
<i class="fa fa-server fa-lg" />
|
||||
<h2 class="staatliches text-2xl">Your relays</h2>
|
||||
</div>
|
||||
<Anchor type="button-accent" on:click={() => modal.set({type: "relay/add"})}>
|
||||
<Anchor type="button-accent" on:click={() => modal.push({type: "relay/add"})}>
|
||||
<i class="fa-solid fa-plus" /> Add Relay
|
||||
</Anchor>
|
||||
</div>
|
||||
|
@ -11,5 +11,5 @@
|
||||
|
||||
<Content>
|
||||
<Heading class="text-center">{topic}</Heading>
|
||||
<Feed inModal {relays} {filter} />
|
||||
<Feed {relays} {filter} />
|
||||
</Content>
|
||||
|
@ -43,7 +43,7 @@
|
||||
return {selection, node, offset, word}
|
||||
}
|
||||
|
||||
const autocomplete = ({person, force = false}) => {
|
||||
const autocomplete = ({person = null, force = false} = {}) => {
|
||||
const {selection, node, offset, word} = getInfo()
|
||||
|
||||
const annotate = (prefix, text, value) => {
|
||||
@ -70,7 +70,7 @@
|
||||
}
|
||||
|
||||
// Mentions
|
||||
if ((force || word.length > 1) && word.startsWith("@")) {
|
||||
if ((force || word.length > 1) && word.startsWith("@") && person) {
|
||||
annotate("@", displayPerson(person).trim(), pubkeyEncoder.encode(person.pubkey))
|
||||
}
|
||||
|
||||
@ -102,6 +102,11 @@
|
||||
if (["Enter"].includes(e.code)) {
|
||||
autocomplete({person: suggestions.get()})
|
||||
}
|
||||
|
||||
// Only autocomplete topics on space
|
||||
if (["Space"].includes(e.code)) {
|
||||
autocomplete()
|
||||
}
|
||||
}
|
||||
|
||||
const onKeyUp = e => {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import {prop, fromPairs, last} from "ramda"
|
||||
import {prop, fromPairs} from "ramda"
|
||||
import {uuid, switcher} from "hurdak/lib/hurdak"
|
||||
import type {Writable} from "svelte/store"
|
||||
import {navigate} from "svelte-routing"
|
||||
import {writable, get} from "svelte/store"
|
||||
import {globalHistory} from "svelte-routing/src/history"
|
||||
import {sleep, synced} from "src/util/misc"
|
||||
import {sleep, synced, WritableList} from "src/util/misc"
|
||||
|
||||
// Location
|
||||
|
||||
@ -47,38 +47,32 @@ toast.show = (type, message, timeout = 5) => {
|
||||
export const openModals = writable(0)
|
||||
|
||||
export const modal = {
|
||||
history: [],
|
||||
set: data => {
|
||||
if (data) {
|
||||
modal.history.push(data)
|
||||
navigate(window.location.pathname + `#m=${modal.history.length - 1}`)
|
||||
} else {
|
||||
modal.history = []
|
||||
navigate(window.location.pathname)
|
||||
}
|
||||
stack: new WritableList([]),
|
||||
sync: $stack => {
|
||||
const hash = $stack.length > 0 ? `#m=${$stack.length}` : ""
|
||||
|
||||
navigate(window.location.pathname + hash)
|
||||
|
||||
return $stack
|
||||
},
|
||||
close: () => modal.set(null),
|
||||
push: data => modal.stack.update($stack => modal.sync($stack.concat(data))),
|
||||
pop: () => modal.stack.update($stack => modal.sync($stack.slice(0, -1))),
|
||||
clear: async () => {
|
||||
// Reverse history so the back button doesn't bring our modal back up
|
||||
while (get(modal)) {
|
||||
while (get(modal.stack)) {
|
||||
history.back()
|
||||
await sleep(30)
|
||||
await sleep(100)
|
||||
}
|
||||
},
|
||||
subscribe: cb => {
|
||||
cb(last(modal.history))
|
||||
|
||||
return location.subscribe($location => {
|
||||
const match = $location.hash.match(/\bm=(\d+)/)
|
||||
const i = match ? parseInt(match[1]) : null
|
||||
|
||||
modal.history.splice(i === null ? -1 : i + 1)
|
||||
|
||||
cb(modal.history[i])
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
location.subscribe($location => {
|
||||
const match = $location.hash.match(/\bm=(\d+)/)
|
||||
const i = match ? parseInt(match[1]) : 0
|
||||
|
||||
modal.stack.update($stack => (i < $stack.length ? $stack.slice(0, i) : $stack))
|
||||
})
|
||||
|
||||
// Themes
|
||||
|
||||
const parseTheme = s => fromPairs(s.split(",").map(x => x.split(":")))
|
||||
|
Loading…
Reference in New Issue
Block a user