"Final-ish" design

This commit is contained in:
Astra 2025-04-20 20:08:13 +09:00
parent 037dea4e40
commit ebca274e5a
Signed by: astra
SSH key fingerprint: SHA256:jQDNS75/33T59Ey4yAzrUPP/5YQaXEetsW8hwUae+ag
5 changed files with 202 additions and 33 deletions

View file

@ -1,7 +1,58 @@
<script lang="ts">
import { Post } from "./pdsfetch";
import { Config } from "../../config";
import { onMount } from "svelte";
let { post }: { post: Post } = $props();
// State for image carousel
let currentImageIndex = $state(0);
// Functions to navigate carousel
function nextImage() {
if (post.imagesCid && currentImageIndex < post.imagesCid.length - 1) {
currentImageIndex++;
}
}
function prevImage() {
if (currentImageIndex > 0) {
currentImageIndex--;
}
}
// Function to preload an image
function preloadImage(index: number): void {
if (!post.imagesCid || index < 0 || index >= post.imagesCid.length) return;
const img = new Image();
img.src = `${Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did=${post.authorDid}&cid=${post.imagesCid[index]}`;
}
// Preload adjacent images when current index changes
$effect(() => {
if (post.imagesCid && post.imagesCid.length > 1) {
// Preload next image if available
if (currentImageIndex < post.imagesCid.length - 1) {
preloadImage(currentImageIndex + 1);
}
// Preload previous image if available
if (currentImageIndex > 0) {
preloadImage(currentImageIndex - 1);
}
}
});
// Initial preload of images
onMount(() => {
if (post.imagesCid && post.imagesCid.length > 1) {
// Preload the next image if it exists
if (post.imagesCid.length > 1) {
preloadImage(1);
}
}
});
</script>
<div id="postContainer">
@ -14,24 +65,30 @@
/>
{/if}
<div id="headerText">
<a href="{Config.FRONTEND_URL}/profile/{post.authorDid}"
>{post.displayName} ( {post.authorHandle} )</a
>
|
<a href="{Config.FRONTEND_URL}/profile/{post.authorDid}/post/{post.cid}"
>{post.timenotstamp}</a
<a id="displayName" href="{Config.FRONTEND_URL}/profile/{post.authorDid}"
>{post.displayName}</a
>
<p id="handle">
<a href="{Config.FRONTEND_URL}/profile/{post.authorHandle}"
>{post.authorHandle}</a
>
<a
id="postLink"
href="{Config.FRONTEND_URL}/profile/{post.authorDid}/post/{post.recordName}"
>{post.timenotstamp}</a
>
</p>
</div>
</div>
<div id="postContent">
{#if post.replyingUri}
<a
id="replyingText"
href="{Config.FRONTEND_URL}/profile/{post.replyingUri.repo}/post/{post
.replyingUri.rkey}">replying to {post.replyingUri.repo}</a
>
<a
id="replyingText"
href="{Config.FRONTEND_URL}/profile/{post.replyingUri.repo}/post/{post
.replyingUri.rkey}">replying to {post.replyingUri.repo}</a
>
{/if}
<div id="postText">{post.text}</div>
{#if post.quotingUri}
<a
id="quotingText"
@ -39,27 +96,54 @@
.quotingUri.rkey}">quoting {post.quotingUri.repo}</a
>
{/if}
{#if post.imagesCid}
<div id="imagesContainer">
{#each post.imagesCid as imageLink}
<img
id="embedImages"
alt="Post Image"
src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={imageLink}"
/>
{/each}
<div id="postText">{post.text}</div>
{#if post.imagesCid && post.imagesCid.length > 0}
<div id="carouselContainer">
<img
id="embedImages"
alt="Post Image {currentImageIndex + 1} of {post.imagesCid.length}"
src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post
.imagesCid[currentImageIndex]}"
/>
{#if post.imagesCid.length > 1}
<div id="carouselControls">
<button
id="prevBtn"
on:click={prevImage}
disabled={currentImageIndex === 0}>←</button
>
<div id="carouselIndicators">
{#each post.imagesCid as _, i}
<div
class="indicator {i === currentImageIndex ? 'active' : ''}"
></div>
{/each}
</div>
<button
id="nextBtn"
on:click={nextImage}
disabled={currentImageIndex === post.imagesCid.length - 1}
>→</button
>
</div>
{/if}
</div>
{/if}
{#if post.videosLinkCid}
<video
id="embedVideo"
src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.videosLinkCid}"
/>
controls
></video>
{/if}
</div>
</div>
<style>
a:hover {
text-decoration: underline;
}
#postContainer {
display: flex;
flex-direction: column;
@ -79,6 +163,26 @@
border-bottom: 1px solid #8054f0;
font-weight: bold;
overflow-wrap: break-word;
height: 60px;
}
#displayName {
color: white;
font-size: 1.2em;
padding: 0;
margin: 0;
}
#handle {
color: #8054f0;
font-size: 0.8em;
padding: 0;
margin: 0;
}
#postLink {
color: #8054f0;
font-size: 0.8em;
padding: 0;
margin: 0;
}
#postContent {
display: flex;
@ -95,9 +199,14 @@
padding: 0;
padding-bottom: 5px;
}
#quotingText {
font-size: 0.7em;
margin: 0;
padding: 0;
padding-bottom: 5px;
}
#postText {
margin: 0;
margin-bottom: 5px;
padding: 0;
}
#headerText {
@ -108,20 +217,68 @@
overflow: hidden;
}
#avatar {
width: 50px;
height: 50px;
height: 100%;
margin: 0px;
margin-left: 0px;
border-right: #8054f0 1px solid;
}
#embedImages {
width: 50%;
height: 50%;
margin-top: 0px;
margin-bottom: -5px;
min-width: 500px;
max-width: 500px;
max-height: 500px;
object-fit: contain;
margin: 0;
}
#carouselContainer {
position: relative;
width: 100%;
margin-top: 10px;
display: flex;
flex-direction: column;
align-items: center;
}
#carouselControls {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
max-width: 500px;
margin-top: 5px;
}
#carouselIndicators {
display: flex;
gap: 5px;
}
.indicator {
width: 8px;
height: 8px;
background-color: #4a4a4a;
}
.indicator.active {
background-color: #8054f0;
}
#prevBtn,
#nextBtn {
background-color: rgba(31, 17, 69, 0.7);
color: white;
border: 1px solid #8054f0;
width: 30px;
height: 30px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
#prevBtn:disabled,
#nextBtn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
#embedVideo {
width: 50%;
height: 50%;
width: 100%;
max-width: 500px;
margin-top: 10px;
align-self: center;
}
</style>

View file

@ -32,6 +32,7 @@ class Post {
authorDid: string;
authorAvatarCid: string | null;
postCid: string;
recordName: string;
authorHandle: string;
displayName: string;
text: string;
@ -47,6 +48,7 @@ class Post {
account: AccountMetadata,
) {
this.postCid = record.cid;
this.recordName = record.uri.split("/").slice(-1)[0];
this.authorDid = account.did;
this.authorAvatarCid = account.avatarCid;
this.authorHandle = account.handle;