WIP: My personal website
0

Configure Feed

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

at main 2.9 kB View raw
1<script lang="ts"> 2 import { reveal } from '$lib/actions/reveal'; 3 import LazyLoadingImg from './LazyLoadingImg.svelte'; 4 import webDev from '$lib/assets/seenOn/webDev.webp'; 5 import atadventWorkshop from '$lib/assets/seenOn/atadventWorkshop.webp'; 6 type Appearance = { 7 title: string; 8 description: string; 9 image: string; 10 href: string; 11 platform: string; // e.g. 'YouTube', 'Talk', 'Podcast' 12 action?: string; // e.g. 'Watch', 'Listen' 13 }; 14 15 const appearances: Appearance[] = [ 16 { 17 title: 'CodeTV Web Dev Challenge with ATproto', 18 description: 19 'I was on an episode of CodeTV where me and 5 others rebuilt our personal websites (again) but using ATproto.', 20 image: webDev, 21 href: 'https://www.youtube.com/watch?v=S-XytKfGCO8', 22 platform: 'YouTube', 23 action: 'Watch' 24 }, 25 { 26 title: 'at://advent, an atproto adventure', 27 description: 28 'Me and Fig hosted a workshop at the Atmosphere Conf 2026 where we showed off at://advent, an atproto adventure and a fun way for developers to learn atproto.', 29 image: atadventWorkshop, 30 href: 'https://advent.codes/', 31 platform: 'Workshop', 32 action: 'Learn' 33 } 34 ]; 35 36 const INITIAL_COUNT = 4; 37 const LOAD_STEP = 2; 38 let visibleCount = $state(INITIAL_COUNT); 39 const visibleAppearances = $derived(appearances.slice(0, visibleCount)); 40 const hasMore = $derived(visibleCount < appearances.length); 41</script> 42 43<div id="as-seen-on" class="mt-10 flex flex-col items-center justify-center md:mt-20" use:reveal> 44 <div class="flex flex-col items-center justify-center"> 45 <h1 class="text-center font-urbanist text-2xl font-semibold md:text-5xl">As Seen On</h1> 46 <span class="text-md mt-2 px-2 text-center font-urbanist md:mt-4 md:px-5 md:text-xl"> 47 Talks, videos, and places I've shown up. 48 </span> 49 </div> 50 <div class="container mt-10 grid gap-10 p-4 md:grid-cols-2 xl:grid-cols-3"> 51 {#each visibleAppearances as item (item.title)} 52 <div class="card bg-base-100 shadow-sm transition duration-300 hover:-translate-y-1"> 53 <figure> 54 <LazyLoadingImg class="h-48 w-full" src={item.image} alt={item.title} /> 55 </figure> 56 <div class="card-body"> 57 <div class="badge font-urbanist badge-secondary">{item.platform}</div> 58 <h2 class="card-title font-urbanist text-2xl font-black">{item.title}</h2> 59 <p class="text-md font-urbanist font-medium opacity-60">{item.description}</p> 60 <div class="mt-2 card-actions justify-end"> 61 <a 62 class="btn font-urbanist btn-primary" 63 href={item.href} 64 target="_blank" 65 rel="noopener noreferrer" 66 > 67 {item.action ?? 'Watch'} 68 </a> 69 </div> 70 </div> 71 </div> 72 {/each} 73 </div> 74 {#if hasMore} 75 <button 76 class="btn mt-10 font-urbanist btn-primary" 77 onclick={() => (visibleCount = Math.min(visibleCount + LOAD_STEP, appearances.length))} 78 > 79 Load More 80 </button> 81 {/if} 82</div>