Coves frontend - a photon fork
at main 188 lines 5.3 kB view raw
1<script lang="ts"> 2 import type { CommunityViewDetailed } from '$lib/api/coves/types' 3 import { coves } from '$lib/api/client.svelte' 4 import { profile } from '$lib/app/auth.svelte' 5 import { t } from '$lib/app/i18n' 6 import EntityHeader from '$lib/ui/generic/EntityHeader.svelte' 7 import { action, Button, Menu, MenuButton, modal, toast } from 'mono-svelte' 8 import { formatRelativeDate } from 'mono-svelte/util/RelativeDate.svelte' 9 import { 10 Check, 11 Cog6Tooth, 12 EllipsisHorizontal, 13 Fire, 14 Icon, 15 Newspaper, 16 Plus, 17 ShieldCheck, 18 } from 'svelte-hero-icons/dist' 19 import { purgeCommunity } from './CommunityCard.svelte' 20 import { communityDisplayName, communityIdentifier } from './helpers' 21 22 interface Props { 23 community: CommunityViewDetailed 24 banner?: boolean 25 class?: string 26 compact?: 'always' | 'lg' 27 avatarCircle?: boolean 28 } 29 30 let { 31 community = $bindable(), 32 banner = true, 33 class: clazz = '', 34 compact, 35 ...rest 36 }: Props = $props() 37 38 let subscribing = $state(false) 39 40 async function handleSubscribe(): Promise<void> { 41 if (!profile.current?.jwt) return 42 subscribing = true 43 44 const wasSubscribed = community.viewer?.subscribed === true 45 46 try { 47 if (wasSubscribed) { 48 await coves().unsubscribe({ community: community.did }) 49 } else { 50 await coves().subscribe({ community: community.did }) 51 } 52 53 // Toggle state only on success 54 if (community.viewer) { 55 community.viewer.subscribed = !wasSubscribed 56 } else { 57 community.viewer = { subscribed: !wasSubscribed } 58 } 59 } catch (err) { 60 const errorMsg = err instanceof Error ? err.message : String(err) 61 toast({ content: errorMsg, type: 'error' }) 62 } 63 64 subscribing = false 65 } 66</script> 67 68<EntityHeader 69 {...rest} 70 {compact} 71 banner={banner ? community.banner : undefined} 72 avatar={community.avatar} 73 name={communityDisplayName(community)} 74 url="/c/{communityIdentifier(community)}" 75 stats={[ 76 { 77 name: $t('cards.community.members'), 78 value: community.subscriberCount.toString(), 79 }, 80 { 81 name: $t('content.posts'), 82 value: community.postCount.toString(), 83 }, 84 { 85 name: $t('stats.created'), 86 format: false, 87 value: formatRelativeDate(new Date(community.createdAt), { 88 style: 'short', 89 }).toString(), 90 }, 91 ]} 92 bio={community.description} 93 class={['tracking-normal', clazz]} 94> 95 {#snippet nameDetail()} 96 <button 97 onclick={() => { 98 navigator?.clipboard?.writeText?.(`!${communityIdentifier(community)}`) 99 toast({ content: $t('toast.copied') }) 100 }} 101 class="text-sm flex gap-0 items-center" 102 > 103 !{communityIdentifier(community)} 104 </button> 105 {/snippet} 106 <div 107 class={[ 108 'flex items-center gap-2 h-max w-max', 109 compact == 'lg' && 'lg:hidden', 110 ]} 111 > 112 {#if profile.current?.jwt} 113 {@const subscribed = community.viewer?.subscribed === true} 114 <Button 115 disabled={subscribing} 116 loading={subscribing} 117 color={!subscribed ? 'primary' : 'secondary'} 118 onclick={handleSubscribe} 119 class="relative z-[inherit]" 120 size="lg" 121 icon={subscribed ? Check : Plus} 122 > 123 {subscribed 124 ? $t('cards.community.subscribed') 125 : $t('cards.community.subscribe')} 126 </Button> 127 {/if} 128 129 {#if profile.isMod(community)} 130 <Button 131 color="secondary" 132 size="square-lg" 133 href="/c/{communityIdentifier(community)}/settings" 134 > 135 <Icon src={Cog6Tooth} size="16" mini /> 136 </Button> 137 {/if} 138 <Menu placement="top-end"> 139 {#snippet target(attachment)} 140 <Button {@attach attachment} size="square-lg" icon={EllipsisHorizontal} 141 ></Button> 142 {/snippet} 143 <MenuButton href="/modlog?community={community.did}"> 144 <Icon src={Newspaper} size="16" mini /> 145 {$t('cards.community.modlog')} 146 </MenuButton> 147 {#if profile.isMod(community)} 148 <MenuButton 149 color="success-subtle" 150 href="/moderation?community={community.did}" 151 > 152 <Icon src={ShieldCheck} size="16" micro /> 153 {$t('routes.moderation.feed')} 154 </MenuButton> 155 {/if} 156 {#if profile.current?.jwt} 157 {#if profile.isAdmin} 158 <MenuButton 159 color="danger-subtle" 160 onclick={() => 161 modal({ 162 title: $t('admin.purgeCommunity.title'), 163 body: `${communityDisplayName(community)}: ${$t('admin.purgeCommunity.warning')}`, 164 actions: [ 165 action({ 166 close: true, 167 content: $t('common.cancel'), 168 }), 169 action({ 170 action: () => purgeCommunity(community.did), 171 close: true, 172 content: $t('admin.purge'), 173 type: 'danger', 174 icon: Fire, 175 }), 176 ], 177 dismissable: true, 178 type: 'error', 179 })} 180 icon={Fire} 181 > 182 {$t('admin.purge')} 183 </MenuButton> 184 {/if} 185 {/if} 186 </Menu> 187 </div> 188</EntityHeader>