grain.social is a photo sharing platform built on atproto.
at main 2.1 kB view raw
1import { GalleryView } from "$lexicon/types/social/grain/gallery/defs.ts"; 2import { BffContext, RouteHandler } from "@bigmoves/bff"; 3import { ActorInfo } from "../components/ActorInfo.tsx"; 4import { Breadcrumb } from "../components/Breadcrumb.tsx"; 5import { GalleryPreviewLink } from "../components/GalleryPreviewLink.tsx"; 6import { Header } from "../components/Header.tsx"; 7import { RenderFacetedText } from "../components/RenderFacetedText.tsx"; 8import { getGalleriesByHashtag } from "../lib/gallery.ts"; 9import { State } from "../state.ts"; 10 11export const handler: RouteHandler = ( 12 _req, 13 params, 14 ctx: BffContext<State>, 15) => { 16 const tag = params.tag; 17 18 const galleries = getGalleriesByHashtag(tag, ctx); 19 20 ctx.state.meta = [{ title: `Hashtag — Grain` }]; 21 22 return ctx.render( 23 <div class="p-4 flex flex-col gap-4"> 24 <Breadcrumb 25 class="m-0" 26 items={[{ label: "home", href: "/" }, { 27 label: tag, 28 }]} 29 /> 30 <Header>#{tag}</Header> 31 32 {galleries.length > 0 33 ? ( 34 <div class="grid grid-cols-1 sm:grid-cols-3 gap-4"> 35 {galleries.map((gallery) => ( 36 <HashtagGalleryItem gallery={gallery} key={gallery.uri} /> 37 ))} 38 </div> 39 ) 40 : <div>No galleries found.</div>} 41 </div>, 42 ); 43}; 44 45function HashtagGalleryItem( 46 { gallery }: Readonly<{ 47 gallery: GalleryView; 48 }>, 49) { 50 const title = gallery.title; 51 const description = gallery.description; 52 const facets = gallery.facets || []; 53 return ( 54 <div class="flex flex-col gap-2" key={gallery.uri}> 55 <ActorInfo profile={gallery.creator} /> 56 <GalleryPreviewLink gallery={gallery} /> 57 <div class="font-semibold"> 58 {title} 59 </div> 60 {description && ( 61 <p class="text-sm text-zinc-600 dark:text-zinc-500"> 62 {facets && Array.isArray(facets) && 63 facets.length > 0 64 ? ( 65 <RenderFacetedText 66 text={description} 67 facets={facets} 68 /> 69 ) 70 : description} 71 </p> 72 )} 73 </div> 74 ); 75}