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 npmx likes
Florian
3 days ago
0705fd4d
dbe50174
+143
-3
4 changed files
expand all
collapse all
unified
split
src
lib
cards
index.ts
social
NpmxLikesCard
NpmxLikesCard.svelte
index.ts
visual
FluidTextCard
FluidTextCard.svelte
+3
-1
src/lib/cards/index.ts
···
40
40
import { GitHubContributorsCardDefinition } from './social/GitHubContributorsCard';
41
41
import { ProductHuntCardDefinition } from './social/ProductHuntCard';
42
42
import { KickstarterCardDefinition } from './social/KickstarterCard';
43
43
+
import { NpmxLikesCardDefinition } from './social/NpmxLikesCard';
43
44
// import { Model3DCardDefinition } from './visual/Model3DCard';
44
45
45
46
export const AllCardDefinitions = [
···
84
85
FriendsCardDefinition,
85
86
GitHubContributorsCardDefinition,
86
87
ProductHuntCardDefinition,
87
87
-
KickstarterCardDefinition
88
88
+
KickstarterCardDefinition,
89
89
+
NpmxLikesCardDefinition
88
90
] as const;
89
91
90
92
export const CardDefinitionsByType = AllCardDefinitions.reduce(
+103
src/lib/cards/social/NpmxLikesCard/NpmxLikesCard.svelte
···
1
1
+
<script lang="ts">
2
2
+
import type { Item } from '$lib/types';
3
3
+
import { onMount } from 'svelte';
4
4
+
import { getAdditionalUserData, getDidContext, getHandleContext } from '$lib/website/context';
5
5
+
import { CardDefinitionsByType } from '../..';
6
6
+
import { RelativeTime } from '@foxui/time';
7
7
+
8
8
+
interface NpmxLike {
9
9
+
uri: string;
10
10
+
value: {
11
11
+
subjectRef: string;
12
12
+
createdAt: string;
13
13
+
};
14
14
+
}
15
15
+
16
16
+
let { item }: { item: Item } = $props();
17
17
+
18
18
+
const data = getAdditionalUserData();
19
19
+
// svelte-ignore state_referenced_locally
20
20
+
let feed = $state(data[item.cardType] as NpmxLike[] | undefined);
21
21
+
22
22
+
let did = getDidContext();
23
23
+
let handle = getHandleContext();
24
24
+
25
25
+
onMount(async () => {
26
26
+
if (feed) return;
27
27
+
28
28
+
feed = (await CardDefinitionsByType[item.cardType]?.loadData?.([], {
29
29
+
did,
30
30
+
handle
31
31
+
})) as NpmxLike[] | undefined;
32
32
+
33
33
+
data[item.cardType] = feed;
34
34
+
});
35
35
+
36
36
+
function getPackageName(like: NpmxLike): string {
37
37
+
return like.value.subjectRef.split('/package/')[1] ?? like.value.subjectRef;
38
38
+
}
39
39
+
</script>
40
40
+
41
41
+
{#snippet likeItem(like: NpmxLike)}
42
42
+
<div class="flex w-full items-center gap-3">
43
43
+
<div
44
44
+
class="text-accent-500 accent:text-accent-950 flex size-8 shrink-0 items-center justify-center"
45
45
+
>
46
46
+
<svg
47
47
+
xmlns="http://www.w3.org/2000/svg"
48
48
+
fill="none"
49
49
+
viewBox="0 0 24 24"
50
50
+
stroke-width="1.5"
51
51
+
stroke="currentColor"
52
52
+
class="size-5"
53
53
+
>
54
54
+
<path
55
55
+
stroke-linecap="round"
56
56
+
stroke-linejoin="round"
57
57
+
d="m21 7.5-9-5.25L3 7.5m18 0-9 5.25m9-5.25v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9"
58
58
+
/>
59
59
+
</svg>
60
60
+
</div>
61
61
+
<div class="min-w-0 flex-1">
62
62
+
<div class="inline-flex w-full max-w-full items-baseline justify-between gap-2">
63
63
+
<div
64
64
+
class="text-accent-500 accent:text-accent-950 min-w-0 flex-1 shrink truncate text-sm font-semibold"
65
65
+
>
66
66
+
{getPackageName(like)}
67
67
+
</div>
68
68
+
{#if like.value.createdAt}
69
69
+
<div class="text-base-500 dark:text-base-400 accent:text-white/60 shrink-0 text-xs">
70
70
+
<RelativeTime date={new Date(like.value.createdAt)} locale="en-US" /> ago
71
71
+
</div>
72
72
+
{/if}
73
73
+
</div>
74
74
+
</div>
75
75
+
</div>
76
76
+
{/snippet}
77
77
+
78
78
+
<div class="z-10 flex h-full w-full flex-col gap-3 overflow-y-scroll p-4">
79
79
+
{#if feed && feed.length > 0}
80
80
+
{#each feed as like (like.uri)}
81
81
+
<a
82
82
+
href="https://npmx.dev/package/{getPackageName(like)}"
83
83
+
target="_blank"
84
84
+
rel="noopener noreferrer"
85
85
+
class="w-full"
86
86
+
>
87
87
+
{@render likeItem(like)}
88
88
+
</a>
89
89
+
{/each}
90
90
+
{:else if feed}
91
91
+
<div
92
92
+
class="text-base-500 dark:text-base-400 accent:text-white/60 flex h-full items-center justify-center text-center text-sm"
93
93
+
>
94
94
+
No liked packages found.
95
95
+
</div>
96
96
+
{:else}
97
97
+
<div
98
98
+
class="text-base-500 dark:text-base-400 accent:text-white/60 flex h-full items-center justify-center text-center text-sm"
99
99
+
>
100
100
+
Loading likes...
101
101
+
</div>
102
102
+
{/if}
103
103
+
</div>
+31
src/lib/cards/social/NpmxLikesCard/index.ts
···
1
1
+
import type { CardDefinition } from '../../types';
2
2
+
import { listRecords } from '$lib/atproto';
3
3
+
import NpmxLikesCard from './NpmxLikesCard.svelte';
4
4
+
5
5
+
export const NpmxLikesCardDefinition = {
6
6
+
type: 'npmxLikes',
7
7
+
contentComponent: NpmxLikesCard,
8
8
+
createNew: (card) => {
9
9
+
card.w = 4;
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({
16
16
+
did,
17
17
+
collection: 'dev.npmx.feed.like',
18
18
+
limit: 99
19
19
+
});
20
20
+
21
21
+
return data;
22
22
+
},
23
23
+
minW: 4,
24
24
+
canHaveLabel: true,
25
25
+
26
26
+
keywords: ['npm', 'package', 'npmx', 'likes'],
27
27
+
name: 'npmx Likes',
28
28
+
29
29
+
groups: ['Social'],
30
30
+
icon: `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-4"><path stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12Z" /></svg>`
31
31
+
} as CardDefinition & { type: 'npmxLikes' };
+6
-2
src/lib/cards/visual/FluidTextCard/FluidTextCard.svelte
···
1773
1773
? 'bg-base-50 dark:bg-base-900'
1774
1774
: 'bg-black'}"
1775
1775
>
1776
1776
-
<canvas bind:this={shadowCanvas} class="absolute inset-0.5 h-[calc(100%-4px)] w-[calc(100%-4px)] rounded-[inherit]"></canvas>
1777
1777
-
<canvas bind:this={fluidCanvas} class="absolute inset-0.5 h-[calc(100%-4px)] w-[calc(100%-4px)]"></canvas>
1776
1776
+
<canvas
1777
1777
+
bind:this={shadowCanvas}
1778
1778
+
class="absolute inset-0.5 h-[calc(100%-4px)] w-[calc(100%-4px)] rounded-[inherit]"
1779
1779
+
></canvas>
1780
1780
+
<canvas bind:this={fluidCanvas} class="absolute inset-0.5 h-[calc(100%-4px)] w-[calc(100%-4px)]"
1781
1781
+
></canvas>
1778
1782
<canvas bind:this={maskCanvas} class="absolute h-full w-full"></canvas>
1779
1783
</div>