diff --git a/homework/index.js b/homework/index.js index 23a60f971..0c0a06f4c 100644 --- a/homework/index.js +++ b/homework/index.js @@ -1,81 +1,158 @@ '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 fetchJSON(url) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'json'; + xhr.onload = () => { + if (xhr.status >= 200 && xhr.status <= 299) { + resolve(xhr.response); + } else { + reject(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`)); + } + }; + xhr.onerror = () => reject(new Error('Network request failed')); + xhr.send(); + }); + } -function addRow(property, key, parent, link) { - const tr = createAndAppend('tr', parent); - createAndAppend('th', tr, { - text: `${property} :`, - }); + 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; + } - if (link) { - const td = createAndAppend('td', tr); - createAndAppend('a', td, { - href: link, + function addContributor(contributor, parent) { + const tr = createAndAppend('tr', parent); + const imageColumn = createAndAppend('th', tr); + createAndAppend('img', imageColumn, { + src: contributor.avatar_url, + class: 'contributor-img', + }); + const name = createAndAppend('td', tr); + createAndAppend('a', name, { + href: contributor.html_url, target: '_blank', - text: key, + text: contributor.login, + }); + const contributeNamePlace = createAndAppend('td', tr); + createAndAppend('span', contributeNamePlace, { + text: contributor.contributions, + class: 'contribute-number', + }); + } + + function addRow(property, key, parent) { + const tr = createAndAppend('tr', parent); + createAndAppend('th', tr, { + text: `${property} :`, }); - } else { createAndAppend('td', tr, { text: key }); + return tr; } -} -function renderRepoDetails(repo, div) { - const table = createAndAppend('table', div, { - class: 'container', - }); + function renderContributorDetails(contributors, contributorsContainer) { + const table = createAndAppend('table', contributorsContainer); + contributors.forEach(contributor => { + addContributor(contributor, table); + }); + } - addRow('Repository', repo.name, table, repo.html_url); - addRow('Description', repo.description, table); - addRow('Forks', repo.forks, table); - addRow('Updated', repo.updated_at, table); -} + function renderRepoDetails(repo, div) { + const table = createAndAppend('table', div); + const firstRow = addRow('Repository', '', table); + createAndAppend('a', firstRow.lastChild, { + href: repo.html_url, + target: '_blank', + text: repo.name, + }); + addRow('Description', repo.description, table); + addRow('Forks', repo.forks, table); + addRow('Updated', repo.updated_at, table); + } + function renderError(error, contributorsContainer) { + createAndAppend('div', contributorsContainer, { + text: error.message, + class: 'alert-error', + }); + } -function main(url) { - fetchJSON(url, (err, repos) => { - const root = document.getElementById('root'); - if (err) { - createAndAppend('div', root, { - text: err.message, - class: 'alert-error', - }); - return; + function fetchContributors(url, contributorsContainer) { + const promiseContributor = fetchJSON(url); + promiseContributor + .then(contributors => { + renderContributorDetails(contributors, contributorsContainer); + }) + .catch(error => renderError(error, contributorsContainer)); + } + + function deleteContainers() { + const selectButton = document.getElementById('selectButton'); + let firstOption = selectButton.firstChild; + while (firstOption) { + selectButton.removeChild(firstOption); + firstOption = selectButton.firstChild; } - createAndAppend('header', root, { text: 'HYF Repositories' }); - const div = createAndAppend('div', root); - // eslint-disable-next-line func-names + document.getElementById('flex-container').remove(); + } + + function makeFlexContainer(root, repos, selectButton) { + const flexContainer = createAndAppend('section', root, { + id: 'flex-container', + }); + const repoContainer = createAndAppend('section', flexContainer, { + class: 'container', + }); + const contributorsContainer = createAndAppend('section', flexContainer, { + class: 'container', + }); + createAndAppend('h5', contributorsContainer, { text: 'Contributions' }); + repos .sort((a, b) => a.name.localeCompare(b.name)) - .forEach(repo => renderRepoDetails(repo, div)); - }); -} + .forEach((repo, index) => { + createAndAppend('option', selectButton, { + text: repo.name, + value: index, + }); + }); + renderRepoDetails(repos[selectButton.value], repoContainer); + fetchContributors( + repos[selectButton.value].contributors_url, + contributorsContainer, + ); + } -const HYF_REPOS_URL = - 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; -window.onload = () => main(HYF_REPOS_URL); + function main(url) { + const root = document.getElementById('root'); + const header = createAndAppend('header', root, { + text: 'HYF Repositories', + }); + const promise = fetchJSON(url); + promise + .then(repos => { + const selectButton = createAndAppend('select', header, { + id: 'selectButton', + }); + selectButton.addEventListener('change', () => { + deleteContainers(); + makeFlexContainer(root, repos, selectButton); + }); + makeFlexContainer(root, repos, selectButton); + }) + .catch(error => renderError(error, root)); + } + + const HYF_REPOS_URL = + 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; + window.onload = () => main(HYF_REPOS_URL); +} diff --git a/homework/style.css b/homework/style.css index b1f439ece..72318c342 100644 --- a/homework/style.css +++ b/homework/style.css @@ -8,21 +8,34 @@ body { } header { - margin: 3px; + margin: 4px; padding: 10px; padding-left: 20px; background: rgb(25, 25, 25); border: black solid 3px; border-radius: 10px; - max-width: 700px; + max-width: 1100px; position: relative; margin: auto; } +select { + margin: 10px; +} + +#flex-container { + display: flex; + flex-wrap: wrap; + border: solid black 2px; + max-width: 1100px; + position: relative; + margin: auto; + align-items: flex-start; +} .container { - margin-left: 4px; - padding: 8px; - padding-left: 12px; + margin: 2px; + padding: 6px; + padding-left: 8px; background: rgb(40, 40, 40); border-left: rgb(60, 60, 60) solid 2px; border-top: rgb(100, 100, 100) solid 2px; @@ -30,14 +43,13 @@ header { border-bottom: black solid 3px; border-radius: 5px; max-width: 700px; - align-content: center; - position: relative; - margin: auto; + min-width: 300px; + flex: 1; + vertical-align: top; } table { width: 100%; margin-left: 6px; - padding-left: 10px; } tr:hover { @@ -59,3 +71,16 @@ a { a:visited { color: lightgreen; } +.contributor-img { + width: 60px; +} +.contribute-number { + background: rgb(50, 50, 50); + border-left: rgb(60, 60, 60) solid 2px; + border-top: rgb(100, 100, 100) solid 2px; + border-right: rgb(20, 20, 20) solid 3px; + border-bottom: black solid 3px; + border-radius: 5px; + position: relative; + text-align: right; +}