your personal website on atproto - mirror blento.app
at qr-codes 315 lines 10 kB view raw
1<script lang="ts"> 2 import Embed from './embeds/Embed.svelte'; 3 import { cn, Prose } from '@foxui/core'; 4 import type { WithChildren, WithElementRef } from 'bits-ui'; 5 import type { HTMLAttributes } from 'svelte/elements'; 6 import type { PostData } from '.'; 7 import PostAction from './PostAction.svelte'; 8 import type { Snippet } from 'svelte'; 9 import { numberToHumanReadable } from '..'; 10 import { RelativeTime } from '@foxui/time'; 11 12 let { 13 ref = $bindable(), 14 data, 15 class: className, 16 bookmarked = $bindable(false), 17 liked = $bindable(false), 18 19 showReply = $bindable(true), 20 showRepost = $bindable(true), 21 showLike = $bindable(true), 22 showBookmark = $bindable(true), 23 24 onReplyClick, 25 onRepostClick, 26 onLikeClick, 27 onBookmarkClick, 28 29 replyHref, 30 repostHref, 31 likeHref, 32 33 customActions, 34 35 children, 36 37 logo 38 }: WithElementRef<WithChildren<HTMLAttributes<HTMLDivElement>>> & { 39 data: PostData; 40 class?: string; 41 42 bookmarked?: boolean; 43 liked?: boolean; 44 45 showReply?: boolean; 46 showRepost?: boolean; 47 showLike?: boolean; 48 showBookmark?: boolean; 49 50 onReplyClick?: () => void; 51 onRepostClick?: () => void; 52 onLikeClick?: () => void; 53 onBookmarkClick?: () => void; 54 55 replyHref?: string; 56 repostHref?: string; 57 likeHref?: string; 58 59 customActions?: Snippet; 60 61 logo?: Snippet; 62 } = $props(); 63</script> 64 65<div 66 bind:this={ref} 67 class={cn('text-base-950 dark:text-base-50 transition-colors duration-200', className)} 68> 69 {#if data.reposted} 70 <div class="mb-3 inline-flex items-center gap-2 text-xs"> 71 <svg 72 xmlns="http://www.w3.org/2000/svg" 73 viewBox="0 0 24 24" 74 fill="currentColor" 75 class="size-3" 76 > 77 <path 78 fill-rule="evenodd" 79 d="M4.755 10.059a7.5 7.5 0 0 1 12.548-3.364l1.903 1.903h-3.183a.75.75 0 1 0 0 1.5h4.992a.75.75 0 0 0 .75-.75V4.356a.75.75 0 0 0-1.5 0v3.18l-1.9-1.9A9 9 0 0 0 3.306 9.67a.75.75 0 1 0 1.45.388Zm15.408 3.352a.75.75 0 0 0-.919.53 7.5 7.5 0 0 1-12.548 3.364l-1.902-1.903h3.183a.75.75 0 0 0 0-1.5H2.984a.75.75 0 0 0-.75.75v4.992a.75.75 0 0 0 1.5 0v-3.18l1.9 1.9a9 9 0 0 0 15.059-4.035.75.75 0 0 0-.53-.918Z" 80 clip-rule="evenodd" 81 /> 82 </svg> 83 84 <div class="inline-flex gap-1"> 85 reposted by 86 <a 87 href={data.reposted.href} 88 class="hover:text-accent-600 dark:hover:text-accent-400 font-bold" 89 > 90 @{data.reposted.handle} 91 </a> 92 </div> 93 </div> 94 {/if} 95 {#if data.replyTo} 96 <div class="mb-3 inline-flex items-center gap-2 text-xs"> 97 <svg 98 xmlns="http://www.w3.org/2000/svg" 99 viewBox="0 0 24 24" 100 fill="currentColor" 101 class="size-3" 102 > 103 <path 104 fill-rule="evenodd" 105 d="M14.47 2.47a.75.75 0 0 1 1.06 0l6 6a.75.75 0 0 1 0 1.06l-6 6a.75.75 0 1 1-1.06-1.06l4.72-4.72H9a5.25 5.25 0 1 0 0 10.5h3a.75.75 0 0 1 0 1.5H9a6.75 6.75 0 0 1 0-13.5h10.19l-4.72-4.72a.75.75 0 0 1 0-1.06Z" 106 clip-rule="evenodd" 107 /> 108 </svg> 109 110 <div class="inline-flex gap-1"> 111 replying to 112 <a 113 href={data.replyTo.href} 114 class="hover:text-accent-600 dark:hover:text-accent-400 font-bold" 115 > 116 @{data.replyTo.handle} 117 </a> 118 </div> 119 </div> 120 {/if} 121 <div class="flex gap-4"> 122 <div class="w-full"> 123 <div class="mb-1 flex items-start justify-between gap-2"> 124 <div class="flex items-start gap-4"> 125 {#if data.author.href} 126 <a 127 class="hover:bg-accent-900/5 accent:hover:bg-accent-100/10 group/post-author -mx-2 -my-0.5 flex flex-col items-baseline gap-x-2 gap-y-0.5 rounded-xl px-2 py-0.5 sm:flex-row" 128 href={data.author.href} 129 > 130 {#if data.author.displayName} 131 <div 132 class="text-base-900 group-hover/post-author:text-accent-600 dark:text-base-50 dark:group-hover/post-author:text-accent-300 accent:group-hover/post-author:text-accent-950 line-clamp-1 text-sm leading-tight font-semibold" 133 > 134 {data.author.displayName} 135 </div> 136 {/if} 137 <div 138 class={cn( 139 'group-hover/post-author:text-accent-600 dark:group-hover/post-author:text-accent-400 accent:text-accent-950 accent:group-hover/post-author:text-accent-900 text-sm', 140 !data.author.displayName 141 ? 'text-base-900 dark:text-base-50 font-semibold' 142 : 'text-base-600 dark:text-base-400' 143 )} 144 > 145 @{data.author.handle} 146 </div> 147 </a> 148 {:else} 149 <div 150 class="-mx-2 -my-0.5 flex flex-col items-baseline gap-x-2 gap-y-0.5 rounded-xl px-2 py-0.5 sm:flex-row" 151 > 152 <div class="text-base-900 dark:text-base-50 text-sm leading-tight font-semibold"> 153 {data.author.displayName} 154 </div> 155 <div class="text-base-600 dark:text-base-400 accent:text-accent-950 text-sm"> 156 @{data.author.handle} 157 </div> 158 </div> 159 {/if} 160 161 <div 162 class="text-base-600 dark:text-base-400 accent:text-accent-950 block text-sm no-underline" 163 > 164 <RelativeTime date={new Date(data.createdAt)} locale="en" /> 165 </div> 166 </div> 167 168 {#if logo} 169 {@render logo?.()} 170 {/if} 171 </div> 172 173 <Prose 174 size="md" 175 class="accent:prose-a:text-accent-950 accent:text-base-900 accent:prose-p:text-base-900 accent:prose-a:underline" 176 > 177 {#if data.htmlContent} 178 {@html data.htmlContent} 179 {:else} 180 {@render children?.()} 181 {/if} 182 </Prose> 183 184 {#if data.embed} 185 <Embed embed={data.embed} /> 186 {/if} 187 188 {#if showReply || showRepost || showLike || showBookmark || customActions} 189 <div 190 class="text-base-500 dark:text-base-400 accent:text-base-900 mt-4 flex justify-between gap-2" 191 > 192 {#if showReply} 193 <PostAction onclick={onReplyClick} href={replyHref}> 194 <svg 195 xmlns="http://www.w3.org/2000/svg" 196 fill="none" 197 viewBox="0 0 24 24" 198 stroke-width="1.5" 199 stroke="currentColor" 200 class="group-hover/post-action:bg-accent-500/10 group-hover/post-action:text-accent-700 dark:group-hover/post-action:text-accent-400 -m-1.5 size-7 rounded-full p-1.5 transition-all duration-100" 201 > 202 <path 203 stroke-linecap="round" 204 stroke-linejoin="round" 205 d="M12 20.25c4.97 0 9-3.694 9-8.25s-4.03-8.25-9-8.25S3 7.444 3 12c0 2.104.859 4.023 2.273 5.48.432.447.74 1.04.586 1.641a4.483 4.483 0 0 1-.923 1.785A5.969 5.969 0 0 0 6 21c1.282 0 2.47-.402 3.445-1.087.81.22 1.668.337 2.555.337Z" 206 /> 207 </svg> 208 {#if data.replyCount} 209 {numberToHumanReadable(data.replyCount)} 210 {/if} 211 </PostAction> 212 {/if} 213 214 {#if showRepost} 215 <PostAction onclick={onRepostClick} href={repostHref}> 216 <svg 217 xmlns="http://www.w3.org/2000/svg" 218 fill="none" 219 viewBox="0 0 24 24" 220 stroke-width="1.5" 221 stroke="currentColor" 222 class="group-hover/post-action:bg-accent-500/10 group-hover/post-action:text-accent-700 dark:group-hover/post-action:text-accent-400 -m-1.5 size-7 rounded-full p-1.5 transition-all duration-100" 223 > 224 <path 225 stroke-linecap="round" 226 stroke-linejoin="round" 227 d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" 228 /> 229 </svg> 230 {#if data.repostCount} 231 {numberToHumanReadable(data.repostCount)} 232 {/if} 233 </PostAction> 234 {/if} 235 {#if showLike} 236 <PostAction 237 class={liked ? 'text-accent-700 dark:text-accent-500 font-semibold' : ''} 238 onclick={onLikeClick} 239 href={likeHref} 240 > 241 {#if liked} 242 <svg 243 xmlns="http://www.w3.org/2000/svg" 244 viewBox="0 0 24 24" 245 fill="currentColor" 246 class="group-hover/post-action:bg-accent-500/10 text-accent-700 dark:text-accent-500 -m-1.5 size-7 rounded-full p-1.5 transition-all duration-100" 247 > 248 <path 249 d="m11.645 20.91-.007-.003-.022-.012a15.247 15.247 0 0 1-.383-.218 25.18 25.18 0 0 1-4.244-3.17C4.688 15.36 2.25 12.174 2.25 8.25 2.25 5.322 4.714 3 7.688 3A5.5 5.5 0 0 1 12 5.052 5.5 5.5 0 0 1 16.313 3c2.973 0 5.437 2.322 5.437 5.25 0 3.925-2.438 7.111-4.739 9.256a25.175 25.175 0 0 1-4.244 3.17 15.247 15.247 0 0 1-.383.219l-.022.012-.007.004-.003.001a.752.752 0 0 1-.704 0l-.003-.001Z" 250 /> 251 </svg> 252 {:else} 253 <svg 254 xmlns="http://www.w3.org/2000/svg" 255 fill="none" 256 viewBox="0 0 24 24" 257 stroke-width="1.5" 258 stroke="currentColor" 259 class="group-hover/post-action:bg-accent-500/10 group-hover/post-action:text-accent-700 dark:group-hover/post-action:text-accent-400 -m-1.5 size-7 rounded-full p-1.5 transition-all duration-100" 260 > 261 <path 262 stroke-linecap="round" 263 stroke-linejoin="round" 264 d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z" 265 /> 266 </svg> 267 {/if} 268 {#if data.likeCount} 269 {numberToHumanReadable(data.likeCount)} 270 {/if} 271 </PostAction> 272 {/if} 273 274 {#if showBookmark} 275 <PostAction onclick={onBookmarkClick}> 276 <span class="sr-only">Bookmark</span> 277 278 {#if bookmarked} 279 <svg 280 xmlns="http://www.w3.org/2000/svg" 281 viewBox="0 0 24 24" 282 fill="currentColor" 283 class="group-hover/post-action:bg-accent-500/10 text-accent-700 dark:text-accent-400 -m-1.5 size-7 rounded-full p-1.5 transition-all duration-100" 284 > 285 <path 286 fill-rule="evenodd" 287 d="M6.32 2.577a49.255 49.255 0 0 1 11.36 0c1.497.174 2.57 1.46 2.57 2.93V21a.75.75 0 0 1-1.085.67L12 18.089l-7.165 3.583A.75.75 0 0 1 3.75 21V5.507c0-1.47 1.073-2.756 2.57-2.93Z" 288 clip-rule="evenodd" 289 /> 290 </svg> 291 {:else} 292 <svg 293 xmlns="http://www.w3.org/2000/svg" 294 fill="none" 295 viewBox="0 0 24 24" 296 stroke-width="1.5" 297 stroke="currentColor" 298 class="group-hover/post-action:bg-accent-500/10 group-hover/post-action:text-accent-700 dark:group-hover/post-action:text-accent-400 -m-1.5 size-7 rounded-full p-1.5 transition-all duration-100" 299 > 300 <path 301 stroke-linecap="round" 302 stroke-linejoin="round" 303 d="M17.593 3.322c1.1.128 1.907 1.077 1.907 2.185V21L12 17.25 4.5 21V5.507c0-1.108.806-2.057 1.907-2.185a48.507 48.507 0 0 1 11.186 0Z" 304 /> 305 </svg> 306 {/if} 307 </PostAction> 308 {/if} 309 310 {@render customActions?.()} 311 </div> 312 {/if} 313 </div> 314 </div> 315</div>