diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..558536033 Binary files /dev/null and b/.DS_Store differ diff --git a/Week1/.DS_Store b/Week1/.DS_Store new file mode 100644 index 000000000..06a56cf4e Binary files /dev/null and b/Week1/.DS_Store differ diff --git a/Week1/homework/.DS_Store b/Week1/homework/.DS_Store new file mode 100644 index 000000000..0aa1adfb0 Binary files /dev/null and b/Week1/homework/.DS_Store differ diff --git a/Week1/homework/hack-repo-1/.DS_Store b/Week1/homework/hack-repo-1/.DS_Store new file mode 100644 index 000000000..1343c3279 Binary files /dev/null and b/Week1/homework/hack-repo-1/.DS_Store differ diff --git a/Week1/homework/hack-repo-1/hyf.png b/Week1/homework/hack-repo-1/hyf.png new file mode 100755 index 000000000..76bc5a13b Binary files /dev/null and b/Week1/homework/hack-repo-1/hyf.png differ diff --git a/Week1/homework/hack-repo-1/index.html b/Week1/homework/hack-repo-1/index.html new file mode 100755 index 000000000..5710a7b4b --- /dev/null +++ b/Week1/homework/hack-repo-1/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + HYF-GITHUB + + + + + +
+ + + + \ No newline at end of file diff --git a/Week1/homework/hack-repo-1/index.js b/Week1/homework/hack-repo-1/index.js new file mode 100755 index 000000000..05238b250 --- /dev/null +++ b/Week1/homework/hack-repo-1/index.js @@ -0,0 +1,67 @@ +'use strict'; + +{ + function fetchJSON(url, cb) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'json'; + xhr.onload = () => { + if (xhr.status >= 200 && xhr.status <= 299) { + cb(false, xhr.response); + } else { + cb(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`)); + } + }; + xhr.onerror = () => cb(new Error('Network request failed')); + xhr.send(); + } + + function createAndAppend(name, parent, options = {}) { + const elem = document.createElement(name); + parent.appendChild(elem); + Object.entries(options).forEach(([key, value]) => { + if (key === 'text') { + elem.innerHTML = value; + } else { + elem.setAttribute(key, value); + } + }); + return elem; + } + + function renderRepoDetails(repo, ul) { + createAndAppend('li', ul, { + text : `Repository: ${repo.name}
+ Description: ${repo.description}
+ Forks: ${repo.forks}
+ Uptade: ${repo.updated_at.slice(0,4)}/${repo.updated_at.slice(5,7)}/${repo.updated_at.slice(8,10)}, ${repo.updated_at.slice(11,19)}` + }); + } + + function main(url) { + createAndAppend("p" , root, { text : "HYF Repositories" }); //append the header on DOM + + fetchJSON(url, (err, repos) => { + const root = document.getElementById('root'); + if (err) { + createAndAppend('div', root, { + text: err.message, + class: 'alert-error', + }); + return; + } + const ul = createAndAppend('ul', root); + sortByName(repos); + repos.forEach(repo => renderRepoDetails(repo, ul)); + }); + } + + //function to sort the repos based on their names + function sortByName(repos){ + repos.sort((a , b) => (a.name > b.name)? 1 : -1); + } + + + const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=10'; + window.onload = () => main(HYF_REPOS_URL); +} diff --git a/Week1/homework/hack-repo-1/style.css b/Week1/homework/hack-repo-1/style.css new file mode 100755 index 000000000..fd56b41d9 --- /dev/null +++ b/Week1/homework/hack-repo-1/style.css @@ -0,0 +1,43 @@ +.alert-error { + background-color: #f8d7da; + color: #721c24; + padding: 20px 30px; + border-radius: 5px; +} + +#root{ + font-family: sans-serif; + font-size: 1.2em; + width: 80vw; + margin-left: auto; + margin-right: auto; + letter-spacing: 0.3px; +} + +li{ + list-style: none; + line-height: 1.5em; + margin-bottom: 5px; + padding: 30px; + box-shadow: 0px 4px 8px grey; +} + +ul{ + padding: 0; + margin: 0; +} + +p{ + background-color: #3f51b5; + color: white; + padding: 30px; + letter-spacing: 1px; + margin-bottom: 5px; +} + +@media all and (max-width:499px){ + #root{ + width: 93vw; + font-size: 1em; + } +} diff --git a/Week1/homework/js-exercises/dog-photo.js b/Week1/homework/js-exercises/dog-photo.js new file mode 100644 index 000000000..757d12aeb --- /dev/null +++ b/Week1/homework/js-exercises/dog-photo.js @@ -0,0 +1,36 @@ +//render dogs with XHR +function dogPhotosXHR(){ + const xhr = new XMLHttpRequest() + xhr.open("GET", "https://dog.ceo/api/breeds/image/random", true); + xhr.send(); + xhr.addEventListener("load", () => { + if (xhr.status === 200){ + const res = JSON.parse(xhr.response); + //append img in a new
  • + const li = document.createElement("li"); + li.innerHTML = ``; + document.getElementById("list").appendChild(li); + }else { console.log("Error on request..."); } + }) + + xhr.addEventListener("error", () => console.log("Error on request...")) +} + +document.getElementById("btn1").addEventListener("click", dogPhotosXHR); + + + +//render dogs with Axios +function dogPhotosAxios(){ + axios + .get('https://dog.ceo/api/breeds/image/random') + .then(res => { + //append img in a new
  • + const li = document.createElement("li"); + li.innerHTML = ``; + document.getElementById("list").appendChild(li); + }) + .catch(err => console.error(err)); +} + +document.getElementById("btn2").addEventListener("click", dogPhotosAxios); \ No newline at end of file diff --git a/Week1/homework/js-exercises/index.html b/Week1/homework/js-exercises/index.html new file mode 100644 index 000000000..d128ec143 --- /dev/null +++ b/Week1/homework/js-exercises/index.html @@ -0,0 +1,18 @@ + + + + + + + Random Dogs + + + + +


    + + + + + + \ No newline at end of file diff --git a/Week1/homework/js-exercises/programmer-humor.js b/Week1/homework/js-exercises/programmer-humor.js new file mode 100644 index 000000000..c960857ae --- /dev/null +++ b/Week1/homework/js-exercises/programmer-humor.js @@ -0,0 +1,53 @@ +// //API with XMLHttpRequest +// function apiXHR(){ +// let xhr = new XMLHttpRequest(); + +// xhr.open("GET", "https://xkcd.com/info.0.json", true); + +// xhr.send(); + +// xhr.addEventListener("load", () => { +// if (xhr.status === 200){ +// res = JSON.parse(xhr.responseText); +// console.log(res); +// //render img on DOM +// const body = document.body; +// const img = document.createElement("img"); +// img.src = res.img; +// body.appendChild(img); +// }else { console.log("Error on request...") } +// }); + +// xhr.addEventListener("error", () => console.log("Error on request...")); +// } + +// apiXHR(); + + +// //API with Axios +// function apiAxios(){ +// axios +// .get("https://xkcd.com/info.0.json") +// .then(res => { +// console.log(res.data) +// //render img on DOM +// const body = document.body; +// const img = document.createElement("img"); +// img.src = res.data.img; +// body.appendChild(img); +// }) +// .catch(err => console.log(err)); +// } + +// apiAxios(); + + + +async function asyncAwait (){ + try{ + let res = await fetch("https://xkcd.com/info.0.json"); + console.log(res.data); + }catch(err) { console.error(err) }; +} + +asyncAwait(); \ No newline at end of file diff --git a/Week1/homework/js-exercises/who-here.js b/Week1/homework/js-exercises/who-here.js new file mode 100644 index 000000000..2620157fc --- /dev/null +++ b/Week1/homework/js-exercises/who-here.js @@ -0,0 +1,30 @@ +//API call with XMLHttpRequest +function newFriendXhr(){ + let xhr = new XMLHttpRequest(); + + xhr.open('GET', 'https://www.randomuser.me/api', true); + + xhr.send(); + + xhr.addEventListener("load", () => { + if (xhr.status === 200){ + res = JSON.parse(xhr.response); + console.log((res.results)); + }else{console.log("Error on request...")} + }) + + xhr.addEventListener("error", () => console.log("Error on request...")); +} + +newFriendXhr(); + + +//API call with Axios +function newFriendAxios(){ + axios + .get('https://www.randomuser.me/api') + .then(res => console.log(res.data.results)) + .catch(err => console.log(err)); +} + +newFriendAxios(); \ No newline at end of file diff --git a/Week1/homework/number-facts/index.html b/Week1/homework/number-facts/index.html new file mode 100644 index 000000000..e52e8cdc9 --- /dev/null +++ b/Week1/homework/number-facts/index.html @@ -0,0 +1,53 @@ + + + + + + + Numbers & Years Facts + + + + + + +
    +

    Numbers & Years Facts

    +

    Enter a number or a year, take and random Fact...

    + + + +
    +

    +

    +
    +
    + + + + \ No newline at end of file diff --git a/Week1/homework/number-facts/num-facts.js b/Week1/homework/number-facts/num-facts.js new file mode 100644 index 000000000..92e56c6eb --- /dev/null +++ b/Week1/homework/number-facts/num-facts.js @@ -0,0 +1,76 @@ +//initialize some variables +let buttonNumbers = false; +let buttonYears = false; +let input = document.getElementById("input"); + + +//API call for Numbers or Years Facts +function callFacts(){ + const num = input.value; + //API call only if there is an input + if (num === ""){ + document.querySelector(".fact").style.display = "none"; + }else{ + //API call based on the button that clicked last + const xhr = new XMLHttpRequest(); + if (buttonNumbers === true){ + xhr.open("GET", `http://numbersapi.com/${num}`, true); + }else{ + xhr.open("GET", `http://numbersapi.com/${num}/year`, true); + } + + xhr.send(); + xhr.addEventListener("load",function(){ + if (xhr.status === 200){ + showFact(xhr.responseText); + }else {console.log("Error on request...")} + }); + + xhr.addEventListener("error", () => console.log("Error on request...")); + } +} + + +//render the fact on DOM +function showFact(res){ + if (buttonNumbers === true){ + document.getElementById("fact-title").innerText = "Number Fact" + }else if (buttonYears === true){ + document.getElementById("fact-title").innerText = "Year Fact" + } + document.getElementById("fact-para").innerText = res; + document.querySelector(".fact").style.display = "block"; + /* check here too if input.value === 0 cause response comes asynchronously + and if delete input realy quick, the fact remaines */ + if (input.value === ""){ + document.querySelector(".fact").style.display = "none"; + } +} + + +//EVENT: when button 'Numbers' clicked show input bar and change url +document.getElementById("btn-numbers").addEventListener("click", () => { + input.style.display = "block"; + buttonNumbers = true; + buttonYears = false; + + if (input.style.display === "block"){ + callFacts() + } +}); + + +//EVENT: when button 'Years' clicked show input bar and change url +document.getElementById("btn-years").addEventListener("click", () => { + input.style.display = "block"; + buttonNumbers = false; + buttonYears = true; + + if (input.style.display === "block"){ + callFacts() + } +}); + + +//event: when 'input', make the API call +input.addEventListener("input", callFacts); diff --git a/Week2/.DS_Store b/Week2/.DS_Store new file mode 100644 index 000000000..692d7cf6a Binary files /dev/null and b/Week2/.DS_Store differ diff --git a/Week2/homework/.DS_Store b/Week2/homework/.DS_Store new file mode 100644 index 000000000..eeb5db019 Binary files /dev/null and b/Week2/homework/.DS_Store differ diff --git a/Week2/homework/hack-repo-2/hyf.png b/Week2/homework/hack-repo-2/hyf.png new file mode 100755 index 000000000..76bc5a13b Binary files /dev/null and b/Week2/homework/hack-repo-2/hyf.png differ diff --git a/Week2/homework/hack-repo-2/index.html b/Week2/homework/hack-repo-2/index.html new file mode 100755 index 000000000..200a6346e --- /dev/null +++ b/Week2/homework/hack-repo-2/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + HYF-GITHUB + + + + + +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/Week2/homework/hack-repo-2/index.js b/Week2/homework/hack-repo-2/index.js new file mode 100755 index 000000000..3161abe4a --- /dev/null +++ b/Week2/homework/hack-repo-2/index.js @@ -0,0 +1,130 @@ +'use strict'; + +{ + function fetchJSON(url, cb) { + fetch(url) + .then(res => { + if (res.status != 200) { + return cb(new Error(`Network error: ${res.status} - ${res.statusText}`)) + } + return res.json() + }) + .then(data => cb(false, data)) + } + + + function createAndAppend(name, parent, options = {}) { + const elem = document.createElement(name); + parent.appendChild(elem); + Object.entries(options).forEach(([key, value]) => { + if (key === 'text') { + elem.innerHTML = value; + } else { + elem.setAttribute(key, value); + } + }); + return elem; + } + + + function renderRepoDetails(data, parent) { + createAndAppend('div', parent, { + text : `Repository: ${data.name}
    + Description: ${data.description}
    + Forks: ${data.forks}
    + Uptade: ${data.updated_at.slice(0,4)}/${data.updated_at.slice(5,7)}/${data.updated_at.slice(8,10)}, ${data.updated_at.slice(11,19)}` + }); + } + + + function renderRepoContributors(contributors, contributorsDiv){ + contributorsDiv.innerHTML = `Contributions` + contributors.forEach(contributor => { + contributorsDiv.innerHTML += ` +
    + + ${contributor.login} + ${contributor.contributions} +
    +
    + ` + }) + } + + + function sortByName(repos){ + repos.sort((a , b) => (a.name > b.name)? 1 : -1); + } + + + function removeFromDom(parent){ + while (parent.hasChildNodes()){ + parent.removeChild(parent.firstChild); + } + } + + + //main function + function mainPart(url) { + const root = document.getElementById('root'); + const header = document.querySelector("header"); + const main = document.querySelector("main"); + //append title on DOM + createAndAppend("p" , header, { text : "HYF Repositories" }); + + //make the API call via fetchJSON function + fetchJSON(url, (err, repos) => { + //handle error + if (err) { + createAndAppend('div', root, { + text: err.message, + class: 'alert-error' + }); + return; + } + //if it goes just fine + sortByName(repos); + createAndAppend("select", header); + const select = document.querySelector("select"); + repos.forEach(repo => createAndAppend("option", select, { + text : repo.name, + value : repo.name, + })) + select.value = repos[displayRepo].name; + renderRepoDetails(repos[displayRepo], main); + + //make a new API call via fetchJSON function to get the contributions from 'repos.contributors_url' + fetchJSON(repos[displayRepo].contributors_url, (err, contributors) => { + //handle error + if (err) { + createAndAppend('div', root, { + text: err.message, + class: 'alert-error' + }); + return; + } + + //if it goes right + createAndAppend('div', main); + const contributorsDiv = document.querySelector("main div:last-child"); + renderRepoContributors(contributors, contributorsDiv); + }) + + //Event: change repo when user choose another repo from selection input + select.addEventListener("change", () => { + repos.forEach(repo => { + if (repo.name === select.value) { displayRepo = repos.indexOf(repo) } + }) + removeFromDom(header); + removeFromDom(main); + mainPart(HYF_REPOS_URL) + }) + }); + } + + + let displayRepo = 0; + const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos'; + //start rendering when window is loaded + window.onload = () => mainPart(HYF_REPOS_URL); +} \ No newline at end of file diff --git a/Week2/homework/hack-repo-2/style.css b/Week2/homework/hack-repo-2/style.css new file mode 100755 index 000000000..2d6e73812 --- /dev/null +++ b/Week2/homework/hack-repo-2/style.css @@ -0,0 +1,109 @@ +.alert-error { + background-color: #f8d7da; + color: #721c24; + padding: 20px 30px; + border-radius: 5px; +} + +#root{ + background-color:#f7f7f7; + height: 100vh; + font-family: sans-serif; + font-size: 1.2em; + width: 80vw; + margin-left: auto; + margin-right: auto; + letter-spacing: 0.3px; +} + +/* ul{ + padding: 0; + margin: 0; +} */ + +header{ + display: flex; + align-items: center; + background-color: #3f51b5; + color: white; + padding: 30px; + letter-spacing: 1px; + margin-bottom: 5px; +} + +select{ + font-size: 0.9em; + margin: 10px; + outline: none; +} + +main{ + display: flex; + align-items: flex-start; + padding: 0 8px; +} + +main>div{ + flex: 1; + background-color: white; + margin-left: 15px; + list-style: none; + line-height: 1.5em; + margin-bottom: 5px; + padding: 30px; + box-shadow: 0px 4px 8px grey; +} + +main>div:first-child{ + margin-left: 0; +} + +.contributor{ + display: flex; + align-items: center; + margin-top: 25px; +} + +.contributor img{ + border-radius: 8px; + +} + +.contributor a{ + text-decoration: none; + margin-left: 15px; +} + +.contributor span{ + margin-left: auto; + background-color: #808080; + border-radius: 8px; + padding: 6px; + color: white; +} + +hr{ + margin-top: 25px; +} + +@media all and (max-width:799px){ + main{ + display: block; + } + main>div{ + margin-left: 0; + } + header{ + display: block; + } + select{ + margin: 0; + } +} + +@media all and (max-width:499px){ + #root{ + width: 93vw; + font-size: 1em; + } +} diff --git a/Week2/homework/weather-app/.DS_Store b/Week2/homework/weather-app/.DS_Store new file mode 100644 index 000000000..d08f0b3a0 Binary files /dev/null and b/Week2/homework/weather-app/.DS_Store differ diff --git a/Week2/homework/weather-app/index.html b/Week2/homework/weather-app/index.html new file mode 100644 index 000000000..ac194269d --- /dev/null +++ b/Week2/homework/weather-app/index.html @@ -0,0 +1,24 @@ + + + + + + + Weather App + + + +
    +
    +

    + +
    +
    +
    +
    + + + +
    + + \ No newline at end of file diff --git a/Week2/homework/weather-app/skycons.js b/Week2/homework/weather-app/skycons.js new file mode 100644 index 000000000..a869a208b --- /dev/null +++ b/Week2/homework/weather-app/skycons.js @@ -0,0 +1,726 @@ +(function(global) { + "use strict"; + + /* Set up a RequestAnimationFrame shim so we can animate efficiently FOR + * GREAT JUSTICE. */ + var requestInterval, cancelInterval; + + (function() { + var raf = global.requestAnimationFrame || + global.webkitRequestAnimationFrame || + global.mozRequestAnimationFrame || + global.oRequestAnimationFrame || + global.msRequestAnimationFrame , + caf = global.cancelAnimationFrame || + global.webkitCancelAnimationFrame || + global.mozCancelAnimationFrame || + global.oCancelAnimationFrame || + global.msCancelAnimationFrame ; + + if(raf && caf) { + requestInterval = function(fn) { + var handle = {value: null}; + + function loop() { + handle.value = raf(loop); + fn(); + } + + loop(); + return handle; + }; + + cancelInterval = function(handle) { + caf(handle.value); + }; + } + + else { + requestInterval = setInterval; + cancelInterval = clearInterval; + } + }()); + + /* Catmull-rom spline stuffs. */ + /* + function upsample(n, spline) { + var polyline = [], + len = spline.length, + bx = spline[0], + by = spline[1], + cx = spline[2], + cy = spline[3], + dx = spline[4], + dy = spline[5], + i, j, ax, ay, px, qx, rx, sx, py, qy, ry, sy, t; + + for(i = 6; i !== spline.length; i += 2) { + ax = bx; + bx = cx; + cx = dx; + dx = spline[i ]; + px = -0.5 * ax + 1.5 * bx - 1.5 * cx + 0.5 * dx; + qx = ax - 2.5 * bx + 2.0 * cx - 0.5 * dx; + rx = -0.5 * ax + 0.5 * cx ; + sx = bx ; + + ay = by; + by = cy; + cy = dy; + dy = spline[i + 1]; + py = -0.5 * ay + 1.5 * by - 1.5 * cy + 0.5 * dy; + qy = ay - 2.5 * by + 2.0 * cy - 0.5 * dy; + ry = -0.5 * ay + 0.5 * cy ; + sy = by ; + + for(j = 0; j !== n; ++j) { + t = j / n; + + polyline.push( + ((px * t + qx) * t + rx) * t + sx, + ((py * t + qy) * t + ry) * t + sy + ); + } + } + + polyline.push( + px + qx + rx + sx, + py + qy + ry + sy + ); + + return polyline; + } + + function downsample(n, polyline) { + var len = 0, + i, dx, dy; + + for(i = 2; i !== polyline.length; i += 2) { + dx = polyline[i ] - polyline[i - 2]; + dy = polyline[i + 1] - polyline[i - 1]; + len += Math.sqrt(dx * dx + dy * dy); + } + + len /= n; + + var small = [], + target = len, + min = 0, + max, t; + + small.push(polyline[0], polyline[1]); + + for(i = 2; i !== polyline.length; i += 2) { + dx = polyline[i ] - polyline[i - 2]; + dy = polyline[i + 1] - polyline[i - 1]; + max = min + Math.sqrt(dx * dx + dy * dy); + + if(max > target) { + t = (target - min) / (max - min); + + small.push( + polyline[i - 2] + dx * t, + polyline[i - 1] + dy * t + ); + + target += len; + } + + min = max; + } + + small.push(polyline[polyline.length - 2], polyline[polyline.length - 1]); + + return small; + } + */ + + /* Define skycon things. */ + /* FIXME: I'm *really really* sorry that this code is so gross. Really, I am. + * I'll try to clean it up eventually! Promise! */ + var KEYFRAME = 500, + STROKE = 0.08, + TAU = 2.0 * Math.PI, + TWO_OVER_SQRT_2 = 2.0 / Math.sqrt(2); + + function circle(ctx, x, y, r) { + ctx.beginPath(); + ctx.arc(x, y, r, 0, TAU, false); + ctx.fill(); + } + + function line(ctx, ax, ay, bx, by) { + ctx.beginPath(); + ctx.moveTo(ax, ay); + ctx.lineTo(bx, by); + ctx.stroke(); + } + + function puff(ctx, t, cx, cy, rx, ry, rmin, rmax) { + var c = Math.cos(t * TAU), + s = Math.sin(t * TAU); + + rmax -= rmin; + + circle( + ctx, + cx - s * rx, + cy + c * ry + rmax * 0.5, + rmin + (1 - c * 0.5) * rmax + ); + } + + function puffs(ctx, t, cx, cy, rx, ry, rmin, rmax) { + var i; + + for(i = 5; i--; ) + puff(ctx, t + i / 5, cx, cy, rx, ry, rmin, rmax); + } + + function cloud(ctx, t, cx, cy, cw, s, color) { + t /= 30000; + + var a = cw * 0.21, + b = cw * 0.12, + c = cw * 0.24, + d = cw * 0.28; + + ctx.fillStyle = color; + puffs(ctx, t, cx, cy, a, b, c, d); + + ctx.globalCompositeOperation = 'destination-out'; + puffs(ctx, t, cx, cy, a, b, c - s, d - s); + ctx.globalCompositeOperation = 'source-over'; + } + + function sun(ctx, t, cx, cy, cw, s, color) { + t /= 120000; + + var a = cw * 0.25 - s * 0.5, + b = cw * 0.32 + s * 0.5, + c = cw * 0.50 - s * 0.5, + i, p, cos, sin; + + ctx.strokeStyle = color; + ctx.lineWidth = s; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + + ctx.beginPath(); + ctx.arc(cx, cy, a, 0, TAU, false); + ctx.stroke(); + + for(i = 8; i--; ) { + p = (t + i / 8) * TAU; + cos = Math.cos(p); + sin = Math.sin(p); + line(ctx, cx + cos * b, cy + sin * b, cx + cos * c, cy + sin * c); + } + } + + function moon(ctx, t, cx, cy, cw, s, color) { + t /= 15000; + + var a = cw * 0.29 - s * 0.5, + b = cw * 0.05, + c = Math.cos(t * TAU), + p = c * TAU / -16; + + ctx.strokeStyle = color; + ctx.lineWidth = s; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + + cx += c * b; + + ctx.beginPath(); + ctx.arc(cx, cy, a, p + TAU / 8, p + TAU * 7 / 8, false); + ctx.arc(cx + Math.cos(p) * a * TWO_OVER_SQRT_2, cy + Math.sin(p) * a * TWO_OVER_SQRT_2, a, p + TAU * 5 / 8, p + TAU * 3 / 8, true); + ctx.closePath(); + ctx.stroke(); + } + + function rain(ctx, t, cx, cy, cw, s, color) { + t /= 1350; + + var a = cw * 0.16, + b = TAU * 11 / 12, + c = TAU * 7 / 12, + i, p, x, y; + + ctx.fillStyle = color; + + for(i = 4; i--; ) { + p = (t + i / 4) % 1; + x = cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a; + y = cy + p * p * cw; + ctx.beginPath(); + ctx.moveTo(x, y - s * 1.5); + ctx.arc(x, y, s * 0.75, b, c, false); + ctx.fill(); + } + } + + function sleet(ctx, t, cx, cy, cw, s, color) { + t /= 750; + + var a = cw * 0.1875, + i, p, x, y; + + ctx.strokeStyle = color; + ctx.lineWidth = s * 0.5; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + + for(i = 4; i--; ) { + p = (t + i / 4) % 1; + x = Math.floor(cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a) + 0.5; + y = cy + p * cw; + line(ctx, x, y - s * 1.5, x, y + s * 1.5); + } + } + + function snow(ctx, t, cx, cy, cw, s, color) { + t /= 3000; + + var a = cw * 0.16, + b = s * 0.75, + u = t * TAU * 0.7, + ux = Math.cos(u) * b, + uy = Math.sin(u) * b, + v = u + TAU / 3, + vx = Math.cos(v) * b, + vy = Math.sin(v) * b, + w = u + TAU * 2 / 3, + wx = Math.cos(w) * b, + wy = Math.sin(w) * b, + i, p, x, y; + + ctx.strokeStyle = color; + ctx.lineWidth = s * 0.5; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + + for(i = 4; i--; ) { + p = (t + i / 4) % 1; + x = cx + Math.sin((p + i / 4) * TAU) * a; + y = cy + p * cw; + + line(ctx, x - ux, y - uy, x + ux, y + uy); + line(ctx, x - vx, y - vy, x + vx, y + vy); + line(ctx, x - wx, y - wy, x + wx, y + wy); + } + } + + function fogbank(ctx, t, cx, cy, cw, s, color) { + t /= 30000; + + var a = cw * 0.21, + b = cw * 0.06, + c = cw * 0.21, + d = cw * 0.28; + + ctx.fillStyle = color; + puffs(ctx, t, cx, cy, a, b, c, d); + + ctx.globalCompositeOperation = 'destination-out'; + puffs(ctx, t, cx, cy, a, b, c - s, d - s); + ctx.globalCompositeOperation = 'source-over'; + } + + /* + var WIND_PATHS = [ + downsample(63, upsample(8, [ + -1.00, -0.28, + -0.75, -0.18, + -0.50, 0.12, + -0.20, 0.12, + -0.04, -0.04, + -0.07, -0.18, + -0.19, -0.18, + -0.23, -0.05, + -0.12, 0.11, + 0.02, 0.16, + 0.20, 0.15, + 0.50, 0.07, + 0.75, 0.18, + 1.00, 0.28 + ])), + downsample(31, upsample(16, [ + -1.00, -0.10, + -0.75, 0.00, + -0.50, 0.10, + -0.25, 0.14, + 0.00, 0.10, + 0.25, 0.00, + 0.50, -0.10, + 0.75, -0.14, + 1.00, -0.10 + ])) + ]; + */ + + var WIND_PATHS = [ + [ + -0.7500, -0.1800, -0.7219, -0.1527, -0.6971, -0.1225, + -0.6739, -0.0910, -0.6516, -0.0588, -0.6298, -0.0262, + -0.6083, 0.0065, -0.5868, 0.0396, -0.5643, 0.0731, + -0.5372, 0.1041, -0.5033, 0.1259, -0.4662, 0.1406, + -0.4275, 0.1493, -0.3881, 0.1530, -0.3487, 0.1526, + -0.3095, 0.1488, -0.2708, 0.1421, -0.2319, 0.1342, + -0.1943, 0.1217, -0.1600, 0.1025, -0.1290, 0.0785, + -0.1012, 0.0509, -0.0764, 0.0206, -0.0547, -0.0120, + -0.0378, -0.0472, -0.0324, -0.0857, -0.0389, -0.1241, + -0.0546, -0.1599, -0.0814, -0.1876, -0.1193, -0.1964, + -0.1582, -0.1935, -0.1931, -0.1769, -0.2157, -0.1453, + -0.2290, -0.1085, -0.2327, -0.0697, -0.2240, -0.0317, + -0.2064, 0.0033, -0.1853, 0.0362, -0.1613, 0.0672, + -0.1350, 0.0961, -0.1051, 0.1213, -0.0706, 0.1397, + -0.0332, 0.1512, 0.0053, 0.1580, 0.0442, 0.1624, + 0.0833, 0.1636, 0.1224, 0.1615, 0.1613, 0.1565, + 0.1999, 0.1500, 0.2378, 0.1402, 0.2749, 0.1279, + 0.3118, 0.1147, 0.3487, 0.1015, 0.3858, 0.0892, + 0.4236, 0.0787, 0.4621, 0.0715, 0.5012, 0.0702, + 0.5398, 0.0766, 0.5768, 0.0890, 0.6123, 0.1055, + 0.6466, 0.1244, 0.6805, 0.1440, 0.7147, 0.1630, + 0.7500, 0.1800 + ], + [ + -0.7500, 0.0000, -0.7033, 0.0195, -0.6569, 0.0399, + -0.6104, 0.0600, -0.5634, 0.0789, -0.5155, 0.0954, + -0.4667, 0.1089, -0.4174, 0.1206, -0.3676, 0.1299, + -0.3174, 0.1365, -0.2669, 0.1398, -0.2162, 0.1391, + -0.1658, 0.1347, -0.1157, 0.1271, -0.0661, 0.1169, + -0.0170, 0.1046, 0.0316, 0.0903, 0.0791, 0.0728, + 0.1259, 0.0534, 0.1723, 0.0331, 0.2188, 0.0129, + 0.2656, -0.0064, 0.3122, -0.0263, 0.3586, -0.0466, + 0.4052, -0.0665, 0.4525, -0.0847, 0.5007, -0.1002, + 0.5497, -0.1130, 0.5991, -0.1240, 0.6491, -0.1325, + 0.6994, -0.1380, 0.7500, -0.1400 + ] + ], + WIND_OFFSETS = [ + {start: 0.36, end: 0.11}, + {start: 0.56, end: 0.16} + ]; + + function leaf(ctx, t, x, y, cw, s, color) { + var a = cw / 8, + b = a / 3, + c = 2 * b, + d = (t % 1) * TAU, + e = Math.cos(d), + f = Math.sin(d); + + ctx.fillStyle = color; + ctx.strokeStyle = color; + ctx.lineWidth = s; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + + ctx.beginPath(); + ctx.arc(x , y , a, d , d + Math.PI, false); + ctx.arc(x - b * e, y - b * f, c, d + Math.PI, d , false); + ctx.arc(x + c * e, y + c * f, b, d + Math.PI, d , true ); + ctx.globalCompositeOperation = 'destination-out'; + ctx.fill(); + ctx.globalCompositeOperation = 'source-over'; + ctx.stroke(); + } + + function swoosh(ctx, t, cx, cy, cw, s, index, total, color) { + t /= 2500; + + var path = WIND_PATHS[index], + a = (t + index - WIND_OFFSETS[index].start) % total, + c = (t + index - WIND_OFFSETS[index].end ) % total, + e = (t + index ) % total, + b, d, f, i; + + ctx.strokeStyle = color; + ctx.lineWidth = s; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + + if(a < 1) { + ctx.beginPath(); + + a *= path.length / 2 - 1; + b = Math.floor(a); + a -= b; + b *= 2; + b += 2; + + ctx.moveTo( + cx + (path[b - 2] * (1 - a) + path[b ] * a) * cw, + cy + (path[b - 1] * (1 - a) + path[b + 1] * a) * cw + ); + + if(c < 1) { + c *= path.length / 2 - 1; + d = Math.floor(c); + c -= d; + d *= 2; + d += 2; + + for(i = b; i !== d; i += 2) + ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); + + ctx.lineTo( + cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw, + cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw + ); + } + + else + for(i = b; i !== path.length; i += 2) + ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); + + ctx.stroke(); + } + + else if(c < 1) { + ctx.beginPath(); + + c *= path.length / 2 - 1; + d = Math.floor(c); + c -= d; + d *= 2; + d += 2; + + ctx.moveTo(cx + path[0] * cw, cy + path[1] * cw); + + for(i = 2; i !== d; i += 2) + ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); + + ctx.lineTo( + cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw, + cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw + ); + + ctx.stroke(); + } + + if(e < 1) { + e *= path.length / 2 - 1; + f = Math.floor(e); + e -= f; + f *= 2; + f += 2; + + leaf( + ctx, + t, + cx + (path[f - 2] * (1 - e) + path[f ] * e) * cw, + cy + (path[f - 1] * (1 - e) + path[f + 1] * e) * cw, + cw, + s, + color + ); + } + } + + var Skycons = function(opts) { + this.list = []; + this.interval = null; + this.color = opts && opts.color ? opts.color : "black"; + this.resizeClear = !!(opts && opts.resizeClear); + }; + + Skycons.CLEAR_DAY = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + sun(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); + }; + + Skycons.CLEAR_NIGHT = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + moon(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); + }; + + Skycons.PARTLY_CLOUDY_DAY = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + sun(ctx, t, w * 0.625, h * 0.375, s * 0.75, s * STROKE, color); + cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color); + }; + + Skycons.PARTLY_CLOUDY_NIGHT = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + moon(ctx, t, w * 0.667, h * 0.375, s * 0.75, s * STROKE, color); + cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color); + }; + + Skycons.CLOUDY = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + cloud(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); + }; + + Skycons.RAIN = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + rain(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); + cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); + }; + + Skycons.SLEET = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + sleet(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); + cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); + }; + + Skycons.SNOW = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + snow(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); + cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); + }; + + Skycons.WIND = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h); + + swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 0, 2, color); + swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 1, 2, color); + }; + + Skycons.FOG = function(ctx, t, color) { + var w = ctx.canvas.width, + h = ctx.canvas.height, + s = Math.min(w, h), + k = s * STROKE; + + fogbank(ctx, t, w * 0.5, h * 0.32, s * 0.75, k, color); + + t /= 5000; + + var a = Math.cos((t ) * TAU) * s * 0.02, + b = Math.cos((t + 0.25) * TAU) * s * 0.02, + c = Math.cos((t + 0.50) * TAU) * s * 0.02, + d = Math.cos((t + 0.75) * TAU) * s * 0.02, + n = h * 0.936, + e = Math.floor(n - k * 0.5) + 0.5, + f = Math.floor(n - k * 2.5) + 0.5; + + ctx.strokeStyle = color; + ctx.lineWidth = k; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + + line(ctx, a + w * 0.2 + k * 0.5, e, b + w * 0.8 - k * 0.5, e); + line(ctx, c + w * 0.2 + k * 0.5, f, d + w * 0.8 - k * 0.5, f); + }; + + Skycons.prototype = { + _determineDrawingFunction: function(draw) { + if(typeof draw === "string") + draw = Skycons[draw.toUpperCase().replace(/-/g, "_")] || null; + + return draw; + }, + add: function(el, draw) { + var obj; + + if(typeof el === "string") + el = document.getElementById(el); + + // Does nothing if canvas name doesn't exists + if(el === null || el === undefined) + return; + + draw = this._determineDrawingFunction(draw); + + // Does nothing if the draw function isn't actually a function + if(typeof draw !== "function") + return; + + obj = { + element: el, + context: el.getContext("2d"), + drawing: draw + }; + + this.list.push(obj); + this.draw(obj, KEYFRAME); + }, + set: function(el, draw) { + var i; + + if(typeof el === "string") + el = document.getElementById(el); + + for(i = this.list.length; i--; ) + if(this.list[i].element === el) { + this.list[i].drawing = this._determineDrawingFunction(draw); + this.draw(this.list[i], KEYFRAME); + return; + } + + this.add(el, draw); + }, + remove: function(el) { + var i; + + if(typeof el === "string") + el = document.getElementById(el); + + for(i = this.list.length; i--; ) + if(this.list[i].element === el) { + this.list.splice(i, 1); + return; + } + }, + draw: function(obj, time) { + var canvas = obj.context.canvas; + + if(this.resizeClear) + canvas.width = canvas.width; + + else + obj.context.clearRect(0, 0, canvas.width, canvas.height); + + obj.drawing(obj.context, time, this.color); + }, + play: function() { + var self = this; + + this.pause(); + this.interval = requestInterval(function() { + var now = Date.now(), + i; + + for(i = self.list.length; i--; ) + self.draw(self.list[i], now); + }, 1000 / 60); + }, + pause: function() { + if(this.interval) { + cancelInterval(this.interval); + this.interval = null; + } + } + }; + + global.Skycons = Skycons; +}(this)); diff --git a/Week2/homework/weather-app/weather.css b/Week2/homework/weather-app/weather.css new file mode 100644 index 000000000..591940197 --- /dev/null +++ b/Week2/homework/weather-app/weather.css @@ -0,0 +1,113 @@ +body{ + background-image: linear-gradient(#258ca2, #1a2857); + background-repeat: no-repeat; + color: white; + font-family: sans-serif; + font-size: 1.5em; + -webkit-touch-callout: none; /* iOS Safari */ + -webkit-user-select: none; /* Safari */ + -khtml-user-select: none; /* Konqueror HTML */ + -moz-user-select: none; /* Old versions of Firefox */ + -ms-user-select: none; /* Internet Explorer/Edge */ + user-select: none; /* Non-prefixed version, currently supported by Chrome, Opera and Firefox */ +} + +/* loader animation */ +.loader{ + position: fixed; + left: auto; + top: 35%; + border: 16px solid #f3f3f3; + border-radius: 50%; + border-top: 16px solid #3498db; + width: 100px; + height: 100px; + animation: spin 2s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + + +/* app css */ +.app{ + width: 100vw; + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.timezone-icon{ + display: flex; + align-items: center; + width: 55%; +} + +.timezone-icon h1{ + flex: 1; +} + +.timezone-icon canvas{ + flex: 1; + text-align: right; + width: 120px; +} + +.temp{ + font-size: 4em; + margin-top: 10%; + cursor: pointer; +} + +.desc{ + margin-top: 10%; +} + + +@media all and (max-width: 999px){ + .timezone-icon{ + width: 70%; + } +} + +@media all and (max-width: 599px){ + .timezone-icon{ + width: 80%; + } + + .temp,.desc{ + margin-top: 20%; + } +} + +@media all and (max-width: 499px){ + body{ + font-size: 1em; + } + + .temp,.desc{ + margin-top: 40%; + } +} + +@media all and (max-width: 385px){ + .app{ + justify-content: flex-start; + } + + .timezone-icon{ + flex-direction: column; + } + + .temp,.desc{ + margin-top: 20%; + } + + .timezone-icon canvas{ + width: 200px; + } +} \ No newline at end of file diff --git a/Week2/homework/weather-app/weather.js b/Week2/homework/weather-app/weather.js new file mode 100644 index 000000000..8dae9df25 --- /dev/null +++ b/Week2/homework/weather-app/weather.js @@ -0,0 +1,42 @@ +//initialize some variables +const timezone = document.querySelector(".timezone-icon h1"); +const skycon = document.querySelector(".timezone-icon canvas"); +const temp = document.querySelector(".temp"); +const desc = document.querySelector(".desc"); +const loader = document.querySelector(".loader"); + + +//catch the current position +if (navigator.geolocation){ + navigator.geolocation.getCurrentPosition(position => { + + //make an API call to get the weather data, based on the current position + fetch(`https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/a6495b1412e84a86bd9367f6bfb8ef66/${position.coords.latitude},${position.coords.longitude}`) + .then(resp => resp.json()) + .then(data => { + //vanish the loader first + loader.style.display = "none"; + + //manipulate the DOM to show the data from the API call + const icon = new Skycons({"color":"white"}); + icon.add(skycon, data.daily.icon.toUpperCase().replace(/-/g, "_")); //transform the data to much with skycons.js + icon.play(); + + timezone.innerText = data.timezone; + desc.innerText = data.daily.summary; + temp.innerText = `${data.currently.temperature} F`; + + //Event: when click on the temperature change from 'F' to 'C' and vise versa + temp.addEventListener("click", () => { + if (temp.innerText.includes("F")) { + temp.innerText = `${((data.currently.temperature - 32) / 1.8).toFixed(2)} C` + } + else { + temp.innerText = `${data.currently.temperature} F`; + } + }); + }) + .catch(err => console.error(err)); + }); +}; + diff --git a/Week3/.DS_Store b/Week3/.DS_Store new file mode 100644 index 000000000..8be67eb3f Binary files /dev/null and b/Week3/.DS_Store differ diff --git a/Week3/homework/.DS_Store b/Week3/homework/.DS_Store new file mode 100644 index 000000000..506ba766f Binary files /dev/null and b/Week3/homework/.DS_Store differ diff --git a/Week3/homework/hack-repo-3.1/hyf.png b/Week3/homework/hack-repo-3.1/hyf.png new file mode 100755 index 000000000..76bc5a13b Binary files /dev/null and b/Week3/homework/hack-repo-3.1/hyf.png differ diff --git a/Week3/homework/hack-repo-3.1/index.html b/Week3/homework/hack-repo-3.1/index.html new file mode 100755 index 000000000..c7d10d48d --- /dev/null +++ b/Week3/homework/hack-repo-3.1/index.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + HYF-GITHUB + + + + + +
    +
    +
    +
    + + + + + + + \ No newline at end of file diff --git a/Week3/homework/hack-repo-3.1/index.js b/Week3/homework/hack-repo-3.1/index.js new file mode 100755 index 000000000..fc225f0c2 --- /dev/null +++ b/Week3/homework/hack-repo-3.1/index.js @@ -0,0 +1,128 @@ +'use strict'; + +{ + async function fetchJSON(url, cb) { + try{ + var res = await axios.get(url); + return cb(false, res.data); + }catch(err){ + return cb(new Error(`Network error: ${res.status} - ${res.statusText}`)) + } + } + + + function createAndAppend(name, parent, options = {}) { + const elem = document.createElement(name); + parent.appendChild(elem); + Object.entries(options).forEach(([key, value]) => { + if (key === 'text') { + elem.innerHTML = value; + } else { + elem.setAttribute(key, value); + } + }); + return elem; + } + + + function renderRepoDetails(data, parent) { + createAndAppend('div', parent, { + text : `Repository: ${data.name}
    + Description: ${data.description}
    + Forks: ${data.forks}
    + Uptade: ${data.updated_at.slice(0,4)}/${data.updated_at.slice(5,7)}/${data.updated_at.slice(8,10)}, ${data.updated_at.slice(11,19)}` + }); + } + + + function renderRepoContributors(contributors, contributorsDiv){ + contributorsDiv.innerHTML = `Contributions` + contributors.forEach(contributor => { + contributorsDiv.innerHTML += ` +
    + + ${contributor.login} + ${contributor.contributions} +
    +
    + ` + }) + } + + + function sortByName(repos){ + repos.sort((a , b) => (a.name > b.name)? 1 : -1); + } + + + function removeFromDom(parent){ + while (parent.hasChildNodes()){ + parent.removeChild(parent.firstChild); + } + } + + + //main function + function mainPart(url) { + const root = document.getElementById('root'); + const header = document.querySelector("header"); + const main = document.querySelector("main"); + //append title on DOM + createAndAppend("p" , header, { text : "HYF Repositories" }); + + //make the API call via fetchJSON function + fetchJSON(url, (err, repos) => { + //handle error + if (err) { + createAndAppend('div', root, { + text: err.message, + class: 'alert-error' + }); + return; + } + //if it goes just fine + sortByName(repos); + createAndAppend("select", header); + const select = document.querySelector("select"); + repos.forEach(repo => createAndAppend("option", select, { + text : repo.name, + value : repo.name, + })) + select.value = repos[displayRepo].name; + renderRepoDetails(repos[displayRepo], main); + + //make a new API call via fetchJSON function to get the contributions from 'repos.contributors_url' + fetchJSON(repos[displayRepo].contributors_url, (err, contributors) => { + //handle error + if (err) { + createAndAppend('div', root, { + text: err.message, + class: 'alert-error' + }); + return; + } + + //if it goes right + createAndAppend('div', main); + const contributorsDiv = document.querySelector("main div:last-child"); + renderRepoContributors(contributors, contributorsDiv); + }) + + //Event: change repo when user choose another repo from selection input + select.addEventListener("change", () => { + repos.forEach(repo => { + if (repo.name === select.value) { displayRepo = repos.indexOf(repo) } + }) + removeFromDom(header); + removeFromDom(main); + mainPart(HYF_REPOS_URL) + }) + }); + } + + + let displayRepo = 0; + const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos'; + //start rendering when window is loaded + window.onload = () => mainPart(HYF_REPOS_URL); +} \ No newline at end of file diff --git a/Week3/homework/hack-repo-3.1/style.css b/Week3/homework/hack-repo-3.1/style.css new file mode 100755 index 000000000..2d6e73812 --- /dev/null +++ b/Week3/homework/hack-repo-3.1/style.css @@ -0,0 +1,109 @@ +.alert-error { + background-color: #f8d7da; + color: #721c24; + padding: 20px 30px; + border-radius: 5px; +} + +#root{ + background-color:#f7f7f7; + height: 100vh; + font-family: sans-serif; + font-size: 1.2em; + width: 80vw; + margin-left: auto; + margin-right: auto; + letter-spacing: 0.3px; +} + +/* ul{ + padding: 0; + margin: 0; +} */ + +header{ + display: flex; + align-items: center; + background-color: #3f51b5; + color: white; + padding: 30px; + letter-spacing: 1px; + margin-bottom: 5px; +} + +select{ + font-size: 0.9em; + margin: 10px; + outline: none; +} + +main{ + display: flex; + align-items: flex-start; + padding: 0 8px; +} + +main>div{ + flex: 1; + background-color: white; + margin-left: 15px; + list-style: none; + line-height: 1.5em; + margin-bottom: 5px; + padding: 30px; + box-shadow: 0px 4px 8px grey; +} + +main>div:first-child{ + margin-left: 0; +} + +.contributor{ + display: flex; + align-items: center; + margin-top: 25px; +} + +.contributor img{ + border-radius: 8px; + +} + +.contributor a{ + text-decoration: none; + margin-left: 15px; +} + +.contributor span{ + margin-left: auto; + background-color: #808080; + border-radius: 8px; + padding: 6px; + color: white; +} + +hr{ + margin-top: 25px; +} + +@media all and (max-width:799px){ + main{ + display: block; + } + main>div{ + margin-left: 0; + } + header{ + display: block; + } + select{ + margin: 0; + } +} + +@media all and (max-width:499px){ + #root{ + width: 93vw; + font-size: 1em; + } +} diff --git a/Week3/homework/hack-repo-3.2/.DS_Store b/Week3/homework/hack-repo-3.2/.DS_Store new file mode 100644 index 000000000..779c2f038 Binary files /dev/null and b/Week3/homework/hack-repo-3.2/.DS_Store differ diff --git a/Week3/homework/hack-repo-3.2/App.js b/Week3/homework/hack-repo-3.2/App.js new file mode 100755 index 000000000..8788f8b85 --- /dev/null +++ b/Week3/homework/hack-repo-3.2/App.js @@ -0,0 +1,56 @@ +'use strict'; + +{ + const accounts = { + hyf: { + name: 'HackYourFuture', + type: 'org', + }, + microsoft: { + name: 'Microsoft', + type: 'org', + }, + jim: { + name: 'remarcmij', + type: 'user', + }, + }; + + const { Model, HeaderView, RepoView, ContributorsView, ErrorView } = window; + const { createAndAppend } = window.Util; + + class App { + constructor(account) { + const containers = App.renderContainers(); + + const model = new Model(account); + const fetchData = model.fetchData.bind(model); + + model.subscribe(new HeaderView(account, containers.header, fetchData)); + model.subscribe(new RepoView(containers.repo)); + model.subscribe(new ContributorsView(containers.contributors)); + model.subscribe(new ErrorView(containers.error)); + + fetchData(); + } + + static renderContainers() { + const root = document.getElementById('root'); + const header = createAndAppend('header', root, { class: 'header' }); + const error = createAndAppend('div', root); + const main = createAndAppend('main', root, { + class: 'main-container', + }); + const repo = createAndAppend('section', main, { + class: 'repo-container whiteframe', + }); + const contributors = createAndAppend('section', main, { + class: 'contributors-container whiteframe', + }); + return { header, error, main, repo, contributors }; + } + } + + const ACCOUNT_KEY = 'hyf'; + window.onload = () => new App(accounts[ACCOUNT_KEY]); +} diff --git a/Week3/homework/hack-repo-3.2/ContributorsView.js b/Week3/homework/hack-repo-3.2/ContributorsView.js new file mode 100755 index 000000000..0ddbf3791 --- /dev/null +++ b/Week3/homework/hack-repo-3.2/ContributorsView.js @@ -0,0 +1,41 @@ +'use strict'; + +{ + const { createAndAppend } = window.Util; + + class ContributorsView { + constructor(container) { + this.container = container; + } + + update(state) { + if (!state.error) { + this.render(state.contributors); + } + } + + /** + * Renders the list of contributors + * @param {Object[]} contributors An array of contributor objects + */ + render(contributors) { + // TODO: replace this comment and the console.log with your own code + function renderRepoContributors(contributors, parent){ + parent.innerHTML = `Contributions` + contributors.forEach(contributor => { + parent.innerHTML += ` +
    + + ${contributor.login} + ${contributor.contributions} +
    +
    + ` + }) + } + renderRepoContributors(contributors, document.querySelector(".contributors-container")) + } + } + + window.ContributorsView = ContributorsView; +} diff --git a/Week3/homework/hack-repo-3.2/ErrorView.js b/Week3/homework/hack-repo-3.2/ErrorView.js new file mode 100755 index 000000000..d161b7af6 --- /dev/null +++ b/Week3/homework/hack-repo-3.2/ErrorView.js @@ -0,0 +1,32 @@ +'use strict'; + +{ + const { createAndAppend } = window.Util; + + class ErrorView { + constructor(container) { + this.container = container; + } + + update(state) { + this.render(state.error); + } + + /** + * Renders an error for the 'error' message type. + * @param {Error} error An Error object + */ + render(error) { + this.container.innerHTML = ''; + if (error) { + document.querySelector("main").remove(); + createAndAppend('div', this.container, { + text: error.message, + class: 'alert alert-error', + }); + } + } + } + + window.ErrorView = ErrorView; +} diff --git a/Week3/homework/hack-repo-3.2/HeaderView.js b/Week3/homework/hack-repo-3.2/HeaderView.js new file mode 100755 index 000000000..11f9c8971 --- /dev/null +++ b/Week3/homework/hack-repo-3.2/HeaderView.js @@ -0,0 +1,46 @@ +'use strict'; + +{ + const { createAndAppend } = window.Util; + + class HeaderView { + constructor(account, header, fetchData) { + this.account = account; + this.header = header; + this.fetchData = fetchData; + this.select = null; + } + + update(state) { + if (!this.select && !state.error) { + this.render(state.repos); + } + } + + /** + * Renders the data for the 'select' message type. Create a + + + + +
    + +
    + + + + + + + + + diff --git a/Week3/homework/y-tube-api/main.js b/Week3/homework/y-tube-api/main.js new file mode 100644 index 000000000..23f63b7a8 --- /dev/null +++ b/Week3/homework/y-tube-api/main.js @@ -0,0 +1,142 @@ +const clientId = "295208744617-4g1v0mm429tra9a8orjrd14fp0obb78l.apps.googleusercontent.com"; +const discoveryDocs = ["https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest"]; +const scopes = "https://www.googleapis.com/auth/youtube.readonly"; + +const authorizeButton = document.getElementById("authorize-button"); +const signoutButton = document.getElementById("signout-button"); +const content = document.getElementById("content"); +const channelForm = document.getElementById("channel-form"); +const channelInput = document.getElementById("channel-input"); +const videoContainer = document.getElementById("video-container"); + +const defaultChannel = "techguyweb"; + +//Form submit and change channel +channelForm.addEventListener("submit", e => { + e.preventDefault(); + const channel = channelInput.value; + getChannel(channel); +}); + + +//Load auth2 library +function handleClientLoad(){ + gapi.load('client:auth2', initClient); +} + +//Init Api client library and set up sign in listeners +function initClient(){ + gapi.client.init({ + clientId: clientId, + discoveryDocs: discoveryDocs, + scope: scopes + }).then(() => { + //listen for sign in changes + gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus); + //handle initial sign in state + updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get()); + authorizeButton.onclick = handleAuthClick; + signoutButton.onclick = handleSignoutClick; + }) +} + +//update UI sign state changes +function updateSigninStatus(isSignedIn){ + if (isSignedIn){ + authorizeButton.style.display = "none"; + signoutButton.style.display = "block"; + content.style.display = "block"; + videoContainer.style.display = "block"; + getChannel(defaultChannel); + }else{ + authorizeButton.style.display = "block"; + signoutButton.style.display = "none"; + content.style.display = "none"; + videoContainer.style.display = "none"; + } +} + +//Handle log in +function handleAuthClick(){ + gapi.auth2.getAuthInstance().signIn(); +} + +//Handle log out +function handleSignoutClick(){ + gapi.auth2.getAuthInstance().signOut(); +} + + +//Display channel Data +function showChannelData(data){ + const channelData = document.getElementById("channel-data"); + channelData.innerHTML = data; +} + + + +//get channel from API +function getChannel(channel){ + gapi.client.youtube.channels + .list({ + part:'snippet,contentDetails,statistics', + forUsername: channel + }) + .then(res => { + console.log(res) + const channel = res.result.items[0]; + + const output = ` + +

    ${channel.snippet.description}

    +
    + Visit Channel + `; + + showChannelData(output); + const playListId = channel.contentDetails.relatedPlaylists.uploads; + requestVideoPlaylist(playListId); + }) + .catch(err => alert('No Channel By That Name...')) +} + + +//Show the videos to UI +function requestVideoPlaylist(playListId){ + const requestOptions = { + playlistId: playListId, + part: 'snippet', + maxResults:10 + } + const request = gapi.client.youtube.playlistItems.list(requestOptions); + request.execute(res => { + const playlistItems = res.result.items; + if (playlistItems){ + let output = `

    Latest Videos

    ` + //loop through videos and append the output + playlistItems.forEach(item => { + const videoId = item.snippet.resourceId.videoId; + output += `
    + +
    ` + }) + //output the videos + videoContainer.innerHTML = output; + }else{ + videoContainer.innerHTML = 'No Uploaded Videos...'; + } + + }) +} + +//add dots to numbers +function numberWithDots(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); +}