your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import Card from '../cards/Card/Card.svelte';
3 import Profile from './Profile.svelte';
4 import {
5 getDescription,
6 getHideProfileSection,
7 getProfilePosition,
8 getName,
9 sortItems
10 } from '../helper';
11 import { innerWidth } from 'svelte/reactivity/window';
12 import { setDidContext, setHandleContext, setIsMobile } from './context';
13 import BaseCard from '../cards/BaseCard/BaseCard.svelte';
14 import type { WebsiteData } from '$lib/types';
15 import Context from './Context.svelte';
16 import MadeWithBlento from './MadeWithBlento.svelte';
17 import Head from './Head.svelte';
18 import type { Did, Handle } from '@atcute/lexicons';
19 import QRModalProvider from '$lib/components/qr/QRModalProvider.svelte';
20 import EmptyState from './EmptyState.svelte';
21 import FloatingEditButton from './FloatingEditButton.svelte';
22 import { user } from '$lib/atproto';
23 import { env } from '$env/dynamic/public';
24
25 let { data }: { data: WebsiteData } = $props();
26
27 // Check if floating edit button will be visible (to hide MadeWithBlento)
28 const isOwnPage = $derived(user.isLoggedIn && user.profile?.did === data.did);
29 const isBlento = $derived(!env.PUBLIC_IS_SELFHOSTED && data.handle === 'blento.app');
30 const showFloatingButton = $derived(
31 isOwnPage ||
32 (isBlento && !user.isInitializing && !user.isLoggedIn) ||
33 (isBlento && user.isLoggedIn && user.profile?.handle !== data.handle)
34 );
35
36 let isMobile = $derived((innerWidth.current ?? 1000) < 1024);
37 setIsMobile(() => isMobile);
38
39 // svelte-ignore state_referenced_locally
40 setDidContext(data.did as Did);
41 // svelte-ignore state_referenced_locally
42 setHandleContext(data.handle as Handle);
43
44 let maxHeight = $derived(
45 data.cards.reduce(
46 (max, item) => Math.max(max, isMobile ? item.mobileY + item.mobileH : item.y + item.h),
47 0
48 )
49 );
50
51 let container: HTMLDivElement | undefined = $state();
52</script>
53
54<Head
55 favicon={data.profile.avatar ?? null}
56 title={getName(data)}
57 image={'/' + data.handle + '/og.png'}
58 description={getDescription(data)}
59/>
60
61<Context {data}>
62 <QRModalProvider />
63 <div class="@container/wrapper relative w-full">
64 {#if !getHideProfileSection(data)}
65 <Profile {data} hideBlento={showFloatingButton} />
66 {/if}
67
68 <div
69 class={[
70 'mx-auto max-w-lg',
71 !getHideProfileSection(data) && getProfilePosition(data) === 'side'
72 ? '@5xl/wrapper:grid @5xl/wrapper:max-w-7xl @5xl/wrapper:grid-cols-4'
73 : '@5xl/wrapper:max-w-4xl'
74 ]}
75 >
76 <div></div>
77 <div bind:this={container} class="@container/grid relative col-span-3 px-2 py-8 lg:px-8">
78 {#if data.cards.length === 0}
79 <EmptyState {data} />
80 {:else}
81 {#each data.cards.toSorted(sortItems) as item (item.id)}
82 <BaseCard {item}>
83 <Card {item} />
84 </BaseCard>
85 {/each}
86 <div style="height: {(maxHeight / 8) * 100}cqw;"></div>
87 {/if}
88 </div>
89 </div>
90
91 <MadeWithBlento class="mx-auto block pb-8 text-center @5xl/wrapper:hidden" />
92 </div>
93
94 <FloatingEditButton {data} />
95</Context>