From 958fa25f6cd4e1044df0e4433e2b6353062be02a Mon Sep 17 00:00:00 2001 From: unbedenklich <106080544+unbedenklich@users.noreply.github.com> Date: Wed, 14 Jan 2026 20:13:10 +0100 Subject: [PATCH 1/2] Add Big Social card for social media links - New card type that displays social media platform logos prominently - Supports Instagram, Facebook, X/Twitter, YouTube, TikTok, LinkedIn, Bluesky, Threads, Snapchat, Pinterest, Twitch, Discord, GitHub, Spotify, Reddit, WhatsApp, Telegram, Mastodon - Auto-detects platform from URL and applies brand colors - Logo stays centered when card is scaled - Also fixes Profile.svelte crash when user has no avatar Co-Authored-By: Claude Opus 4.5 --- src/lib/Profile.svelte | 16 +- .../cards/BigSocialCard/BigSocialCard.svelte | 139 ++++++++++++++++++ .../CreateBigSocialCardModal.svelte | 107 ++++++++++++++ .../SidebarItemBigSocialCard.svelte | 21 +++ src/lib/cards/BigSocialCard/index.ts | 26 ++++ src/lib/cards/index.ts | 2 + 6 files changed, 305 insertions(+), 6 deletions(-) create mode 100644 src/lib/cards/BigSocialCard/BigSocialCard.svelte create mode 100644 src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte create mode 100644 src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte create mode 100644 src/lib/cards/BigSocialCard/index.ts diff --git a/src/lib/Profile.svelte b/src/lib/Profile.svelte index e92233d..771cbc7 100644 --- a/src/lib/Profile.svelte +++ b/src/lib/Profile.svelte @@ -22,7 +22,7 @@ @@ -32,11 +32,15 @@ class="mx-auto flex max-w-2xl flex-col justify-between px-8 @5xl/wrapper:fixed @5xl/wrapper:h-screen @5xl/wrapper:w-1/4 @5xl/wrapper:max-w-none @5xl/wrapper:px-12" >
- + {#if profileData?.avatar?.ref?.$link} + + {:else} +
+ {/if}
{profileData?.displayName || handle}
diff --git a/src/lib/cards/BigSocialCard/BigSocialCard.svelte b/src/lib/cards/BigSocialCard/BigSocialCard.svelte new file mode 100644 index 0000000..16a2bdc --- /dev/null +++ b/src/lib/cards/BigSocialCard/BigSocialCard.svelte @@ -0,0 +1,139 @@ + + + +
+ {#if platform === 'instagram'} + + + + {:else if platform === 'facebook'} + + + + {:else if platform === 'twitter' || platform === 'x'} + + + + {:else if platform === 'youtube'} + + + + {:else if platform === 'tiktok'} + + + + {:else if platform === 'linkedin'} + + + + {:else if platform === 'bluesky'} + + + + {:else if platform === 'threads'} + + + + {:else if platform === 'snapchat'} + + + + {:else if platform === 'pinterest'} + + + + {:else if platform === 'twitch'} + + + + {:else if platform === 'discord'} + + + + {:else if platform === 'github'} + + + + {:else if platform === 'spotify'} + + + + {:else if platform === 'reddit'} + + + + {:else if platform === 'whatsapp'} + + + + {:else if platform === 'telegram'} + + + + {:else if platform === 'mastodon'} + + + + {:else} + + + + {/if} +
+
diff --git a/src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte b/src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte new file mode 100644 index 0000000..47f53ac --- /dev/null +++ b/src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte @@ -0,0 +1,107 @@ + + + + Enter a social media link + { + if (e.key === 'Enter') handleCreate(); + }} + /> + +

+ Supported: Instagram, Facebook, X/Twitter, YouTube, TikTok, LinkedIn, Bluesky, Threads, + Snapchat, Pinterest, Twitch, Discord, GitHub, Spotify, Reddit, WhatsApp, Telegram, Mastodon +

+ + {#if errorMessage} + {errorMessage} + {/if} + +
+ + +
+
diff --git a/src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte b/src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte new file mode 100644 index 0000000..18ec6bc --- /dev/null +++ b/src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte @@ -0,0 +1,21 @@ + + + diff --git a/src/lib/cards/BigSocialCard/index.ts b/src/lib/cards/BigSocialCard/index.ts new file mode 100644 index 0000000..f42f2e3 --- /dev/null +++ b/src/lib/cards/BigSocialCard/index.ts @@ -0,0 +1,26 @@ +import type { CardDefinition } from '../types'; +import BigSocialCard from './BigSocialCard.svelte'; +import CreateBigSocialCardModal from './CreateBigSocialCardModal.svelte'; +import SidebarItemBigSocialCard from './SidebarItemBigSocialCard.svelte'; + +export const BigSocialCardDefinition = { + type: 'bigsocial', + contentComponent: BigSocialCard, + creationModalComponent: CreateBigSocialCardModal, + sidebarComponent: SidebarItemBigSocialCard, + createNew: (card) => { + card.cardType = 'bigsocial'; + card.cardData = { + href: '', + platform: '' + }; + card.w = 2; + card.h = 2; + card.mobileW = 2; + card.mobileH = 2; + }, + allowSetColor: true, + defaultColor: 'accent', + minW: 1, + minH: 1 +} as CardDefinition & { type: 'bigsocial' }; diff --git a/src/lib/cards/index.ts b/src/lib/cards/index.ts index 7e53899..f6634bd 100644 --- a/src/lib/cards/index.ts +++ b/src/lib/cards/index.ts @@ -1,5 +1,6 @@ import type { Item } from '$lib/types'; import { ATProtoCollectionsCardDefinition } from './ATProtoCollectionsCard'; +import { BigSocialCardDefinition } from './BigSocialCard'; import { BlueskyMediaCardDefinition } from './BlueskyMediaCard'; import { BlueskyPostCardDefinition } from './BlueskyPostCard'; import { EmbedCardDefinition } from './EmbedCard'; @@ -17,6 +18,7 @@ export const AllCardDefinitions = [ ImageCardDefinition, TextCardDefinition, LinkCardDefinition, + BigSocialCardDefinition, UpdatedBlentosCardDefitition, YoutubeCardDefinition, BlueskyPostCardDefinition, -- 2.51.2 From 1b9377e9cfa945f41aab531b8401024bc87593fa Mon Sep 17 00:00:00 2001 From: Florian <45694132+flo-bit@users.noreply.github.com> Date: Thu, 15 Jan 2026 03:43:36 +0100 Subject: [PATCH 2/2] commit --- package.json | 1 + pnpm-lock.yaml | 9 ++ src/app.html | 4 +- src/lib/EditableWebsite.svelte | 59 +++++++- src/lib/Profile.svelte | 4 +- src/lib/Website.svelte | 2 +- src/lib/cards/BaseCard/BaseCard.svelte | 4 +- src/lib/cards/BaseCard/BaseEditingCard.svelte | 13 +- .../cards/BigSocialCard/BigSocialCard.svelte | 133 ++---------------- .../CreateBigSocialCardModal.svelte | 57 +------- .../SidebarItemBigSocialCard.svelte | 2 +- src/lib/cards/BigSocialCard/index.ts | 95 ++++++++++++- src/lib/cards/LinkCard/EditingLinkCard.svelte | 3 +- src/lib/cards/LinkCard/LinkCard.svelte | 5 +- .../UpdatedBlentos/UpdatedBlentosCard.svelte | 2 +- src/lib/cards/TextCard/EditingTextCard.svelte | 24 +++- src/lib/cards/TextCard/TextCard.svelte | 7 +- .../cards/TextCard/TextCardSettings.svelte | 51 ++++++- src/lib/cards/TextCard/index.ts | 11 +- src/lib/cards/types.ts | 2 + src/lib/cards/utils/MarkdownTextEditor.svelte | 23 ++- src/lib/components/ImageDropper.svelte | 66 +++++++++ 22 files changed, 355 insertions(+), 222 deletions(-) create mode 100644 src/lib/components/ImageDropper.svelte diff --git a/package.json b/package.json index 7fad2f7..8c72d4b 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "link-preview-js": "^4.0.0", "marked": "^15.0.11", "plyr": "^3.8.4", + "simple-icons": "^16.5.0", "svelte-sonner": "^1.0.7", "tailwind-merge": "^3.4.0", "tailwind-variants": "^3.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50eb35a..ae6f3ca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,9 @@ importers: plyr: specifier: ^3.8.4 version: 3.8.4 + simple-icons: + specifier: ^16.5.0 + version: 16.5.0 svelte-sonner: specifier: ^1.0.7 version: 1.0.7(svelte@5.45.8) @@ -2669,6 +2672,10 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==, tarball: https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz} engines: {node: '>= 0.4'} + simple-icons@16.5.0: + resolution: {integrity: sha512-72nn0oHADKx6Hknu7q6M0vfL8LiCUMKABOHane2+4xdqaFBSHfNNBjuZioihiqVQMz7IvVle4NKAM0IlXvl/9A==, tarball: https://registry.npmjs.org/simple-icons/-/simple-icons-16.5.0.tgz} + engines: {node: '>=0.12.18'} + simple-swizzle@0.2.4: resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==, tarball: https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz} @@ -5439,6 +5446,8 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + simple-icons@16.5.0: {} + simple-swizzle@0.2.4: dependencies: is-arrayish: 0.3.4 diff --git a/src/app.html b/src/app.html index c06c350..c4f961f 100644 --- a/src/app.html +++ b/src/app.html @@ -1,5 +1,5 @@ - + @@ -11,7 +11,7 @@ data-website-id="c55efa23-9abe-4a7e-b8fd-81b9fa7e8052" > - +
%sveltekit.body%
diff --git a/src/lib/EditableWebsite.svelte b/src/lib/EditableWebsite.svelte index 8048050..e251264 100644 --- a/src/lib/EditableWebsite.svelte +++ b/src/lib/EditableWebsite.svelte @@ -28,6 +28,7 @@ import { setDidContext, setHandleContext } from './website/context'; import BaseEditingCard from './cards/BaseCard/BaseEditingCard.svelte'; import Settings from './Settings.svelte'; + import ImageDropper from './components/ImageDropper.svelte'; let { handle, @@ -234,6 +235,60 @@ } + { + const target = event.target; + + const active = document.activeElement; + const isEditable = + active instanceof HTMLInputElement || + active instanceof HTMLTextAreaElement || + active?.isContentEditable; + + if (isEditable) { + // Let normal paste happen + return; + } + + const text = event.clipboardData?.getData('text/plain'); + + if (!text) return; + + try { + const url = new URL(text); + + let item: Item = { + id: TID.nextStr(), + x: 0, + y: 0, + w: 2, + h: 2, + mobileH: 4, + mobileW: 4, + mobileX: 0, + mobileY: 0, + cardType: '', + cardData: {} + }; + + newItem.item = item; + + for (const cardDef of AllCardDefinitions) { + if (cardDef.onUrlHandler?.(text, item)) { + item.cardType = cardDef.type; + saveNewItem(); + } + } + + newItem = {}; + } catch (e) { + return; + } + }} +/> + + + {#if !dev}
-
+
{#if profileData?.avatar?.ref?.$link} diff --git a/src/lib/Website.svelte b/src/lib/Website.svelte index 23f0a3d..dfdb907 100644 --- a/src/lib/Website.svelte +++ b/src/lib/Website.svelte @@ -39,7 +39,7 @@
-
+
= minW && w*2 <= maxW && h >= minH && h*2 <= maxH; } return w >= minW && w <= maxW && h >= minH && h <= maxH; @@ -155,7 +154,7 @@ let settingsPopoverOpen = $state(false); - + {@render children?.()} {#snippet controls()} diff --git a/src/lib/cards/BigSocialCard/BigSocialCard.svelte b/src/lib/cards/BigSocialCard/BigSocialCard.svelte index 16a2bdc..0ddfe53 100644 --- a/src/lib/cards/BigSocialCard/BigSocialCard.svelte +++ b/src/lib/cards/BigSocialCard/BigSocialCard.svelte @@ -1,139 +1,24 @@ -
- {#if platform === 'instagram'} - - - - {:else if platform === 'facebook'} - - - - {:else if platform === 'twitter' || platform === 'x'} - - - - {:else if platform === 'youtube'} - - - - {:else if platform === 'tiktok'} - - - - {:else if platform === 'linkedin'} - - - - {:else if platform === 'bluesky'} - - - - {:else if platform === 'threads'} - - - - {:else if platform === 'snapchat'} - - - - {:else if platform === 'pinterest'} - - - - {:else if platform === 'twitch'} - - - - {:else if platform === 'discord'} - - - - {:else if platform === 'github'} - - - - {:else if platform === 'spotify'} - - - - {:else if platform === 'reddit'} - - - - {:else if platform === 'whatsapp'} - - - - {:else if platform === 'telegram'} - - - - {:else if platform === 'mastodon'} - - - - {:else} - - - - {/if} +
+ {@html platformsData[platform].svg}
diff --git a/src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte b/src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte index 47f53ac..cc09334 100644 --- a/src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte +++ b/src/lib/cards/BigSocialCard/CreateBigSocialCardModal.svelte @@ -1,64 +1,12 @@ diff --git a/src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte b/src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte index 18ec6bc..fa90eee 100644 --- a/src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte +++ b/src/lib/cards/BigSocialCard/SidebarItemBigSocialCard.svelte @@ -17,5 +17,5 @@ clip-rule="evenodd" /> - Big Social diff --git a/src/lib/cards/BigSocialCard/index.ts b/src/lib/cards/BigSocialCard/index.ts index f42f2e3..9435302 100644 --- a/src/lib/cards/BigSocialCard/index.ts +++ b/src/lib/cards/BigSocialCard/index.ts @@ -16,11 +16,94 @@ export const BigSocialCardDefinition = { }; card.w = 2; card.h = 2; - card.mobileW = 2; - card.mobileH = 2; + card.mobileW = 4; + card.mobileH = 4; }, - allowSetColor: true, - defaultColor: 'accent', - minW: 1, - minH: 1 + allowSetColor: false, + defaultColor: 'transparent', + minW: 2, + minH: 2, + onUrlHandler: (url, item) => { + const platform = detectPlatform(url); + if (!platform) return null; + + item.cardData.platform = platform; + item.cardData.color = platformsData[platform].hex; + item.cardData.href = url; + + return item; + } } as CardDefinition & { type: 'bigsocial' }; + +export const platformPatterns: Record = { + instagram: /(?:instagram\.com|instagr\.am)/i, + facebook: /(?:facebook\.com|fb\.com|fb\.me)/i, + twitter: /(?:twitter\.com)/i, + x: /(?:x\.com)/i, + youtube: /(?:youtube\.com|youtu\.be)/i, + tiktok: /(?:tiktok\.com)/i, + linkedin: /(?:linkedin\.com)/i, + bluesky: /(?:bsky\.app|bsky\.social)/i, + threads: /(?:threads\.net)/i, + snapchat: /(?:snapchat\.com)/i, + pinterest: /(?:pinterest\.com|pin\.it)/i, + twitch: /(?:twitch\.tv)/i, + discord: /(?:discord\.gg|discord\.com)/i, + github: /(?:github\.com)/i, + spotify: /(?:spotify\.com|open\.spotify\.com)/i, + reddit: /(?:reddit\.com)/i, + whatsapp: /(?:whatsapp\.com|wa\.me)/i, + telegram: /(?:t\.me|telegram\.org)/i, + mastodon: /(?:mastodon\.social|mastodon\.online|mstdn\.social)/i +}; + +import { + siInstagram, + siFacebook, + siX, + siYoutube, + siTiktok, + siBluesky, + siThreads, + siSnapchat, + siPinterest, + siTwitch, + siDiscord, + siGithub, + siSpotify, + siReddit, + siWhatsapp, + siTelegram, + siMastodon, + type SimpleIcon +} from 'simple-icons'; + +export const platformsData: Record = { + instagram: siInstagram, + facebook: siFacebook, + twitter: siX, + x: siX, + youtube: siYoutube, + tiktok: siTiktok, + bluesky: siBluesky, + threads: siThreads, + snapchat: siSnapchat, + pinterest: siPinterest, + twitch: siTwitch, + discord: siDiscord, + github: siGithub, + spotify: siSpotify, + reddit: siReddit, + whatsapp: siWhatsapp, + telegram: siTelegram, + mastodon: siMastodon +}; + +export function detectPlatform(url: string): string | null { + for (const [platform, pattern] of Object.entries(platformPatterns)) { + if (pattern.test(url)) { + return platform; + } + } + return null; +} diff --git a/src/lib/cards/LinkCard/EditingLinkCard.svelte b/src/lib/cards/LinkCard/EditingLinkCard.svelte index dec9c16..b16850a 100644 --- a/src/lib/cards/LinkCard/EditingLinkCard.svelte +++ b/src/lib/cards/LinkCard/EditingLinkCard.svelte @@ -1,4 +1,5 @@ + +
{ + editor?.commands.focus('end'); + }} > - +
diff --git a/src/lib/cards/TextCard/TextCard.svelte b/src/lib/cards/TextCard/TextCard.svelte index 2525ade..c592d20 100644 --- a/src/lib/cards/TextCard/TextCard.svelte +++ b/src/lib/cards/TextCard/TextCard.svelte @@ -1,7 +1,7 @@ -
+