diff --git a/Week1/homework/js-exercises/dogPhotoGallary.js b/Week1/homework/js-exercises/dogPhotoGallary.js new file mode 100644 index 000000000..61bb2fd02 --- /dev/null +++ b/Week1/homework/js-exercises/dogPhotoGallary.js @@ -0,0 +1,42 @@ +'use strict' +//add event listener + +const xhrBtn = document.getElementById('xhr'); +const axiosBtn = document.getElementById('axi'); + +xhrBtn.addEventListener('click', imageXHR); +axiosBtn.addEventListener('click', imageAxios); + +//XHR function +function imageXHR() { + const xhr = new XMLHttpRequest(); + xhr.open('GET', 'https://dog.ceo/api/breeds/image/random'); + xhr.responseType = 'json'; + xhr.onload = () => { + createImage(xhr.response.message); + }; + xhr.send(); +} +//Axios function +function imageAxios() { + axios + .get('https://dog.ceo/api/breeds/image/random') + .then(res => { + createImage(res.data.message); + }) + .catch(err => console.error(err)); +} + +//Manupolating DOM function +function createImage(dogImg) { + + const imgUl = document.getElementById('imgUl'); + const img = document.createElement('img'); + const li = document.createElement('li'); + + img.setAttribute('src', dogImg); + img.style = 'width:200px; height:200px'; + + li.appendChild(img); + imgUl.appendChild(li); +} \ No newline at end of file diff --git a/Week1/homework/js-exercises/dogPhotoGallery.html b/Week1/homework/js-exercises/dogPhotoGallery.html new file mode 100644 index 000000000..9143fd811 --- /dev/null +++ b/Week1/homework/js-exercises/dogPhotoGallery.html @@ -0,0 +1,48 @@ + + + + + + + + + + + Dog Photos + + + + +
+ + +
+ +
+ +
+ + + + + diff --git a/Week1/homework/js-exercises/programmerHumor.html b/Week1/homework/js-exercises/programmerHumor.html new file mode 100644 index 000000000..1edcfc706 --- /dev/null +++ b/Week1/homework/js-exercises/programmerHumor.html @@ -0,0 +1,13 @@ + + + + + + + Programmer Humor + + + + + + \ No newline at end of file diff --git a/Week1/homework/js-exercises/programmerHumor.js b/Week1/homework/js-exercises/programmerHumor.js new file mode 100644 index 000000000..f7edc350d --- /dev/null +++ b/Week1/homework/js-exercises/programmerHumor.js @@ -0,0 +1,48 @@ + +//XHR function +function apiWithXhr(url, callback) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'json'; + xhr.onload = () => { + callback(null, { + response: xhr.response, + status: xhr.status, + readyState: xhr.readyState, + }); + } + xhr.onerror = () => callback('Error!'); + xhr.send(); +} + +const url = 'https://xkcd.now.sh/?comic=614'; +//error handeler +apiWithXhr(url, (err, data) => { + if (err) { + console.error(err); + return; + }else if (data.status == 200 && data.readyState == 4) { + renderImg(data.response, 'Images with XHR'); + }else { + console.error('Error(load: ', data.response, 'Status: ', data.status); + } +}); + +//axios function +axios +.get('https://xkcd.now.sh/?comic=614') +.then(res => { + renderImg(res.data, 'Images with AXIOS'); +}) +.catch(err => console.error(err)); + +function renderImg(data, text) { + + console.log(data); + const h1 = document.createElement('h1'); + h1.textContent = text; + const img = document.createElement('img'); + img.setAttribute('src', data.img); + document.body.appendChild(h1); + document.body.appendChild(img); +} \ No newline at end of file diff --git a/Week1/homework/js-exercises/whoDo.html b/Week1/homework/js-exercises/whoDo.html new file mode 100644 index 000000000..2990181d5 --- /dev/null +++ b/Week1/homework/js-exercises/whoDo.html @@ -0,0 +1,39 @@ + + + + + + Who Do we have here? + + + + + + + + + \ No newline at end of file diff --git a/Week1/homework/project/index.html b/Week1/homework/project/index.html new file mode 100644 index 000000000..ebbfb1120 --- /dev/null +++ b/Week1/homework/project/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + HYF-GITHUB + + + + + +
+ + + + \ No newline at end of file diff --git a/Week1/homework/project/index.js b/Week1/homework/project/index.js new file mode 100644 index 000000000..874014316 --- /dev/null +++ b/Week1/homework/project/index.js @@ -0,0 +1,91 @@ +'use strict'; + +{ + function fetchJSON(url, cb) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'json'; + xhr.onload = () => { + if (xhr.status >= 200 && xhr.status <= 299) { + cb(null, 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.textContent = value; + } else { + elem.setAttribute(key, value); + } + }); + return elem; + } + + function renderRepoDetails(repo, ul) { + // create repositories list + const li = createAndAppend('li', ul, { class: 'repoList' }); + const div = createAndAppend('div', li, { class: 'repository' }); + // create Repository table + const table = createAndAppend('table', div); + + // create Repository title row + const tr1 = createAndAppend('tr', table); + createAndAppend('td', tr1, { text: 'Repository:', class: 'title' }); + const td = createAndAppend('td', tr1); + createAndAppend('a', td, { + href: repo.html_url, + text: repo.name, + target: '_blank' + }); + + // create Description row + const tr2 = createAndAppend('tr', table); + createAndAppend('td', tr2, { text: 'Description:', class: 'title' }); + createAndAppend('td', tr2, { text: repo.description }); + + // create Fork row + const tr3 = createAndAppend('tr', table); + createAndAppend('td', tr3, { text: 'Forks:', class: 'title' }); + createAndAppend('td', tr3, { text: repo.forks }); + + // create Updated row + const tr4 = createAndAppend('tr', table); + createAndAppend('td', tr4, { text: 'Updated:', class: 'title' }); + createAndAppend('td', tr4, { text: repo.updated_at }); + } + + function main(url) { + fetchJSON(url, (err, repos) => { + const root = document.getElementById('root'); + // create the page header + createAndAppend('div', root, { + text: 'HYF Repositories', + class: 'head', + }); + + if (err) { + createAndAppend('div', root, { + text: err.message, + class: 'alert-error', + }); + return; + } + const ul = createAndAppend('ul', root, {class: 'repoUl'}); + // sorting the repositories form A to Z + repos.sort((currentRepo, nextRepo) => currentRepo.name.localeCompare(nextRepo.name)); + repos.forEach(repo => renderRepoDetails(repo, ul)); + }); + } + + const HYF_REPOS_URL = + 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; + window.onload = () => main(HYF_REPOS_URL); +} \ No newline at end of file diff --git a/Week1/homework/project/style.css b/Week1/homework/project/style.css new file mode 100644 index 000000000..734ee9180 --- /dev/null +++ b/Week1/homework/project/style.css @@ -0,0 +1,57 @@ +body { + font-family: italic 20px Serif; +} + + #root { + width: 80%; + margin: auto; + } + + .alert-error { + color: #9D1C24; + background-color: #F8D7DA; + height: 50px; + padding: 20px 0 0 10px; + margin-top: 5px; + } + + .head { + background-color: purple; + color: #ffffff; + height: 50px; + padding: 20px 0 0 10px; + margin-top: 5px;; + font-size: 1.5rem; + } + + .title { + font-weight: bold; + padding: 5px 0 5px 5px; + } + + .repoUl { + margin: 0; + padding: 0; + } + + .repoList { + list-style: none; + margin: 0; + padding: 0; + } + + .repository { + box-shadow: 2px 2px 15px -2px rgba(133,126,133,1); + margin: 7px 0 7px 0; + } + + @media only screen and (max-width: 600px) { + #root { + width: 100%; + font-size: 14px; + } + + .head { + text-align: center; + } + } \ No newline at end of file diff --git a/Week2/homework/index.html b/Week2/homework/index.html new file mode 100644 index 000000000..d71898f8f --- /dev/null +++ b/Week2/homework/index.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + HYF Version-2 + + + + + +
+
+

HYF Repositories

+ +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/Week2/homework/index.js b/Week2/homework/index.js new file mode 100644 index 000000000..dc309f91a --- /dev/null +++ b/Week2/homework/index.js @@ -0,0 +1,141 @@ +/* eslint-disable no-console */ +/* eslint-disable no-use-before-define */ +/* eslint-disable no-unused-vars */ +const createAndAppend = (name, parent, options = {}) => { + const elem = document.createElement(name); + parent.appendChild(elem); + Object.entries(options).forEach(([key, value]) => { + if (key === 'innerHTML') { + elem.innerHTML = value; + } else if (key === 'text') { + elem.textContent = value; + } else { + elem.setAttribute(key, value); + } + }); + return elem; + }; + const errorHandler = err => { + const root = document.getElementById('root'); + createAndAppend('div', root, { + text: err.message, + class: 'alert-error', + }); + }; + + const optionLoading = items => { + const selectEl = document.querySelector('#reposName'); + items + .sort((current, next) => current.name.localeCompare(next.name)) + .forEach(repo => { + createAndAppend('option', selectEl, { + text: repo.name, + value: repo.name, + }); + }); + }; + + const renderRepoContainer = repo => { + const { selectedIndex } = document.querySelector('select'); + const convertedDate = new Date( + repo[selectedIndex].updated_at, + ).toLocaleString(); + const repoContainer = document.querySelector('.repo-container'); + + createAndAppend('ul', repoContainer, { class: 'repoDetails' }); + const cardUl = document.querySelector('.repoDetails'); + + createAndAppend('li', cardUl, { + innerHTML: `Repository :${repo[selectedIndex].name}`, + }); + createAndAppend('li', cardUl, { + innerHTML: `Description: ${repo[selectedIndex].description}`, + }); + createAndAppend('li', cardUl, { + innerHTML: `Forks: ${repo[selectedIndex].forks_count}`, + }); + createAndAppend('li', cardUl, { + innerHTML: `Updated: ${convertedDate}`, + }); + + return repo; + }; + + const renderRepoContributors = repo => { + const { selectedIndex } = document.querySelector('select'); + const selectedRepo = repo[selectedIndex]; + + const repoContributors = document.querySelector('.contributors-container'); + createAndAppend('ul', repoContributors, { class: 'repoContributors' }); + const ulContributors = document.querySelector('.repoContributors'); + + createAndAppend('h5', ulContributors, { + text: 'Contributions', + style: 'margin:0 0 5px 0; font-size: 15px; ', + }); + + fetchJSON(selectedRepo.contributors_url) + .then(data => + data.forEach(dataSelected => { + const li = createAndAppend('li', ulContributors, { + style: + 'display: flex;text-align: center; justify-content: space-between; border-bottom: 2px solid #687466;', + }); + const imgAvatar = createAndAppend('img', li, { + src: dataSelected.avatar_url, + class: 'avatar', + }); + const contInfo = createAndAppend('a', li, { + text: dataSelected.login, + href: dataSelected.html_url, + target: '_blank', + style: 'margin: 20px auto 0 5px; text-decoration: none;', + }); + const contCount = createAndAppend('span', li, { + text: dataSelected.contributions, + class: 'contributions-count', + }); + }), + ) + .catch(err => console.error(err)); + }; + + const renderSelectedOptionChange = repo => { + const selectRepo = document.querySelector('select'); + selectRepo.addEventListener('change', () => { + document.querySelector('section.repo-container ul').remove(); + document.querySelector('.repoContributors').remove(); + + renderRepoContainer(repo); + renderRepoContributors(repo); + }); + }; + + const fetchJSON = url => { + const repos = fetch(url) + .then(res => { + if (!res.ok) { + throw new Error('Network response was not ok'); + } + return res.json(); + }) + .then(data => data) + .catch(err => errorHandler(err)); + return repos; + }; + + const main = url => { + fetchJSON(url) + .then(data => { + optionLoading(data); + renderRepoContainer(data); + renderRepoContributors(data); + renderSelectedOptionChange(data); + }) + .catch(err => errorHandler(err)); + }; + + const HYF_REPOS_URL = + 'https://api.github.com/orgs/HackYourFuture/repos?per_page=30'; + + main(HYF_REPOS_URL); \ No newline at end of file diff --git a/Week2/homework/style.css b/Week2/homework/style.css new file mode 100644 index 000000000..fbae9cdfa --- /dev/null +++ b/Week2/homework/style.css @@ -0,0 +1,84 @@ + +body { + font-family: italic 20px Serif; +} +.CardHeader { + background-color:palevioletred; + color: white; + justify-content: left; + padding:10px; + margin-bottom: 5px; + border: 1px solid aqua; + width: auto; +} + +.repoDetails { + display: inline-block; + background-color: white; + padding: 15px; + line-height: 20px; + border: 1px solid black; + list-style-type: none; +} + +.repoDetails li span { + font-size: 15px; + white-space: normal; +} +.firstText { + display: inline-block; + margin-right: 5px; + font-weight: bolder; + width: 85px; +} +.main-container { + display: flex; +} +.repoContributors { + display: inline-block; + width: 90%; + background-color: white; + padding: 15px; + line-height: 20px; + border: 1px solid black; + list-style-type: none; +} + +.repo-container { + width: 100%; + margin-left: 15px; +} +.contributors-container { + width: 100%; +} +.avatar { + margin-bottom: 3px; + margin-top: 3px; + width: 65px; + border-radius: 50%; +} +.contributions-count { + background-color: cadetblue; + border: 2px solid rgba(0, 0, 0, 0.17); + font-weight: bold; + border-radius: 5px; + padding: 7px; + margin: 15px 5px 25px 0; +} +.alert-error { + width: 72%; + margin: 2px 0; + padding: 10px; + border-radius: 3px 3px 3px 3px; + color: #d8000c; + background-color: #ffbaba; +} +@media screen and (max-width: 700px) { + .repo-container, + .contributors-container { + width: 100%; + } + .main-container { + display: block; + } +} \ No newline at end of file diff --git a/Week3/homework/part1/hyf.png b/Week3/homework/part1/hyf.png new file mode 100644 index 000000000..76bc5a13b Binary files /dev/null and b/Week3/homework/part1/hyf.png differ diff --git a/Week3/homework/part1/index.html b/Week3/homework/part1/index.html new file mode 100644 index 000000000..f9cc7119e --- /dev/null +++ b/Week3/homework/part1/index.html @@ -0,0 +1,34 @@ + + + + + + + + + + + + + HYF-GITHUB + + + + + + +
+
+

HYF Repositories

+ +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/Week3/homework/part1/index.js b/Week3/homework/part1/index.js new file mode 100644 index 000000000..4e4cbc7e9 --- /dev/null +++ b/Week3/homework/part1/index.js @@ -0,0 +1,175 @@ +'use strict'; + +{ + // root div declaration + const root = document.getElementById('root'); + + // this function will fetch JSON data using async/await and axios + async function fetchJSON(url) { + + try { + + const response = await axios.get(url); + // throw the error if exists + if (!response.statusText) { + throw new Error(`Network error: ${response.status},${response.statusText}`); + } + const resData = await response.data; + // return the fetched data + return resData; + + } + catch (error) { + // catch the error if exists + printError(error); + + } + } + + // this function create and append elements + function createAndAppend(name, parent, options = {}) { + const elem = document.createElement(name); + parent.appendChild(elem); + Object.entries(options).forEach(([key, value]) => { + if (key === 'text') { + elem.textContent = value; + } else { + elem.setAttribute(key, value); + } + }); + return elem; + } + + // this function render the selected Repository details + function renderRepoDetails(repo, repoContainer) { + // create Repository table + const table = createAndAppend('table', repoContainer); + + // create Repository title row + const titleTr = createAndAppend('tr', table); + createAndAppend('td', titleTr, { text: 'Repository:', class: 'title' }); + const td = createAndAppend('td', titleTr); + createAndAppend('a', td, { + href: repo.html_url, + text: repo.name, + target: '_blank' + }); + + // create Description row + const descriptionTr = createAndAppend('tr', table); + createAndAppend('td', descriptionTr, { text: 'Description:', class: 'title' }); + createAndAppend('td', descriptionTr, { text: repo.description }); + + // create Fork row + const forksTr = createAndAppend('tr', table); + createAndAppend('td', forksTr, { text: 'Forks:', class: 'title' }); + createAndAppend('td', forksTr, { text: repo.forks }); + + // create Updated row + const updatedTr = createAndAppend('tr', table); + createAndAppend('td', updatedTr, { text: 'Updated:', class: 'title' }); + createAndAppend('td', updatedTr, { text: repo.updated_at }); + } + + // this function render the Contributions details + async function renderContributorsDetails(repo, contributorsContainer) { + // create section title + const ul = createAndAppend('ul', contributorsContainer, { + text: 'Contributions', + class: 'contributors-ul' + }); + + // fetch contributors data + try { + const contributors = await fetchJSON(repo.contributors_url); + // create contributors list + contributors.forEach( Contributor => { + const li = createAndAppend('li', ul, { class: 'Contributor-li' }); + const ContributorDiv = createAndAppend('div', li, { class: 'Contributor-div' }); + + // create contributor image + createAndAppend('img', ContributorDiv, { + class: 'contributors-img', + src: Contributor.avatar_url, + }); + + // create contributor name + createAndAppend('a', ContributorDiv, { + class: 'contributors-a', + text: Contributor.login, + href: Contributor.html_url, + target: '_blank', + }); + + // create contributors number + createAndAppend('span', ContributorDiv, { + class: 'contributors-span', + text: Contributor.contributions, + }); + }); + } + catch(err) { + // catch the error if exists + printError(err); + } + } + + // this function removes all childs of passed element + function removeElems(elem) { + while (elem.lastElementChild) { + elem.removeChild(elem.lastElementChild); + } + } + + // this function print the catched error to window + function printError(err) { + createAndAppend('div', root, { + text: err.message, + class: 'alert-error', + }); + } + + // this is the main function + async function main(url) { + // fetch Repositories data + try { + const repos = await fetchJSON(url); + // declare the DOM elements for list and containers + const reposList = document.getElementById('repos-List'); + const repoContainer = document.querySelector('.repo-container'); + const contributorsContainer = document.querySelector('.contributors-container'); + + // sorting the repositories form A to Z + repos.sort((currentRepo, nextRepo) => currentRepo.name.localeCompare(nextRepo.name)); + + // filling the dropdown list with sorted repositories titles + repos.forEach(repo => { + createAndAppend('option', reposList, { text: repo.name, value: repo.name }); + }); + + // display information about the first repository + renderRepoDetails(repos[0], repoContainer); + renderContributorsDetails(repos[0], contributorsContainer); + + // refreshed for the newly selected repository when the user changes the selection + reposList.addEventListener('change', () => { + // empty the containers from old data when the user changes the selection + removeElems(repoContainer); + removeElems(contributorsContainer); + // find the selected repository and render the details + let currentRepo = repos.filter( repo => repo.name == reposList.value ); + renderRepoDetails(currentRepo[0], repoContainer); + renderContributorsDetails(currentRepo[0], contributorsContainer); + }); + + } + catch(err) { + // catch the error if exists + printError(err); + } + } + + const HYF_REPOS_URL = + 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; + window.onload = () => main(HYF_REPOS_URL); +} \ No newline at end of file diff --git a/Week3/homework/part1/style.css b/Week3/homework/part1/style.css new file mode 100644 index 000000000..9913dba3f --- /dev/null +++ b/Week3/homework/part1/style.css @@ -0,0 +1,146 @@ +body { + margin: 0; + padding: 0; + font-size: 16px; + font-family: Arial, Helvetica, sans-serif; + } + + #root { + width: 80%; + margin: auto; + } + + .alert-error { + color: #9D1C24; + background-color: #F8D7DA; + height: 50px; + padding: 20px 0 0 10px; + margin-top: 5px; + } + + .head { + background-color: #3F51B5; + color: #ffffff; + height: 100px; + padding: 0px; + margin-top: 5px; + display: flex; + } + + .head > h1 { + padding: 0.5rem 0 0 1rem; + } + + #repos-List { + height: auto; + width: 20rem; + margin: auto 1rem ; + font-size: large; + } + + .title { + font-weight: bold; + padding: 5px 0 5px 5px; + } + + .main-container { + display: flex; + } + + .repo-container, .contributors-container { + box-shadow: 2px 2px 15px -2px rgba(133,126,133,1); + margin: 7px 0 7px 0; + width: 50%; + } + + .repo-container { + height: 8rem; + margin-right: 0.5rem; + } + + .contributors-ul { + font-weight: bold; + padding: 5px 0 5px 5px; + list-style: none; + } + + .Contributor-li { + margin: 1rem 0 1rem 0; + border-bottom: 1px solid #dfdcdc; + } + + .Contributor-div { + height: 4.5rem; + } + + .contributors-img { + width: 50px; + margin-left: 1rem; + } + + .contributors-a { + margin: auto 1rem; + font-weight: normal; + position: relative; + bottom: 1.5rem; + } + + .contributors-span { + margin: 1rem 1rem 0 0; + float: right; + font-weight: normal; + font-size: small; + text-align: center; + width: 2rem; + color: #ffffff; + background-color: #5f5d5d; + border-radius: 0.2rem; + } + + /* Change style to be responsive to ---Mobile devices--- */ + + @media (max-width: 600px) { + #root { + width: 100%; + font-size: 14px; + } + + .head > h1 { + font-size: 1rem; + padding: 2rem 0 0 1rem; + } + + #repos-List { + width: 5rem; + margin: auto 1rem ; + font-size: small; + position: relative; + + } + + #repos-List option{ + width: 5rem; + + } + + .main-container { + display: block; + } + .repo-container, .contributors-container { + width: 100%; + } + } + + /* Change style to be responsive to --Tablets devices--*/ + + @media (min-width: 600px) and (max-width: 1024px) { + #root { + width: 95%; + font-size: 14px; + } + + .head > h1 { + font-size: 1.5rem; + padding: 1rem 0 0 1rem; + } + } \ No newline at end of file diff --git a/Week3/homework/part2/App.js b/Week3/homework/part2/App.js new file mode 100644 index 000000000..316fb93a7 --- /dev/null +++ b/Week3/homework/part2/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]); +} \ No newline at end of file diff --git a/Week3/homework/part2/ContributorsView.js b/Week3/homework/part2/ContributorsView.js new file mode 100644 index 000000000..9161a3ddb --- /dev/null +++ b/Week3/homework/part2/ContributorsView.js @@ -0,0 +1,62 @@ +'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 + + // empty the conatainer from its old data + this.container.textContent = ''; + + // create section title + const ul = createAndAppend('ul', this.container, { + text: 'Contributions', + class: 'contributors-ul' + }); + + // create the contributors list + contributors.forEach( Contributor => { + const li = createAndAppend('li', ul, { class: 'Contributor-li' }); + const ContributorDiv = createAndAppend('div', li, { class: 'Contributor-div' }); + + // create contributor image + createAndAppend('img', ContributorDiv, { + class: 'contributors-img', + src: Contributor.avatar_url, + }); + + // create contributor name + createAndAppend('a', ContributorDiv, { + class: 'contributors-a', + text: Contributor.login, + href: Contributor.html_url, + target: '_blank', + }); + + // create contributors number + createAndAppend('span', ContributorDiv, { + class: 'contributors-span', + text: Contributor.contributions, + }); + }); + } + } + + window.ContributorsView = ContributorsView; +} \ No newline at end of file diff --git a/Week3/homework/part2/ErrorView.js b/Week3/homework/part2/ErrorView.js new file mode 100644 index 000000000..d71aec290 --- /dev/null +++ b/Week3/homework/part2/ErrorView.js @@ -0,0 +1,31 @@ +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) { + createAndAppend('div', this.container, { + text: error.message, + class: 'alert alert-error', + }); + } + } + } + + window.ErrorView = ErrorView; +} \ No newline at end of file diff --git a/Week3/homework/part2/HeaderView.js b/Week3/homework/part2/HeaderView.js new file mode 100644 index 000000000..f49c3e77e --- /dev/null +++ b/Week3/homework/part2/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