forked from coracle/flotilla
Tweak errors so that actionable links are rendered
This commit is contained in:
+10
@@ -294,6 +294,16 @@ html {
|
|||||||
color: var(--base-content);
|
color: var(--base-content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* content rendered by welshman/content */
|
||||||
|
|
||||||
|
.welshman-content a {
|
||||||
|
@apply link;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welshman-content-error a {
|
||||||
|
@apply underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* date input */
|
/* date input */
|
||||||
|
|
||||||
.picker {
|
.picker {
|
||||||
|
|||||||
+8
-6
@@ -1,6 +1,6 @@
|
|||||||
import * as nip19 from "nostr-tools/nip19"
|
import * as nip19 from "nostr-tools/nip19"
|
||||||
import {get} from "svelte/store"
|
import {get} from "svelte/store"
|
||||||
import {randomId, ifLet, poll, uniq, equals, TIMEZONE, LOCALE} from "@welshman/lib"
|
import {randomId, poll, uniq, equals, TIMEZONE, LOCALE} from "@welshman/lib"
|
||||||
import type {Feed} from "@welshman/feeds"
|
import type {Feed} from "@welshman/feeds"
|
||||||
import type {TrustedEvent, EventContent} from "@welshman/util"
|
import type {TrustedEvent, EventContent} from "@welshman/util"
|
||||||
import {
|
import {
|
||||||
@@ -266,18 +266,20 @@ export const checkRelayAccess = async (url: string, claim = "") => {
|
|||||||
relays: [url],
|
relays: [url],
|
||||||
})
|
})
|
||||||
|
|
||||||
ifLet(await getThunkError(thunk), error => {
|
const error = await getThunkError(thunk)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
const message =
|
const message =
|
||||||
socket.auth.details?.replace(/^.*: /, "") ||
|
socket.auth.details?.replace(/^\w+: /, "") ||
|
||||||
error?.replace(/^.*: /, "") ||
|
error?.replace(/^\w+: /, "") ||
|
||||||
"join request rejected"
|
"join request rejected"
|
||||||
|
|
||||||
// If it's a strict NIP 29 relay don't worry about requesting access
|
// If it's a strict NIP 29 relay don't worry about requesting access
|
||||||
// TODO: remove this if relay29 ever gets less strict
|
// TODO: remove this if relay29 ever gets less strict
|
||||||
if (message !== "missing group (`h`) tag") {
|
if (message !== "missing group (`h`) tag") {
|
||||||
return `Failed to join relay (${message})`
|
return message
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const checkRelayProfile = async (url: string) => {
|
export const checkRelayProfile = async (url: string) => {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import {clip} from "@app/toast"
|
import {clip} from "@app/toast"
|
||||||
|
|
||||||
const {code} = $props()
|
const {code, ...props} = $props()
|
||||||
|
|
||||||
let canvas: Element | undefined = $state()
|
let canvas: Element | undefined = $state()
|
||||||
let wrapper: Element | undefined = $state()
|
let wrapper: Element | undefined = $state()
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button class="max-w-full" onclick={copy}>
|
<Button class="max-w-full {props.class}" onclick={copy}>
|
||||||
<div bind:this={wrapper} style={`height: ${height}px`}>
|
<div bind:this={wrapper} style={`height: ${height}px`}>
|
||||||
<canvas
|
<canvas
|
||||||
class="rounded-box"
|
class="rounded-box"
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {displayRelayUrl} from "@welshman/util"
|
import {displayRelayUrl} from "@welshman/util"
|
||||||
|
import {parse, renderAsHtml} from "@welshman/content"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
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 Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import {preventDefault} from "@lib/html"
|
import {preventDefault} from "@lib/html"
|
||||||
|
import {ucFirst} from "@lib/util"
|
||||||
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 {pushToast} from "@app/toast"
|
import {pushToast} from "@app/toast"
|
||||||
@@ -15,8 +16,8 @@
|
|||||||
|
|
||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
|
|
||||||
const joinRelay = async (claim: string) => {
|
const joinRelay = async () => {
|
||||||
const error = await attemptRelayAccess(url, claim)
|
const error = await attemptRelayAccess(url)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return pushToast({theme: "error", message: error})
|
return pushToast({theme: "error", message: error})
|
||||||
@@ -33,13 +34,12 @@
|
|||||||
loading = true
|
loading = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await joinRelay(claim)
|
await joinRelay()
|
||||||
} finally {
|
} finally {
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let claim = $state("")
|
|
||||||
let loading = $state(false)
|
let loading = $state(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -53,32 +53,17 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<p>
|
<p>
|
||||||
We received an error from the relay indicating you don't have access to {displayRelayUrl(url)}.
|
We received an error from the relay indicating you don't have access to {displayRelayUrl(url)}:
|
||||||
</p>
|
</p>
|
||||||
<p class="border-l border-solid border-error pl-4 text-error">
|
<p class="bg-alt card2 welshman-content">
|
||||||
{error}
|
{@html renderAsHtml(parse({content: ucFirst(error)}))}
|
||||||
</p>
|
</p>
|
||||||
<p>If you have one, you can try entering an invite code below to request access.</p>
|
|
||||||
<Field>
|
|
||||||
{#snippet label()}
|
|
||||||
<p>Invite code</p>
|
|
||||||
{/snippet}
|
|
||||||
{#snippet input()}
|
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
|
||||||
<Icon icon="link-round" />
|
|
||||||
<input bind:value={claim} class="grow" type="text" />
|
|
||||||
</label>
|
|
||||||
{/snippet}
|
|
||||||
{#snippet info()}
|
|
||||||
<p>Enter an invite code provided to you by the admin of the relay.</p>
|
|
||||||
{/snippet}
|
|
||||||
</Field>
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button class="btn btn-link" onclick={back}>
|
<Button class="btn btn-link" onclick={back}>
|
||||||
<Icon icon="alt-arrow-left" />
|
<Icon icon="alt-arrow-left" />
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" class="btn btn-primary" disabled={!claim || loading}>
|
<Button type="submit" class="btn btn-primary" disabled={loading}>
|
||||||
<Spinner {loading}>Request Access</Spinner>
|
<Spinner {loading}>Request Access</Spinner>
|
||||||
<Icon icon="alt-arrow-right" />
|
<Icon icon="alt-arrow-right" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
const error = await attemptRelayAccess(url, claim)
|
const error = await attemptRelayAccess(url, claim)
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return pushToast({theme: "error", message: error})
|
return pushToast({theme: "error", message: error, timeout: 30_000})
|
||||||
}
|
}
|
||||||
|
|
||||||
const socket = Pool.get().get(url)
|
const socket = Pool.get().get(url)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import {parse, renderAsHtml} from "@welshman/content"
|
||||||
import {fly} from "@lib/transition"
|
import {fly} from "@lib/transition"
|
||||||
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"
|
||||||
@@ -15,7 +16,9 @@
|
|||||||
class:bg-base-100={theme === "info"}
|
class:bg-base-100={theme === "info"}
|
||||||
class:text-base-content={theme === "info"}
|
class:text-base-content={theme === "info"}
|
||||||
class:alert-error={theme === "error"}>
|
class:alert-error={theme === "error"}>
|
||||||
{$toast.message}
|
<p class="welshman-content-error">
|
||||||
|
{@html renderAsHtml(parse({content: $toast.message}))}
|
||||||
|
</p>
|
||||||
<Button class="flex items-center opacity-75" onclick={() => popToast($toast.id)}>
|
<Button class="flex items-center opacity-75" onclick={() => popToast($toast.id)}>
|
||||||
<Icon icon="close-circle" />
|
<Icon icon="close-circle" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -15,3 +15,5 @@ export const nsecDecode = (nsec: string) => {
|
|||||||
export const day = (seconds: number) => Math.floor(seconds / DAY)
|
export const day = (seconds: number) => Math.floor(seconds / DAY)
|
||||||
|
|
||||||
export const daysBetween = (start: number, end: number) => [...range(start, end, DAY)].map(day)
|
export const daysBetween = (start: number, end: number) => [...range(start, end, DAY)].map(day)
|
||||||
|
|
||||||
|
export const ucFirst = (s: string) => s.slice(0, 1).toUpperCase() + s.slice(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user