Show image link if image fails to load

This commit is contained in:
Jon Staab
2025-06-05 13:37:50 -07:00
parent 11aa841241
commit 45397e7fb8
6 changed files with 34 additions and 12 deletions
+1 -1
View File
@@ -31,7 +31,7 @@
</script> </script>
<Link external href={url} class="my-2 block"> <Link external href={url} class="my-2 block">
<div class="overflow-hidden rounded-box leading-[0]"> <div class="overflow-hidden rounded-box">
{#if url.match(/\.(mov|webm|mp4)$/)} {#if url.match(/\.(mov|webm|mp4)$/)}
<video controls src={url} class="max-h-96 object-contain object-center"> <video controls src={url} class="max-h-96 object-contain object-center">
<track kind="captions" /> <track kind="captions" />
@@ -1,7 +1,9 @@
<script lang="ts"> <script lang="ts">
import {onMount, onDestroy} from "svelte" import {onMount, onDestroy} from "svelte"
import {displayUrl} from "@welshman/lib"
import {getTags, getTagValue, tagsFromIMeta} from "@welshman/util" import {getTags, getTagValue, tagsFromIMeta} from "@welshman/util"
import {decryptFile} from "@welshman/editor" import {decryptFile} from "@welshman/editor"
import Icon from "@lib/components/Icon.svelte"
import {imgproxy} from "@app/state" import {imgproxy} from "@app/state"
const {value, event, ...props} = $props() const {value, event, ...props} = $props()
@@ -16,6 +18,11 @@
const nonce = getTagValue("decryption-nonce", meta) const nonce = getTagValue("decryption-nonce", meta)
const encryptionAlgorithm = getTagValue("encryption-algorithm", meta) const encryptionAlgorithm = getTagValue("encryption-algorithm", meta)
const onError = () => {
hasError = true
}
let hasError = $state(false)
let src = $state(imgproxy(url)) let src = $state(imgproxy(url))
onMount(async () => { onMount(async () => {
@@ -36,4 +43,11 @@
}) })
</script> </script>
<img alt="" {src} {...props} /> {#if hasError}
<a href={url} class="link-content whitespace-nowrap">
<Icon icon="link-round" size={3} class="inline-block" />
{displayUrl(url)}
</a>
{:else}
<img alt="" {src} onerror={onError} {...props} />
{/if}
+5 -2
View File
@@ -10,6 +10,7 @@
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import ProfileSpaces from "@app/components/ProfileSpaces.svelte" import ProfileSpaces from "@app/components/ProfileSpaces.svelte"
import {membershipsByPubkey} from "@app/state" import {membershipsByPubkey} from "@app/state"
import {goToEvent} from "@app/routes"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
type Props = { type Props = {
@@ -23,6 +24,8 @@
const membership = $derived($membershipsByPubkey.get(pubkey)) const membership = $derived($membershipsByPubkey.get(pubkey))
const relays = $derived(getRelayTags(getListTags(membership))) const relays = $derived(getRelayTags(getListTags(membership)))
const viewEvent = () => goToEvent($events[0]!)
const openSpaces = () => pushModal(ProfileSpaces, {pubkey, url}) const openSpaces = () => pushModal(ProfileSpaces, {pubkey, url})
onMount(async () => { onMount(async () => {
@@ -42,9 +45,9 @@
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
{#if $events.length > 0} {#if $events.length > 0}
<div class="badge badge-neutral"> <Button onclick={viewEvent} class="badge badge-neutral">
Last active {formatTimestampRelative($events[0].created_at)} Last active {formatTimestampRelative($events[0].created_at)}
</div> </Button>
{/if} {/if}
{#if relays.length > 0} {#if relays.length > 0}
<Button onclick={openSpaces} class="badge badge-neutral"> <Button onclick={openSpaces} class="badge badge-neutral">
@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import {derived} from "svelte/store" import {derived} from "svelte/store"
import {groupBy, first, last, uniq, avg, overlappingPairs} from "@welshman/lib" import {groupBy, ago, MONTH, first, last, uniq, avg, overlappingPairs} from "@welshman/lib"
import {formatTimestamp} from "@welshman/lib" import {formatTimestamp} from "@welshman/lib"
import {MESSAGE, getTagValue} from "@welshman/util" import {MESSAGE, getTagValue} from "@welshman/util"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
@@ -17,8 +17,8 @@
} }
const {url}: Props = $props() const {url}: Props = $props()
const since = ago(MONTH)
const messages = deriveEventsForUrl(url, [{kinds: [MESSAGE]}]) const messages = deriveEventsForUrl(url, [{kinds: [MESSAGE], since}])
const conversations = derived(messages, $messages => { const conversations = derived(messages, $messages => {
const convs = [] const convs = []
+8 -3
View File
@@ -1,4 +1,5 @@
import type {Page} from "@sveltejs/kit" import type {Page} from "@sveltejs/kit"
import * as nip19 from "nostr-tools/nip19"
import {goto} from "$app/navigation" import {goto} from "$app/navigation"
import {nthEq, sleep} from "@welshman/lib" import {nthEq, sleep} from "@welshman/lib"
import type {TrustedEvent} from "@welshman/util" import type {TrustedEvent} from "@welshman/util"
@@ -13,7 +14,7 @@ import {
THREAD, THREAD,
EVENT_TIME, EVENT_TIME,
} from "@welshman/util" } from "@welshman/util"
import {makeChatId, decodeRelay, encodeRelay, userRoomsByUrl, ROOM} from "@app/state" import {makeChatId, entityLink, decodeRelay, encodeRelay, userRoomsByUrl, ROOM} from "@app/state"
export const makeSpacePath = (url: string, ...extra: (string | undefined)[]) => { export const makeSpacePath = (url: string, ...extra: (string | undefined)[]) => {
let path = `/spaces/${encodeRelay(url)}` let path = `/spaces/${encodeRelay(url)}`
@@ -72,10 +73,12 @@ export const goToEvent = async (event: TrustedEvent) => {
return await scrollToEvent(event.id) return await scrollToEvent(event.id)
} }
const [url] = tracker.getRelays(event.id) const urls = Array.from(tracker.getRelays(event.id))
const room = getTagValue(ROOM, event.tags) const room = getTagValue(ROOM, event.tags)
if (url) { if (urls.length > 0) {
const url = urls[0]
if (event.kind === THREAD) { if (event.kind === THREAD) {
return goto(makeThreadPath(url, event.id)) return goto(makeThreadPath(url, event.id))
} }
@@ -105,4 +108,6 @@ export const goToEvent = async (event: TrustedEvent) => {
} }
} }
} }
window.open(entityLink(nip19.neventEncode({id: event.id, relays: urls})))
} }
+2 -2
View File
@@ -2,7 +2,7 @@
import type {Snippet} from "svelte" import type {Snippet} from "svelte"
import {onMount} from "svelte" import {onMount} from "svelte"
import {page} from "$app/stores" import {page} from "$app/stores"
import {ago, WEEK} from "@welshman/lib" import {ago, MONTH} from "@welshman/lib"
import {GROUP_META, EVENT_TIME, THREAD, COMMENT, MESSAGE} from "@welshman/util" import {GROUP_META, EVENT_TIME, THREAD, COMMENT, MESSAGE} from "@welshman/util"
import Page from "@lib/components/Page.svelte" import Page from "@lib/components/Page.svelte"
import SecondaryNav from "@lib/components/SecondaryNav.svelte" import SecondaryNav from "@lib/components/SecondaryNav.svelte"
@@ -53,7 +53,7 @@
checkConnection() checkConnection()
const relays = [url] const relays = [url]
const since = ago(WEEK) const since = ago(MONTH)
const controller = new AbortController() const controller = new AbortController()
// Load group meta, threads, calendar events, comments, and recent messages // Load group meta, threads, calendar events, comments, and recent messages