forked from coracle/flotilla
Add themes page
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import {goto} from '$app/navigation'
|
||||
import {append, uniqBy, now} from '@welshman/lib'
|
||||
import {GROUPS, asDecryptedEvent, readList, editList, makeList, createList} from "@welshman/util"
|
||||
import {pushToast} from '@app/toast'
|
||||
import {pk, signer, repository, INDEXER_RELAYS} from '@app/base'
|
||||
import {splitGroupId, loadRelay, loadGroup, getWriteRelayUrls, loadRelaySelections, publish, ensurePlaintext} from '@app/state'
|
||||
|
||||
export type ModifyTags = (tags: string[][]) => string[][]
|
||||
|
||||
export const updateList = async (kind: number, modifyTags: ModifyTags) => {
|
||||
const $pk = pk.get()!
|
||||
const $signer = signer.get()!
|
||||
const [prev] = repository.query([{kinds: [kind], authors: [$pk]}])
|
||||
|
||||
// Preserve content instead of use encrypted tags because kind 3 content is used for
|
||||
// relay selections in many places. Content isn't supported for mutes or relays so this is ok
|
||||
const relays = [...INDEXER_RELAYS, ...getWriteRelayUrls(await loadRelaySelections($pk))]
|
||||
const encrypt = (content: string) => $signer.nip44.encrypt($pk, content)
|
||||
|
||||
let encryptable
|
||||
if (prev) {
|
||||
const content = await ensurePlaintext(prev)
|
||||
const list = readList(asDecryptedEvent(prev, {content}))
|
||||
const publicTags = modifyTags(list.publicTags)
|
||||
|
||||
encryptable = editList({...list, publicTags})
|
||||
} else {
|
||||
const list = makeList({kind})
|
||||
const publicTags = modifyTags(list.publicTags)
|
||||
|
||||
encryptable = createList({...list, publicTags})
|
||||
}
|
||||
|
||||
const template = await encryptable.reconcile(encrypt)
|
||||
const event = await $signer.sign({...template, created_at: now()})
|
||||
|
||||
await publish({event, relays})
|
||||
}
|
||||
|
||||
export const joinGroup = async (id: string) => {
|
||||
const [url, nom] = splitGroupId(id)
|
||||
const relay = await loadRelay(url)
|
||||
|
||||
if (!relay) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Sorry, we weren't able to find that relay."
|
||||
})
|
||||
}
|
||||
|
||||
if (!relay.supported_nips?.includes(29)) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Sorry, it looks like that relay doesn't support nostr spaces."
|
||||
})
|
||||
}
|
||||
|
||||
const group = await loadGroup(nom, [url])
|
||||
|
||||
if (!group) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Sorry, we weren't able to find that space."
|
||||
})
|
||||
}
|
||||
|
||||
await updateList(GROUPS, (tags: string[][]) => uniqBy(t => t.join(''), append(["group", nom, url], tags)))
|
||||
|
||||
goto(`/spaces/${nom}`)
|
||||
pushToast({
|
||||
message: "Welcome to the space!"
|
||||
})
|
||||
}
|
||||
@@ -52,7 +52,7 @@
|
||||
<div class="absolute z-nav-active ml-2 h-[144px] w-12 bg-base-300" style={`top: ${$activeOffset}px`} />
|
||||
<div class="flex h-full flex-col justify-between">
|
||||
<div>
|
||||
<PrimaryNavItem title={$userProfile?.name} on:click={gotoHome}>
|
||||
<PrimaryNavItem on:click={gotoHome}>
|
||||
<div class="!flex w-10 items-center justify-center rounded-full border border-solid border-base-300">
|
||||
{#if $userProfile?.picture}
|
||||
<img alt="" src={$userProfile.picture} />
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
</div>
|
||||
<div
|
||||
in:fly={{delay: 150}}
|
||||
class="text-stark-content flex items-center justify-between px-4 py-2 text-sm font-bold uppercase">
|
||||
class="flex items-center justify-between px-4 py-2 text-sm font-bold uppercase">
|
||||
Conversations
|
||||
<div class="cursor-pointer">
|
||||
<Icon icon="add-circle" class="bg-stark-content" />
|
||||
<Icon icon="add-circle" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -10,59 +10,24 @@
|
||||
import SpaceCreateFinish from '@app/components/SpaceCreateFinish.svelte'
|
||||
import {pushModal} from '@app/modal'
|
||||
import {pushToast} from '@app/toast'
|
||||
import {GROUP_DELIMITER, splitGroupId, loadRelay, loadGroup, updateList} from '@app/state'
|
||||
import {GROUP_DELIMITER, splitGroupId, loadRelay, loadGroup} from '@app/state'
|
||||
import {joinGroup} from '@app/commands'
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
const browse = () => goto("/browse", {state: {}})
|
||||
|
||||
const tryJoin = async () => {
|
||||
const [url, nom] = splitGroupId(id)
|
||||
|
||||
const info = await loadRelay(url)
|
||||
|
||||
if (!info) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Sorry, we weren't able to find that relay."
|
||||
})
|
||||
}
|
||||
|
||||
if (!info.supported_nips?.includes(29)) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Sorry, it looks like that relay doesn't support nostr spaces."
|
||||
})
|
||||
}
|
||||
|
||||
const group = await loadGroup(nom, [url])
|
||||
|
||||
if (!group) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Sorry, we weren't able to find that space."
|
||||
})
|
||||
}
|
||||
|
||||
await updateList(GROUPS, (tags: string[][]) => uniqBy(t => t.join(''), append(["group", nom, url], tags)))
|
||||
|
||||
goto(`/spaces/${nom}`)
|
||||
pushToast({
|
||||
message: "Welcome to the space!"
|
||||
})
|
||||
}
|
||||
|
||||
const join = async () => {
|
||||
loading = true
|
||||
|
||||
try {
|
||||
await tryJoin()
|
||||
await joinGroup(id)
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
let id = "wss://devrelay.highlighter.com'group628195"
|
||||
let id = ""
|
||||
let loading = false
|
||||
|
||||
$: linkIsValid = Boolean(id.match(/.+\..+'.+/))
|
||||
|
||||
+8
-34
@@ -5,8 +5,8 @@ import type {Maybe} from "@welshman/lib"
|
||||
import {uniq, uniqBy, groupBy, pushToMapKey, nthEq, batcher, postJson, stripProtocol, assoc, indexBy, now} from "@welshman/lib"
|
||||
import {getIdentifier, getRelayTags, getRelayTagValues, normalizeRelayUrl, getPubkeyTagValues, GROUP_META, PROFILE, RELAYS, FOLLOWS, MUTES, GROUPS, getGroupTags, readProfile, readList, asDecryptedEvent, editList, makeList, createList} from "@welshman/util"
|
||||
import type {Filter, SignedEvent, CustomEvent, PublishedProfile, PublishedList} from '@welshman/util'
|
||||
import type {SubscribeRequest} from '@welshman/net'
|
||||
import {publish, subscribe} from '@welshman/net'
|
||||
import type {SubscribeRequest, PublishRequest} from '@welshman/net'
|
||||
import {publish as basePublish, subscribe} from '@welshman/net'
|
||||
import {decrypt} from '@welshman/signer'
|
||||
import {deriveEvents, deriveEventsMapped, getter, withGetter} from "@welshman/store"
|
||||
import {parseJson, createSearch} from '@lib/util'
|
||||
@@ -68,6 +68,12 @@ export const createCollection = <T>({
|
||||
return {indexStore, getIndex, deriveItem, loadItem, getItem}
|
||||
}
|
||||
|
||||
export const publish = (request: PublishRequest) => {
|
||||
repository.publish(request.event)
|
||||
|
||||
return basePublish(request)
|
||||
}
|
||||
|
||||
export const load = (request: SubscribeRequest) =>
|
||||
new Promise<Maybe<CustomEvent>>(resolve => {
|
||||
const sub = subscribe({closeOnEose: true, timeout: 3000, delay: 50, ...request})
|
||||
@@ -81,38 +87,6 @@ export const load = (request: SubscribeRequest) =>
|
||||
sub.emitter.on('complete', () => resolve(undefined))
|
||||
})
|
||||
|
||||
export type ModifyTags = (tags: string[][]) => string[][]
|
||||
|
||||
export const updateList = async (kind: number, modifyTags: ModifyTags) => {
|
||||
const $pk = pk.get()!
|
||||
const $signer = signer.get()!
|
||||
const [prev] = repository.query([{kinds: [kind], authors: [$pk]}])
|
||||
|
||||
// Preserve content instead of use encrypted tags because kind 3 content is used for
|
||||
// relay selections in many places. Content isn't supported for mutes or relays so this is ok
|
||||
const relays = [...INDEXER_RELAYS, ...getWriteRelayUrls(await loadRelaySelections($pk))]
|
||||
const encrypt = (content: string) => $signer.nip44.encrypt($pk, content)
|
||||
|
||||
let encryptable
|
||||
if (prev) {
|
||||
const content = await ensurePlaintext(prev)
|
||||
const list = readList(asDecryptedEvent(prev, {content}))
|
||||
const publicTags = modifyTags(list.publicTags)
|
||||
|
||||
encryptable = editList({...list, publicTags})
|
||||
} else {
|
||||
const list = makeList({kind})
|
||||
const publicTags = modifyTags(list.publicTags)
|
||||
|
||||
encryptable = createList({...list, publicTags})
|
||||
}
|
||||
|
||||
const template = await encryptable.reconcile(encrypt)
|
||||
const event = await $signer.sign({...template, created_at: now()})
|
||||
|
||||
await publish({event, relays})
|
||||
}
|
||||
|
||||
// Freshness
|
||||
|
||||
export const freshness = withGetter(writable<Record<string, number>>({}))
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import {synced} from '@lib/util'
|
||||
|
||||
export const theme = synced<string>("theme", "dark")
|
||||
Reference in New Issue
Block a user