Coves frontend - a photon fork
1<script lang="ts">
2 // @ts-nocheck TODO(coves-migration): Needs Coves instance/site info API
3 import type { PersonView, SiteView, Tagline } from '$lib/api/types'
4 import { t } from '$lib/app/i18n'
5 import Markdown from '$lib/app/markdown/Markdown.svelte'
6 import { settings } from '$lib/app/settings.svelte'
7 import { userLink } from '$lib/app/util.svelte'
8 import EntityHeader from '$lib/ui/generic/EntityHeader.svelte'
9 import ItemList from '$lib/ui/generic/ItemList.svelte'
10 import LabelStat from '$lib/ui/info/LabelStat.svelte'
11 import EndPlaceholder from '$lib/ui/layout/EndPlaceholder.svelte'
12 import SidebarButton from '$lib/ui/sidebar/SidebarButton.svelte'
13 import { Badge, Expandable, Popover } from 'mono-svelte'
14 import {
15 BuildingOffice,
16 Icon,
17 Newspaper,
18 ServerStack,
19 } from 'svelte-hero-icons/dist'
20 import type { ClassValue, HTMLAttributes } from 'svelte/elements'
21
22 interface Props extends HTMLAttributes<HTMLDivElement> {
23 site: SiteView
24 taglines?: Tagline[]
25 admins?: PersonView[]
26 version?: string
27 class?: ClassValue
28 }
29
30 let { site, taglines, admins, version, class: clazz = '' }: Props = $props()
31</script>
32
33<aside
34 class={[
35 'w-full text-slate-600 dark:text-zinc-400 flex flex-col gap-4 text-sm',
36 clazz,
37 ]}
38>
39 <EntityHeader
40 name={site.site.name}
41 avatar={site.site.icon}
42 banner={site.site.banner || null}
43 compact="always"
44 avatarCircle={false}
45 />
46 <div class="flex flex-col gap-1">
47 {#if taglines && taglines.length > 0}
48 <Markdown
49 class="px-3"
50 source={taglines[Math.floor(Math.random() * taglines.length)].content}
51 />
52 {/if}
53
54 <EndPlaceholder size="xs" margin="sm">
55 {$t('nav.menu.instance')}
56 </EndPlaceholder>
57 <SidebarButton
58 href="/modlog"
59 label={$t('routes.modlog.title')}
60 icon={Newspaper}
61 />
62 <SidebarButton
63 href="/legal"
64 label={$t('routes.legal.title')}
65 icon={BuildingOffice}
66 />
67 <SidebarButton
68 href="/instances"
69 label={$t('routes.instances')}
70 icon={ServerStack}
71 />
72
73 <EndPlaceholder size="xs" margin="sm">
74 {$t('cards.site.stats')}
75 </EndPlaceholder>
76 <div class="flex flex-row gap-4 flex-wrap px-3">
77 <LabelStat
78 label={$t('content.users')}
79 content={site.counts.users.toString()}
80 formatted
81 />
82 <LabelStat
83 label={$t('content.posts')}
84 content={site.counts.posts.toString()}
85 formatted
86 />
87 <LabelStat
88 label={$t('content.comments')}
89 content={site.counts.comments.toString()}
90 formatted
91 />
92 <Popover openOnHover placement="bottom-end">
93 {#snippet target(attachment)}
94 <button class="text-left cursor-pointer" {@attach attachment}>
95 <LabelStat
96 label={$t('cards.community.activeDay')}
97 content={site.counts.users_active_day.toString()}
98 formatted
99 />
100 </button>
101 {/snippet}
102 <div class="flex flex-row gap-4 flex-wrap px-3">
103 <LabelStat
104 label={$t('filter.sort.top.time.week')}
105 content={site.counts.users_active_week.toString()}
106 formatted
107 />
108 <LabelStat
109 label={$t('filter.sort.top.time.month')}
110 content={site.counts.users_active_month.toString()}
111 formatted
112 />
113 <LabelStat
114 label={$t('filter.sort.top.time.6months')}
115 content={site.counts.users_active_half_year.toString()}
116 formatted
117 />
118 </div>
119 </Popover>
120 <LabelStat
121 label={$t('content.communities')}
122 content={site.counts.communities.toString()}
123 formatted
124 />
125 </div>
126
127 <EndPlaceholder size="xs" margin="sm">
128 {$t('common.info')}
129 </EndPlaceholder>
130 <div class="space-y-3 px-1.5 text-sm">
131 <Expandable bind:open={settings.expand.about}>
132 {#snippet title()}
133 <span class="flex items-center gap-1 py-1 px-2 w-full">
134 {$t('cards.site.about')}
135 </span>
136 {/snippet}
137 <Markdown source={site.site.description} />
138 <div class="my-4"></div>
139 <Markdown source={site.site.sidebar} />
140
141 {#if version}
142 <div class="w-max">
143 <Badge label="Lemmy version">
144 <Icon src={ServerStack} micro size="14" />
145 {version}
146 </Badge>
147 </div>
148 {/if}
149 </Expandable>
150
151 {#if admins}
152 <Expandable bind:open={settings.expand.team}>
153 {#snippet title()}
154 <span class="flex items-center gap-1 py-1 px-2 w-full">
155 {$t('cards.site.admins')}
156 </span>
157 {/snippet}
158 <ItemList
159 items={admins.map((i) => ({
160 id: i.person.id,
161 name: i.person.display_name || i.person.name,
162 url: userLink(i.person),
163 avatar: i.person.avatar,
164 instance: new URL(i.person.actor_id).hostname,
165 }))}
166 />
167 </Expandable>
168 {/if}
169 </div>
170 </div>
171</aside>