tangled
alpha
login
or
join now
flo-bit.dev
/
blento
your personal website on atproto - mirror
blento.app
20
fork
atom
overview
issues
pulls
pipelines
add popfeed reviews
Florian
2 weeks ago
b901933e
e4d39faa
+134
-2
6 changed files
expand all
collapse all
unified
split
docs
Autofill.md
src
lib
cards
PopfeedReviews
PopfeedReviewsCard.svelte
Rating.svelte
index.ts
index.ts
website
Settings.svelte
+12
docs/Autofill.md
···
1
1
+
# autofilling a profile
2
2
+
3
3
+
- find all links in bluesky profile
4
4
+
- check for lexicons:
5
5
+
- place.stream.livestream
6
6
+
- social.popfeed.challenge.participation
7
7
+
- social.popfeed.feed.review
8
8
+
- site.standard.document
9
9
+
- com.germnetwork.declaration
10
10
+
- pub.leaflet.document
11
11
+
- blue.flashes.actor.portfolio
12
12
+
- add bluesky profile card
+46
src/lib/cards/PopfeedReviews/PopfeedReviewsCard.svelte
···
1
1
+
<script lang="ts">
2
2
+
import type { Item } from '$lib/types';
3
3
+
import { onMount } from 'svelte';
4
4
+
import { BlueskyPost } from '../../components/bluesky-post';
5
5
+
import { getAdditionalUserData, getDidContext, getHandleContext } from '$lib/website/context';
6
6
+
import { CardDefinitionsByType } from '..';
7
7
+
import Rating from './Rating.svelte';
8
8
+
9
9
+
let { item }: { item: Item } = $props();
10
10
+
11
11
+
const data = getAdditionalUserData();
12
12
+
// svelte-ignore state_referenced_locally
13
13
+
let feed = $state(data[item.cardType] as any);
14
14
+
15
15
+
let did = getDidContext();
16
16
+
let handle = getHandleContext();
17
17
+
18
18
+
onMount(async () => {
19
19
+
console.log(feed);
20
20
+
if (!feed) {
21
21
+
feed = (await CardDefinitionsByType[item.cardType]?.loadData?.([], {
22
22
+
did,
23
23
+
handle
24
24
+
})) as any;
25
25
+
26
26
+
console.log(feed);
27
27
+
28
28
+
data[item.cardType] = feed;
29
29
+
}
30
30
+
});
31
31
+
</script>
32
32
+
33
33
+
<div class="z-10 flex h-full gap-4 overflow-x-scroll p-4">
34
34
+
{#each feed ?? [] as review}
35
35
+
<a target="_blank" class="flex" href="https://popfeed.social/review/{review.uri}">
36
36
+
<div
37
37
+
class="relative flex aspect-[2/3] h-full flex-col items-center justify-end overflow-hidden p-1 rounded-xl"
38
38
+
>
39
39
+
<img src={review.value.posterUrl} alt="" class="absolute inset-0 -z-10" />
40
40
+
<div class="from-base-900/80 absolute bottom-0 left-0 right-0 h-1/3 bg-gradient-to-t via-transparent"></div>
41
41
+
42
42
+
<Rating class="z-10 text-lg" rating={review.value.rating} />
43
43
+
</div>
44
44
+
</a>
45
45
+
{/each}
46
46
+
</div>
+51
src/lib/cards/PopfeedReviews/Rating.svelte
···
1
1
+
<script lang="ts">
2
2
+
import { cn } from '@foxui/core';
3
3
+
4
4
+
let { rating, class: className }: { rating: number; class?: string } = $props();
5
5
+
6
6
+
// Convert 0-10 rating to 0-5 stars
7
7
+
const starRating = $derived(Math.max(0, Math.min(10, rating ?? 0)) / 2);
8
8
+
const fullStars = $derived(Math.floor(starRating));
9
9
+
const hasHalfStar = $derived(rating % 2 === 1);
10
10
+
const emptyStars = $derived(Math.max(0, 5 - fullStars - (hasHalfStar ? 1 : 0)));
11
11
+
</script>
12
12
+
13
13
+
{#snippet star(className: string)}
14
14
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="size-5 {className}">
15
15
+
<path
16
16
+
fill="currentColor"
17
17
+
fill-rule="evenodd"
18
18
+
d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z"
19
19
+
clip-rule="evenodd"
20
20
+
/>
21
21
+
</svg>
22
22
+
{/snippet}
23
23
+
24
24
+
{#snippet halfStar()}
25
25
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="size-5 fill-accent-500">
26
26
+
<defs>
27
27
+
<linearGradient id="half-filled" x1="0%" y1="0%" x2="100%" y2="0%">
28
28
+
<stop offset="50%" stop-color="currentColor" />
29
29
+
<stop offset="50%" stop-color="var(--color-base-400)" />
30
30
+
</linearGradient>
31
31
+
</defs>
32
32
+
<path
33
33
+
fill="url(#half-filled)"
34
34
+
fill-rule="evenodd"
35
35
+
d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z"
36
36
+
clip-rule="evenodd"
37
37
+
/>
38
38
+
</svg>
39
39
+
{/snippet}
40
40
+
41
41
+
<div class={cn('text-accent-500 flex', className)}>
42
42
+
{#each Array(fullStars) as _}
43
43
+
{@render star("text-accent-500")}
44
44
+
{/each}
45
45
+
{#if hasHalfStar}
46
46
+
{@render halfStar()}
47
47
+
{/if}
48
48
+
{#each Array(emptyStars) as _}
49
49
+
{@render star("text-base-400")}
50
50
+
{/each}
51
51
+
</div>
+21
src/lib/cards/PopfeedReviews/index.ts
···
1
1
+
import type { CardDefinition } from '../types';
2
2
+
import { listRecords } from '$lib/oauth/atproto';
3
3
+
import PopfeedReviewsCard from './PopfeedReviewsCard.svelte';
4
4
+
5
5
+
export const PopfeedReviewsCardDefinition = {
6
6
+
type: 'recentPopfeedReviews',
7
7
+
contentComponent: PopfeedReviewsCard,
8
8
+
createNew: (card) => {
9
9
+
card.w = 8;
10
10
+
card.mobileW = 8;
11
11
+
card.h = 3;
12
12
+
card.mobileH = 6;
13
13
+
},
14
14
+
loadData: async (items, { did }) => {
15
15
+
const data = await listRecords({ did, collection: 'social.popfeed.feed.review' });
16
16
+
17
17
+
return data;
18
18
+
},
19
19
+
minH: 3,
20
20
+
sidebarButtonText: 'Popfeed Reviews'
21
21
+
} as CardDefinition & { type: 'recentPopfeedReviews' };
+3
-1
src/lib/cards/index.ts
···
18
18
import { YoutubeCardDefinition } from './YoutubeVideoCard';
19
19
import { BlueskyProfileCardDefinition } from './BlueskyProfileCard';
20
20
import { GithubProfileCardDefitition } from './GitHubProfileCard';
21
21
+
import { PopfeedReviewsCardDefinition } from './PopfeedReviews';
21
22
22
23
export const AllCardDefinitions = [
23
24
ImageCardDefinition,
···
38
39
DinoGameCardDefinition,
39
40
BlueskyProfileCardDefinition,
40
41
GithubProfileCardDefitition,
41
41
-
TetrisCardDefinition
42
42
+
TetrisCardDefinition,
43
43
+
PopfeedReviewsCardDefinition
42
44
] as const;
43
45
44
46
export const CardDefinitionsByType = AllCardDefinitions.reduce(
+1
-1
src/lib/website/Settings.svelte
···
50
50
(value) => {
51
51
data.publication ??= {};
52
52
data.publication.preferences ??= {};
53
53
-
data.publication.preferences.hideProfile = value;
53
53
+
data.publication.preferences.hideProfileSection = value;
54
54
55
55
data = { ...data };
56
56
}