mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-18 19:23:40 +00:00
Manage modals with a mega modal model
This commit is contained in:
parent
dfb1916b02
commit
e43caba359
@ -19,7 +19,7 @@
|
||||
import * as db from "src/agent/db"
|
||||
import user from "src/agent/user"
|
||||
import {loadAppData} from "src/app/state"
|
||||
import {theme, getThemeVariables, modal, openModals} from "src/partials/state"
|
||||
import {theme, getThemeVariables, modal} from "src/partials/state"
|
||||
import {logUsage} from "src/app/state"
|
||||
import SideNav from "src/app/SideNav.svelte"
|
||||
import Routes from "src/app/Routes.svelte"
|
||||
@ -54,16 +54,11 @@
|
||||
onMount(() => {
|
||||
let scrollY
|
||||
|
||||
// Log modals
|
||||
// Log modals, keep scroll position on body, but don't allow scrolling
|
||||
const unsubModal = modal.stack.subscribe($stack => {
|
||||
if ($stack.length > 0) {
|
||||
logUsage(btoa(["modal", last($stack).type].join(":")))
|
||||
}
|
||||
})
|
||||
|
||||
// Keep scroll position on body, but don't allow scrolling
|
||||
const unsubOpenModals = openModals.subscribe(n => {
|
||||
if (n > 0) {
|
||||
// This is not idempotent, so don't duplicate it
|
||||
if (document.body.style.position !== "fixed") {
|
||||
scrollY = window.scrollY
|
||||
@ -71,9 +66,11 @@
|
||||
document.body.style.top = `-${scrollY}px`
|
||||
document.body.style.position = `fixed`
|
||||
}
|
||||
} else {
|
||||
} else if (scrollY) {
|
||||
document.body.setAttribute("style", "")
|
||||
window.scrollTo(0, scrollY)
|
||||
|
||||
scrollY = null
|
||||
}
|
||||
})
|
||||
|
||||
@ -94,7 +91,6 @@
|
||||
|
||||
return () => {
|
||||
unsubModal()
|
||||
unsubOpenModals()
|
||||
unsubHistory()
|
||||
}
|
||||
})
|
||||
|
@ -31,52 +31,54 @@
|
||||
</script>
|
||||
|
||||
{#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 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 m.type === "login/pubkey"}
|
||||
<LoginPubKey />
|
||||
{:else if m.type === "login/connect"}
|
||||
<LoginConnect />
|
||||
{:else if m.type === "person/feed"}
|
||||
<PersonFeed pubkey={m.pubkey} />
|
||||
{: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 m.type === "list/list"}
|
||||
<ListList />
|
||||
{:else if m.type === "list/select"}
|
||||
<ListSelect item={m.item} />
|
||||
{:else if m.type === "list/edit"}
|
||||
<ListEdit list={m.list} />
|
||||
{:else if m.type === "message"}
|
||||
<Content size="lg">
|
||||
<div class="text-center">{m.message}</div>
|
||||
{#if m.spinner}
|
||||
<Spinner delay={0} />
|
||||
{/if}
|
||||
</Content>
|
||||
{/if}
|
||||
</Modal>
|
||||
{#if !m.virtual}
|
||||
<Modal virtual={false} onEscape={m.noEscape || m !== last($stack) ? null : closeModal}>
|
||||
{#if m.type === "note/detail"}
|
||||
{#key m.note.id}
|
||||
<NoteDetail {...m} invertColors />
|
||||
{/key}
|
||||
{: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 m.type === "login/pubkey"}
|
||||
<LoginPubKey />
|
||||
{:else if m.type === "login/connect"}
|
||||
<LoginConnect />
|
||||
{:else if m.type === "person/feed"}
|
||||
<PersonFeed pubkey={m.pubkey} />
|
||||
{: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 m.type === "list/list"}
|
||||
<ListList />
|
||||
{:else if m.type === "list/select"}
|
||||
<ListSelect item={m.item} />
|
||||
{:else if m.type === "list/edit"}
|
||||
<ListEdit list={m.list} />
|
||||
{:else if m.type === "message"}
|
||||
<Content size="lg">
|
||||
<div class="text-center">{m.message}</div>
|
||||
{#if m.spinner}
|
||||
<Spinner delay={0} />
|
||||
{/if}
|
||||
</Content>
|
||||
{/if}
|
||||
</Modal>
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -2,7 +2,6 @@
|
||||
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"
|
||||
|
@ -10,7 +10,7 @@
|
||||
export let feedRelay
|
||||
export let notes
|
||||
|
||||
$: filteredNotes = notes.filter(n => n.seen_on.includes(feedRelay.url))
|
||||
$: filteredNotes = notes.filter(n => n.seen_on?.includes(feedRelay.url))
|
||||
</script>
|
||||
|
||||
<Content>
|
||||
|
@ -1,8 +1,9 @@
|
||||
<script>
|
||||
import {pluck, find} from "ramda"
|
||||
import {Tags, displayPerson, displayRelay} from "src/util/nostr"
|
||||
import {Tags, displayRelay} from "src/util/nostr"
|
||||
import {modal, toast} from "src/partials/state"
|
||||
import Heading from "src/partials/Heading.svelte"
|
||||
import PersonBadge from "src/app/shared/PersonBadge.svelte"
|
||||
import Content from "src/partials/Content.svelte"
|
||||
import Button from "src/partials/Button.svelte"
|
||||
import Input from "src/partials/Input.svelte"
|
||||
@ -22,10 +23,14 @@
|
||||
|
||||
const search = q => {
|
||||
if (q.startsWith("#")) {
|
||||
return $searchTopics(q).map(({name}) => ["t", name])
|
||||
return $searchTopics(q)
|
||||
.slice(0, 5)
|
||||
.map(({name}) => ["t", name])
|
||||
}
|
||||
|
||||
return $searchPeople(q).map(({pubkey}) => ["p", pubkey])
|
||||
return $searchPeople(q)
|
||||
.slice(0, 5)
|
||||
.map(({pubkey}) => ["p", pubkey])
|
||||
}
|
||||
|
||||
const _searchRelays = q => pluck("url", $searchRelays(q)).map(url => ["r", url])
|
||||
@ -63,9 +68,11 @@
|
||||
<MultiSelect {search} bind:value={values.params}>
|
||||
<div slot="item" let:item>
|
||||
{#if item[0] === "p"}
|
||||
{displayPerson(getPersonWithFallback(item[1]))}
|
||||
<div class="-my-1">
|
||||
<PersonBadge inert person={getPersonWithFallback(item[1])} />
|
||||
</div>
|
||||
{:else}
|
||||
#{item[1]}
|
||||
<strong>#{item[1]}</strong>
|
||||
{/if}
|
||||
</div>
|
||||
</MultiSelect>
|
||||
|
@ -1,18 +1,26 @@
|
||||
<script>
|
||||
import {randomId} from "hurdak/lib/hurdak"
|
||||
import {onMount, onDestroy} from "svelte"
|
||||
import {fly, fade} from "svelte/transition"
|
||||
import {openModals} from "src/partials/state"
|
||||
import {modal} from "src/partials/state"
|
||||
|
||||
export let virtual = true
|
||||
export let onEscape = null
|
||||
|
||||
let root, content
|
||||
|
||||
const id = randomId()
|
||||
|
||||
onMount(() => {
|
||||
openModals.update(n => n + 1)
|
||||
if (virtual) {
|
||||
modal.push({id, virtual: true})
|
||||
}
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
openModals.update(n => n - 1)
|
||||
if (virtual) {
|
||||
modal.remove(id)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
<div class="mt-2 flex flex-col rounded border border-solid border-gray-6" in:fly={{y: 20}}>
|
||||
{#each data as item, i}
|
||||
<button
|
||||
class="cursor-pointer border-l-2 border-solid border-black py-2 px-4 text-left text-white"
|
||||
class="cursor-pointer border-l-2 border-solid border-black py-2 px-4 text-left text-gray-1 hover:border-accent hover:bg-gray-7"
|
||||
class:bg-gray-8={index !== i}
|
||||
class:bg-gray-7={index === i}
|
||||
class:border-accent={index === i}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {prop, fromPairs} from "ramda"
|
||||
import {prop, whereEq, reject, last, fromPairs} from "ramda"
|
||||
import {uuid, switcher} from "hurdak/lib/hurdak"
|
||||
import type {Writable} from "svelte/store"
|
||||
import {navigate} from "svelte-routing"
|
||||
@ -44,15 +44,10 @@ toast.show = (type, message, timeout = 5) => {
|
||||
|
||||
// Modals
|
||||
|
||||
export const openModals = writable(0)
|
||||
|
||||
export const modal = {
|
||||
stack: new WritableList([]) as WritableList<any>,
|
||||
getCurrent() {
|
||||
const $stack = get(modal.stack)
|
||||
const $openModals = get(openModals)
|
||||
|
||||
return $stack[$openModals - 1]
|
||||
return last(get(modal.stack))
|
||||
},
|
||||
sync($stack, opts = {}) {
|
||||
const hash = $stack.length > 0 ? `#m=${$stack.length}` : ""
|
||||
@ -63,6 +58,9 @@ export const modal = {
|
||||
|
||||
return $stack
|
||||
},
|
||||
remove(id) {
|
||||
modal.stack.update($stack => modal.sync(reject(whereEq({id}), $stack)))
|
||||
},
|
||||
push(data) {
|
||||
modal.stack.update($stack => modal.sync($stack.concat(data)))
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user