diff --git a/features/features.json b/features/features.json index 779defe0..8667e36c 100644 --- a/features/features.json +++ b/features/features.json @@ -1,5 +1,10 @@ [ { + "version": 2, + "id": "recent-followers-and-following", + "versionAdded": "v4.1.0" + }, + { "version": 2, "id": "remove-confirmation", "versionAdded": "v4.0.0" diff --git a/features/recent-followers-and-following/data.json b/features/recent-followers-and-following/data.json new file mode 100644 index 00000000..240263c2 --- /dev/null +++ b/features/recent-followers-and-following/data.json @@ -0,0 +1,15 @@ +{ + "title": "Show Recent Followers and Followings", + "description": "Displays the most recent followers and followings of a user on their profile page.", + "credits": [ + { + "username": "-Brass_Glass-", + "url": "https://scratch.mit.edu/users/-Brass_Glass-/" + }, + { "username": "MaterArc", "url": "https://scratch.mit.edu/users/MaterArc/" } + ], + "type": ["Website"], + "tags": ["New", "Featured"], + "dynamic": true, + "scripts": [{ "file": "script.js", "runOn": "/users/*" }] +} diff --git a/features/recent-followers-and-following/script.js b/features/recent-followers-and-following/script.js new file mode 100644 index 00000000..f50ca063 --- /dev/null +++ b/features/recent-followers-and-following/script.js @@ -0,0 +1,110 @@ +export default async function ({ feature, console }) { + const username = window.location.pathname.split('/')[2]; + if (!username) return; + + const followersEndpoint = `https://api.scratch.mit.edu/users/${username}/followers/`; + const followingEndpoint = `https://api.scratch.mit.edu/users/${username}/following/`; + + try { + const followersResponse = await fetch(followersEndpoint); + if (!followersResponse.ok) return; + + const followersData = await followersResponse.json(); + if (!Array.isArray(followersData)) return; + + const mostRecentFollowers = followersData + .slice(0, 9) + .filter(follower => follower.username && follower.profile && follower.profile.images) + .map(follower => ({ + username: follower.username, + profileImage: follower.profile.images['90x90'] || follower.profile.images['50x50'] || '', + })); + + const followingResponse = await fetch(followingEndpoint); + if (!followingResponse.ok) return; + + const followingData = await followingResponse.json(); + if (!Array.isArray(followingData)) return; + + const mostRecentFollowing = followingData + .slice(0, 9) + .filter(follow => follow.username && follow.profile && follow.profile.images) + .map(follow => ({ + username: follow.username, + profileImage: follow.profile.images['90x90'] || follow.profile.images['50x50'] || '', + })); + + const allFeaturedElements = document.querySelectorAll("#featured"); + if (allFeaturedElements.length === 0) return; + + const lastFeaturedElement = allFeaturedElements[allFeaturedElements.length - 1]; + lastFeaturedElement.innerHTML = ""; + + mostRecentFollowers.forEach(follower => { + const li = document.createElement("li"); + li.className = "user thumb item"; + + const link = document.createElement("a"); + link.href = `/users/${follower.username}/`; + link.title = follower.username; + + const img = document.createElement("img"); + img.className = "lazy"; + img.src = follower.profileImage; + img.alt = follower.username; + img.width = 60; + img.height = 60; + + const span = document.createElement("span"); + span.className = "title"; + + const spanLink = document.createElement("a"); + spanLink.href = `/users/${follower.username}/`; + spanLink.textContent = follower.username; + + link.appendChild(img); + span.appendChild(spanLink); + li.appendChild(link); + li.appendChild(span); + + lastFeaturedElement.appendChild(li); + }); + + if (allFeaturedElements.length > 1) { + const secondLastFeaturedElement = allFeaturedElements[allFeaturedElements.length - 2]; + secondLastFeaturedElement.innerHTML = ""; + + mostRecentFollowing.forEach(follow => { + const li = document.createElement("li"); + li.className = "user thumb item"; + + const link = document.createElement("a"); + link.href = `/users/${follow.username}/`; + link.title = follow.username; + + const img = document.createElement("img"); + img.className = "lazy"; + img.src = follow.profileImage; + img.alt = follow.username; + img.width = 60; + img.height = 60; + + const span = document.createElement("span"); + span.className = "title"; + + const spanLink = document.createElement("a"); + spanLink.href = `/users/${follow.username}/`; + spanLink.textContent = follow.username; + + link.appendChild(img); + span.appendChild(spanLink); + li.appendChild(link); + li.appendChild(span); + + secondLastFeaturedElement.appendChild(li); + }); + } + } catch (error) { + return; + } +}