mirror of
https://git.shipoclu.com/moon/plspace.git
synced 2026-08-14 03:02:31 +00:00
pics timeline
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* Image attachments from an account timeline, presented like a MySpace photo
|
||||
* stream. Videos/audio stay in the Blog; reposted pictures are not somebody's
|
||||
* own Pics.
|
||||
*/
|
||||
import type { MediaAttachment, Status } from '$lib/api/types'
|
||||
import type { Feed } from '$lib/stores/feed.svelte'
|
||||
import { toPlainText } from '$lib/util/html'
|
||||
import { stampDate } from '$lib/util/time'
|
||||
import Pager from '../common/Pager.svelte'
|
||||
|
||||
interface Props {
|
||||
feed: Feed<Status>
|
||||
ownerName: string
|
||||
}
|
||||
|
||||
interface Picture {
|
||||
key: string
|
||||
media: MediaAttachment
|
||||
status: Status
|
||||
caption: string
|
||||
}
|
||||
|
||||
let { feed, ownerName }: Props = $props()
|
||||
let revealed = $state<Record<string, boolean>>({})
|
||||
|
||||
const pictures = $derived.by<Picture[]>(() =>
|
||||
feed.items.flatMap((status) => {
|
||||
if (status.reblog) return []
|
||||
const entryCaption = toPlainText(status.content)
|
||||
return status.media_attachments
|
||||
.filter((media) => media.type === 'image')
|
||||
.map((media) => ({
|
||||
key: `${status.id}:${media.id}`,
|
||||
media,
|
||||
status,
|
||||
caption: media.description?.trim() || entryCaption,
|
||||
}))
|
||||
}),
|
||||
)
|
||||
|
||||
function toggle(key: string): void {
|
||||
revealed = { ...revealed, [key]: !revealed[key] }
|
||||
}
|
||||
</script>
|
||||
|
||||
<p class="pic-stream-intro">
|
||||
Pictures from {ownerName}'s Blog Entries. Click a picture to view the full-size original.
|
||||
</p>
|
||||
|
||||
{#if !feed.initialized && feed.loading}
|
||||
<p class="loading-note">Loading pictures…</p>
|
||||
{:else if pictures.length === 0 && feed.items.length > 0}
|
||||
<p class="empty-note">
|
||||
No image attachments in the entries loaded so far.
|
||||
</p>
|
||||
{:else}
|
||||
<ul class="pic-stream">
|
||||
{#each pictures as picture (picture.key)}
|
||||
{@const hidden = picture.status.sensitive && !revealed[picture.key]}
|
||||
<li
|
||||
class="pic-card"
|
||||
data-status-id={picture.status.id}
|
||||
data-sensitive={picture.status.sensitive ? 'true' : 'false'}
|
||||
data-revealed={hidden ? 'false' : 'true'}
|
||||
>
|
||||
<figure class="pic-card-figure">
|
||||
<a
|
||||
class="pic-card-image-link"
|
||||
href={picture.media.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label={hidden ? 'Sensitive picture; reveal it before opening' : 'View full-size picture'}
|
||||
aria-disabled={hidden ? 'true' : undefined}
|
||||
onclick={hidden ? (event) => event.preventDefault() : undefined}
|
||||
>
|
||||
<img
|
||||
class="pic-card-image"
|
||||
src={picture.media.preview_url ?? picture.media.url}
|
||||
alt={picture.media.description ?? ''}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</a>
|
||||
|
||||
{#if picture.status.sensitive}
|
||||
<button
|
||||
type="button"
|
||||
class="button button--small pic-card-reveal"
|
||||
onclick={() => toggle(picture.key)}
|
||||
>
|
||||
{hidden ? 'Show' : 'Hide'} sensitive picture
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<figcaption class="pic-card-caption">
|
||||
{#if hidden}
|
||||
<span class="pic-card-description">
|
||||
{picture.status.spoiler_text || 'Sensitive picture'}
|
||||
</span>
|
||||
{:else if picture.caption}
|
||||
<span class="pic-card-description">{picture.caption}</span>
|
||||
{/if}
|
||||
<a class="pic-card-entry-link" href={`#/blog/${picture.status.id}`}>
|
||||
Posted {stampDate(picture.status.created_at)} · view entry
|
||||
</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{/if}
|
||||
|
||||
<Pager
|
||||
{feed}
|
||||
label="View More Pictures"
|
||||
emptyText={`${ownerName} hasn't posted any pictures yet.`}
|
||||
endText={pictures.length > 0 ? 'That’s the whole picture stream.' : ''}
|
||||
/>
|
||||
Reference in New Issue
Block a user