A Raycast extension to search and manage Semble Cards and Collections
1import { SembleCard, SembleCollection } from "./types";
2
3/**
4 * Extract the collection ID from an AT Protocol URI
5 * Example: at://did:plc:xxx/network.cosmik.collection/3m5a3ww5m4g2o -> 3m5a3ww5m4g2o
6 */
7export function extractCollectionId(uri: string): string {
8 const parts = uri.split("/");
9 return parts[parts.length - 1];
10}
11
12/**
13 * Extract username from identifier (handle or DID)
14 * Example: renderg.host -> renderg.host
15 */
16export function extractUsername(identifier: string): string {
17 // If it's a DID, we'd need to resolve it, but for now we'll use the identifier as-is
18 return identifier;
19}
20
21/**
22 * Generate a Semble card link
23 * Format: https://semble.so/url?id={cardUrl}
24 */
25export function generateCardLink(card: SembleCard): string {
26 const cardUrl = card.value.url || "";
27 return cardUrl ? `https://semble.so/url?id=${encodeURIComponent(cardUrl)}` : "";
28}
29
30/**
31 * Generate a Semble collection link
32 * Format: https://semble.so/profile/{username}/collections/{collectionId}
33 */
34export function generateCollectionLink(collection: SembleCollection, username: string): string {
35 const collectionId = extractCollectionId(collection.uri);
36 return `https://semble.so/profile/${username}/collections/${collectionId}`;
37}
38
39/**
40 * Get the title of a card
41 */
42export function getCardTitle(card: SembleCard): string {
43 return card.value.content?.metadata?.title || card.value.url || "Untitled Card";
44}
45
46/**
47 * Get the subtitle/description of a card
48 */
49export function getCardSubtitle(card: SembleCard): string {
50 return card.value.content?.metadata?.description || card.value.url || "No description";
51}
52
53/**
54 * Format date for display
55 */
56export function formatDate(dateString: string): string {
57 const date = new Date(dateString);
58 return date.toLocaleDateString(undefined, {
59 year: "numeric",
60 month: "short",
61 day: "numeric",
62 });
63}