diff --git a/src/lib/cards/index.ts b/src/lib/cards/index.ts --- a/src/lib/cards/index.ts +++ b/src/lib/cards/index.ts @@ -36,6 +36,7 @@ import { ButtonCardDefinition } from './ButtonCard'; import { GuestbookCardDefinition } from './GuestbookCard'; import { FriendsCardDefinition } from './FriendsCard'; +import { GitHubContributorsCardDefinition } from './GitHubContributorsCard'; // import { Model3DCardDefinition } from './Model3DCard'; export const AllCardDefinitions = [ @@ -76,7 +77,8 @@ SpotifyCardDefinition, AppleMusicCardDefinition, // Model3DCardDefinition - FriendsCardDefinition + FriendsCardDefinition, + GitHubContributorsCardDefinition ] as const; export const CardDefinitionsByType = AllCardDefinitions.reduce( diff --git a/src/lib/website/EditableWebsite.svelte b/src/lib/website/EditableWebsite.svelte --- a/src/lib/website/EditableWebsite.svelte +++ b/src/lib/website/EditableWebsite.svelte @@ -271,7 +271,7 @@ // Refresh cached data await fetch('/' + data.handle + '/api/refresh'); } catch (error) { - console.log(error); + console.error(error); showSaveModal = false; toast.error('Error saving page!'); } finally { diff --git a/src/lib/website/EmptyState.svelte b/src/lib/website/EmptyState.svelte --- a/src/lib/website/EmptyState.svelte +++ b/src/lib/website/EmptyState.svelte @@ -2,6 +2,7 @@ import BaseCard from '$lib/cards/BaseCard/BaseCard.svelte'; import Card from '$lib/cards/Card/Card.svelte'; import type { Item, WebsiteData } from '$lib/types'; + import { text } from '@sveltejs/kit'; let { data }: { data: WebsiteData } = $props(); @@ -44,6 +45,43 @@ platform: 'bluesky', href: `https://bsky.app/profile/${data.handle}`, color: '0285FF' + } + }); + + items.push({ + id: 'empty-instruction', + x: 0, + y: 3, + w: 8, + h: 1, + mobileX: 0, + mobileY: 6, + mobileW: 8, + mobileH: 2, + cardType: 'text', + color: 'transparent', + cardData: { + text: `Is this your account? Login to start creating your blento!`, + textAlign: 'center', + verticalAlign: 'bottom' + } + }); + + items.push({ + id: 'empty-login-button', + x: 0, + y: 4, + w: 8, + h: 1, + mobileX: 0, + mobileY: 8, + mobileW: 8, + mobileH: 2, + cardType: 'button', + color: 'transparent', + cardData: { + href: '#login', + text: `Login` } }); diff --git a/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte b/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte --- a/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte +++ b/src/lib/cards/BlueskyMediaCard/CreateBlueskyMediaCardModal.svelte @@ -62,7 +62,6 @@ {#each mediaList as media (media.thumbnail || media.playlist)} + + + + diff --git a/src/lib/cards/GitHubContributorsCard/GitHubContributorsCard.svelte b/src/lib/cards/GitHubContributorsCard/GitHubContributorsCard.svelte new file mode 100644 --- /dev/null +++ b/src/lib/cards/GitHubContributorsCard/GitHubContributorsCard.svelte @@ -0,0 +1,149 @@ + + +
+ {#if !owner || !repo} + {#if canEdit()} + + Enter a repository + + {/if} + {:else if totalItems > 0} +
+
+ {#each namedContributors as contributor (contributor.username)} + + {/each} +
+
+ {/if} +
diff --git a/src/lib/cards/GitHubContributorsCard/index.ts b/src/lib/cards/GitHubContributorsCard/index.ts new file mode 100644 --- /dev/null +++ b/src/lib/cards/GitHubContributorsCard/index.ts @@ -0,0 +1,55 @@ +import type { CardDefinition } from '../types'; +import GitHubContributorsCard from './GitHubContributorsCard.svelte'; +import CreateGitHubContributorsCardModal from './CreateGitHubContributorsCardModal.svelte'; + +export type GitHubContributor = { + username: string; + avatarUrl: string | null; + contributions: number; + anonymous: boolean; +}; + +export type GitHubContributorsLoadedData = Record; + +export const GitHubContributorsCardDefinition = { + type: 'githubContributors', + contentComponent: GitHubContributorsCard, + creationModalComponent: CreateGitHubContributorsCardModal, + createNew: (card) => { + card.w = 4; + card.h = 2; + card.mobileW = 8; + card.mobileH = 4; + card.cardData.owner = ''; + card.cardData.repo = ''; + }, + loadData: async (items) => { + const contributorsData: GitHubContributorsLoadedData = {}; + for (const item of items) { + const { owner, repo } = item.cardData; + if (!owner || !repo) continue; + const key = `${owner}/${repo}`; + if (contributorsData[key]) continue; + try { + const response = await fetch( + `https://blento.app/api/github/contributors?owner=${encodeURIComponent(owner)}&repo=${encodeURIComponent(repo)}` + ); + if (response.ok) { + contributorsData[key] = await response.json(); + } + } catch (error) { + console.error('Failed to fetch GitHub contributors:', error); + } + } + return contributorsData; + }, + allowSetColor: true, + defaultColor: 'base', + minW: 2, + minH: 2, + name: 'GitHub Contributors', + groups: ['Social'], + keywords: ['github', 'contributors', 'open source', 'repository'], + icon: ``, + canHaveLabel: true +} as CardDefinition & { type: 'githubContributors' }; diff --git a/src/lib/cards/GitHubProfileCard/GitHubProfileCard.svelte b/src/lib/cards/GitHubProfileCard/GitHubProfileCard.svelte --- a/src/lib/cards/GitHubProfileCard/GitHubProfileCard.svelte +++ b/src/lib/cards/GitHubProfileCard/GitHubProfileCard.svelte @@ -21,7 +21,6 @@ ); onMount(async () => { - console.log(contributionsData); if (!contributionsData && item.cardData?.user) { try { const response = await fetch(`/api/github?user=${encodeURIComponent(item.cardData.user)}`); diff --git a/src/lib/cards/GitHubProfileCard/index.ts b/src/lib/cards/GitHubProfileCard/index.ts --- a/src/lib/cards/GitHubProfileCard/index.ts +++ b/src/lib/cards/GitHubProfileCard/index.ts @@ -30,7 +30,6 @@ onUrlHandler: (url, item) => { const username = getGitHubUsername(url); - console.log(username); if (!username) return; item.cardData.href = url; diff --git a/src/lib/cards/LatestBlueskyPostCard/LatestBlueskyPostCard.svelte b/src/lib/cards/LatestBlueskyPostCard/LatestBlueskyPostCard.svelte --- a/src/lib/cards/LatestBlueskyPostCard/LatestBlueskyPostCard.svelte +++ b/src/lib/cards/LatestBlueskyPostCard/LatestBlueskyPostCard.svelte @@ -23,8 +23,6 @@ })) as any ).feed; - console.log(feed); - data[item.cardType] = feed; } }); diff --git a/src/lib/cards/LivestreamCard/index.ts b/src/lib/cards/LivestreamCard/index.ts --- a/src/lib/cards/LivestreamCard/index.ts +++ b/src/lib/cards/LivestreamCard/index.ts @@ -65,7 +65,6 @@ }, onUrlHandler: (url, item) => { - console.log(url, 'https://stream.place/' + user.profile?.handle); if (url === 'https://stream.place/' + user.profile?.handle) { item.w = 4; item.h = 4; diff --git a/src/lib/cards/MapCard/CreateMapCardModal.svelte b/src/lib/cards/MapCard/CreateMapCardModal.svelte --- a/src/lib/cards/MapCard/CreateMapCardModal.svelte +++ b/src/lib/cards/MapCard/CreateMapCardModal.svelte @@ -20,8 +20,6 @@ if (response.ok) { const data = await response.json(); - console.log(data); - if (!data.lat || !data.lon) throw new Error('lat or lon not found'); item.cardData.lat = data.lat; diff --git a/src/lib/cards/MapCard/Map.svelte b/src/lib/cards/MapCard/Map.svelte --- a/src/lib/cards/MapCard/Map.svelte +++ b/src/lib/cards/MapCard/Map.svelte @@ -15,7 +15,7 @@ onMount(() => { if (!mapContainer || !env.PUBLIC_MAPBOX_TOKEN) { - console.log('no map container or no mapbox token'); + console.error('no map container or no mapbox token'); return; } diff --git a/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte b/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte --- a/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte +++ b/src/lib/cards/PhotoGalleryCard/PhotoGalleryCard.svelte @@ -33,7 +33,6 @@ let handle = getHandleContext(); onMount(async () => { - console.log(feed); if (!feed) { feed = ( (await CardDefinitionsByType[item.cardType]?.loadData?.([item], { @@ -41,8 +40,6 @@ handle })) as Record | undefined )?.[item.cardData.galleryUri]; - - console.log(feed); data[item.cardType] = feed; } diff --git a/src/lib/cards/PopfeedReviews/PopfeedReviewsCard.svelte b/src/lib/cards/PopfeedReviews/PopfeedReviewsCard.svelte --- a/src/lib/cards/PopfeedReviews/PopfeedReviewsCard.svelte +++ b/src/lib/cards/PopfeedReviews/PopfeedReviewsCard.svelte @@ -21,14 +21,11 @@ let handle = getHandleContext(); onMount(async () => { - console.log(feed); if (!feed) { feed = (await CardDefinitionsByType[item.cardType]?.loadData?.([], { did, handle })) as any; - - console.log(feed); data[item.cardType] = feed; } diff --git a/src/lib/components/bluesky-post/index.ts b/src/lib/components/bluesky-post/index.ts --- a/src/lib/components/bluesky-post/index.ts +++ b/src/lib/components/bluesky-post/index.ts @@ -35,8 +35,6 @@ // const reason = data.reason; // const reply = data.reply?.parent; // const replyId = reply?.uri?.split('/').pop(); - console.log(JSON.parse(JSON.stringify(data))); - const id = post.uri.split('/').pop(); return { diff --git a/src/routes/api/github/+server.ts b/src/routes/api/github/+server.ts --- a/src/routes/api/github/+server.ts +++ b/src/routes/api/github/+server.ts @@ -26,10 +26,9 @@ try { const response = await fetch(GithubAPIURL + user); - console.log('hello', user); if (!response.ok) { - console.log('error', response.statusText); + console.error('error', response.statusText); return json( { error: 'Failed to fetch GitHub data ' + response.statusText }, { status: response.status } @@ -39,7 +38,6 @@ const data = await response.json(); if (!data?.user) { - console.log('user not found', response.statusText); return json({ error: 'User not found' }, { status: 404 }); } diff --git a/src/routes/api/update/+server.ts b/src/routes/api/update/+server.ts --- a/src/routes/api/update/+server.ts +++ b/src/routes/api/update/+server.ts @@ -18,7 +18,6 @@ for (const handle of existingUsersHandle) { if (!handle) continue; - console.log('updating', handle); try { const cached = await getCache(handle, 'self', cache as UserCache); if (!cached) await loadData(handle, cache as UserCache, true); @@ -26,7 +25,6 @@ console.error(error); return json('error'); } - console.log('updated', handle); } return json('ok'); diff --git a/src/routes/(auth)/oauth/callback/+page.svelte b/src/routes/(auth)/oauth/callback/+page.svelte --- a/src/routes/(auth)/oauth/callback/+page.svelte +++ b/src/routes/(auth)/oauth/callback/+page.svelte @@ -4,7 +4,6 @@ import { getHandleOrDid } from '$lib/atproto/methods'; $effect(() => { - console.log('hello', user); if (user.profile) { goto('/' + getHandleOrDid(user.profile) + '/edit', {}); } diff --git a/src/routes/api/github/contributors/+server.ts b/src/routes/api/github/contributors/+server.ts new file mode 100644 --- /dev/null +++ b/src/routes/api/github/contributors/+server.ts @@ -0,0 +1,53 @@ +import { json } from '@sveltejs/kit'; +import type { RequestHandler } from './$types'; + +const GithubContributorsAPIURL = + 'https://edge-function-github-contribution.vercel.app/api/github-contributors'; + +export const GET: RequestHandler = async ({ url, platform }) => { + const owner = url.searchParams.get('owner'); + const repo = url.searchParams.get('repo'); + + if (!owner || !repo) { + return json({ error: 'Missing owner or repo parameter' }, { status: 400 }); + } + + const cacheKey = `#github-contributors:${owner}/${repo}`; + const cachedData = await platform?.env?.USER_DATA_CACHE?.get(cacheKey); + + if (cachedData) { + const parsedCache = JSON.parse(cachedData); + + const TWELVE_HOURS = 12 * 60 * 60 * 1000; + const now = Date.now(); + + if (now - (parsedCache.updatedAt || 0) < TWELVE_HOURS) { + return json(parsedCache.data); + } + } + + try { + const response = await fetch( + `${GithubContributorsAPIURL}?owner=${encodeURIComponent(owner)}&repo=${encodeURIComponent(repo)}` + ); + + if (!response.ok) { + return json( + { error: 'Failed to fetch GitHub contributors ' + response.statusText }, + { status: response.status } + ); + } + + const data = await response.json(); + + await platform?.env?.USER_DATA_CACHE?.put( + cacheKey, + JSON.stringify({ data, updatedAt: Date.now() }) + ); + + return json(data); + } catch (error) { + console.error('Error fetching GitHub contributors:', error); + return json({ error: 'Failed to fetch GitHub contributors' }, { status: 500 }); + } +};