Coves frontend - a photon fork
at main 161 lines 3.9 kB view raw
1<script lang="ts"> 2 import { PostBody } from '$lib/feature/post' 3 import { Material } from 'mono-svelte' 4 import type { ClassValue } from 'svelte/elements' 5 import LabelStat from '../info/LabelStat.svelte' 6 import TextProps from '../text/TextProps.svelte' 7 import Avatar from './Avatar.svelte' 8 import Blobs from './Blobs.svelte' 9 10 interface Props { 11 avatar?: string 12 name: string 13 bio?: string 14 banner?: string | null 15 url?: string 16 stats?: { 17 name: string 18 value: string | number 19 format?: boolean 20 }[] 21 class?: ClassValue 22 nameDetail?: import('svelte').Snippet 23 actions?: import('svelte').Snippet 24 children?: import('svelte').Snippet 25 compact?: 'always' | 'lg' 26 avatarCircle?: boolean 27 } 28 29 let { 30 avatar, 31 name, 32 bio, 33 banner, 34 url, 35 stats = [], 36 class: clazz = '', 37 nameDetail, 38 actions, 39 children, 40 compact, 41 avatarCircle = true, 42 ...rest 43 }: Props = $props() 44</script> 45 46<div {...rest} class={['z-10 text-sm w-full space-y-4 @container', clazz]}> 47 <Material padding="xl" rounding="3xl" class="flex flex-col gap-2 @lg:gap-4"> 48 {#if banner !== null} 49 <div 50 class="relative overflow-hidden rounded-t-[inherit] -m-6 mask-b-from-0 h-32 @lg:h-48" 51 > 52 {#if banner} 53 <img 54 src={banner} 55 class="w-full object-cover h-full bg-white dark:bg-zinc-900" 56 height="192" 57 alt="User banner" 58 /> 59 {:else} 60 <div class="scale-150 h-full"> 61 <Blobs seed={name} /> 62 </div> 63 {/if} 64 </div> 65 {/if} 66 67 {#snippet pfp(width: number)} 68 <Avatar 69 {width} 70 url={avatar} 71 alt={name} 72 circle={avatarCircle} 73 class={[ 74 'relative', 75 banner !== null && '-mt-4 @md:-mt-8', 76 !avatarCircle && 'rounded-xl @md:rounded-3xl!', 77 ]} 78 /> 79 {/snippet} 80 81 <div class="contents @md:hidden"> 82 {@render pfp(48)} 83 </div> 84 85 <div class="hidden @md:contents"> 86 {@render pfp(72)} 87 </div> 88 89 <div class="space-y-1"> 90 <svelte:element 91 this={url ? 'a' : 'h1'} 92 href={url} 93 class={[ 94 'text-xl @md:text-2xl font-medium tracking-tight', 95 url && 96 'hover:underline hover:text-primary-900 dark:hover:text-primary-100', 97 ]} 98 > 99 {name} 100 </svelte:element> 101 {#if nameDetail} 102 <p 103 class="flex items-center gap-0 text-sm text-slate-600 dark:text-zinc-400 max-w-full w-max" 104 > 105 <TextProps wrap="no-wrap"> 106 {@render nameDetail?.()} 107 </TextProps> 108 </p> 109 {/if} 110 </div> 111 </Material> 112 {#if actions || stats.length > 0} 113 <div class="space-y-4"> 114 <div class="flex flex-col flex-1"> 115 {#if actions} 116 {@render actions?.()} 117 {/if} 118 </div> 119 {#if stats.length > 0} 120 <div 121 class={[ 122 compact == 'lg' && 'lg:hidden', 123 compact == 'always' ? 'hidden' : 'flex', 124 'text-sm flex-row flex-wrap overflow-hidden gap-4 h-full', 125 ]} 126 > 127 {#each stats as stat} 128 <LabelStat 129 label={stat.name} 130 content={stat.value} 131 labelClass="text-sm" 132 contentClass="text-lg" 133 /> 134 {/each} 135 </div> 136 {/if} 137 </div> 138 {/if} 139 {#if bio} 140 <PostBody 141 body={bio} 142 class={[ 143 compact == 'lg' && 'lg:hidden', 144 compact == 'always' && 'hidden', 145 'relative', 146 ]} 147 clickThrough={false} 148 /> 149 {/if} 150 {#if children} 151 <div class="space-y-3 py-4 pt-0 mt-4"> 152 {@render children?.()} 153 </div> 154 {/if} 155</div> 156 157<style> 158 .banner-mask { 159 mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); 160 } 161</style>