This commit is contained in:
Jon Staab
2024-10-17 16:03:50 -07:00
parent 2f561149fa
commit fd5b0a9af3
33 changed files with 129 additions and 140 deletions
+11 -4
View File
@@ -45,7 +45,14 @@ import {
nip44EncryptToSelf, nip44EncryptToSelf,
loadRelay, loadRelay,
} from "@welshman/app" } from "@welshman/app"
import {tagRoom, userMembership, MEMBERSHIPS, INDEXER_RELAYS, loadMembership, loadSettings} from "@app/state" import {
tagRoom,
userMembership,
MEMBERSHIPS,
INDEXER_RELAYS,
loadMembership,
loadSettings,
} from "@app/state"
// Utils // Utils
@@ -98,7 +105,7 @@ export const loadUserData = (
await sleep(300) await sleep(300)
for (const pubkey of pubkeys) { for (const pubkey of pubkeys) {
loadMembership(pubkey), loadMembership(pubkey)
loadProfile(pubkey) loadProfile(pubkey)
loadFollows(pubkey) loadFollows(pubkey)
loadMutes(pubkey) loadMutes(pubkey)
@@ -284,9 +291,9 @@ export const sendWrapped = async ({
event: await nip59.wrap(recipient, stamp(template)), event: await nip59.wrap(recipient, stamp(template)),
relays: ctx.app.router.PublishMessage(recipient).getUrls(), relays: ctx.app.router.PublishMessage(recipient).getUrls(),
delay, delay,
}) }),
), ),
) ),
) )
} }
+12 -14
View File
@@ -1,18 +1,13 @@
<script lang="ts"> <script lang="ts">
import {readable, derived} from "svelte/store" import {readable} from "svelte/store"
import {hash, sleep, ellipsize, uniqBy, groupBy, now} from "@welshman/lib" import {hash, ellipsize, uniqBy, groupBy} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {deriveEvents, throttled} from "@welshman/store" import {deriveEvents} from "@welshman/store"
import { import {deriveProfile, deriveProfileDisplay, formatTimestampAsTime, pubkey} from "@welshman/app"
deriveProfile,
deriveProfileDisplay,
formatTimestampAsTime,
pubkey,
} from "@welshman/app"
import type {Thunk} from "@welshman/app" import type {Thunk} from "@welshman/app"
import {REACTION, ZAP_RESPONSE, displayRelayUrl} from "@welshman/util" import {REACTION, ZAP_RESPONSE} from "@welshman/util"
import {repository} from "@welshman/app" import {repository} from "@welshman/app"
import {slideAndFade, conditionalTransition} from '@lib/transition' import {slideAndFade, conditionalTransition} from "@lib/transition"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Delay from "@lib/components/Delay.svelte" import Delay from "@lib/components/Delay.svelte"
import Avatar from "@lib/components/Avatar.svelte" import Avatar from "@lib/components/Avatar.svelte"
@@ -42,7 +37,7 @@
const rootId = rootTag?.[1] const rootId = rootTag?.[1]
const rootHints = [rootTag?.[2]].filter(Boolean) as string[] const rootHints = [rootTag?.[2]].filter(Boolean) as string[]
const rootEvent = rootId ? deriveEvent(rootId, rootHints) : readable(null) const rootEvent = rootId ? deriveEvent(rootId, rootHints) : readable(null)
const [colorName, colorValue] = colors[parseInt(hash(event.pubkey)) % colors.length] const [_, colorValue] = colors[parseInt(hash(event.pubkey)) % colors.length]
const transition = conditionalTransition(thunk, slideAndFade) const transition = conditionalTransition(thunk, slideAndFade)
@@ -95,7 +90,10 @@
<div class="flex w-full gap-3"> <div class="flex w-full gap-3">
{#if showPubkey} {#if showPubkey}
<Button on:click={showProfile}> <Button on:click={showProfile}>
<Avatar src={$profile?.picture} class="border border-solid border-base-content" size={10} /> <Avatar
src={$profile?.picture}
class="border border-solid border-base-content"
size={10} />
</Button> </Button>
{:else} {:else}
<div class="w-10 min-w-10 max-w-10" /> <div class="w-10 min-w-10 max-w-10" />
@@ -103,7 +101,7 @@
<div class="-mt-1 flex-grow pr-1"> <div class="-mt-1 flex-grow pr-1">
{#if showPubkey} {#if showPubkey}
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Button class="font-bold text-sm" style="color: {colorValue}" on:click={showProfile}> <Button class="text-sm font-bold" style="color: {colorValue}" on:click={showProfile}>
{$profileDisplay} {$profileDisplay}
</Button> </Button>
<span class="text-xs opacity-50">{formatTimestampAsTime(event.created_at)}</span> <span class="text-xs opacity-50">{formatTimestampAsTime(event.created_at)}</span>
+4 -4
View File
@@ -1,11 +1,11 @@
<script lang="ts"> <script lang="ts">
import {pubkey} from '@welshman/app' import {pubkey} from "@welshman/app"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Confirm from "@lib/components/Confirm.svelte" import Confirm from "@lib/components/Confirm.svelte"
import EventInfo from "@app/components/EventInfo.svelte" import EventInfo from "@app/components/EventInfo.svelte"
import {publishDelete} from '@app/commands' import {publishDelete} from "@app/commands"
import {pushModal} from '@app/modal' import {pushModal} from "@app/modal"
export let url export let url
export let event export let event
@@ -33,7 +33,7 @@
} }
</script> </script>
<ul class="menu rounded-box bg-base-100 p-2 shadow-xl whitespace-nowrap"> <ul class="menu whitespace-nowrap rounded-box bg-base-100 p-2 shadow-xl">
<li> <li>
<Button on:click={showInfo}> <Button on:click={showInfo}>
<Icon size={4} icon="code-2" /> <Icon size={4} icon="code-2" />
@@ -5,8 +5,6 @@
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import ChannelMessageMenu from "@app/components/ChannelMessageMenu.svelte" import ChannelMessageMenu from "@app/components/ChannelMessageMenu.svelte"
import {tagRoom} from "@app/state"
import {publishReaction} from "@app/commands"
export let url, room, event export let url, room, event
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {writable} from 'svelte/store' import {writable} from "svelte/store"
import {assoc, sortBy, append} from "@welshman/lib" import {assoc, sortBy, append} from "@welshman/lib"
import {createEvent} from "@welshman/util" import {createEvent} from "@welshman/util"
import type {EventContent, TrustedEvent} from "@welshman/util" import type {EventContent, TrustedEvent} from "@welshman/util"
+5 -12
View File
@@ -1,21 +1,14 @@
<script lang="ts"> <script lang="ts">
import {derived} from "svelte/store"
import {type Instance} from "tippy.js" import {type Instance} from "tippy.js"
import {hash, sleep, uniqBy, groupBy, now} from "@welshman/lib" import {hash, uniqBy, groupBy} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {deriveEvents, throttled} from "@welshman/store" import {deriveEvents} from "@welshman/store"
import { import {deriveProfile, deriveProfileDisplay, formatTimestampAsTime, pubkey} from "@welshman/app"
deriveProfile,
deriveProfileDisplay,
formatTimestampAsTime,
pubkey,
} from "@welshman/app"
import type {MergedThunk} from "@welshman/app" import type {MergedThunk} from "@welshman/app"
import {REACTION, ZAP_RESPONSE, displayRelayUrl} from "@welshman/util" import {REACTION, ZAP_RESPONSE} from "@welshman/util"
import {repository} from "@welshman/app" import {repository} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import Delay from "@lib/components/Delay.svelte"
import Avatar from "@lib/components/Avatar.svelte" import Avatar from "@lib/components/Avatar.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Content from "@app/components/Content.svelte" import Content from "@app/components/Content.svelte"
@@ -95,7 +88,7 @@
<div class="-mt-1 flex-grow pr-1"> <div class="-mt-1 flex-grow pr-1">
{#if showPubkey} {#if showPubkey}
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Button class="font-bold text-sm" style="color: {colorValue}" on:click={showProfile}> <Button class="text-sm font-bold" style="color: {colorValue}" on:click={showProfile}>
{$profileDisplay} {$profileDisplay}
</Button> </Button>
<span class="text-xs opacity-50">{formatTimestampAsTime(event.created_at)}</span> <span class="text-xs opacity-50">{formatTimestampAsTime(event.created_at)}</span>
@@ -1,10 +1,8 @@
<script lang="ts"> <script lang="ts">
import {type Instance} from "tippy.js" import {type Instance} from "tippy.js"
import type {NativeEmoji} from "emoji-picker-element/shared" import type {NativeEmoji} from "emoji-picker-element/shared"
import {ctx, uniq, between} from "@welshman/lib" import {between} from "@welshman/lib"
import {Nip59} from "@welshman/signer"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
import {signer, publishThunk} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
+1 -2
View File
@@ -70,8 +70,7 @@
} }
let warning = let warning =
$userSettings?.values.hide_sensitive && $userSettings?.values.hide_sensitive && event.tags.find(nthEq(0, "content-warning"))?.[1]
event.tags.find(nthEq(0, "content-warning"))?.[1]
$: shortContent = showEntire $: shortContent = showEntire
? fullContent ? fullContent
+2 -3
View File
@@ -1,10 +1,9 @@
<script lang="ts"> <script lang="ts">
import {ellipsize, postJson} from "@welshman/lib" import {ellipsize, postJson} from "@welshman/lib"
import {fade} from '@lib/transition'
import {dufflepud, imgproxy} from "@app/state" import {dufflepud, imgproxy} from "@app/state"
import Link from "@lib/components/Link.svelte" import Link from "@lib/components/Link.svelte"
import ContentLinkDetail from '@app/components/ContentLinkDetail.svelte' import ContentLinkDetail from "@app/components/ContentLinkDetail.svelte"
import {pushModal} from '@app/modal' import {pushModal} from "@app/modal"
export let value export let value
+3 -3
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import Button from '@lib/components/Button.svelte' import Button from "@lib/components/Button.svelte"
import {imgproxy} from "@app/state" import {imgproxy} from "@app/state"
export let url export let url
@@ -7,6 +7,6 @@
const back = () => history.back() const back = () => history.back()
</script> </script>
<Button class="m-auto h-screen w-screen p-4 cursor-pointer" on:click={back}> <Button class="m-auto h-screen w-screen cursor-pointer p-4" on:click={back}>
<img alt="" src={imgproxy(url)} class="m-auto rounded-box max-w-full max-h-full" /> <img alt="" src={imgproxy(url)} class="m-auto max-h-full max-w-full rounded-box" />
</Button> </Button>
+2 -2
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {nip19} from 'nostr-tools' import {nip19} from "nostr-tools"
import {getPubkey} from "@welshman/signer" import {getPubkey} from "@welshman/signer"
import {addSession} from "@welshman/app" import {addSession} from "@welshman/app"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
@@ -18,7 +18,7 @@
const onSubmit = async () => { const onSubmit = async () => {
let secret = key let secret = key
if (secret.startsWith('nsec')) { if (secret.startsWith("nsec")) {
secret = nip19.decode(secret).data as string secret = nip19.decode(secret).data as string
} }
+2 -2
View File
@@ -24,10 +24,10 @@
<div class="flex flex-col gap-2 {$$props.class}"> <div class="flex flex-col gap-2 {$$props.class}">
{#if muted} {#if muted}
<div class="flex justify-between items-center"> <div class="flex items-center justify-between">
<div class="row-2 relative"> <div class="row-2 relative">
<Icon icon="danger" class="mt-1" /> <Icon icon="danger" class="mt-1" />
<p>You have muted this person.<p> <p>You have muted this person.</p>
</div> </div>
<Button class="link ml-8" on:click={ignoreMute}>Show anyway</Button> <Button class="link ml-8" on:click={ignoreMute}>Show anyway</Button>
</div> </div>
+1 -1
View File
@@ -33,7 +33,7 @@
<Icon icon="magnifer" /> <Icon icon="magnifer" />
<input bind:value={term} class="grow" type="text" placeholder="Search for relays..." /> <input bind:value={term} class="grow" type="text" placeholder="Search for relays..." />
</label> </label>
<div class="column -m-6 mt-0 p-6 pt-2 h-[50vh] gap-2 overflow-auto" bind:this={element}> <div class="column -m-6 mt-0 h-[50vh] gap-2 overflow-auto p-6 pt-2" bind:this={element}>
{#each $relaySearch {#each $relaySearch
.searchValues(term) .searchValues(term)
.filter(url => !$relays.includes(url)) .filter(url => !$relays.includes(url))
+3 -5
View File
@@ -1,17 +1,15 @@
<script lang="ts"> <script lang="ts">
import {nip19} from 'nostr-tools' import {nip19} from "nostr-tools"
import {goto} from '$app/navigation' import {goto} from "$app/navigation"
import {hexToBytes} from '@noble/hashes/utils' import {hexToBytes} from "@noble/hashes/utils"
import {getPubkey, makeSecret} from "@welshman/signer" import {getPubkey, makeSecret} from "@welshman/signer"
import {addSession} from "@welshman/app" import {addSession} from "@welshman/app"
import Spinner from "@lib/components/Spinner.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Field from "@lib/components/Field.svelte" import Field from "@lib/components/Field.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte"
import InfoKeys from "@app/components/InfoKeys.svelte" import InfoKeys from "@app/components/InfoKeys.svelte"
import {loadUserData} from "@app/commands"
import {pushModal, clearModals} from "@app/modal" import {pushModal, clearModals} from "@app/modal"
import {clip} from "@app/toast" import {clip} from "@app/toast"
+7 -12
View File
@@ -1,19 +1,16 @@
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte' import {onMount} from "svelte"
import {goto} from "$app/navigation"
import {sleep, identity, nthEq} from "@welshman/lib" import {sleep, identity, nthEq} from "@welshman/lib"
import {load} from "@welshman/app" import {load} from "@welshman/app"
import {displayRelayUrl, AUTH_INVITE} from "@welshman/util" import {displayRelayUrl, AUTH_INVITE} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util" import {slide} from "@lib/transition"
import {slide} from '@lib/transition'
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import Field from "@lib/components/Field.svelte" import Field from "@lib/components/Field.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte"
import {pushModal} from '@app/modal' import {clip} from "@app/toast"
import {clip} from '@app/toast'
export let url export let url
@@ -32,16 +29,14 @@
sleep(2000), sleep(2000),
]) ])
claim = event?.tags.find(nthEq(0, 'claim'))?.[1] || "" claim = event?.tags.find(nthEq(0, "claim"))?.[1] || ""
loading = false loading = false
}) })
</script> </script>
<div class="col-4"> <div class="col-4">
<ModalHeader> <ModalHeader>
<div slot="title"> <div slot="title">Create an Invite</div>
Create an Invite
</div>
<div slot="info"> <div slot="info">
Get a link that you can use to invite people to Get a link that you can use to invite people to
<span class="text-primary">{displayRelayUrl(url)}</span> <span class="text-primary">{displayRelayUrl(url)}</span>
@@ -65,8 +60,8 @@
<p slot="info"> <p slot="info">
This invite link can be used by clicking "Add Space" and pasting it there. This invite link can be used by clicking "Add Space" and pasting it there.
{#if !claim} {#if !claim}
This space did not issue a claim for this link, so additional steps might be This space did not issue a claim for this link, so additional steps might be required
required for people using this invite link. for people using this invite link.
{/if} {/if}
</p> </p>
</Field> </Field>
+6 -7
View File
@@ -1,17 +1,16 @@
<script lang="ts"> <script lang="ts">
import {displayRelayUrl} from "@welshman/util"
import {PublishStatus} from "@welshman/net" import {PublishStatus} from "@welshman/net"
import {mergeThunks, publishThunk} from "@welshman/app" import {mergeThunks, publishThunk} from "@welshman/app"
import type {Thunk, MergedThunk} from "@welshman/app" import type {Thunk, MergedThunk} from "@welshman/app"
import {throttled} from "@welshman/store" import {throttled} from "@welshman/store"
import Icon from '@lib/components/Icon.svelte' import Icon from "@lib/components/Icon.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import Button from '@lib/components/Button.svelte' import Button from "@lib/components/Button.svelte"
import ThunkStatusDetail from '@app/components/ThunkStatusDetail.svelte' import ThunkStatusDetail from "@app/components/ThunkStatusDetail.svelte"
export let thunk: Thunk | MergedThunk export let thunk: Thunk | MergedThunk
const {Pending, Success, Failure, Timeout} = PublishStatus const {Pending, Failure, Timeout} = PublishStatus
const abort = () => thunk.controller.abort() const abort = () => thunk.controller.abort()
@@ -30,7 +29,7 @@
</script> </script>
{#if canCancel || isPending} {#if canCancel || isPending}
<span class="flex gap-1 mt-2 items-center"> <span class="mt-2 flex items-center gap-1">
<span class="loading loading-spinner mx-1 h-3 w-3 translate-y-px" /> <span class="loading loading-spinner mx-1 h-3 w-3 translate-y-px" />
<span class="opacity-50">Sending...</span> <span class="opacity-50">Sending...</span>
{#if canCancel} {#if canCancel}
@@ -43,7 +42,7 @@
component={ThunkStatusDetail} component={ThunkStatusDetail}
props={{url, message, status, retry}} props={{url, message, status, retry}}
params={{interactive: true}}> params={{interactive: true}}>
<span class="flex tooltip cursor-pointer gap-1 mt-2 items-center"> <span class="tooltip mt-2 flex cursor-pointer items-center gap-1">
<Icon icon="danger" size={3} /> <Icon icon="danger" size={3} />
<span class="opacity-50">Failed to send!</span> <span class="opacity-50">Failed to send!</span>
</span> </span>
+3 -3
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import {PublishStatus} from '@welshman/net' import {PublishStatus} from "@welshman/net"
import {displayRelayUrl} from '@welshman/util' import {displayRelayUrl} from "@welshman/util"
import Button from '@lib/components/Button.svelte' import Button from "@lib/components/Button.svelte"
export let url: string export let url: string
export let status: string export let status: string
+7 -12
View File
@@ -11,7 +11,6 @@ import {
uniq, uniq,
partition, partition,
nth, nth,
max,
pushToMapKey, pushToMapKey,
nthEq, nthEq,
shuffle, shuffle,
@@ -20,12 +19,10 @@ import {
import { import {
getIdFilters, getIdFilters,
WRAP, WRAP,
RELAYS,
REACTION, REACTION,
ZAP_RESPONSE, ZAP_RESPONSE,
DIRECT_MESSAGE, DIRECT_MESSAGE,
getRelayTagValues, getRelayTagValues,
isShareableRelayUrl,
getPubkeyTagValues, getPubkeyTagValues,
isHashedEvent, isHashedEvent,
displayProfile, displayProfile,
@@ -41,9 +38,7 @@ import {
pubkey, pubkey,
repository, repository,
load, load,
subscribe,
collection, collection,
loadRelay,
profilesByPubkey, profilesByPubkey,
getDefaultAppContext, getDefaultAppContext,
getDefaultNetContext, getDefaultNetContext,
@@ -180,7 +175,7 @@ export const pullConservatively = ({relays, filters}: AppSyncOpts) => {
const events = sortBy(e => -e.created_at, repository.query(filters)) const events = sortBy(e => -e.created_at, repository.query(filters))
if (events.length > 100) { if (events.length > 100) {
filters = filters.map(assoc('since', events[100]!.created_at)) filters = filters.map(assoc("since", events[100]!.created_at))
} }
promises.push(pull({relays: dumb, filters})) promises.push(pull({relays: dumb, filters}))
@@ -247,10 +242,10 @@ export const deriveEventsForUrl = (url: string, kinds: number[]) =>
export const SETTINGS = 38489 export const SETTINGS = 38489
export type Settings = { export type Settings = {
event: TrustedEvent, event: TrustedEvent
values: { values: {
hide_sensitive: boolean hide_sensitive: boolean
}, }
} }
export const defaultSettings = { export const defaultSettings = {
@@ -260,8 +255,10 @@ export const defaultSettings = {
export const settings = deriveEventsMapped<Settings>(repository, { export const settings = deriveEventsMapped<Settings>(repository, {
filters: [{kinds: [SETTINGS]}], filters: [{kinds: [SETTINGS]}],
itemToEvent: item => item.event, itemToEvent: item => item.event,
eventToItem: async (event: TrustedEvent) => eventToItem: async (event: TrustedEvent) => ({
({event, values: {...defaultSettings, ...parseJson(await ensurePlaintext(event))}}) event,
values: {...defaultSettings, ...parseJson(await ensurePlaintext(event))},
}),
}) })
export const { export const {
@@ -276,8 +273,6 @@ export const {
load({...request, filters: [{kinds: [SETTINGS], authors: [pubkey]}]}), load({...request, filters: [{kinds: [SETTINGS], authors: [pubkey]}]}),
}) })
// Membership // Membership
export const getMembershipUrls = (list?: List) => sort(getRelayTagValues(getListTags(list))) export const getMembershipUrls = (list?: List) => sort(getRelayTagValues(getListTags(list)))
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {sleep} from '@welshman/lib' import {sleep} from "@welshman/lib"
export let delay = 1 export let delay = 1
</script> </script>
+4 -3
View File
@@ -1,11 +1,12 @@
<script lang="ts"> <script lang="ts">
import {noop} from '@welshman/lib' import {noop} from "@welshman/lib"
import {fade, fly} from "@lib/transition" import {fade, fly} from "@lib/transition"
export let onClose: any = noop export let onClose: any = noop
export let fullscreen = false export let fullscreen = false
$: extraClass = !fullscreen && "card2 bg-alt max-h-[90vh] w-[90vw] overflow-auto text-base-content sm:w-[520px]" $: extraClass =
!fullscreen && "card2 bg-alt max-h-[90vh] w-[90vw] overflow-auto text-base-content sm:w-[520px]"
</script> </script>
<div class="center fixed inset-0 z-modal"> <div class="center fixed inset-0 z-modal">
@@ -13,7 +14,7 @@
class="absolute inset-0 cursor-pointer bg-black opacity-75" class="absolute inset-0 cursor-pointer bg-black opacity-75"
transition:fade={{duration: 300}} transition:fade={{duration: 300}}
on:click={onClose} /> on:click={onClose} />
<div class="relative scroll-container {extraClass}" transition:fly={{duration: 300}}> <div class="scroll-container relative {extraClass}" transition:fly={{duration: 300}}>
<slot /> <slot />
</div> </div>
</div> </div>
+1 -1
View File
@@ -1,3 +1,3 @@
<div class="max-h-screen flex-grow overflow-auto bg-base-200 pb-14 sm:pb-0 scroll-container"> <div class="scroll-container max-h-screen flex-grow overflow-auto bg-base-200 pb-14 sm:pb-0">
<slot /> <slot />
</div> </div>
+1 -1
View File
@@ -22,7 +22,7 @@
popover = tippy(element, { popover = tippy(element, {
content: target, content: target,
animation: "shift-away", animation: "shift-away",
appendTo: document.querySelector('.tippy-target')!, appendTo: document.querySelector(".tippy-target")!,
...params, ...params,
}) })
-2
View File
@@ -10,8 +10,6 @@
} from "@welshman/app" } from "@welshman/app"
import Avatar from "@lib/components/Avatar.svelte" import Avatar from "@lib/components/Avatar.svelte"
import WotScore from "@lib/components/WotScore.svelte" import WotScore from "@lib/components/WotScore.svelte"
import ProfileDetail from "@app/components/ProfileDetail.svelte"
import {pushDrawer} from "@app/modal"
export let value export let value
+1 -1
View File
@@ -34,7 +34,7 @@ export const createScroller = ({
let done = false let done = false
const check = async () => { const check = async () => {
const container = element.closest('.scroll-container') const container = element.closest(".scroll-container")
if (container) { if (container) {
// While we have empty space, fill it // While we have empty space, fill it
+7 -6
View File
@@ -9,8 +9,8 @@ export const fly = (node: Element, params?: FlyParams | undefined) =>
baseFly(node, {y: 20, ...params}) baseFly(node, {y: 20, ...params})
export type TranslateParams = { export type TranslateParams = {
delay?: number, delay?: number
duration?: number, duration?: number
easing?: (t: number) => number easing?: (t: number) => number
axis?: "x" | "y" axis?: "x" | "y"
reverse?: boolean reverse?: boolean
@@ -18,7 +18,7 @@ export type TranslateParams = {
export const translate = ( export const translate = (
node: Element, node: Element,
{delay = 0, duration = 400, easing = cubicOut, axis = "y", reverse = false}: TranslateParams = {} {delay = 0, duration = 400, easing = cubicOut, axis = "y", reverse = false}: TranslateParams = {},
) => { ) => {
return { return {
delay, delay,
@@ -32,7 +32,7 @@ export const translate = (
} else { } else {
return `transform: translateY(${p})` return `transform: translateY(${p})`
} }
} },
} }
} }
@@ -75,5 +75,6 @@ export function slideAndFade(
} }
} }
export const conditionalTransition = (condition: any, transition: any) => export const conditionalTransition =
(node: any, args?: any) => condition ? transtion(node, args) : null (condition: any, transition: any) => (node: any, args?: any) =>
condition ? transtion(node, args) : null
+20 -17
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import {derived} from 'svelte/store' import {derived} from "svelte/store"
import {addToMapKey, dec, gt, inc} from "@welshman/lib" import {addToMapKey, dec, gt} from "@welshman/lib"
import type {Relay} from "@welshman/app" import type {Relay} from "@welshman/app"
import {relays, createSearch, relaySelections} from "@welshman/app" import {relays, createSearch, relaySelections} from "@welshman/app"
import {createScroller} from "@lib/html" import {createScroller} from "@lib/html"
@@ -12,24 +12,27 @@
import RelayDescription from "@app/components/RelayDescription.svelte" import RelayDescription from "@app/components/RelayDescription.svelte"
import SpaceCheck from "@app/components/SpaceCheck.svelte" import SpaceCheck from "@app/components/SpaceCheck.svelte"
import ProfileCircles from "@app/components/ProfileCircles.svelte" import ProfileCircles from "@app/components/ProfileCircles.svelte"
import {userMembership, memberships, membershipByPubkey, getMembershipUrls, getDefaultPubkeys} from "@app/state" import {
userMembership,
memberships,
membershipByPubkey,
getMembershipUrls,
getDefaultPubkeys,
} from "@app/state"
import {discoverRelays} from "@app/commands" import {discoverRelays} from "@app/commands"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
const wotGraph = derived( const wotGraph = derived(membershipByPubkey, $m => {
membershipByPubkey, const scores = new Map<string, Set<string>>()
$m => {
const scores = new Map<string, Set<string>>()
for (const pubkey of getDefaultPubkeys()) { for (const pubkey of getDefaultPubkeys()) {
for (const url of getMembershipUrls($m.get(pubkey))) { for (const url of getMembershipUrls($m.get(pubkey))) {
addToMapKey(scores, url, pubkey) addToMapKey(scores, url, pubkey)
}
} }
return scores
} }
)
return scores
})
const openSpace = (url: string) => pushModal(SpaceCheck, {url}) const openSpace = (url: string) => pushModal(SpaceCheck, {url})
@@ -83,7 +86,7 @@
class="card2 bg-alt col-4 text-left shadow-xl transition-all hover:shadow-2xl hover:brightness-[1.1]" class="card2 bg-alt col-4 text-left shadow-xl transition-all hover:shadow-2xl hover:brightness-[1.1]"
on:click={() => openSpace(relay.url)}> on:click={() => openSpace(relay.url)}>
<div class="col-2"> <div class="col-2">
<div class="flex gap-4 relative"> <div class="relative flex gap-4">
<div class="relative"> <div class="relative">
<div class="avatar relative"> <div class="avatar relative">
<div <div
@@ -97,14 +100,14 @@
</div> </div>
{#if getMembershipUrls($userMembership).includes(relay.url)} {#if getMembershipUrls($userMembership).includes(relay.url)}
<div <div
class="absolute -right-1 -top-1 tooltip h-5 w-5 rounded-full bg-primary" class="tooltip absolute -right-1 -top-1 h-5 w-5 rounded-full bg-primary"
data-tip="You are already a member of this space."> data-tip="You are already a member of this space.">
<Icon icon="check-circle" class="scale-110" /> <Icon icon="check-circle" class="scale-110" />
</div> </div>
{/if} {/if}
</div> </div>
<div> <div>
<h2 class="text-xl ellipsize whitespace-nowrap"> <h2 class="ellipsize whitespace-nowrap text-xl">
<RelayName url={relay.url} /> <RelayName url={relay.url} />
</h2> </h2>
<p class="text-sm opacity-75">{relay.url}</p> <p class="text-sm opacity-75">{relay.url}</p>
+1 -1
View File
@@ -11,7 +11,7 @@
import {onMount} from "svelte" import {onMount} from "svelte"
import {page} from "$app/stores" import {page} from "$app/stores"
import {derived, writable} from "svelte/store" import {derived, writable} from "svelte/store"
import {ctx, assoc, sortBy, now, remove} from "@welshman/lib" import {assoc, sortBy, remove} from "@welshman/lib"
import type {TrustedEvent, EventContent} from "@welshman/util" import type {TrustedEvent, EventContent} from "@welshman/util"
import {createEvent, DIRECT_MESSAGE} from "@welshman/util" import {createEvent, DIRECT_MESSAGE} from "@welshman/util"
import { import {
+2 -5
View File
@@ -1,13 +1,10 @@
<script lang="ts"> <script lang="ts">
import {onMount} from "svelte" import {onMount} from "svelte"
import {createScroller} from "@lib/html" import {createScroller} from "@lib/html"
import {uniq, shuffle} from "@welshman/lib" import {profileSearch} from "@welshman/app"
import {getPubkeyTagValues, getListTags} from "@welshman/util"
import {profileSearch, userFollows} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import PageHeader from "@lib/components/PageHeader.svelte"
import PeopleItem from "@app/components/PeopleItem.svelte" import PeopleItem from "@app/components/PeopleItem.svelte"
import {getDefaultPubkeys} from '@app/state' import {getDefaultPubkeys} from "@app/state"
const defaultPubkeys = getDefaultPubkeys() const defaultPubkeys = getDefaultPubkeys()
+11 -4
View File
@@ -9,6 +9,8 @@
import {pushToast} from "@app/toast" import {pushToast} from "@app/toast"
import {SETTINGS, userSettings} from "@app/state" import {SETTINGS, userSettings} from "@app/state"
const settings = {...$userSettings?.values}
const reset = () => { const reset = () => {
mutedPubkeys = getPubkeyTagValues(getListTags($userMutes)) mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
} }
@@ -29,12 +31,11 @@
pushToast({message: "Your settings have been saved!"}) pushToast({message: "Your settings have been saved!"})
} }
let settings = {...$userSettings?.values}
let mutedPubkeys = getPubkeyTagValues(getListTags($userMutes)) let mutedPubkeys = getPubkeyTagValues(getListTags($userMutes))
</script> </script>
<form class="content column gap-4" on:submit|preventDefault={onSubmit}> <form class="content column gap-4" on:submit|preventDefault={onSubmit}>
<div class="card2 bg-alt shadow-xl col-4"> <div class="card2 bg-alt col-4 shadow-xl">
<Field> <Field>
<p slot="label">Muted Accounts</p> <p slot="label">Muted Accounts</p>
<div slot="input"> <div slot="input">
@@ -43,8 +44,14 @@
</Field> </Field>
<FieldInline> <FieldInline>
<p slot="label">Hide sensitive content?</p> <p slot="label">Hide sensitive content?</p>
<input slot="input" type="checkbox" class="toggle toggle-primary" bind:checked={settings.hide_sensitive} /> <input
<p slot="info">If content is marked by the author as sensitive, flotilla will hide it by default.</p> slot="input"
type="checkbox"
class="toggle toggle-primary"
bind:checked={settings.hide_sensitive} />
<p slot="info">
If content is marked by the author as sensitive, flotilla will hide it by default.
</p>
</FieldInline> </FieldInline>
<div class="mt-4 flex flex-row items-center justify-between gap-4"> <div class="mt-4 flex flex-row items-center justify-between gap-4">
<Button class="btn btn-neutral" on:click={reset}>Discard Changes</Button> <Button class="btn btn-neutral" on:click={reset}>Discard Changes</Button>
+4 -1
View File
@@ -43,7 +43,10 @@
</span> </span>
</p> </p>
<p class="text-xs"> <p class="text-xs">
Icons by <Link external class="link" href="https://www.figma.com/community/file/1166831539721848736">480 Design</Link> Icons by <Link
external
class="link"
href="https://www.figma.com/community/file/1166831539721848736">480 Design</Link>
</p> </p>
</div> </div>
<div class="flex justify-center gap-4"> <div class="flex justify-center gap-4">
+1 -1
View File
@@ -9,7 +9,7 @@
createProfile, createProfile,
isPublishedProfile, isPublishedProfile,
} from "@welshman/util" } from "@welshman/util"
import {pubkey, profilesByPubkey, publishThunk, displayNip05, deriveProfile} from "@welshman/app" import {pubkey, publishThunk, displayNip05, deriveProfile} from "@welshman/app"
import {slide} from "@lib/transition" import {slide} from "@lib/transition"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Field from "@lib/components/Field.svelte" import Field from "@lib/components/Field.svelte"
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte' import {onMount} from "svelte"
import {derived} from "svelte/store" import {derived} from "svelte/store"
import { import {
getRelayUrls, getRelayUrls,
@@ -8,9 +8,9 @@
</script> </script>
<script lang="ts"> <script lang="ts">
import {onMount} from 'svelte' import {onMount} from "svelte"
import {page} from "$app/stores" import {page} from "$app/stores"
import {writable} from 'svelte/store' import {writable} from "svelte/store"
import {sortBy, now, assoc, append} from "@welshman/lib" import {sortBy, now, assoc, append} from "@welshman/lib"
import type {TrustedEvent, EventContent} from "@welshman/util" import type {TrustedEvent, EventContent} from "@welshman/util"
import {createEvent} from "@welshman/util" import {createEvent} from "@welshman/util"
@@ -82,7 +82,7 @@
} }
onMount(() => { onMount(() => {
subscribe({filters: [{'#~': [room], since: now()}], relays: [url]}) subscribe({filters: [{"#~": [room], since: now()}], relays: [url]})
}) })
setTimeout(() => { setTimeout(() => {