diff --git a/scripts/main.js b/scripts/main.js
index 14e674cb3f..692c859304 100644
--- a/scripts/main.js
+++ b/scripts/main.js
@@ -1,299 +1,3 @@
-
-// Initialize AOS (Animate On Scroll)
-AOS.init();
-
-// Array containing contributors data
-const Contributors = contributors;
-
-// ---------- Utilities for safe rendering and URL parsing ----------
-function getGithubUsernameFromUrl(possibleUrl) {
- try {
- if (typeof possibleUrl !== "string" || possibleUrl.trim() === "") return null;
- // Accept plain usernames as well as full URLs
- if (!possibleUrl.includes("/")) return possibleUrl.trim();
- const url = new URL(possibleUrl);
- if (url.hostname !== "github.com") return null;
- const path = url.pathname.replace(/^\/+/, "").split("/");
- const username = path[0] || null;
- return username && username.length > 0 ? username : null;
- } catch (_) {
- // Handle malformed URLs like 'https://github,com/...'
- const fixed = possibleUrl.replace(",", ".");
- try {
- const url = new URL(fixed);
- if (url.hostname !== "github.com") return null;
- const path = url.pathname.replace(/^\/+/, "").split("/");
- const username = path[0] || null;
- return username && username.length > 0 ? username : null;
- } catch (__){
- return null;
- }
- }
-}
-
-function createAvatarImg(username, eager = false) {
- const img = document.createElement("img");
- img.loading = eager ? "eager" : "lazy";
- img.decoding = "async";
- img.width = 40;
- img.height = 40;
- // lightweight placeholder to reserve space
- img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
- img.dataset.src = username
- ? `https://avatars.githubusercontent.com/${username}`
- : "https://avatars.githubusercontent.com/ghost";
- if (eager) {
- img.src = img.dataset.src;
- img.removeAttribute("data-src");
- img.setAttribute("fetchpriority", "high");
- }
- img.alt = username ? `${username}'s avatar` : "avatar";
- return img;
-}
-
-function createContributorAnchor(item, eager = false) {
- const anchor = document.createElement("a");
- anchor.className = "box-item";
- const username = getGithubUsernameFromUrl(item.username);
- const href = typeof item.username === "string" ? item.username : "";
- if (href) {
- anchor.setAttribute("href", href);
- anchor.setAttribute("target", "_blank");
- anchor.setAttribute("rel", "noopener noreferrer");
- }
-
- const nameSpan = document.createElement("span");
- nameSpan.textContent = item.fullname || "Anonymous";
- anchor.appendChild(nameSpan);
-
- const img = createAvatarImg(username, eager);
- anchor.appendChild(img);
- return anchor;
-}
-
-// Variables
-const searchbox = document.getElementById("search");
-let searchResult = null;
-// Pagination state
-let pageSize = 60;
-let currentPage = 1;
-
-// Get the current year dynamically
-const currentYear = new Date().getFullYear();
-
-// Function to set the current year in the HTML
-function setCurrentYear() {
- const yearElements = [
- // { id: "current-year", defaultValue: currentYear },
- { id: "current-year-title", defaultValue: currentYear },
- { id: "current-year-footer", defaultValue: currentYear },
- { id: "current-year-copyright", defaultValue: currentYear },
- ];
-
- yearElements.forEach((element) => {
- const el = document.getElementById(element.id);
- if (el) {
- el.textContent = element.defaultValue;
- } else {
- console.warn(`Element with ID '${element.id}' not found in the DOM.`);
- }
- });
-
- // Set the document title with the current year
- document.title = `Hacktoberfest ${currentYear} - Contributors`;
-}
-
-// Call the function to set the current year
-setCurrentYear();
-
-/**
- * Filters contributors based on the search string.
- * @param {string} str - The search string.
- * @param {Array} array - The array of contributors.
- * @returns {Array} - The filtered list of contributors.
- */
-function filterUsers(str = "ContributorName", array) {
- const inputString = typeof str === "string" ? str.toLowerCase() : "";
- if (str === "") return "Cannot be empty, please enter a name";
- return array.filter((item) => {
- const fullName = item.fullname || "";
- return fullName.toLowerCase().includes(inputString);
- });
-}
-
-/**
- * Renders the contributors on the page.
- * @param {Array} array - The array of contributors to render.
- * @param {Object} options - render options
- * @param {boolean} options.paginate - whether to paginate the array
- */
-function render(array, options = { paginate: true }) {
- const container = document.getElementById("contributors");
- if (!container) {
- console.warn("Contributors container not found");
- return;
- }
- const list = options.paginate
- ? array.slice(0, currentPage * pageSize)
- : array;
- list.forEach((item, index) => {
- // Eager-load the first row or two on initial page for faster perceived load
- const shouldEagerLoad = currentPage === 1 && index < 12;
- const anchor = createContributorAnchor(item, shouldEagerLoad);
- anchor.setAttribute("id", item.id);
- container.appendChild(anchor);
- });
- // After rendering batch, invoke lazy loading for avatars
- setupLazyLoadImages();
- // And ensure infinite scroll sentinel is available
- setupLoadMoreOnScroll();
-}
-
-// Load contributors after document loads.
-render(contributors, { paginate: true });
-
-/**
- * Loads more contributors when "Load More" button is clicked.
- */
-function loadMore() {
- const container = document.getElementById("contributors");
- if (!container) return;
- const totalPages = Math.ceil(contributors.length / pageSize);
- if (currentPage >= totalPages) {
- render(contributors, { paginate: true });
- } else {
- currentPage += 1;
- container.innerHTML = "
Loading...
";
- render(contributors, { paginate: true });
- const loading = document.getElementById("loading");
- if (loading) loading.setAttribute("hidden", true);
- if (currentPage >= totalPages) {
- const loadMoreEl = document.getElementById("loadMore");
- if (loadMoreEl) loadMoreEl.setAttribute("hidden", true);
- }
- }
-}
-
-// Event listener for "Load More" button
-const loadMoreBtn = document.getElementById("loadMore");
-if (loadMoreBtn) {
- loadMoreBtn.addEventListener("click", loadMore);
-}
-
-// Add avatars to existing contributor links (in case initial render occurred earlier)
-document.querySelectorAll("a.box-item").forEach((con) => {
- const username = getGithubUsernameFromUrl(con.getAttribute("href"));
- const hasImg = con.querySelector("img");
- if (!hasImg) {
- con.appendChild(createAvatarImg(username));
- }
-});
-setupLazyLoadImages();
-setupLoadMoreOnScroll();
-
-// -------- Lazy loading avatars with IntersectionObserver --------
-function setupLazyLoadImages() {
- const images = document.querySelectorAll("a.box-item img[data-src]");
- if (!("IntersectionObserver" in window)) {
- images.forEach((img) => {
- img.src = img.dataset.src;
- img.removeAttribute("data-src");
- });
- return;
- }
- const imgObserver = new IntersectionObserver((entries, observer) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting) {
- const img = entry.target;
- img.src = img.dataset.src;
- img.removeAttribute("data-src");
- observer.unobserve(img);
- }
- });
- }, { rootMargin: "300px 0px", threshold: 0.01 });
- images.forEach((img) => imgObserver.observe(img));
-}
-
-// -------- Infinite scroll: auto load more when near bottom --------
-function setupLoadMoreOnScroll() {
- const loadMoreBtn = document.getElementById("loadMore");
- if (!loadMoreBtn) return;
- let sentinel = document.getElementById("load-more-sentinel");
- if (!sentinel) {
- sentinel = document.createElement("div");
- sentinel.id = "load-more-sentinel";
- sentinel.style.height = "1px";
- const container = document.getElementById("contributors");
- if (container) container.appendChild(sentinel);
- }
- if (!("IntersectionObserver" in window)) return;
- const totalPages = Math.ceil(contributors.length / pageSize);
- const observer = new IntersectionObserver((entries) => {
- entries.forEach((entry) => {
- if (entry.isIntersecting) {
- if (currentPage < totalPages && (!searchbox || searchbox.value === "")) {
- loadMore();
- }
- }
- });
- }, { rootMargin: "200px 0px", threshold: 0 });
- observer.observe(sentinel);
-}
-
-function debounce(fn, delay) {
- let timer;
- return function(...args) {
- clearTimeout(timer);
- timer = setTimeout(() => fn.apply(this, args), delay);
- };
-}
-
-// Event listener for the search box with debounce
-if (searchbox) {
- searchbox.addEventListener(
- "keyup",
- debounce(async (e) => {
- const loadMoreEl = document.getElementById("loadMore");
- if (loadMoreEl) {
- if (searchbox.value !== "") loadMoreEl.classList.add("hidden");
- else loadMoreEl.classList.remove("hidden");
- }
-
- searchResult = await filterUsers(e.target.value, contributors);
- const container = document.getElementById("contributors");
- if (!container) return;
- container.innerHTML = e.target.value !== "" ? "Loading...
" : "";
-
- if (e.target.value !== "") {
- searchResult.forEach((item) => {
- const anchor = createContributorAnchor(item);
- container.appendChild(anchor);
- });
- } else {
- // Reset pagination when clearing search
- currentPage = 1;
- render(contributors, { paginate: true });
- }
-
- const loading = document.getElementById("loading");
- if (loading) loading.setAttribute("hidden", true);
- }, 200)
- );
-}
-
-/* Back-to-top button functionality */
-const backToTopButton = document.querySelector("#back-to-top-btn");
-
-window.addEventListener("scroll", scrollFunction);
-function scrollFunction() {
- if (window.pageYOffset > 300) {
- if (!backToTopButton.classList.contains("btnEntrance")) {
- backToTopButton.classList.remove("btnExit");
- backToTopButton.classList.add("btnEntrance");
- backToTopButton.style.display = "block";
- }
- } else {
- if (backToTopButton.classList.contains("btnEntrance")) {
backToTopButton.classList.remove("btnEntrance");
backToTopButton.classList.add("btnExit");
setTimeout(function () {
@@ -311,7 +15,9 @@ function smoothScrollBackToTop() {
const distance = targetPosition - startPosition;
const duration = 750;
let start = null;
+
window.requestAnimationFrame(step);
+
function step(timestamp) {
if (!start) start = timestamp;
const progress = timestamp - start;
@@ -340,4 +46,25 @@ $(".tdnn").click(function () {
// Display live stats with the dynamic year
document.getElementById(
"stats"
-).innerHTML = `You guys are awesome, we have again passed the GitHub rate limit this hour. Here is a link to check out our repo's live stats.`;
+).innerHTML = `You guys are awesome, we have again passed the GitHub rate limit this hour. Here is a link to check out our repo's live stats.`;
+
+// ============================================================
+// Contributor Sort Functionality - Issue #8533
+// ============================================================
+// TODO: Implement alphabetical sorting for contributor cards
+// This function will be triggered by a sort button in the UI
+// to reorder contributors alphabetically by name
+
+/**
+ * Sorts contributor cards alphabetically by name
+ * @param {string} order - Sort order: 'asc' for ascending, 'desc' for descending
+ * @returns {void}
+ */
+function sortContributorsAlphabetically(order = 'asc') {
+ // TODO: Select all contributor card elements from the DOM
+ // TODO: Extract contributor names and sort them
+ // TODO: Reorder the DOM elements based on sorted order
+ // TODO: Apply animation or transition effects if needed
+
+ console.log(`Sorting contributors in ${order} order - functionality to be implemented`);
+}