-
Notifications
You must be signed in to change notification settings - Fork 418
New addons: Compact Profile Sliders + User Stats In Profile #8569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
33665c6
2d76596
8dea897
22fe3bd
1645c79
1cd82b6
2fa4341
52110b8
7a4d418
d8fbb4f
5b1c8ed
605ac5a
ea7cef2
7f39b80
df44200
732e82a
3f8d2ac
f9b5bf5
5985186
be66e30
6073dd8
7a3fca5
0ac8210
13e5623
5f8a874
66fb1f1
82da879
18956b8
28befad
229f050
6012a88
452b779
e334093
46040d2
f3555ac
d10cb68
0d8d406
fe892e0
c667d9c
2f3fa10
7657e57
1a2c898
a09f1ac
1bb044c
938b281
0a4ef2a
a769696
918740d
7decc0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| { | ||
| "id": "compact-profile", | ||
| "name": "Compact Scratch Profile Sliders", | ||
| "description": "Rearranges the profile sections into a cleaner two-column layout by pairing sliders side by side, making profiles more compact and readable.", | ||
| "credits": [ | ||
| { | ||
| "name": "VIGARPAST_777", | ||
| "link": "https://scratch.mit.edu/users/VIGARPAST_777/" | ||
| } | ||
| ], | ||
| "userscripts": [ | ||
| { | ||
| "url": "userscript.js", | ||
| "matches": ["https://scratch.mit.edu/users/*/"] | ||
| } | ||
| ], | ||
| "userstyles": [ | ||
| { | ||
| "url": "userstyles.css", | ||
| "matches": ["https://scratch.mit.edu/users/*/"] | ||
| } | ||
| ], | ||
| "settings": [], | ||
| "enabledByDefault": false, | ||
| "targets": ["profiles"], | ||
| "versionAdded": "1.44.0", | ||
| "tags": ["profiles", "ui", "featured"] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| export default async function ({ addon }) { | ||
| function groupSliders() { | ||
| const allSliders = Array.from(document.querySelectorAll(".box.slider-carousel-container")); | ||
| const parentContainer = allSliders[0]?.parentNode; | ||
| if (!allSliders.length || !parentContainer) return; | ||
|
|
||
| const order = []; | ||
| allSliders.forEach((slider) => { | ||
| const carousel = slider.querySelector(".slider-carousel"); | ||
| if (!carousel) return; | ||
| const items = carousel.querySelectorAll("li"); | ||
| if (!items.length) return; | ||
| order.push(slider); | ||
| }); | ||
|
|
||
| for (let i = 0; i < order.length - 1; i += 2) { | ||
| const left = order[i]; | ||
| const right = order[i + 1]; | ||
|
|
||
| const flexWrapper = document.createElement("div"); | ||
| flexWrapper.style.display = "flex"; | ||
| flexWrapper.style.justifyContent = "space-between"; | ||
| flexWrapper.style.marginBottom = "20px"; | ||
|
|
||
| left.style.width = "48%"; | ||
| right.style.width = "48%"; | ||
| left.style.display = "block"; | ||
| right.style.display = "block"; | ||
|
|
||
| parentContainer.insertBefore(flexWrapper, left); | ||
| flexWrapper.appendChild(left); | ||
| flexWrapper.appendChild(right); | ||
|
|
||
| [left, right].forEach((box) => { | ||
| const carousel = box.querySelector(".slider-carousel"); | ||
| if (carousel) { | ||
| carousel.style.overflowX = "auto"; | ||
| carousel.style.scrollBehavior = "smooth"; | ||
| } | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| groupSliders(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| .sa-compact-row { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This class is not applied to any elements, so all the styles in this file are unused. |
||
| display: flex; | ||
| justify-content: space-between; | ||
| margin-bottom: 20px; | ||
| gap: 2%; | ||
| } | ||
|
|
||
| .sa-compact-row .box.slider-carousel-container { | ||
| width: 48%; | ||
| display: block; | ||
| } | ||
|
|
||
| .sa-compact-row .box.slider-carousel-container .slider-carousel { | ||
| overflow-x: auto; | ||
| scroll-behavior: smooth; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "name": "User Stats in Profile", | ||
| "description": "Displays project statistics inside user profiles using Scratch icons with real-time data.", | ||
| "credits": [ | ||
| { | ||
| "name": "VIGARPAST_777", | ||
| "link": "https://scratch.mit.edu/users/VIGARPAST_777/" | ||
| } | ||
| ], | ||
| "userscripts": [ | ||
| { | ||
| "url": "userscript.js", | ||
| "matches": ["https://scratch.mit.edu/users/*"] | ||
| } | ||
| ], | ||
| "userstyles": [ | ||
| { | ||
| "url": "userstyles.css", | ||
| "matches": ["https://scratch.mit.edu/users/*"] | ||
| } | ||
| ], | ||
| "enabledByDefault": false, | ||
| "versionAdded": "1.44.0", | ||
| "tags": ["community", "profiles"] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| export default async function ({ addon }) { | ||
| const username = location.pathname.split("/")[2]; | ||
| if (!username) return; | ||
|
|
||
| const profileBox = document.querySelector("#profile-box .inner"); | ||
| if (!profileBox) return; | ||
|
|
||
| if (document.querySelector(".scratch-stats-box")) return; | ||
|
|
||
| const statsDiv = document.createElement("div"); | ||
| statsDiv.className = "scratch-stats-box"; | ||
| statsDiv.style.display = "flex"; | ||
| statsDiv.style.justifyContent = "space-between"; | ||
| statsDiv.style.alignItems = "center"; | ||
| statsDiv.style.padding = "10px"; | ||
| statsDiv.style.marginTop = "15px"; | ||
| statsDiv.style.fontSize = "14px"; | ||
| statsDiv.style.backgroundColor = "#f9f9f9"; | ||
| statsDiv.style.borderTop = "1px solid #ddd"; | ||
|
|
||
| const statsElements = [ | ||
| { icon: "https://scratch.mit.edu/svgs/project/love-red.svg", count: "?", alt: "❤", key: "loves" }, | ||
| { icon: "https://scratch.mit.edu/svgs/project/fav-yellow.svg", count: "?", alt: "⭐", key: "faves" }, | ||
| { | ||
| icon: "https://scratch.mit.edu/svgs/project/remix-gray.svg", | ||
| count: "?", | ||
| alt: "🔄", | ||
| className: "remix-icon", | ||
| key: "remixes", | ||
| }, | ||
| { | ||
| icon: "https://scratch.mit.edu/svgs/project/views-gray.svg", | ||
| count: "?", | ||
| alt: "👁️", | ||
| className: "views-icon", | ||
| key: "views", | ||
| }, | ||
| ]; | ||
|
|
||
| const domElements = {}; | ||
|
|
||
| statsElements.forEach((stat) => { | ||
| const statDiv = document.createElement("div"); | ||
| statDiv.style.display = "flex"; | ||
| statDiv.style.alignItems = "center"; | ||
| statDiv.style.gap = "6px"; | ||
|
|
||
| const img = document.createElement("img"); | ||
| img.src = stat.icon; | ||
| img.alt = stat.alt; | ||
| img.style.width = "20px"; | ||
| img.style.height = "20px"; | ||
| if (stat.className) img.classList.add(stat.className); | ||
|
|
||
| const span = document.createElement("span"); | ||
| span.textContent = stat.count; | ||
|
|
||
| statDiv.appendChild(img); | ||
| statDiv.appendChild(span); | ||
| statsDiv.appendChild(statDiv); | ||
|
|
||
| domElements[stat.key] = span; | ||
| }); | ||
|
|
||
| profileBox.appendChild(statsDiv); | ||
|
|
||
| const style = document.createElement("style"); | ||
| style.textContent = ` | ||
| img.views-icon { filter: invert(37%) sepia(95%) saturate(4000%) hue-rotate(200deg) brightness(95%) contrast(90%); } | ||
| img.remix-icon { filter: invert(55%) sepia(72%) saturate(500%) hue-rotate(90deg) brightness(95%) contrast(90%); } | ||
| `; | ||
| document.head.appendChild(style); | ||
|
|
||
| // Fetch views, loves, faves from ScratchInfo API | ||
| try { | ||
| const res = await fetch(`https://scratchinfo.quuq.dev/api/v1/users/${username}/projectStats`); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know who runs this API?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| const data = await res.json(); | ||
| domElements.views.textContent = Number(data.totalViews).toLocaleString(); | ||
| domElements.loves.textContent = Number(data.totalLoves).toLocaleString(); | ||
| domElements.faves.textContent = Number(data.totalFaves).toLocaleString(); | ||
| } catch (e) { | ||
| console.error("Failed to fetch ScratchInfo stats", e); | ||
| } | ||
|
|
||
| // Calculate remixes by fetching all user projects and then fetching each project individually | ||
| async function calculateRemixes() { | ||
| let totalRemixes = 0; | ||
| let offset = 0; | ||
| const limit = 40; | ||
| let projects; | ||
|
|
||
| do { | ||
| const res = await fetch( | ||
| `https://api.scratch.mit.edu/users/${username}/projects/?limit=${limit}&offset=${offset}` | ||
| ); | ||
| projects = await res.json(); | ||
| for (const project of projects) { | ||
| try { | ||
| const projRes = await fetch(`https://api.scratch.mit.edu/projects/${project.id}/`); | ||
| const projData = await projRes.json(); | ||
| totalRemixes += projData.stats?.remixes || 0; | ||
| } catch {} | ||
| } | ||
| offset += limit; | ||
| } while (projects.length === limit); | ||
|
|
||
| domElements.remixes.textContent = totalRemixes.toLocaleString(); | ||
| } | ||
|
|
||
| calculateRemixes(); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| .scratch-stats-box img.views-icon { | ||
| filter: invert(37%) sepia(95%) saturate(4000%) hue-rotate(200deg) brightness(95%) contrast(90%); | ||
| } | ||
|
|
||
| .scratch-stats-box img.remix-icon { | ||
| filter: invert(55%) sepia(72%) saturate(500%) hue-rotate(90deg) brightness(95%) contrast(90%); | ||
| } | ||
|
|
||
| .scratch-stats-box { | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| padding: 10px; | ||
| margin-top: 15px; | ||
| font-size: 14px; | ||
| background-color: #f9f9f9; | ||
| border-top: 1px solid #ddd; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.