|
1 | 1 | /**
|
| 2 | + * Populates the content in the experience blocks using the HTML template |
| 3 | + * @param {JSON Array} experienceData |
| 4 | + */ |
| 5 | +function populateExperienceField(experienceData){ |
| 6 | + const experienceInjectPoint = document.querySelector("#experienceBoxes"); |
| 7 | + const experienceTemplate = experienceInjectPoint.querySelector("[experienceBoxTemplate]"); |
| 8 | + const subItemTemplate = experienceTemplate.content.querySelector("[experienceSubItemTemplate]"); |
| 9 | + experienceData.forEach(experience => { |
| 10 | + const currExperienceTemplate = experienceTemplate.content.cloneNode(true).children[0]; |
| 11 | + const subItemInjectPoint = currExperienceTemplate.querySelector("ul"); |
| 12 | + const companyImage = currExperienceTemplate.querySelector("img"); |
| 13 | + companyImage.src = experience["companyImageLink"]; |
| 14 | + companyImage.alt = `${experience.company} logo`; |
| 15 | + currExperienceTemplate.querySelector("h3").textContent = experience["position"]; |
| 16 | + experience["content"].forEach(subItem => { |
| 17 | + const currSubItemTemplate = subItemTemplate.content.cloneNode(true).children[0]; |
| 18 | + const locationField = currSubItemTemplate.querySelectorAll("strong")[1]; |
| 19 | + const location = subItem["location"]; |
| 20 | + if (location) { |
| 21 | + locationField.textContent = ` @ ${location}`; |
| 22 | + } else { |
| 23 | + locationField.style.display = "none"; |
| 24 | + } |
| 25 | + currSubItemTemplate.querySelectorAll("strong")[0].textContent = `${subItem["subtitle"]}`; |
| 26 | + currSubItemTemplate.querySelector("span").textContent = `: ${subItem["description"]}`; |
| 27 | + subItemInjectPoint.appendChild(currSubItemTemplate); |
| 28 | + }); |
| 29 | + experienceInjectPoint.appendChild(currExperienceTemplate); |
| 30 | + // experienceInjectPoint.querySelectorAll(".experienceBox").forEach(experienceBox => { |
| 31 | + // const img = experienceBox.querySelector("img"); |
| 32 | + // img.onload = () => { |
| 33 | + // const currHeight = parseFloat(window.getComputedStyle(experienceBox).height); |
| 34 | + // experienceBox.style.height = `${currHeight + img.height}px`; |
| 35 | + // updateExperienceHeights(); |
| 36 | + // } |
| 37 | + // }); |
| 38 | + }); |
| 39 | + updateCopy(); |
| 40 | +} |
| 41 | + |
| 42 | +/** |
| 43 | + * Updates the copy of the experience elements depending on screen width. |
| 44 | + */ |
| 45 | +function updateCopy(){ |
| 46 | + if(window.innerWidth < 470){ |
| 47 | + document.querySelectorAll(".experienceCopy").forEach(copySection => { |
| 48 | + copySection.style.display = "none"; |
| 49 | + }); |
| 50 | + } else { |
| 51 | + document.querySelectorAll(".experienceCopy").forEach(copySection => { |
| 52 | + copySection.style.display = "inline"; |
| 53 | + }); |
| 54 | + } |
| 55 | +} |
| 56 | +/** |
| 57 | + * Updates the heights of the experience blocks to allow use of gradient border |
| 58 | + * needs to be called AFTER company images load (present issue) |
| 59 | + * Can be done by implementing eager loading on headers, but ideally not implemented that way; |
| 60 | + */ |
| 61 | +// function updateExperienceHeights(){ |
| 62 | +// let currLargestBlock = 0; |
| 63 | +// document.querySelectorAll(".experienceBox").forEach(experienceBlock => { |
| 64 | +// currLargestBlock = Math.max(currLargestBlock, parseFloat(window.getComputedStyle(experienceBlock).height)); |
| 65 | +// }); |
| 66 | +// document.querySelectorAll(".experienceBox").forEach(experienceBlock => { |
| 67 | +// experienceBlock.style.height = `${currLargestBlock}px`; |
| 68 | +// }); |
| 69 | +// } |
| 70 | + |
| 71 | +fetch("/assets/json/experiences.json").then(response => { |
| 72 | + response.json().then(data => { |
| 73 | + populateExperienceField(data); |
| 74 | + }); |
| 75 | +}); |
| 76 | + |
| 77 | +addEventListener("resize", () => { |
| 78 | + updateCopy(); |
| 79 | +});/** |
| 80 | + * Populates the Portfolio items with content. |
| 81 | + * @param {JSON Array} portfolioData |
| 82 | + */ |
| 83 | +function populatePortfolio(portfolioData){ |
| 84 | + const portfolioItemInjectPoint = document.querySelector("#portfolioItems"); |
| 85 | + const portfolioItemTemplate = portfolioItemInjectPoint.querySelector("[portfolioItemTemplate]"); |
| 86 | + const languageBoxTemplate = portfolioItemTemplate.content.querySelector("[languageBoxTemplate]"); |
| 87 | + portfolioData.forEach(portfolioElement => { |
| 88 | + const currPortfolioItemTemplate = portfolioItemTemplate.content.cloneNode(true).children[0]; |
| 89 | + currPortfolioItemTemplate.querySelector("h3").textContent = portfolioElement.title; |
| 90 | + currPortfolioItemTemplate.querySelector("p").textContent = portfolioElement.description; |
| 91 | + const languageInjectPoint = currPortfolioItemTemplate.querySelector(".languages"); |
| 92 | + portfolioElement.languages.forEach(language => { |
| 93 | + const currLanguageTemplate = languageBoxTemplate.content.cloneNode(true).children[0]; |
| 94 | + currLanguageTemplate.textContent = language; |
| 95 | + languageInjectPoint.appendChild(currLanguageTemplate); |
| 96 | + }); |
| 97 | + portfolioItemInjectPoint.appendChild(currPortfolioItemTemplate); |
| 98 | + }); |
| 99 | +} |
| 100 | + |
| 101 | +/** |
| 102 | + * Updates the size of the elements in the portfolio section. |
| 103 | + */ |
| 104 | +function updateSize(){ |
| 105 | + let maxItemHeight = 0; |
| 106 | + const portfolioItems = document.querySelectorAll('.portfolioItem'); |
| 107 | + const firstItemStyle = getComputedStyle(portfolioItems[0]); |
| 108 | + getItemWidth = () => {return firstItemStyle.width} |
| 109 | + const paddingOffset = parseFloat(firstItemStyle.padding) * 2; |
| 110 | + portfolioItems.forEach(item => { |
| 111 | + maxItemHeight = Math.max(maxItemHeight, item.clientHeight); |
| 112 | + }); |
| 113 | + |
| 114 | + maxItemHeight -= paddingOffset; |
| 115 | + |
| 116 | + portfolioItems.forEach(item => { |
| 117 | + item.style.height = `${maxItemHeight}px`; |
| 118 | + }); |
| 119 | +} |
| 120 | + |
| 121 | +/** |
| 122 | + * Sleeps for a certain period of time. |
| 123 | + * @param {int} ms how many ms to sleep for. |
| 124 | + * @returns {Promise<Function>} sleep event. |
| 125 | +*/ |
| 126 | +function sleep(ms) { |
| 127 | + return new Promise(resolve => setTimeout(resolve, ms)); |
| 128 | +} |
| 129 | + |
| 130 | +// Adds the event listeners to enforce these constraints. |
| 131 | + |
| 132 | +window.addEventListener('resize', (event) => { |
| 133 | + const widthPx = parseFloat(event.target.innerWidth); |
| 134 | + if(widthPx >= 1000){ |
| 135 | + updateSize(); |
| 136 | + } |
| 137 | +}); |
| 138 | + |
| 139 | +window.addEventListener('load', async () => { |
| 140 | + for(i = 0; i < 16; i++){ |
| 141 | + try { |
| 142 | + if(parseFloat(window.innerWidth) >= 1000){ |
| 143 | + updateSize(); |
| 144 | + } |
| 145 | + break; |
| 146 | + } catch(err){ |
| 147 | + await sleep(10); |
| 148 | + } |
| 149 | + } |
| 150 | +}); |
| 151 | + |
| 152 | +// Requests data and populates portfolio. |
| 153 | + |
| 154 | +fetch("/assets/json/portfolio.json").then(response => { |
| 155 | + response.json().then(portfolioData => { |
| 156 | + populatePortfolio(portfolioData); |
| 157 | + }); |
| 158 | +});/** |
2 | 159 | * Toggles the provided hamburger.
|
3 | 160 | * @param {HTML Element} hamburger
|
4 | 161 | * @param {HTML Element} navMenu
|
|
0 commit comments