From a3c68b05559fcff2719ff835fdddac8d91fe6f20 Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Sat, 31 Jan 2026 21:59:37 +0100 Subject: [PATCH 1/7] remove buttons --- src/lib/website/EditBar.svelte | 116 --------------------------------- 1 file changed, 116 deletions(-) diff --git a/src/lib/website/EditBar.svelte b/src/lib/website/EditBar.svelte index 4083af6..7ed8dfd 100644 --- a/src/lib/website/EditBar.svelte +++ b/src/lib/website/EditBar.svelte @@ -331,123 +331,7 @@ {:else} -
- - - - - - {#snippet child({ props })} - - {/snippet} - { - if (event.code === 'Enter') { - addLink(linkValue); - event.preventDefault(); - } - }} - placeholder="Enter link" - /> - - - - - diff --git a/src/lib/cards/VideoCard/index.ts b/src/lib/cards/VideoCard/index.ts deleted file mode 100644 index 2138edb..0000000 --- a/src/lib/cards/VideoCard/index.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { uploadBlob } from '$lib/atproto'; -import type { CardDefinition } from '../types'; -import VideoCard from './VideoCard.svelte'; -import VideoCardSettings from './VideoCardSettings.svelte'; - -async function getAspectRatio(videoBlob: Blob): Promise<{ width: number; height: number }> { - return new Promise((resolve, reject) => { - const video = document.createElement('video'); - video.preload = 'metadata'; - - video.onloadedmetadata = () => { - URL.revokeObjectURL(video.src); - resolve({ - width: video.videoWidth, - height: video.videoHeight - }); - }; - - video.onerror = () => { - URL.revokeObjectURL(video.src); - reject(new Error('Failed to load video metadata')); - }; - - video.src = URL.createObjectURL(videoBlob); - }); -} - -export const VideoCardDefinition = { - type: 'video', - contentComponent: VideoCard, - createNew: (card) => { - card.cardType = 'video'; - card.cardData = { - video: null, - href: '' - }; - }, - upload: async (item) => { - if (item.cardData.blob) { - const blob = item.cardData.blob; - const aspectRatio = await getAspectRatio(blob); - const uploadedBlob = await uploadBlob({ blob }); - - item.cardData.video = { - $type: 'app.bsky.embed.video', - video: uploadedBlob, - aspectRatio - }; - - delete item.cardData.blob; - } - - if (item.cardData.objectUrl) { - URL.revokeObjectURL(item.cardData.objectUrl); - delete item.cardData.objectUrl; - } - - return item; - }, - settingsComponent: VideoCardSettings, - - name: 'Video', - groups: ['Media'], - icon: `` -} as CardDefinition & { type: 'video' }; diff --git a/src/lib/cards/YoutubeVideoCard/index.ts b/src/lib/cards/YoutubeVideoCard/index.ts index 5bd3f01..b6dc9df 100644 --- a/src/lib/cards/YoutubeVideoCard/index.ts +++ b/src/lib/cards/YoutubeVideoCard/index.ts @@ -55,6 +55,7 @@ export const YoutubeCardDefinition = { }, name: 'Youtube Video', + keywords: ['video', 'yt', 'stream', 'watch'], groups: ['Media'], icon: ` void; }; -export type SidebarComponentProps = { - onclick: () => void; -}; - export type ContentComponentProps = { item: Item; isEditing?: boolean; @@ -33,9 +29,6 @@ export type CardDefinition = { upload?: (item: Item) => Promise; // optionally upload some other data needed for this card - // has to be set for a card to appear in the sidebar - sidebarButtonText?: string; - // if this component exists, a settings button with a popover will be shown containing this component settingsComponent?: Component; diff --git a/src/lib/website/EditableWebsite.svelte b/src/lib/website/EditableWebsite.svelte index 8672bd1..abfd441 100644 --- a/src/lib/website/EditableWebsite.svelte +++ b/src/lib/website/EditableWebsite.svelte @@ -256,7 +256,7 @@ } } - const sidebarItems = AllCardDefinitions.filter((cardDef) => cardDef.sidebarButtonText); + const sidebarItems = AllCardDefinitions.filter((cardDef) => cardDef.name); let debugPoint = $state({ x: 0, y: 0 }); -- 2.51.2 From cb11c84bae35c71812a88065f6168d78f7685418 Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Sat, 31 Jan 2026 23:16:00 +0100 Subject: [PATCH 4/7] commit --- src/lib/cards/FriendsCard/FriendsCard.svelte | 120 ++++++++++++++++++ .../FriendsCard/FriendsCardSettings.svelte | 104 +++++++++++++++ src/lib/cards/FriendsCard/index.ts | 44 +++++++ .../PhotoGalleryCard/PhotoGalleryCard.svelte | 9 +- src/lib/cards/index.ts | 4 +- src/lib/website/EditableWebsite.svelte | 1 - src/lib/website/layout-mirror.ts | 10 +- 7 files changed, 281 insertions(+), 11 deletions(-) create mode 100644 src/lib/cards/FriendsCard/FriendsCard.svelte create mode 100644 src/lib/cards/FriendsCard/FriendsCardSettings.svelte create mode 100644 src/lib/cards/FriendsCard/index.ts diff --git a/src/lib/cards/FriendsCard/FriendsCard.svelte b/src/lib/cards/FriendsCard/FriendsCard.svelte new file mode 100644 index 0000000..08dd76f --- /dev/null +++ b/src/lib/cards/FriendsCard/FriendsCard.svelte @@ -0,0 +1,120 @@ + + +
+ {#if dids.length === 0} + {#if canEdit()} + + Add friends in settings + + {/if} + {:else} +
+ {#each visibleProfiles as profile, i (profile.did)} + 0 && sizeClass === 'sm'} + class:-ml-5={i > 0 && sizeClass === 'md'} + class:-ml-6={i > 0 && sizeClass === 'lg'} + > + + + {/each} + {#if overflowCount > 0} +
+ + +{overflowCount} + +
+ {/if} +
+ {/if} +
diff --git a/src/lib/cards/FriendsCard/FriendsCardSettings.svelte b/src/lib/cards/FriendsCard/FriendsCardSettings.svelte new file mode 100644 index 0000000..6f70ca6 --- /dev/null +++ b/src/lib/cards/FriendsCard/FriendsCardSettings.svelte @@ -0,0 +1,104 @@ + + +
+ + + {#if dids.length > 0} +
+ {#each dids as did (did)} + {@const profile = getProfile(did)} +
+ + + {profile?.handle ?? did} + + +
+ {/each} +
+ {/if} +
diff --git a/src/lib/cards/FriendsCard/index.ts b/src/lib/cards/FriendsCard/index.ts new file mode 100644 index 0000000..ca13d22 --- /dev/null +++ b/src/lib/cards/FriendsCard/index.ts @@ -0,0 +1,44 @@ +import type { CardDefinition } from '../types'; +import type { Did } from '@atcute/lexicons'; +import { getBlentoOrBskyProfile } from '$lib/atproto/methods'; +import FriendsCard from './FriendsCard.svelte'; +import FriendsCardSettings from './FriendsCardSettings.svelte'; + +export type FriendsProfile = Awaited>; + +export const FriendsCardDefinition = { + type: 'friends', + contentComponent: FriendsCard, + settingsComponent: FriendsCardSettings, + createNew: (card) => { + card.w = 4; + card.h = 2; + card.mobileW = 8; + card.mobileH = 4; + card.cardData.friends = []; + }, + loadData: async (items) => { + const allDids = new Set(); + for (const item of items) { + for (const did of item.cardData.friends ?? []) { + allDids.add(did as Did); + } + } + if (allDids.size === 0) return []; + + const profiles = await Promise.all( + Array.from(allDids).map((did) => + getBlentoOrBskyProfile({ did }).catch(() => undefined) + ) + ); + return profiles.filter((p) => p && p.handle !== 'handle.invalid'); + }, + allowSetColor: true, + defaultColor: 'base', + minW: 2, + minH: 2, + name: 'Friends', + groups: ['Social'], + keywords: ['friends', 'avatars', 'people', 'community', 'blentos'], + icon: `` +} as CardDefinition & { type: 'friends' }; diff --git a/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte b/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte index b97ebcb..4619b05 100644 --- a/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte +++ b/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte @@ -49,7 +49,7 @@ }); let images = $derived( - feed + (feed ?.toSorted((a: PhotoItem, b: PhotoItem) => { return (a.value.position ?? 0) - (b.value.position ?? 0); }) @@ -63,6 +63,13 @@ position: i.value.position ?? 0 }; }) + .filter((i) => i.src !== undefined) || []) as { + src: string; + name: string; + width: number; + height: number; + position: number; + }[] ); let isMobile = getIsMobile(); diff --git a/src/lib/cards/index.ts b/src/lib/cards/index.ts index a95ce54..4efcddf 100644 --- a/src/lib/cards/index.ts +++ b/src/lib/cards/index.ts @@ -35,6 +35,7 @@ import { CountdownCardDefinition } from './CountdownCard'; import { SpotifyCardDefinition } from './SpotifyCard'; import { ButtonCardDefinition } from './ButtonCard'; import { GuestbookCardDefinition } from './GuestbookCard'; +import { FriendsCardDefinition } from './FriendsCard'; // import { Model3DCardDefinition } from './Model3DCard'; export const AllCardDefinitions = [ @@ -73,8 +74,9 @@ export const AllCardDefinitions = [ TimerCardDefinition, ClockCardDefinition, CountdownCardDefinition, - SpotifyCardDefinition + SpotifyCardDefinition, // Model3DCardDefinition + FriendsCardDefinition ] as const; export const CardDefinitionsByType = AllCardDefinitions.reduce( diff --git a/src/lib/website/EditableWebsite.svelte b/src/lib/website/EditableWebsite.svelte index d380a6f..3dfe6f8 100644 --- a/src/lib/website/EditableWebsite.svelte +++ b/src/lib/website/EditableWebsite.svelte @@ -931,7 +931,6 @@ >
-
{ diff --git a/src/lib/website/layout-mirror.ts b/src/lib/website/layout-mirror.ts index afd025b..9de9a8c 100644 --- a/src/lib/website/layout-mirror.ts +++ b/src/lib/website/layout-mirror.ts @@ -51,9 +51,7 @@ export function mirrorLayout(items: Item[], fromMobile: boolean): void { if (fromMobile) { // Mobile → Desktop: reflow items to use the full grid width. // Sort by mobile position so items are placed in reading order. - const sorted = items.toSorted( - (a, b) => a.mobileY - b.mobileY || a.mobileX - b.mobileX - ); + const sorted = items.toSorted((a, b) => a.mobileY - b.mobileY || a.mobileX - b.mobileX); // Place each item into the first available spot on the desktop grid const placed: Item[] = []; @@ -66,11 +64,7 @@ export function mirrorLayout(items: Item[], fromMobile: boolean): void { } else { // Desktop → Mobile: proportional positions for (const item of items) { - item.mobileX = clamp( - Math.floor((item.x * 2) / 2) * 2, - 0, - COLUMNS - item.mobileW - ); + item.mobileX = clamp(Math.floor((item.x * 2) / 2) * 2, 0, COLUMNS - item.mobileW); item.mobileY = Math.max(0, Math.round(item.y * 2)); } fixAllCollisions(items, true); -- 2.51.2 From 37aab1b876c1e561cfeede58e9a69066589e85c2 Mon Sep 17 00:00:00 2001 From: unbedenklich <106080544+unbedenklich@users.noreply.github.com> Date: Sat, 31 Jan 2026 23:30:15 +0100 Subject: [PATCH 5/7] copy pages and add allcards to page in dev mode --- src/lib/cards/index.ts | 2 +- src/lib/website/EditableWebsite.svelte | 293 ++++++++++++++++++++++++- 2 files changed, 291 insertions(+), 4 deletions(-) diff --git a/src/lib/cards/index.ts b/src/lib/cards/index.ts index 80b9d6a..fe98c81 100644 --- a/src/lib/cards/index.ts +++ b/src/lib/cards/index.ts @@ -49,7 +49,7 @@ export const AllCardDefinitions = [ LatestBlueskyPostCardDefinition, LivestreamCardDefitition, LivestreamEmbedCardDefitition, - EmbedCardDefinition, + // EmbedCardDefinition, MapCardDefinition, ATProtoCollectionsCardDefinition, SectionCardDefinition, diff --git a/src/lib/website/EditableWebsite.svelte b/src/lib/website/EditableWebsite.svelte index abfd441..5e3e9f5 100644 --- a/src/lib/website/EditableWebsite.svelte +++ b/src/lib/website/EditableWebsite.svelte @@ -7,6 +7,7 @@ compactItems, createEmptyCard, findValidPosition, + fixAllCollisions, fixCollisions, getHideProfileSection, getProfilePosition, @@ -35,7 +36,8 @@ import EditBar from './EditBar.svelte'; import SaveModal from './SaveModal.svelte'; import FloatingEditButton from './FloatingEditButton.svelte'; - import { user } from '$lib/atproto'; + import { user, resolveHandle, listRecords, getCDNImageBlobUrl } from '$lib/atproto'; + import * as TID from '@atcute/tid'; import { launchConfetti } from '@foxui/visual'; import Controls from './Controls.svelte'; import CardCommand from '$lib/components/card-command/CardCommand.svelte'; @@ -258,6 +260,279 @@ const sidebarItems = AllCardDefinitions.filter((cardDef) => cardDef.name); + function addAllCardTypes() { + const groupOrder = ['Core', 'Social', 'Media', 'Content', 'Visual', 'Utilities', 'Games']; + const grouped = new Map(); + + for (const def of AllCardDefinitions) { + if (!def.name) continue; + const group = def.groups?.[0] ?? 'Other'; + if (!grouped.has(group)) grouped.set(group, []); + grouped.get(group)!.push(def); + } + + // Sort groups by predefined order, unknowns at end + const sortedGroups = [...grouped.keys()].sort((a, b) => { + const ai = groupOrder.indexOf(a); + const bi = groupOrder.indexOf(b); + return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi); + }); + + // Sample data for cards that would otherwise render empty + const sampleData: Record> = { + text: { text: 'The quick brown fox jumps over the lazy dog. This is a sample text card.' }, + link: { + href: 'https://bsky.app', + title: 'Bluesky', + domain: 'bsky.app', + description: 'Social networking that gives you choice', + hasFetched: true + }, + image: { + image: 'https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=600', + alt: 'Mountain landscape' + }, + button: { text: 'Visit Bluesky', href: 'https://bsky.app' }, + bigsocial: { platform: 'bluesky', href: 'https://bsky.app', color: '0085ff' }, + blueskyPost: { + uri: 'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3jt64kgkbbs2y', + href: 'https://bsky.app/profile/bsky.app/post/3jt64kgkbbs2y' + }, + blueskyProfile: { + handle: 'bsky.app', + displayName: 'Bluesky', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:z72i7hdynmk6r22z27h6tvur/bafkreihagr2cmvl2jt4mgx3sppwe2it3fwolkrbtjrhcnwjk4pcnbaq53m@jpeg' + }, + blueskyMedia: {}, + latestPost: {}, + youtubeVideo: { + youtubeId: 'dQw4w9WgXcQ', + poster: 'https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg', + href: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + showInline: true + }, + 'spotify-list-embed': { + spotifyType: 'album', + spotifyId: '4aawyAB9vmqN3uQ7FjRGTy', + href: 'https://open.spotify.com/album/4aawyAB9vmqN3uQ7FjRGTy' + }, + latestLivestream: {}, + livestreamEmbed: { + href: 'https://stream.place/', + embed: 'https://stream.place/embed/' + }, + mapLocation: { lat: 48.8584, lon: 2.2945, zoom: 13, name: 'Eiffel Tower, Paris' }, + gif: { url: 'https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.mp4', alt: 'Cat typing' }, + event: { + uri: 'at://did:plc:257wekqxg4hyapkq6k47igmp/community.lexicon.calendar.event/3mcsoqzy7gm2q' + }, + guestbook: { label: 'Guestbook' }, + githubProfile: { user: 'sveltejs', href: 'https://github.com/sveltejs' }, + photoGallery: { + galleryUri: 'at://did:plc:tas6hj2xjrqben5653v5kohk/social.grain.gallery/3mclhsljs6h2w' + }, + atprotocollections: {}, + publicationList: {}, + recentPopfeedReviews: {}, + recentTealFMPlays: {}, + statusphere: { emoji: '✨' }, + vcard: {}, + 'fluid-text': { text: 'Hello World' }, + draw: { strokesJson: '[]', viewBox: '', strokeWidth: 1, locked: true }, + clock: {}, + countdown: { targetDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString() }, + timer: {}, + 'dino-game': {}, + tetris: {}, + updatedBlentos: {} + }; + + // Labels for cards that support canHaveLabel + const sampleLabels: Record = { + image: 'Mountain Landscape', + mapLocation: 'Eiffel Tower', + gif: 'Cat Typing', + bigsocial: 'Bluesky', + guestbook: 'Guestbook', + statusphere: 'My Status', + recentPopfeedReviews: 'My Reviews', + recentTealFMPlays: 'Recently Played', + clock: 'Local Time', + countdown: 'Launch Day', + timer: 'Timer', + 'dino-game': 'Dino Game', + tetris: 'Tetris', + blueskyMedia: 'Bluesky Media' + }; + + const newItems: Item[] = []; + let cursorY = 0; + let mobileCursorY = 0; + + for (const group of sortedGroups) { + const defs = grouped.get(group)!; + + // Add a section heading for the group + const heading = createEmptyCard(data.page); + heading.cardType = 'section'; + heading.cardData = { text: group, verticalAlign: 'bottom', textSize: 1 }; + heading.w = COLUMNS; + heading.h = 1; + heading.x = 0; + heading.y = cursorY; + heading.mobileW = COLUMNS; + heading.mobileH = 2; + heading.mobileX = 0; + heading.mobileY = mobileCursorY; + newItems.push(heading); + cursorY += 1; + mobileCursorY += 2; + + // Place cards in rows + let rowX = 0; + let rowMaxH = 0; + let mobileRowX = 0; + let mobileRowMaxH = 0; + + for (const def of defs) { + if (def.type === 'section' || def.type === 'embed') continue; + + const item = createEmptyCard(data.page); + item.cardType = def.type; + item.cardData = {}; + def.createNew?.(item); + + // Merge in sample data (without overwriting createNew defaults) + const extra = sampleData[def.type]; + if (extra) { + item.cardData = { ...item.cardData, ...extra }; + } + + // Set item-level color for cards that need it + if (def.type === 'button') { + item.color = 'transparent'; + } + + // Add label if card supports it + const label = sampleLabels[def.type]; + if (label && def.canHaveLabel) { + item.cardData.label = label; + } + + // Desktop layout + if (rowX + item.w > COLUMNS) { + cursorY += rowMaxH; + rowX = 0; + rowMaxH = 0; + } + item.x = rowX; + item.y = cursorY; + rowX += item.w; + rowMaxH = Math.max(rowMaxH, item.h); + + // Mobile layout + if (mobileRowX + item.mobileW > COLUMNS) { + mobileCursorY += mobileRowMaxH; + mobileRowX = 0; + mobileRowMaxH = 0; + } + item.mobileX = mobileRowX; + item.mobileY = mobileCursorY; + mobileRowX += item.mobileW; + mobileRowMaxH = Math.max(mobileRowMaxH, item.mobileH); + + newItems.push(item); + } + + // Move cursor past last row + cursorY += rowMaxH; + mobileCursorY += mobileRowMaxH; + } + + items = newItems; + onLayoutChanged(); + } + + let copyInput = $state(''); + let isCopying = $state(false); + + async function copyPageFrom() { + const input = copyInput.trim(); + if (!input) return; + + isCopying = true; + try { + // Parse "handle" or "handle/page" + const parts = input.split('/'); + const handle = parts[0]; + const pageName = parts[1] || 'self'; + + const did = await resolveHandle({ handle: handle as `${string}.${string}` }); + if (!did) throw new Error('Could not resolve handle'); + + const records = await listRecords({ did, collection: 'app.blento.card' }); + const targetPage = 'blento.' + pageName; + + const copiedCards: Item[] = records + .map((r) => ({ ...r.value }) as Item) + .filter((card) => { + // v0/v1 cards without page field belong to blento.self + if (!card.page) return targetPage === 'blento.self'; + return card.page === targetPage; + }) + .map((card) => { + // Apply v0→v1 migration (coords were halved in old format) + if (!card.version) { + card.x *= 2; + card.y *= 2; + card.h *= 2; + card.w *= 2; + card.mobileX *= 2; + card.mobileY *= 2; + card.mobileH *= 2; + card.mobileW *= 2; + card.version = 1; + } + + // Convert blob refs to CDN URLs using source DID + if (card.cardData) { + for (const key of Object.keys(card.cardData)) { + const val = card.cardData[key]; + if (val && typeof val === 'object' && val.$type === 'blob') { + const url = getCDNImageBlobUrl({ did, blob: val }); + if (url) card.cardData[key] = url; + } + } + } + + // Regenerate ID and assign to current page + card.id = TID.now(); + card.page = data.page; + return card; + }); + + if (copiedCards.length === 0) { + toast.error('No cards found on that page'); + return; + } + + fixAllCollisions(copiedCards); + fixAllCollisions(copiedCards, true); + compactItems(copiedCards); + compactItems(copiedCards, true); + + items = copiedCards; + onLayoutChanged(); + toast.success(`Copied ${copiedCards.length} cards from ${handle}`); + } catch (e) { + console.error('Failed to copy page:', e); + toast.error('Failed to copy page'); + } finally { + isCopying = false; + } + } + let debugPoint = $state({ x: 0, y: 0 }); function getGridPosition( @@ -1152,9 +1427,21 @@ {#if dev}
- editedOn: {editedOn} + editedOn: {editedOn} + + { + if (e.key === 'Enter') copyPageFrom(); + }} + /> +
{/if} -- 2.51.2 From 6e47836b9ada2dc678c702f93f50a9df5c7ea8c1 Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Sat, 31 Jan 2026 23:31:00 +0100 Subject: [PATCH 6/7] commit --- src/lib/cards/FriendsCard/FriendsCard.svelte | 54 ++++++++------------ 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/src/lib/cards/FriendsCard/FriendsCard.svelte b/src/lib/cards/FriendsCard/FriendsCard.svelte index 08dd76f..c1ff18e 100644 --- a/src/lib/cards/FriendsCard/FriendsCard.svelte +++ b/src/lib/cards/FriendsCard/FriendsCard.svelte @@ -80,41 +80,27 @@ {/if} {:else} -
- {#each visibleProfiles as profile, i (profile.did)} - 0 && sizeClass === 'sm'} - class:-ml-5={i > 0 && sizeClass === 'md'} - class:-ml-6={i > 0 && sizeClass === 'lg'} - > - - - {/each} - {#if overflowCount > 0} -
- +
+ {#each profiles as profile (profile.did)} + - +{overflowCount} - -
- {/if} + + + {/each} +
{/if}
-- 2.51.2 From 28a155dfb819b7811177da00796005c7eb37b068 Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Sat, 31 Jan 2026 23:34:21 +0100 Subject: [PATCH 7/7] format --- .claude/settings.local.json | 62 +++++++++---------- src/lib/cards/FriendsCard/FriendsCard.svelte | 5 +- .../FriendsCard/FriendsCardSettings.svelte | 16 +---- src/lib/cards/FriendsCard/index.ts | 4 +- src/lib/website/EditableWebsite.svelte | 3 +- 5 files changed, 38 insertions(+), 52 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 8345922..71d43d5 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -1,33 +1,33 @@ { - "permissions": { - "allow": [ - "Bash(pnpm check:*)", - "mcp__ide__getDiagnostics", - "mcp__plugin_svelte_svelte__svelte-autofixer", - "mcp__plugin_svelte_svelte__list-sections", - "Bash(pkill:*)", - "Bash(timeout 8 pnpm dev:*)", - "Bash(git checkout:*)", - "Bash(npx svelte-kit:*)", - "Bash(ls:*)", - "Bash(pnpm format:*)", - "Bash(pnpm add:*)", - "WebSearch", - "WebFetch(domain:github.com)", - "WebFetch(domain:flipclockjs.com)", - "WebFetch(domain:codepen.io)", - "WebFetch(domain:flo-bit.dev)", - "Bash(pnpm install)", - "Bash(pnpm install:*)", - "Bash(pnpm config:*)", - "Bash(lsof:*)", - "Bash(pnpm dev)", - "Bash(pnpm exec svelte-kit:*)", - "Bash(pnpm build:*)", - "Bash(pnpm remove:*)", - "Bash(grep:*)", - "Bash(find:*)", - "Bash(npx prettier:*)" - ] - } + "permissions": { + "allow": [ + "Bash(pnpm check:*)", + "mcp__ide__getDiagnostics", + "mcp__plugin_svelte_svelte__svelte-autofixer", + "mcp__plugin_svelte_svelte__list-sections", + "Bash(pkill:*)", + "Bash(timeout 8 pnpm dev:*)", + "Bash(git checkout:*)", + "Bash(npx svelte-kit:*)", + "Bash(ls:*)", + "Bash(pnpm format:*)", + "Bash(pnpm add:*)", + "WebSearch", + "WebFetch(domain:github.com)", + "WebFetch(domain:flipclockjs.com)", + "WebFetch(domain:codepen.io)", + "WebFetch(domain:flo-bit.dev)", + "Bash(pnpm install)", + "Bash(pnpm install:*)", + "Bash(pnpm config:*)", + "Bash(lsof:*)", + "Bash(pnpm dev)", + "Bash(pnpm exec svelte-kit:*)", + "Bash(pnpm build:*)", + "Bash(pnpm remove:*)", + "Bash(grep:*)", + "Bash(find:*)", + "Bash(npx prettier:*)" + ] + } } diff --git a/src/lib/cards/FriendsCard/FriendsCard.svelte b/src/lib/cards/FriendsCard/FriendsCard.svelte index c1ff18e..c4ac918 100644 --- a/src/lib/cards/FriendsCard/FriendsCard.svelte +++ b/src/lib/cards/FriendsCard/FriendsCard.svelte @@ -83,10 +83,7 @@ {@const olX = sizeClass === 'sm' ? 12 : sizeClass === 'md' ? 20 : 24} {@const olY = sizeClass === 'sm' ? 8 : sizeClass === 'md' ? 12 : 16}
-
+
{#each profiles as profile (profile.did)} getBlentoOrBskyProfile({ did: did as Did }).catch(() => undefined)) ); - profiles = results.filter( - (p): p is FriendsProfile => !!p && p.handle !== 'handle.invalid' - ); + profiles = results.filter((p): p is FriendsProfile => !!p && p.handle !== 'handle.invalid'); } function addFriend(actor: AppBskyActorDefs.ProfileViewBasic) { @@ -68,11 +66,7 @@ {#each dids as did (did)} {@const profile = getProfile(did)}
- + {profile?.handle ?? did} @@ -90,11 +84,7 @@ stroke="currentColor" class="size-3.5" > - +
diff --git a/src/lib/cards/FriendsCard/index.ts b/src/lib/cards/FriendsCard/index.ts index ca13d22..0afabcf 100644 --- a/src/lib/cards/FriendsCard/index.ts +++ b/src/lib/cards/FriendsCard/index.ts @@ -27,9 +27,7 @@ export const FriendsCardDefinition = { if (allDids.size === 0) return []; const profiles = await Promise.all( - Array.from(allDids).map((did) => - getBlentoOrBskyProfile({ did }).catch(() => undefined) - ) + Array.from(allDids).map((did) => getBlentoOrBskyProfile({ did }).catch(() => undefined)) ); return profiles.filter((p) => p && p.handle !== 'handle.invalid'); }, diff --git a/src/lib/website/EditableWebsite.svelte b/src/lib/website/EditableWebsite.svelte index c83c809..023a862 100644 --- a/src/lib/website/EditableWebsite.svelte +++ b/src/lib/website/EditableWebsite.svelte @@ -42,6 +42,7 @@ import Controls from './Controls.svelte'; import CardCommand from '$lib/components/card-command/CardCommand.svelte'; import { shouldMirror, mirrorLayout } from './layout-mirror'; + import { SvelteMap } from 'svelte/reactivity'; let { data @@ -262,7 +263,7 @@ function addAllCardTypes() { const groupOrder = ['Core', 'Social', 'Media', 'Content', 'Visual', 'Utilities', 'Games']; - const grouped = new Map(); + const grouped = new SvelteMap(); for (const def of AllCardDefinitions) { if (!def.name) continue; -- 2.51.2