diff --git a/_sass/components/_wins-page.scss b/_sass/components/_wins-page.scss index 84f09280b7..d55e4db567 100644 --- a/_sass/components/_wins-page.scss +++ b/_sass/components/_wins-page.scss @@ -245,6 +245,8 @@ height: auto; } } + + } //mobile see more @@ -266,4 +268,27 @@ .wins-card-content > * { flex: 0 0 auto; -} \ No newline at end of file +} + + + +//wins page filter override section begin +.wins-page-contain > ul.filter-list{ + grid-template-columns: repeat(2, 1fr); + min-width: 216px; + width: 46%; + + +} + +.wins-page-contain > ul.filter-list li ul { + width: 100%; +} + +@media #{$bp-below-tablet}{ + .wins-page-contain > ul.wins-filter{ + width: 100%; + grid-template-rows: none; + } +} +//wins page filter override section end \ No newline at end of file diff --git a/wins.html b/wins.html index 775f4458dc..4b24d28f3f 100644 --- a/wins.html +++ b/wins.html @@ -2,264 +2,491 @@ layout: default title: Wins --- + {%- include wins-hero.html -%}
-
-
- - -
-
-
- Blank - -
-
Team(s): Blank
-
Role(s): Blank
-
-

Blank

-

Blank

-
-
-
+
+
+ + +
+
+
+ Blank + +
+
+ Team(s): Blank +
+
+ Role(s): Blank +
+
+

Blank

+

Blank

+
+
+
+
+ + + + +
\ No newline at end of file + //assigning the google form questions to variables for readability + //these variables correspond with a question on the google form + //these variables can be used as a key to access the data + const time = "Timestamp" + const email = "Email Address" + const name = "Full name" + const linkedin_url = "Linkedin URL (optional)" + const linkedin_permission = "Could we use your Linkedin profile picture next to your story?" + const github_url = "Github URL (optional)" + const github_permission = "Could we use your Github profile picture next to your story?" + const team = "Select the team(s) you're on" + const role = "Select your role(s) on the team" + const specific_role = "What is/was your specific role? (optional)" + const join_date = "When did you join Hack for LA? (optional)" + const win = "What do you want to celebrate (select all that apply)?" + const overview = "Give us a brief overview" + const display = "Display?" + + + + function main() { + {% assign localData = site.data.wins-data | jsonify %} + let localData = {{ localData }}; + const rawData = localData.values; + //creates an array of objects where each question is the key and the answer is the value + //cardData[index][question_str] = answer_str + let cardData = [] + const keys = rawData[0] + rawData.slice(1).forEach((data) => { + let cardObj = {} + for (let i = 0; i < keys.length; i++) { + cardObj[keys[i]] = data[i]; + } + cardData.push(cardObj) + + + + }) + + //createFilter(); + window.localStorage.setItem('data', JSON.stringify(cardData)); + makeCards(cardData); + ifPageEmpty(); + + + + } + + //Create The Filters From The Displayed Cards On Page Load + document.addEventListener("DOMContentLoaded", createFilter); + function createFilter(){ + + const roleArr = []; + const teamArr = []; + const responses = document.querySelector("#responses"); + responses.querySelectorAll('.wins-card-team:not([style*="display:none"]):not([style*="display: none"]').forEach(item =>{ + let value = item.textContent.replace("Team(s):","").trim(); + let team = value.split(",").map(x=>x.trim()); + + Array.isArray(team) ? teamArr.push(...team) : teamArr.push(team); + + }) + responses.querySelectorAll('.wins-card-role:not([style*="display:none"]):not([style*="display: none"]').forEach(item =>{ + let value = item.textContent.replace("Role(s):","").trim(); + let role = value.split(",").map(x=>x.trim()); + Array.isArray(role) ? roleArr.push(...role) : roleArr.push(role); + + + }) + + //Create dropdown key,values where the keys are name of the drops downs and the values are the number of occurences of each key + const roleHash = Object.fromEntries([ ...roleArr.reduce((map, key) => map.set(key, (map.get(key) || 0) + 1), new Map()) ]); + const teamHash = Object.fromEntries([ ...teamArr.reduce((map, key) => map.set(key, (map.get(key) || 0) + 1), new Map()) ]); + + + const filterTemplate = document.getElementById("template"); + var cloneFilterTemplate = filterTemplate.content.cloneNode(true); + const roleDropwDown = document.getElementById("role-dropdown"); + const teamDropDown = document.getElementById("team-dropdown"); + + + for(const [key,value] of Object.entries(roleHash) ){ + let cloneFilterTemplate = filterTemplate.content.firstElementChild.cloneNode(true); + cloneFilterTemplate.querySelector("span").textContent = `${key}`; + cloneFilterTemplate.querySelector("span").id=`role_${key.replace(/\s+/g, '')}` + cloneFilterTemplate.querySelector("input").value = `role_${key}`; + cloneFilterTemplate.querySelector("input").addEventListener("click",checkboxClickHandler) + roleDropwDown.append(cloneFilterTemplate); + + } + for(const [key,value] of Object.entries(teamHash) ){ + let cloneFilterTemplate = filterTemplate.content.firstElementChild.cloneNode(true); + cloneFilterTemplate.querySelector("span").textContent = `${key}`; + cloneFilterTemplate.querySelector("span").id=`team_${key.replace(/\s+/g, '')}` + cloneFilterTemplate.querySelector("input").value = `team_${key}`; + cloneFilterTemplate.querySelector("input").addEventListener("click",checkboxClickHandler) + teamDropDown.append(cloneFilterTemplate); + + } + + } + + //Update History State / URL on checkbox click + function checkboxClickHandler(event){ + + let incomingFilterData = document.querySelectorAll("input"); + let queryObj = { }; + + //Calculate and Create Updated Query String + incomingFilterData.forEach(function(e){ + //Find boxes that are checked + if(e.checked){ + let data = e.value.split("_"); + + if(data[0] == 'role'){ + + if(data[0] in queryObj){ + queryObj[data[0]].push(data[1].trim()); + } + else{ + queryObj[data[0]] = []; + queryObj[data[0]].push(data[1].trim()); + } + + } + if(data[0]=='team'){ + if(data[0] in queryObj){ + queryObj[data[0]].push(data[1].trim()); + } + else{ + queryObj[data[0]] = []; + queryObj[data[0]].push(data[1].trim()); + } + + } + } + }) + let questionSymbol = '?'; + let queryString = Object.keys(queryObj).map(key => key + '=' + queryObj[key]).join('&').replaceAll(" ","+"); + let urlParameter = `${questionSymbol}${queryString}`; + + //Update URL parameters + window.history.replaceState(null, '', urlParameter.replaceAll(" ","+")); + + + + + } + + //Update UI on URL history change and on DomContent loaded + window.addEventListener('DOMContentLoaded',updateUI) + window.addEventListener('locationchange',updateUI) + function updateUI(){ + const filterParams = Object.fromEntries(new URLSearchParams(window.location.search)); + const winsCards = document.querySelectorAll("#responses > .wins-card"); + const checkboxes = document.querySelectorAll("input"); + + //If there are no entries in URL display all Cards + if(Object.keys(filterParams).length === 0){ + winsCards.forEach(card=>{card.style.display='flex';}) + return; + } + + //Ensure that checkboxes are marked according to the url query + checkboxes.forEach(checkbox =>{ + let checkboxData = checkbox.value; + let checkboxType = checkboxData.split("_")[0]; + let checkboxValue = checkboxData.split('_')[1]; + if(checkboxType in filterParams){ + let args = filterParams[checkboxType].split(','); + args.includes(checkboxValue) ? checkbox.checked = true : checkbox.checked = false; + } + }) + + + //Card Display/Hide Logic + winsCards.forEach(card=>{ + let teamsInCard = (card.querySelector('.wins-card-team').textContent.replace("Team(s):","")).trim(); + teamsInCard = teamsInCard.split(",").map(x=>x.trim()); + let rolesInCard = (card.querySelector('.wins-card-role').textContent.replace("Role(s):","")).trim(); + rolesInCard = rolesInCard.split(",").map(x=>x.trim()); + let cardUnion = [...rolesInCard,...teamsInCard]; + + + if(('role' in filterParams) && ('team' in filterParams)){ + let roleInURL = filterParams.role.split(','); + let teamInURL = filterParams.team.split(','); + let roleIntersection = rolesInCard.filter(x => roleInURL.includes(x)); + let teamIntersection = teamsInCard.filter(x => teamInURL.includes(x)); + ((roleIntersection.length == 0) || (teamIntersection.length == 0)) ? card.style.display='none' : card.style.display='flex' + } + else if('role' in filterParams){ + let roleInURL = filterParams.role.split(','); + let roleIntersection = rolesInCard.filter(x => roleInURL.includes(x)); + roleIntersection.length == 0 ? card.style.display='none' : card.style.display='flex'; + } + else if('team' in filterParams){ + let teamInURL = filterParams.team.split(','); + let teamIntersection = teamsInCard.filter(x => teamInURL.includes(x)); + teamIntersection.length == 0 ? card.style.display='none' : card.style.display='flex'; + + } + + + }) + + } + + function formatMessage(win) { + let str = ''; + let lastCommaIndex = win.lastIndexOf(","); + if (lastCommaIndex != -1) { + str += win.slice(0, lastCommaIndex + 1) + " and" + win.slice(lastCommaIndex + 1) + '!'; + } else { + str += win + '!'; + } + return str; + } + + function ifPageEmpty() { + if (document.querySelectorAll('.wins-card').length == 0) { + const page = document.querySelector('.wins-page-contain'); + const p = document.createElement('p'); + //p.classList.add("project-card"); + page.appendChild(p); + p.innerHTML = "No one has shared a win yet...be the first!"; + } + } + + function makeElement(elementType, parent, className) { + let child = document.createElement(elementType); + child.classList.add(className); + parent.appendChild(child); + return child; + } + function makeIcon(href, parent, className, src) { + let icon = makeElement('a', parent, 'wins-card-icon'); + icon.setAttribute("href", href); + let iconImg = makeElement('img', icon, className); + iconImg.setAttribute("src", src); + } + + function makeCards(data) { + {% assign githubData = site.data.github-data | jsonify %} + let githubData = {{ githubData }}; + + const list = document.querySelector('#responses'); + let idNum = 0 + data.reverse().forEach( (card) => { + if (card[display] != "TRUE"){ + idNum++; + return; //checks if Display column is set to true + } + + let ghId; + if (card[github_url] && card[github_permission] === "Yes") { + githubData.slice(1) //first key is a timestamp + .forEach(project => { + + /* Exit forEach if githubId is already defined, otherwise + iterate through each project (and its contributors) until + a matching github_url is found */ + if (ghId) return; + project.contributorsComplete.data.forEach(contrib => { + if (contrib.github_url === card[github_url]) { + ghId = contrib.id; + } + }); + }); + + } + + /* if github url is provided in wins-data and permission + is granted, ghId is defined & we can use their github avatar + otherwise, use default avatar */ + + let profileImgSrc = ghId ? + `https://avatars1.githubusercontent.com/u/${ghId}?v=4` : + "/assets/images/wins-page/avatar-default.svg"; + + let cardElement = makeElement('li', list, "project-card"); + cardElement.classList.add("wins-card"); + + let leftDiv = makeElement('div', cardElement, "wins-card-left"); + + let profileImg = makeElement('img', leftDiv, "wins-card-profile-img"); + profileImg.setAttribute("src", profileImgSrc); + + let quote = makeElement('img', leftDiv, "wins-card-big-quote"); + quote.setAttribute("src", "/assets/images/wins-page/quote-icon.svg"); + let rightDiv = makeElement('div', cardElement, "wins-card-content"); + rightDiv.classList.add("project-card-inner"); + + //makes the top of thecard name and icons + let topDiv = makeElement('div', rightDiv, "project-inner"); + topDiv.classList.add("wins-card-top"); + let nameElement = makeElement('span', topDiv, "wins-card-name"); + nameElement.innerHTML = card[name]; + let icons = makeElement('span', topDiv, "wins-card-icons"); + if (card[linkedin_url].length > 0) { + makeIcon(card[linkedin_url], icons, 'linkedin-icon', '/assets/images/wins-page/icon-linkedin-small.svg'); + } if (card[github_url].length > 0) { + makeIcon(card[github_url], icons, 'github-icon', '/assets/images/wins-page/icon-github-small.svg'); + } + + //makes the team and roles portion in the middle + let nameDiv = makeElement('div', rightDiv, "project-inner"); + nameDiv.classList.add("wins-card-team"); + nameDiv.innerHTML = `Team(s): ${card[team]}`; + if (card[role].length > 0) { + let roleDiv = makeElement('div', rightDiv, "project-inner"); + roleDiv.classList.add("wins-card-role"); + roleDiv.innerHTML = `Role(s): ${card[role]}`; + } + + //makes the win and info text on the bottom of the card + let winDiv = makeElement('div', rightDiv, "project-inner"); + winDiv.classList.add("wins__card-text"); + let overviewElement = makeElement('p', winDiv, "wins-card-overview"); + overviewElement.innerHTML = card[overview];//description + let winElement = makeElement('p', winDiv, "wins-card-info"); + winElement.innerHTML = formatMessage(card[win]); //win + + let innerHeight = Array.from(rightDiv.childNodes).reduce((acc, el) => el.offsetHeight + acc, 0) + + //makes the see more span on the bottom of the card + if(innerHeight > rightDiv.offsetHeight){ //checks if see more is needed. + let seeMoreDiv = makeElement('div', rightDiv, "project-inner"); + seeMoreDiv.classList.add("wins__see-more-div") + seeMoreDiv.innerHTML = `...see more` + } + idNum++ + }) + } + function seeMore(id){ + screenWidth = window.innerWidth; + if (screenWidth > 960){ + updateOverlay(id); + }else{ + mobileSeeMore(id); + } + } + function mobileSeeMore(id){ + let span = document.getElementById(id); + let parent = span.parentElement.parentElement + parent.classList.toggle('expanded') + if (parent.classList.contains('expanded')) { + span.innerHTML = "see less" + } + else { + span.innerHTML = "...see more" + } + } + function updateOverlay(i) { + let stringData = window.localStorage.getItem("data"); + let data = JSON.parse(stringData).reverse(); + + const overlayIcons = document.querySelector('#overlay-icons'); + overlayIcons.innerHTML = ""; + + if (data[i][linkedin_url].length > 0) { + makeIcon(data[i][linkedin_url], overlayIcons, 'linkedin-icon', '/assets/images/wins-page/icon-linkedin-small.svg'); + } if (data[i][github_url].length > 0) { + makeIcon(data[i][github_url], overlayIcons, 'github-icon', '/assets/images/wins-page/icon-github-small.svg'); + } + + const overlayName = document.querySelector('#overlay-name'); + overlayName.innerHTML = data[i][name]; + + const overlayTeams = document.querySelector('#overlay-teams'); + overlayTeams.innerHTML = `Team(s): ${data[i][team]}`; + + const overlayRoles = document.querySelector('#overlay-roles'); + overlayRoles.innerHTML = `Role(s): ${data[i][role]}`; + + const overlayOverview = document.querySelector('#overlay-overview'); + overlayOverview.innerHTML = data[i][overview]; + + const overlayInfo = document.querySelector('#overlay-info'); + overlayInfo.innerHTML = formatMessage(data[i][win]); + + const overlayProjectCard = document.querySelector('#overlay-project-card'); + overlayProjectCard.parentNode.classList.add("display-initial"); + } + function hideOverlay(e) { + e = e || window.event; + if (e.target !== e.currentTarget) + return; + + const overlayProjectCard = document.querySelector('#overlay-project-card'); + overlayProjectCard.parentNode.classList.remove("display-initial"); + } + + main(); + + + + + history.pushState = ( f => function pushState(){ + var ret = f.apply(this, arguments); + window.dispatchEvent(new Event('pushstate')); + window.dispatchEvent(new Event('locationchange')); + return ret; + })(history.pushState); + + history.replaceState = ( f => function replaceState(){ + var ret = f.apply(this, arguments); + window.dispatchEvent(new Event('replacestate')); + window.dispatchEvent(new Event('locationchange')); + return ret; + })(history.replaceState); + + window.addEventListener('popstate',()=>{ + window.dispatchEvent(new Event('locationchange')) + }); +