@atmo-dev/kit 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -0
- package/dist/components/ExternalEmbed.svelte +174 -0
- package/dist/components/ExternalEmbed.svelte.d.ts +8 -0
- package/dist/components/GrainAlbumPicker.svelte +218 -0
- package/dist/components/GrainAlbumPicker.svelte.d.ts +14 -0
- package/dist/components/GrainAlbumView.svelte +94 -0
- package/dist/components/GrainAlbumView.svelte.d.ts +10 -0
- package/dist/components/NestedComments.svelte +31 -20
- package/dist/components/NestedComments.svelte.d.ts +4 -0
- package/dist/components/PhotoGrid.svelte +53 -0
- package/dist/components/PhotoGrid.svelte.d.ts +9 -0
- package/dist/components/PhotoLightbox.svelte +332 -0
- package/dist/components/PhotoLightbox.svelte.d.ts +12 -0
- package/dist/components/PostContent.svelte +78 -20
- package/dist/components/PostContent.svelte.d.ts +5 -0
- package/dist/components/SocialClientPicker.svelte +50 -0
- package/dist/components/SocialClientPicker.svelte.d.ts +8 -0
- package/dist/components/StreamplacePicker.svelte +94 -0
- package/dist/components/StreamplacePicker.svelte.d.ts +12 -0
- package/dist/components/UserProfile.svelte +151 -0
- package/dist/components/UserProfile.svelte.d.ts +20 -0
- package/dist/grain/types.d.ts +41 -0
- package/dist/grain/types.js +1 -0
- package/dist/grain/urls.d.ts +7 -0
- package/dist/grain/urls.js +74 -0
- package/dist/grain/xrpc.d.ts +3 -0
- package/dist/grain/xrpc.js +129 -0
- package/dist/grain.d.ts +3 -0
- package/dist/grain.js +2 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +13 -0
- package/dist/lexicons/social.atmo.actor.preferredClient.json +29 -0
- package/dist/media.d.ts +10 -0
- package/dist/media.js +1 -0
- package/dist/social/external-embeds.d.ts +39 -0
- package/dist/social/external-embeds.js +107 -0
- package/dist/social/posts.d.ts +59 -17
- package/dist/social/posts.js +99 -12
- package/dist/social/preferred-client.d.ts +36 -0
- package/dist/social/preferred-client.js +48 -0
- package/dist/social/profile.d.ts +36 -0
- package/dist/social/profile.js +78 -0
- package/dist/social/urls.d.ts +7 -0
- package/dist/social/urls.js +18 -2
- package/dist/social.d.ts +5 -0
- package/dist/social.js +3 -0
- package/dist/streamplace.d.ts +6 -0
- package/dist/streamplace.js +1 -0
- package/package.json +18 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { tokenize } from '@atcute/bluesky-richtext-parser';
|
|
2
|
+
import { safeWebUrl } from './richtext.js';
|
|
3
|
+
import { socialHashtagUrl, socialProfileUrl } from './urls.js';
|
|
4
|
+
/** Only web URLs; never accept executable schemes or disguised credentials. */
|
|
5
|
+
export function safeProfileUrl(value) {
|
|
6
|
+
if (!value ||
|
|
7
|
+
Array.from(value).some((char) => char.charCodeAt(0) <= 0x20 || char.charCodeAt(0) === 0x7f))
|
|
8
|
+
return undefined;
|
|
9
|
+
const href = safeWebUrl(value);
|
|
10
|
+
if (!href)
|
|
11
|
+
return undefined;
|
|
12
|
+
const url = new URL(href);
|
|
13
|
+
return url.username || url.password ? undefined : href;
|
|
14
|
+
}
|
|
15
|
+
export function profileDescriptionSegments(text, options = {}) {
|
|
16
|
+
return Array.from(tokenize(text), (token) => ({
|
|
17
|
+
text: token.raw,
|
|
18
|
+
href: token.type === 'autolink'
|
|
19
|
+
? safeProfileUrl(token.url)
|
|
20
|
+
: token.type === 'mention'
|
|
21
|
+
? (options.mentionUrl?.(token.handle) ??
|
|
22
|
+
socialProfileUrl(token.handle, options.socialClient))
|
|
23
|
+
: token.type === 'topic'
|
|
24
|
+
? socialHashtagUrl(token.name, options.socialClient)
|
|
25
|
+
: undefined
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
export function visibleProfileLinks(links = []) {
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
const result = [];
|
|
31
|
+
for (const link of links) {
|
|
32
|
+
const url = safeProfileUrl(link.url);
|
|
33
|
+
if (!url || seen.has(url))
|
|
34
|
+
continue;
|
|
35
|
+
seen.add(url);
|
|
36
|
+
result.push({ url, title: link.title?.trim() || undefined, icon: safeProfileUrl(link.icon) });
|
|
37
|
+
if (result.length === 10)
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
/** Validate public AppView data at the boundary, including newer optional fields. */
|
|
43
|
+
export function blueskyProfileToProfileData(value) {
|
|
44
|
+
if (!value || typeof value !== 'object')
|
|
45
|
+
return undefined;
|
|
46
|
+
const p = value;
|
|
47
|
+
if (typeof p.did !== 'string' || !p.did.startsWith('did:'))
|
|
48
|
+
return undefined;
|
|
49
|
+
const text = (key) => (typeof p[key] === 'string' ? p[key] : undefined);
|
|
50
|
+
const count = (key) => typeof p[key] === 'number' && Number.isSafeInteger(p[key]) && p[key] >= 0 ? p[key] : undefined;
|
|
51
|
+
const links = [];
|
|
52
|
+
for (const item of Array.isArray(p.links) ? p.links : []) {
|
|
53
|
+
if (!item || typeof item !== 'object' || typeof item.url !== 'string')
|
|
54
|
+
continue;
|
|
55
|
+
// Without viewer-specific moderation preferences, omit labeled links conservatively.
|
|
56
|
+
if (Array.isArray(item.labels) && item.labels.some((label) => !label?.neg))
|
|
57
|
+
continue;
|
|
58
|
+
links.push({
|
|
59
|
+
url: item.url,
|
|
60
|
+
title: typeof item.title === 'string' ? item.title : undefined,
|
|
61
|
+
icon: typeof item.icon === 'string' ? item.icon : undefined
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
did: p.did,
|
|
66
|
+
handle: text('handle'),
|
|
67
|
+
displayName: text('displayName'),
|
|
68
|
+
avatar: safeProfileUrl(text('avatar')),
|
|
69
|
+
banner: safeProfileUrl(text('banner')),
|
|
70
|
+
description: text('description'),
|
|
71
|
+
pronouns: text('pronouns'),
|
|
72
|
+
links: visibleProfileLinks(links),
|
|
73
|
+
followersCount: count('followersCount'),
|
|
74
|
+
followsCount: count('followsCount'),
|
|
75
|
+
postsCount: count('postsCount'),
|
|
76
|
+
createdAt: text('createdAt')
|
|
77
|
+
};
|
|
78
|
+
}
|
package/dist/social/urls.d.ts
CHANGED
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
import { type PreferredSocialClient } from './preferred-client.js';
|
|
1
2
|
/** Bluesky expects literal DIDs in its routes, including colons and did:web escapes. */
|
|
2
3
|
export declare function blueskyProfileUrl(identifier: string): string;
|
|
4
|
+
/** Supported clients share Bluesky's /profile/:actor route. */
|
|
5
|
+
export declare function socialProfileUrl(identifier: string, client?: PreferredSocialClient | null): string;
|
|
6
|
+
/** Open a hashtag in the viewer's preferred Bluesky-compatible client. */
|
|
7
|
+
export declare function socialHashtagUrl(tag: string, client?: PreferredSocialClient | null): string;
|
|
8
|
+
/** Open a feed-post AT URI in the viewer's preferred Bluesky-compatible client. */
|
|
9
|
+
export declare function socialPostUrl(uri: string, client?: PreferredSocialClient | null): string | null;
|
package/dist/social/urls.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
import { isDid } from '@atcute/lexicons/syntax';
|
|
1
|
+
import { isActorIdentifier, isDid, isRecordKey } from '@atcute/lexicons/syntax';
|
|
2
|
+
import { socialClientInfo } from './preferred-client.js';
|
|
2
3
|
/** Bluesky expects literal DIDs in its routes, including colons and did:web escapes. */
|
|
3
4
|
export function blueskyProfileUrl(identifier) {
|
|
5
|
+
return socialProfileUrl(identifier);
|
|
6
|
+
}
|
|
7
|
+
/** Supported clients share Bluesky's /profile/:actor route. */
|
|
8
|
+
export function socialProfileUrl(identifier, client) {
|
|
4
9
|
const actor = isDid(identifier) ? identifier : encodeURIComponent(identifier);
|
|
5
|
-
return
|
|
10
|
+
return `${socialClientInfo(client).url}/profile/${actor}`;
|
|
11
|
+
}
|
|
12
|
+
/** Open a hashtag in the viewer's preferred Bluesky-compatible client. */
|
|
13
|
+
export function socialHashtagUrl(tag, client) {
|
|
14
|
+
return `${socialClientInfo(client).url}/hashtag/${encodeURIComponent(tag)}`;
|
|
15
|
+
}
|
|
16
|
+
/** Open a feed-post AT URI in the viewer's preferred Bluesky-compatible client. */
|
|
17
|
+
export function socialPostUrl(uri, client) {
|
|
18
|
+
const match = /^at:\/\/([^/]+)\/app\.bsky\.feed\.post\/([^/]+)$/.exec(uri);
|
|
19
|
+
if (!match || !isActorIdentifier(match[1]) || !isRecordKey(match[2]))
|
|
20
|
+
return null;
|
|
21
|
+
return `${socialProfileUrl(match[1], client)}/post/${encodeURIComponent(match[2])}`;
|
|
6
22
|
}
|
package/dist/social.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { PREFERRED_CLIENT_COLLECTION, PREFERRED_CLIENT_RKEY, PREFERRED_CLIENT_SCOPE, socialClients, normalizeSocialClientUrl, parsePreferredSocialClient, preferredSocialClientRecord, socialClientInfo } from './social/preferred-client.js';
|
|
2
|
+
export type { SocialClientId, PreferredSocialClient } from './social/preferred-client.js';
|
|
3
|
+
export { defaultExternalEmbedProviders, youtubeEmbedProvider, klipyEmbedProvider, resolveExternalEmbed } from './social/external-embeds.js';
|
|
4
|
+
export type { ExternalPostEmbed, ExternalEmbedProvider, ExternalEmbedPlayer } from './social/external-embeds.js';
|
|
5
|
+
export { blueskyProfileUrl, socialProfileUrl, socialPostUrl, socialHashtagUrl } from './social/urls.js';
|
package/dist/social.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { PREFERRED_CLIENT_COLLECTION, PREFERRED_CLIENT_RKEY, PREFERRED_CLIENT_SCOPE, socialClients, normalizeSocialClientUrl, parsePreferredSocialClient, preferredSocialClientRecord, socialClientInfo } from './social/preferred-client.js';
|
|
2
|
+
export { defaultExternalEmbedProviders, youtubeEmbedProvider, klipyEmbedProvider, resolveExternalEmbed } from './social/external-embeds.js';
|
|
3
|
+
export { blueskyProfileUrl, socialProfileUrl, socialPostUrl, socialHashtagUrl } from './social/urls.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseStreamplaceLink } from './grain/urls.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atmo-dev/kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "The shared UI foundation for Atmo apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -27,6 +27,23 @@
|
|
|
27
27
|
"svelte": "./dist/index.js",
|
|
28
28
|
"default": "./dist/index.js"
|
|
29
29
|
},
|
|
30
|
+
"./grain": {
|
|
31
|
+
"types": "./dist/grain.d.ts",
|
|
32
|
+
"default": "./dist/grain.js"
|
|
33
|
+
},
|
|
34
|
+
"./streamplace": {
|
|
35
|
+
"types": "./dist/streamplace.d.ts",
|
|
36
|
+
"default": "./dist/streamplace.js"
|
|
37
|
+
},
|
|
38
|
+
"./media": {
|
|
39
|
+
"types": "./dist/media.d.ts",
|
|
40
|
+
"default": "./dist/media.js"
|
|
41
|
+
},
|
|
42
|
+
"./social": {
|
|
43
|
+
"types": "./dist/social.d.ts",
|
|
44
|
+
"default": "./dist/social.js"
|
|
45
|
+
},
|
|
46
|
+
"./lexicons/social.atmo.actor.preferredClient.json": "./dist/lexicons/social.atmo.actor.preferredClient.json",
|
|
30
47
|
"./legal": {
|
|
31
48
|
"types": "./dist/legal.d.ts",
|
|
32
49
|
"default": "./dist/legal.js"
|