your personal website on atproto - mirror blento.app
at button 314 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 import PostEmbed from './PostEmbed.svelte'; 12 13 let { 14 ref = $bindable(), 15 data, 16 class: className, 17 bookmarked = $bindable(false), 18 liked = $bindable(false), 19 20 showReply = $bindable(true), 21 showRepost = $bindable(true), 22 showLike = $bindable(true), 23 showBookmark = $bindable(true), 24 25 onReplyClick, 26 onRepostClick, 27 onLikeClick, 28 onBookmarkClick, 29 30 replyHref, 31 repostHref, 32 likeHref, 33 34 customActions, 35 36 children, 37 38 logo 39 }: WithElementRef<WithChildren<HTMLAttributes<HTMLDivElement>>> & { 40 data: PostData; 41 class?: string; 42 43 bookmarked?: boolean; 44 liked?: boolean; 45 46 showReply?: boolean; 47 showRepost?: boolean; 48 showLike?: boolean; 49 showBookmark?: boolean; 50 51 onReplyClick?: () => void; 52 onRepostClick?: () => void; 53 onLikeClick?: () => void; 54 onBookmarkClick?: () => void; 55 56 replyHref?: string; 57 repostHref?: string; 58 likeHref?: string; 59 60 customActions?: Snippet; 61 62 logo?: Snippet; 63 } = $props(); 64</script> 65 66<div 67 bind:this={ref} 68 class={cn('text-base-950 dark:text-base-50 transition-colors duration-200', className)} 69> 70 {#if data.reposted} 71 <div class="mb-3 inline-flex items-center gap-2 text-xs"> 72 <svg 73 xmlns="http://www.w3.org/2000/svg" 74 viewBox="0 0 24 24" 75 fill="currentColor" 76 class="size-3" 77 > 78 <path 79 fill-rule="evenodd" 80 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" 81 clip-rule="evenodd" 82 /> 83 </svg> 84 85 <div class="inline-flex gap-1"> 86 reposted by 87 <a 88 href={data.reposted.href} 89 class="hover:text-accent-600 dark:hover:text-accent-400 font-bold" 90 > 91 @{data.reposted.handle} 92 </a> 93 </div> 94 </div> 95 {/if} 96 {#if data.replyTo} 97 <div class="mb-3 inline-flex items-center gap-2 text-xs"> 98 <svg 99 xmlns="http://www.w3.org/2000/svg" 100 viewBox="0 0 24 24" 101 fill="currentColor" 102 class="size-3" 103 > 104 <path 105 fill-rule="evenodd" 106 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" 107 clip-rule="evenodd" 108 /> 109 </svg> 110 111 <div class="inline-flex gap-1"> 112 replying to 113 <a 114 href={data.replyTo.href} 115 class="hover:text-accent-600 dark:hover:text-accent-400 font-bold" 116 > 117 @{data.replyTo.handle} 118 </a> 119 </div> 120 </div> 121 {/if} 122 <div class="flex gap-4"> 123 <div class="w-full"> 124 <div class="mb-1 flex items-start justify-between gap-2"> 125 <div class="flex items-start gap-4"> 126 {#if data.author.href} 127 <a 128 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" 129 href={data.author.href} 130 > 131 {#if data.author.displayName} 132 <div 133 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" 134 > 135 {data.author.displayName} 136 </div> 137 {/if} 138 <div 139 class={cn( 140 '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', 141 !data.author.displayName 142 ? 'text-base-900 dark:text-base-50 font-semibold' 143 : 'text-base-600 dark:text-base-400' 144 )} 145 > 146 @{data.author.handle} 147 </div> 148 </a> 149 {:else} 150 <div 151 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" 152 > 153 <div class="text-base-900 dark:text-base-50 text-sm leading-tight font-semibold"> 154 {data.author.displayName} 155 </div> 156 <div class="text-base-600 dark:text-base-400 accent:text-accent-950 text-sm"> 157 @{data.author.handle} 158 </div> 159 </div> 160 {/if} 161 162 <div 163 class="text-base-600 dark:text-base-400 accent:text-accent-950 block text-sm no-underline" 164 > 165 <RelativeTime date={new Date(data.createdAt)} locale="en" /> 166 </div> 167 </div> 168 169 {#if logo} 170 {@render logo?.()} 171 {/if} 172 </div> 173 174 <Prose 175 size="md" 176 class="accent:prose-a:text-accent-950 accent:text-base-900 accent:prose-p:text-base-900 accent:prose-a:underline" 177 > 178 {#if data.htmlContent} 179 {@html data.htmlContent} 180 {:else} 181 {@render children?.()} 182 {/if} 183 </Prose> 184 185 <PostEmbed {data} /> 186 187 {#if showReply || showRepost || showLike || showBookmark || customActions} 188 <div 189 class="text-base-500 dark:text-base-400 accent:text-base-900 mt-4 flex justify-between gap-2" 190 > 191 {#if showReply} 192 <PostAction onclick={onReplyClick} href={replyHref}> 193 <svg 194 xmlns="http://www.w3.org/2000/svg" 195 fill="none" 196 viewBox="0 0 24 24" 197 stroke-width="1.5" 198 stroke="currentColor" 199 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" 200 > 201 <path 202 stroke-linecap="round" 203 stroke-linejoin="round" 204 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" 205 /> 206 </svg> 207 {#if data.replyCount} 208 {numberToHumanReadable(data.replyCount)} 209 {/if} 210 </PostAction> 211 {/if} 212 213 {#if showRepost} 214 <PostAction onclick={onRepostClick} href={repostHref}> 215 <svg 216 xmlns="http://www.w3.org/2000/svg" 217 fill="none" 218 viewBox="0 0 24 24" 219 stroke-width="1.5" 220 stroke="currentColor" 221 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" 222 > 223 <path 224 stroke-linecap="round" 225 stroke-linejoin="round" 226 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" 227 /> 228 </svg> 229 {#if data.repostCount} 230 {numberToHumanReadable(data.repostCount)} 231 {/if} 232 </PostAction> 233 {/if} 234 {#if showLike} 235 <PostAction 236 class={liked ? 'text-accent-700 dark:text-accent-500 font-semibold' : ''} 237 onclick={onLikeClick} 238 href={likeHref} 239 > 240 {#if liked} 241 <svg 242 xmlns="http://www.w3.org/2000/svg" 243 viewBox="0 0 24 24" 244 fill="currentColor" 245 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" 246 > 247 <path 248 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" 249 /> 250 </svg> 251 {:else} 252 <svg 253 xmlns="http://www.w3.org/2000/svg" 254 fill="none" 255 viewBox="0 0 24 24" 256 stroke-width="1.5" 257 stroke="currentColor" 258 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" 259 > 260 <path 261 stroke-linecap="round" 262 stroke-linejoin="round" 263 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" 264 /> 265 </svg> 266 {/if} 267 {#if data.likeCount} 268 {numberToHumanReadable(data.likeCount)} 269 {/if} 270 </PostAction> 271 {/if} 272 273 {#if showBookmark} 274 <PostAction onclick={onBookmarkClick}> 275 <span class="sr-only">Bookmark</span> 276 277 {#if bookmarked} 278 <svg 279 xmlns="http://www.w3.org/2000/svg" 280 viewBox="0 0 24 24" 281 fill="currentColor" 282 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" 283 > 284 <path 285 fill-rule="evenodd" 286 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" 287 clip-rule="evenodd" 288 /> 289 </svg> 290 {:else} 291 <svg 292 xmlns="http://www.w3.org/2000/svg" 293 fill="none" 294 viewBox="0 0 24 24" 295 stroke-width="1.5" 296 stroke="currentColor" 297 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" 298 > 299 <path 300 stroke-linecap="round" 301 stroke-linejoin="round" 302 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" 303 /> 304 </svg> 305 {/if} 306 </PostAction> 307 {/if} 308 309 {@render customActions?.()} 310 </div> 311 {/if} 312 </div> 313 </div> 314</div>