Put state shared by ui components with those components

This commit is contained in:
Jonathan Staab 2023-04-12 14:16:21 -05:00
parent 69796ca4cd
commit 76b3479b7d
38 changed files with 142 additions and 134 deletions

View File

@ -7,7 +7,7 @@ import {getUserReadRelays} from "src/agent/relays"
import network from "src/agent/network"
import keys from "src/agent/keys"
import listener from "src/app/listener"
import {modal, toast} from "src/app/ui"
import {modal, toast} from "src/partials/state"
export const loadAppData = async pubkey => {
if (getUserReadRelays().length > 0) {

View File

@ -1,12 +1,7 @@
import Bugsnag from "@bugsnag/js"
import {prop, fromPairs, last} from "ramda"
import {uuid, switcher} from "hurdak/lib/hurdak"
import type {Writable} from "svelte/store"
import {navigate} from "svelte-routing"
import {nip19} from "nostr-tools"
import {writable, get} from "svelte/store"
import {globalHistory} from "svelte-routing/src/history"
import {sleep, synced, hash} from "src/util/misc"
import {writable} from "svelte/store"
import {hash} from "src/util/misc"
import {warn} from "src/util/logger"
import user from "src/agent/user"
@ -16,81 +11,10 @@ export const routes = {
person: (pubkey, tab = "notes") => `/people/${nip19.npubEncode(pubkey)}/${tab}`,
}
export const location = (() => {
const store = writable(window.location)
globalHistory.listen(({location}) => store.set(location))
return store
})()
// Install prompt
export const installPrompt = writable(null)
// Toast
export interface Toast<T> extends Writable<T> {
show(type: string, message: any, timeout?: number): void
}
export const toast = writable(null) as Toast<any>
toast.show = (type, message, timeout = 5) => {
const id = uuid()
toast.set({id, type, message})
if (timeout) {
setTimeout(() => {
if (prop("id", get(toast)) === id) {
toast.set(null)
}
}, timeout * 1000)
}
}
// Menu
export const menuIsOpen = writable(false)
// Modals
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)
}
},
close: () => modal.set(null),
clear: async () => {
// Reverse history so the back button doesn't bring our modal back up
while (get(modal)) {
history.back()
await sleep(30)
}
},
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])
})
},
}
// Redact long strings, especially hex and bech32 keys which are 64 and 63
// characters long, respectively. Put the threshold a little lower in case
// someone accidentally enters a key with the last few digits missing
@ -140,21 +64,3 @@ export const logUsage = async name => {
}
}
}
// Themes
const parseTheme = s => fromPairs(s.split(",").map(x => x.split(":")))
const THEME_LIGHT = parseTheme(import.meta.env.VITE_THEME_LIGHT)
const THEME_DARK = parseTheme(import.meta.env.VITE_THEME_DARK)
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches
export const theme = synced("ui/theme", prefersDark ? "dark" : "light")
export const getThemeColors = $theme => switcher($theme, {light: THEME_LIGHT, dark: THEME_DARK})
export const getThemeColor = ($theme, k) => prop(k, getThemeColors($theme))
export const getThemeVariables = $theme =>
Object.entries(getThemeColors($theme))
.map(([k, v]) => `--${k}: ${v};`)
.join("\n")

View File

@ -19,8 +19,8 @@
import * as db from "src/agent/db"
import user from "src/agent/user"
import {loadAppData} from "src/app"
import {theme, getThemeVariables} from "src/app/ui"
import {modal, openModals, logUsage} from "src/app/ui"
import {theme, getThemeVariables, modal, openModals} from "src/partials/state"
import {logUsage} from "src/app/ui"
import SideNav from "src/app2/SideNav.svelte"
import Routes from "src/app2/Routes.svelte"
import Toast from "src/app2/Toast.svelte"

View File

@ -1,7 +1,7 @@
<script lang="ts">
import {nip19} from "nostr-tools"
import user from "src/agent/user"
import {modal, location} from "src/app/ui"
import {modal, location} from "src/partials/state"
$: showCreateNote = $location.pathname.match(/messages|chat|relays$|keys|settings|logout$/)

View File

@ -1,5 +1,6 @@
<script lang="ts">
import {modal, menuIsOpen} from "src/app/ui"
import {menuIsOpen} from "src/app/ui"
import {modal} from "src/partials/state"
import Modal from "src/partials/Modal.svelte"
import Content from "src/partials/Content.svelte"
import Spinner from "src/partials/Spinner.svelte"

View File

@ -1,9 +1,10 @@
<script lang="ts">
import cx from "classnames"
import {displayPerson} from "src/util/nostr"
import {installPrompt} from "src/partials/state"
import user from "src/agent/user"
import pool from "src/agent/pool"
import {menuIsOpen, installPrompt, routes} from "src/app/ui"
import {routes, menuIsOpen} from "src/app/ui"
import {newNotifications, newDirectMessages, newChatMessages} from "src/app/listener"
import {slowConnections} from "src/app/connection"
import PersonCircle from "src/app2/shared/PersonCircle.svelte"

View File

@ -2,7 +2,7 @@
import cx from "classnames"
import {is} from "ramda"
import {fly} from "svelte/transition"
import {toast} from "src/app/ui"
import {toast} from "src/partials/state"
</script>
{#if $toast}

View File

@ -1,9 +1,9 @@
<script lang="ts">
import {onMount} from "svelte"
import {theme} from "src/partials/state"
import Anchor from "src/partials/Anchor.svelte"
import {menuIsOpen} from "src/app/ui"
import {newNotifications} from "src/app/listener"
import {theme} from "src/app/ui"
const toggleMenu = () => menuIsOpen.update(x => !x)
const toggleTheme = () => theme.update(t => (t === "dark" ? "light" : "dark"))

View File

@ -5,6 +5,7 @@
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"
@ -12,7 +13,6 @@
import Note from "src/app2/shared/Note.svelte"
import user from "src/agent/user"
import network from "src/agent/network"
import {modal} from "src/app/ui"
import {mergeParents} from "src/app"
export let filter

View File

@ -6,13 +6,13 @@
import {findRootId, findReplyId, displayPerson} from "src/util/nostr"
import {formatTimestamp} from "src/util/misc"
import {isMobile} from "src/util/html"
import {modal} from "src/partials/state"
import Popover from "src/partials/Popover.svelte"
import Anchor from "src/partials/Anchor.svelte"
import PersonCircle from "src/app2/shared/PersonCircle.svelte"
import PersonSummary from "src/app2/shared/PersonSummary.svelte"
import NoteReply from "src/app2/shared/NoteReply.svelte"
import NoteActions from "src/app2/shared/NoteActions.svelte"
import {modal} from "src/app/ui"
import Card from "src/partials/Card.svelte"
import user from "src/agent/user"
import {getRelaysForEventParent} from "src/agent/relays"

View File

@ -8,6 +8,7 @@
import {stringToHue, fetchJson, now, formatSats, hsl} from "src/util/misc"
import {displayRelay, isLike, displayPerson, processZaps} from "src/util/nostr"
import {quantify, first} from "hurdak/lib/hurdak"
import {toast, modal} from "src/partials/state"
import Popover from "src/partials/Popover.svelte"
import QRCode from "src/partials/QRCode.svelte"
import Content from "src/partials/Content.svelte"
@ -26,7 +27,6 @@
import user from "src/agent/user"
import keys from "src/agent/keys"
import cmd from "src/agent/cmd"
import {toast, modal} from "src/app/ui"
export let note
export let author

View File

@ -5,6 +5,7 @@
import {splice} from "hurdak/lib/hurdak"
import {warn} from "src/util/logger"
import {displayPerson, parseContent, Tags} from "src/util/nostr"
import {modal} from "src/partials/state"
import MediaSet from "src/partials/MediaSet.svelte"
import Card from "src/partials/Card.svelte"
import Spinner from "src/partials/Spinner.svelte"
@ -14,7 +15,7 @@
import user from "src/agent/user"
import network from "src/agent/network"
import {getPersonWithFallback} from "src/agent/db"
import {routes, modal} from "src/app/ui"
import {routes} from "src/app/ui"
export let note
export let maxLength = 700

View File

@ -4,6 +4,7 @@
import {without, pluck, uniq} from "ramda"
import {slide} from "svelte/transition"
import {Tags, displayPerson} from "src/util/nostr"
import {toast} from "src/partials/state"
import ImageInput from "src/partials/ImageInput.svelte"
import Media from "src/partials/Media.svelte"
import Compose from "src/partials/Compose.svelte"
@ -11,7 +12,6 @@
import {getEventPublishRelays} from "src/agent/relays"
import user from "src/agent/user"
import cmd from "src/agent/cmd"
import {toast} from "src/app/ui"
import {publishWithToast} from "src/app"
export let note

View File

@ -3,16 +3,16 @@
import {updateIn} from "hurdak/lib/hurdak"
import {now, formatTimestamp} from "src/util/misc"
import {toHex} from "src/util/nostr"
import {modal} from "src/partials/state"
import Channel from "src/partials/Channel.svelte"
import PersonBadge from "src/app2/shared/PersonBadge.svelte"
import Anchor from "src/partials/Anchor.svelte"
import PersonBadge from "src/app2/shared/PersonBadge.svelte"
import NoteContent from "src/app2/shared/NoteContent.svelte"
import user from "src/agent/user"
import {getRelaysForEventChildren, sampleRelays} from "src/agent/relays"
import network from "src/agent/network"
import {watch} from "src/agent/db"
import cmd from "src/agent/cmd"
import {modal} from "src/app/ui"
import {lastChecked} from "src/app/listener"
export let entity

View File

@ -7,10 +7,10 @@
import Content from "src/partials/Content.svelte"
import Textarea from "src/partials/Textarea.svelte"
import Button from "src/partials/Button.svelte"
import {toast, modal} from "src/partials/state"
import {getUserWriteRelays} from "src/agent/relays"
import {rooms} from "src/agent/db"
import cmd from "src/agent/cmd"
import {toast, modal} from "src/app/ui"
import {publishWithToast} from "src/app"
export let room = {name: null, id: null, about: null, picture: null}

View File

@ -8,7 +8,7 @@
import {watch} from "src/agent/db"
import network from "src/agent/network"
import {getUserReadRelays} from "src/agent/relays"
import {modal} from "src/app/ui"
import {modal} from "src/partials/state"
let q = ""
let search

View File

@ -1,11 +1,11 @@
<script lang="ts">
import {fly} from "svelte/transition"
import {navigate} from "svelte-routing"
import {modal} from "src/partials/state"
import Anchor from "src/partials/Anchor.svelte"
import Content from "src/partials/Content.svelte"
import Heading from "src/partials/Heading.svelte"
import user from "src/agent/user"
import {modal} from "src/app/ui"
import {login} from "src/app"
const nip07 = "https://github.com/nostr-protocol/nips/blob/master/07.md"

View File

@ -5,6 +5,7 @@
import {navigate} from "svelte-routing"
import {sleep, shuffle} from "src/util/misc"
import {isRelay, userKinds} from "src/util/nostr"
import {toast} from "src/partials/state"
import Content from "src/partials/Content.svelte"
import Spinner from "src/partials/Spinner.svelte"
import Input from "src/partials/Input.svelte"
@ -17,7 +18,6 @@
import user from "src/agent/user"
import pool from "src/agent/pool"
import {loadAppData} from "src/app"
import {toast} from "src/app/ui"
let modal = null
let customRelayUrl = null

View File

@ -1,11 +1,11 @@
<script lang="ts">
import {toHex} from "src/util/nostr"
import {toast} from "src/partials/state"
import Input from "src/partials/Input.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Content from "src/partials/Content.svelte"
import Heading from "src/partials/Heading.svelte"
import keys from "src/agent/keys"
import {toast} from "src/app/ui"
import {login} from "src/app"
let nsec = ""

View File

@ -5,7 +5,7 @@
import Content from "src/partials/Content.svelte"
import Heading from "src/partials/Heading.svelte"
import keys from "src/agent/keys"
import {toast} from "src/app/ui"
import {toast} from "src/partials/state"
import {login} from "src/app"
let npub = ""

View File

@ -20,7 +20,7 @@
import {getPersonWithFallback} from "src/agent/db"
import cmd from "src/agent/cmd"
import user from "src/agent/user"
import {toast, modal} from "src/app/ui"
import {toast, modal} from "src/partials/state"
import {publishWithToast} from "src/app"
export let pubkey = null

View File

@ -9,7 +9,7 @@
import NoteContent from "src/app2/shared/NoteContent.svelte"
import NotificationSection from "src/app2/views/NotificationSection.svelte"
import {getPersonWithFallback, userEvents} from "src/agent/db"
import {modal} from "src/app/ui"
import {modal} from "src/partials/state"
export let event

View File

@ -19,7 +19,7 @@
import user from "src/agent/user"
import keys from "src/agent/keys"
import {loadAppData} from "src/app"
import {modal} from "src/app/ui"
import {modal} from "src/partials/state"
export let stage

View File

@ -8,7 +8,7 @@
import PersonInfo from "src/app2/shared/PersonInfo.svelte"
import {getPersonWithFallback} from "src/agent/db"
import {watch} from "src/agent/db"
import {modal} from "src/app/ui"
import {modal} from "src/partials/state"
export let follows

View File

@ -2,7 +2,7 @@
import Anchor from "src/partials/Anchor.svelte"
import Heading from "src/partials/Heading.svelte"
import Content from "src/partials/Content.svelte"
import {modal} from "src/app/ui"
import {modal} from "src/partials/state"
const tutorialUrl = "https://nostr.com/"
const videoUrl = "https://dufflepud.us-southeast-1.linodeobjects.com/coracle_intro.mp4"

View File

@ -1,12 +1,12 @@
<script lang="ts">
import {nip19} from "nostr-tools"
import {copyToClipboard} from "src/util/html"
import {modal, toast} from "src/partials/state"
import Input from "src/partials/Input.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Heading from "src/partials/Heading.svelte"
import Content from "src/partials/Content.svelte"
import pool from "src/agent/pool"
import {modal, toast} from "src/app/ui"
export let privkey

View File

@ -1,13 +1,13 @@
<script lang="ts">
import {reject, always, pluck, propEq} from "ramda"
import {fuzzy} from "src/util/misc"
import {modal} from "src/partials/state"
import Input from "src/partials/Input.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Heading from "src/partials/Heading.svelte"
import Content from "src/partials/Content.svelte"
import RelayCard from "src/app2/shared/RelayCard.svelte"
import {watch} from "src/agent/db"
import {modal} from "src/app/ui"
export let relays

View File

@ -8,6 +8,7 @@
import {parseHex} from "src/util/html"
import {numberFmt} from "src/util/misc"
import {displayPerson, toHex} from "src/util/nostr"
import {modal, theme, getThemeColor} from "src/partials/state"
import Tabs from "src/partials/Tabs.svelte"
import Content from "src/partials/Content.svelte"
import OverflowMenu from "src/partials/OverflowMenu.svelte"
@ -20,7 +21,7 @@
import {sampleRelays, getPubkeyWriteRelays} from "src/agent/relays"
import network from "src/agent/network"
import {getPersonWithFallback, watch} from "src/agent/db"
import {routes, modal, theme, getThemeColor} from "src/app/ui"
import {routes} from "src/app/ui"
import PersonCircle from "src/app2/shared/PersonCircle.svelte"
import PersonAbout from "src/app2/shared/PersonAbout.svelte"

View File

@ -5,7 +5,7 @@
import Heading from "src/partials/Heading.svelte"
import Button from "src/partials/Button.svelte"
import user from "src/agent/user"
import {toast, modal} from "src/app/ui"
import {toast, modal} from "src/partials/state"
import {loadAppData} from "src/app"
let url = $modal.url

View File

@ -5,7 +5,7 @@
import RelaySearch from "src/app2/shared/RelaySearch.svelte"
import RelayCard from "src/app2/shared/RelayCard.svelte"
import user from "src/agent/user"
import {modal} from "src/app/ui"
import {modal} from "src/partials/state"
const {relays} = user

View File

@ -4,12 +4,12 @@
import {navigate} from "svelte-routing"
import {find} from "ramda"
import {nip05, nip19} from "nostr-tools"
import {toast} from "src/partials/state"
import Heading from "src/partials/Heading.svelte"
import Input from "src/partials/Input.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Spinner from "src/partials/Spinner.svelte"
import Content from "src/partials/Content.svelte"
import {toast} from "src/app/ui"
let video,
value,

View File

@ -10,7 +10,7 @@
import Toggle from "src/partials/Toggle.svelte"
import Heading from "src/partials/Heading.svelte"
import keys from "src/agent/keys"
import {toast} from "src/app/ui"
import {toast} from "src/partials/state"
const {pubkey, privkey} = keys
const nip07 = "https://github.com/nostr-protocol/nips/blob/master/07.md"

View File

@ -2,6 +2,7 @@
import {onMount} from "svelte"
import {fly} from "svelte/transition"
import {navigate} from "svelte-routing"
import {toast} from "src/partials/state"
import Toggle from "src/partials/Toggle.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Input from "src/partials/Input.svelte"
@ -10,7 +11,6 @@
import Heading from "src/partials/Heading.svelte"
import user from "src/agent/user"
import pool from "src/agent/pool"
import {toast} from "src/app/ui"
let values = {...user.getSettings()}

View File

@ -2,7 +2,7 @@ import "src/app.css"
import Bugsnag from "@bugsnag/js"
import App from "src/app2/App.svelte"
import {installPrompt} from "src/app/ui"
import {installPrompt} from "src/partials/state"
Bugsnag.start({
apiKey: "2ea412feabfe14dc9849c6f0b4fa7003",

View File

@ -1,6 +1,6 @@
<script lang="ts">
import {copyToClipboard} from "src/util/html"
import {toast} from "src/app/ui"
import {toast} from "src/partials/state"
export let label
export let value

View File

@ -1,7 +1,7 @@
<script>
import {onMount, onDestroy} from "svelte"
import {fly, fade} from "svelte/transition"
import {openModals} from "src/app/ui"
import {openModals} from "src/partials/state"
export let onEscape = null

View File

@ -3,7 +3,7 @@
import {onMount} from "svelte"
import Input from "src/partials/Input.svelte"
import {copyToClipboard} from "src/util/html"
import {toast} from "src/app/ui"
import {toast} from "src/partials/state"
export let code

98
src/partials/state.ts Normal file
View File

@ -0,0 +1,98 @@
import {prop, fromPairs, last} 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"
// Location
export const location = (() => {
const store = writable(window.location)
globalHistory.listen(({location}) => store.set(location))
return store
})()
// Install prompt
export const installPrompt = writable(null)
// Toast
export interface Toast<T> extends Writable<T> {
show(type: string, message: any, timeout?: number): void
}
export const toast = writable(null) as Toast<any>
toast.show = (type, message, timeout = 5) => {
const id = uuid()
toast.set({id, type, message})
if (timeout) {
setTimeout(() => {
if (prop("id", get(toast)) === id) {
toast.set(null)
}
}, timeout * 1000)
}
}
// Modals
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)
}
},
close: () => modal.set(null),
clear: async () => {
// Reverse history so the back button doesn't bring our modal back up
while (get(modal)) {
history.back()
await sleep(30)
}
},
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])
})
},
}
// Themes
const parseTheme = s => fromPairs(s.split(",").map(x => x.split(":")))
const THEME_LIGHT = parseTheme(import.meta.env.VITE_THEME_LIGHT)
const THEME_DARK = parseTheme(import.meta.env.VITE_THEME_DARK)
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches
export const theme = synced("ui/theme", prefersDark ? "dark" : "light")
export const getThemeColors = $theme => switcher($theme, {light: THEME_LIGHT, dark: THEME_DARK})
export const getThemeColor = ($theme, k) => prop(k, getThemeColors($theme))
export const getThemeVariables = $theme =>
Object.entries(getThemeColors($theme))
.map(([k, v]) => `--${k}: ${v};`)
.join("\n")