WIP: My personal website
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.8 kB View raw
1<script lang="ts"> 2 import { reveal } from '$lib/actions/reveal'; 3 import LazyLoadingImg from './LazyLoadingImg.svelte'; 4 import type { LatestPost, Publication } from '$lib/types'; 5 6 let { 7 publications, 8 latestPosts, 9 subscriberCounts 10 }: { 11 publications: Publication[]; 12 latestPosts: Promise<LatestPost[]>; 13 subscriberCounts: Promise<Record<string, number>>; 14 } = $props(); 15 16 const INITIAL_COUNT = 4; 17 const LOAD_STEP = 2; 18 let visibleCount = $state(INITIAL_COUNT); 19 const visiblePublications = $derived(publications.slice(0, visibleCount)); 20 const hasMore = $derived(visibleCount < publications.length); 21 22 function publishedLabel(iso: string | null): string { 23 if (!iso) return ''; 24 const date = new Date(iso); 25 if (Number.isNaN(date.getTime())) return ''; 26 return date.toLocaleDateString('en', { month: 'short', day: 'numeric', year: 'numeric' }); 27 } 28</script> 29 30{#if publications.length > 0} 31 <div id="writings" class="mt-10 flex flex-col items-center justify-center md:mt-20" use:reveal> 32 <div class="flex flex-col items-center justify-center"> 33 <h1 class="text-center font-urbanist text-2xl font-semibold md:text-5xl">Writings</h1> 34 <span class="text-md mt-2 px-2 text-center font-urbanist md:mt-4 md:px-5 md:text-xl"> 35 My long form writings found across the atmosphere 36 </span> 37 </div> 38 <div class="container mt-10 grid gap-10 p-4 md:grid-cols-2 xl:grid-cols-3"> 39 {#each visiblePublications as item (item.href)} 40 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 41 {#if item.image} 42 <figure> 43 <LazyLoadingImg class="h-48 w-full" src={item.image} alt={item.name} /> 44 </figure> 45 {/if} 46 <div class="card-body"> 47 {#await subscriberCounts then counts} 48 {#if counts[item.uri] > 0} 49 <span class="badge font-urbanist badge-secondary" 50 >{counts[item.uri]} subscribers</span 51 > 52 {/if} 53 {/await} 54 <h2 class="card-title font-urbanist text-2xl font-black">{item.name}</h2> 55 <p class="text-md font-urbanist font-medium opacity-60">{item.description}</p> 56 <div class="mt-2 card-actions justify-end"> 57 <a 58 class="btn font-urbanist btn-primary" 59 href={item.href} 60 target="_blank" 61 rel="noopener noreferrer" 62 > 63 Read 64 </a> 65 </div> 66 </div> 67 </div> 68 {/each} 69 </div> 70 {#if hasMore} 71 <button 72 class="btn mt-10 font-urbanist btn-primary" 73 onclick={() => (visibleCount = Math.min(visibleCount + LOAD_STEP, publications.length))} 74 > 75 Load More 76 </button> 77 {/if} 78 79 <h2 80 class="mt-16 text-center font-urbanist text-xl font-semibold opacity-80 md:mt-24 md:text-3xl" 81 > 82 Latest Posts 83 </h2> 84 <span class="text-md mt-2 px-2 text-center font-urbanist md:mt-4 md:px-5 md:text-xl"> 85 My most recent posts 86 </span> 87 {#await latestPosts} 88 <div class="container mt-10 grid gap-10 p-4 md:grid-cols-2 xl:grid-cols-3"> 89 {#each Array(2) as _, i (i)} 90 <div class="card bg-base-100 shadow-sm"> 91 <div class="h-48 w-full skeleton"></div> 92 <div class="card-body flex flex-col gap-3"> 93 <div class="h-5 w-28 skeleton"></div> 94 <div class="h-7 w-3/4 skeleton"></div> 95 <div class="h-4 w-1/3 skeleton"></div> 96 <div class="h-4 w-full skeleton"></div> 97 </div> 98 </div> 99 {/each} 100 </div> 101 {:then posts} 102 {#if posts.length > 0} 103 <div class="container mt-10 grid gap-10 p-4 md:grid-cols-2 xl:grid-cols-3"> 104 {#each posts as post (post.postUrl)} 105 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 106 {#if post.coverImage} 107 <figure> 108 <LazyLoadingImg class="h-48 w-full" src={post.coverImage} alt={post.title} /> 109 </figure> 110 {/if} 111 <div class="card-body"> 112 <div class="flex flex-wrap items-center gap-2"> 113 <span class="badge font-urbanist badge-primary">{post.publicationName}</span> 114 {#if post.recommendCount > 0} 115 <span class="badge font-urbanist badge-secondary" 116 >{post.recommendCount} recommendations</span 117 > 118 {/if} 119 </div> 120 <h3 class="mt-2 card-title font-urbanist text-2xl font-black">{post.title}</h3> 121 {#if post.publishedAt} 122 <p class="font-urbanist text-xs opacity-40">{publishedLabel(post.publishedAt)}</p> 123 {/if} 124 <p class="text-md font-urbanist font-medium opacity-60">{post.description}</p> 125 <div class="mt-2 card-actions justify-end"> 126 <a 127 class="btn font-urbanist btn-primary" 128 href={post.postUrl} 129 target="_blank" 130 rel="noopener noreferrer" 131 > 132 Read 133 </a> 134 </div> 135 </div> 136 </div> 137 {/each} 138 </div> 139 {/if} 140 {/await} 141 </div> 142{/if}