diff --git a/Week1/index.html b/Week1/index.html
new file mode 100644
index 000000000..9c8f80c1a
--- /dev/null
+++ b/Week1/index.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HYF-GITHUB
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week1/index.js b/Week1/index.js
new file mode 100644
index 000000000..0b08cce3b
--- /dev/null
+++ b/Week1/index.js
@@ -0,0 +1,163 @@
+'use strict';
+
+{
+ function fetchJSON(url, cb) {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status < 400) {
+ 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.keys(options).forEach(key => {
+ const value = options[key];
+ if (key === 'text') {
+ elem.textContent = value;
+ } else {
+ elem.setAttribute(key, value);
+ }
+ });
+ return elem;
+ }
+ function loadDetail(element) {
+ const leftID = document.getElementById('leftID');
+ createAndAppend('ul', leftID, { id: 'leftDetailID', class: 'leftDetailClass' });
+
+ const leftDetailID = document.getElementById('leftDetailID');
+ createAndAppend('li', leftDetailID, {
+ id: 'leftListID',
+ class: 'leftListClass',
+ text: 'Repository: ',
+ });
+
+ const leftListID = document.getElementById('leftListID');
+ createAndAppend('a', leftListID, {
+ text: element.name,
+ href: element.html_url,
+ id: 'repositoryNameID',
+ class: 'repositoryNameClass',
+ });
+
+ createAndAppend('li', leftDetailID, {
+ id: 'descList',
+ text: `Description: ${element.description}`,
+ });
+ createAndAppend('li', leftDetailID, { text: `Forks: ${element.forks}` });
+ const updatedAt = new Date(element.updated_at).toLocaleString();
+ createAndAppend('li', leftDetailID, { text: `Updated: ${updatedAt}` });
+ }
+ function loadContributor(element) {
+ fetchJSON(element.contributors_url, (err, data) => {
+ const root = document.getElementById('root');
+ if (err) {
+ createAndAppend('div', root, { text: err.message, class: 'alert-error' });
+ } else {
+ const rightID = document.getElementById('rightID');
+ createAndAppend('p', rightID, { id: 'contTextID', text: 'Contributors' });
+ createAndAppend('ul', rightID, { id: 'contListID', class: 'contListClass' });
+
+ let contURL;
+ let contData;
+ let contDetail;
+ const contListID = document.getElementById('contListID');
+ for (let i = 0; i < data.length; i++) {
+ contURL = createAndAppend('a', contListID, {
+ href: data[i].html_url,
+ target: '_blank',
+ id: 'contUrlID',
+ class: 'contUrlClass',
+ });
+ contData = createAndAppend('li', contURL, {
+ id: 'contDataID',
+ class: 'contDataClass',
+ });
+
+ createAndAppend('img', contData, {
+ src: data[i].avatar_url,
+ id: 'contImgID',
+ class: 'contImgClass',
+ });
+
+ contDetail = createAndAppend('div', contData, {
+ id: 'contDetailID',
+ class: 'contDetailClass',
+ });
+ createAndAppend('div', contDetail, { text: data[i].login });
+ createAndAppend('div', contDetail, {
+ text: data[i].contributions,
+ id: 'contBadgeID',
+ class: 'contBadgeClass',
+ });
+ }
+ }
+ });
+ }
+
+ function main(url) {
+ fetchJSON(url, (err, data) => {
+ const root = document.getElementById('root');
+ if (err) {
+ createAndAppend('div', root, { text: err.message, class: 'alert-error' });
+ } else {
+ createAndAppend('header', root, { id: 'topBoxID', class: 'topBoxClass' });
+ const topBoxID = document.getElementById('topBoxID');
+ createAndAppend('p', topBoxID, {
+ id: 'topTextID',
+ class: 'topTextClass',
+ text: 'HYF Repositories',
+ });
+
+ createAndAppend('div', root, { id: 'mainContainerID', class: 'mainContainerClass' });
+
+ const mainContainerID = document.getElementById('mainContainerID');
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ createAndAppend('select', topBoxID, { id: 'repsSelectID', Class: 'repsSelectClass' });
+ data.sort((a, b) => a.name.localeCompare(b.name));
+
+ const repsSelectID = document.getElementById('repsSelectID');
+ for (let index = 0; index < data.length; index++) {
+ createAndAppend('option', repsSelectID, {
+ value: index,
+ text: data[index].name,
+ id: 'optionID',
+ class: 'optionClass',
+ });
+ }
+ const selector = document.getElementById('repsSelectID');
+
+ loadDetail(data[0]);
+ loadContributor(data[0]);
+
+ selector.onchange = () => {
+ const leftDetail = document.getElementById('leftID');
+ leftDetail.parentNode.removeChild(leftDetail);
+
+ const rightDetail = document.getElementById('rightID');
+ rightDetail.parentNode.removeChild(rightDetail);
+
+ const i = selector.value;
+
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ loadDetail(data[i]);
+ loadContributor(data[i]);
+ };
+ }
+ });
+ }
+
+ const HYF_REPS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
+
+ window.onload = () => main(HYF_REPS_URL);
+}
diff --git a/Week1/style.css b/Week1/style.css
new file mode 100644
index 000000000..c9040ac64
--- /dev/null
+++ b/Week1/style.css
@@ -0,0 +1,119 @@
+.alert-error {
+ color: #721c24;
+ background-color: #f8d7da;
+}
+
+body {
+ margin-left: auto;
+ margin-right: auto;
+ font-family: Arial, Helvetica, sans-serif;
+ color: black;
+ margin-top: 0;
+ background-color: #f8f8f8;
+ width: 900px;
+}
+
+.mainContainerClass {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+}
+
+@media (max-width: 767px) {
+ body {
+ width: 100%;
+ }
+ #mainContainerClass {
+ margin: 0;
+ flex-direction: column;
+ align-items: stretch;
+ }
+}
+
+.topBoxClass {
+ color: white;
+ background-color: #3f51b5;
+ padding: 8px 16px;
+ margin-bottom: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.topTextClass {
+ margin-left: 40px;
+ font-size: 30px;
+ font-family: 'Trebuchet MS';
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.repsSelectClass {
+ margin-left: 30px;
+ font-size: 18px;
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.leftClass, .rightClass {
+ background-color: white;
+ flex: 1;
+ padding: 16px;
+ margin-right: 16px;
+ margin-bottom: 8px;
+ border: none;
+ border-radius: 2px;
+ background-color: white;
+ box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.2), 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.12)
+}
+
+.leftDetailClass {
+ table-layout: fixed;
+ color: rgb(0, 0, 0, 81%);
+}
+
+@media (max-width: 767px) {
+ .leftClass {
+ margin: 0;
+ }
+}
+
+#contTextID {
+ font-size: 0.9rem;
+ color: rgb(0, 0, 0, 54%);
+ padding: 8px 16px 4px 16px;
+}
+
+.contDataClass {
+ border-bottom: solid 1px rgb(0, 0, 0, 12%);
+ padding: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ cursor: pointer;
+}
+
+.contImgClass {
+ border-radius: 3px;
+ margin-right: 16px;
+ height: 48px;
+}
+
+.contDetailClass {
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-content: center;
+}
+
+.contBadgeClass {
+ font-size: 12px;
+ padding: 2px 8px;
+ line-height: 1rem;
+ background-color: gray;
+ color: white;
+ border-radius: 4px;
+}
\ No newline at end of file
diff --git a/Week2/index.html b/Week2/index.html
new file mode 100644
index 000000000..9c8f80c1a
--- /dev/null
+++ b/Week2/index.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HYF-GITHUB
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week2/index.js b/Week2/index.js
new file mode 100644
index 000000000..aa67fb636
--- /dev/null
+++ b/Week2/index.js
@@ -0,0 +1,164 @@
+'use strict';
+
+{
+ function fetchJSON(url) {
+ return new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status < 400) {
+ resolve(xhr.response);
+ } else {
+ reject(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
+ }
+ };
+ xhr.send();
+ });
+ }
+
+ function createAndAppend(name, parent, options = {}) {
+ const elem = document.createElement(name);
+ parent.appendChild(elem);
+ Object.keys(options).forEach(key => {
+ const value = options[key];
+ if (key === 'text') {
+ elem.textContent = value;
+ } else {
+ elem.setAttribute(key, value);
+ }
+ });
+ return elem;
+ }
+ function loadDetail(element) {
+ const leftID = document.getElementById('leftID');
+ createAndAppend('ul', leftID, { id: 'leftDetailID', class: 'leftDetailClass' });
+
+ const leftDetailID = document.getElementById('leftDetailID');
+ createAndAppend('li', leftDetailID, {
+ id: 'leftListID',
+ class: 'leftListClass',
+ text: 'Repository: ',
+ });
+
+ const leftListID = document.getElementById('leftListID');
+ createAndAppend('a', leftListID, {
+ text: element.name,
+ href: element.html_url,
+ id: 'repositoryNameID',
+ class: 'repositoryNameClass',
+ });
+
+ createAndAppend('li', leftDetailID, {
+ id: 'descList',
+ text: `Description: ${element.description}`,
+ });
+ createAndAppend('li', leftDetailID, { text: `Forks: ${element.forks}` });
+ const updatedAt = new Date(element.updated_at).toLocaleString();
+ createAndAppend('li', leftDetailID, { text: `Updated: ${updatedAt}` });
+ }
+ function loadContributor(element) {
+ const root = document.getElementById('root');
+ fetchJSON(element.contributors_url)
+ .catch(reject => {
+ createAndAppend('div', root, { text: reject.message, class: 'alert-error' });
+ })
+ .then(data => {
+ const rightID = document.getElementById('rightID');
+ createAndAppend('p', rightID, { id: 'contTextID', text: 'Contributors' });
+ createAndAppend('ul', rightID, { id: 'contListID', class: 'contListClass' });
+
+ let contURL;
+ let contData;
+ let contDetail;
+ const contListID = document.getElementById('contListID');
+ for (let i = 0; i < data.length; i++) {
+ contURL = createAndAppend('a', contListID, {
+ href: data[i].html_url,
+ target: '_blank',
+ id: 'contUrlID',
+ class: 'contUrlClass',
+ });
+ contData = createAndAppend('li', contURL, {
+ id: 'contDataID',
+ class: 'contDataClass',
+ });
+
+ createAndAppend('img', contData, {
+ src: data[i].avatar_url,
+ id: 'contImgID',
+ class: 'contImgClass',
+ });
+
+ contDetail = createAndAppend('div', contData, {
+ id: 'contDetailID',
+ class: 'contDetailClass',
+ });
+ createAndAppend('div', contDetail, { text: data[i].login });
+ createAndAppend('div', contDetail, {
+ text: data[i].contributions,
+ id: 'contBadgeID',
+ class: 'contBadgeClass',
+ });
+ }
+ });
+ }
+
+ function main(url) {
+ const root = document.getElementById('root');
+ fetchJSON(url)
+ .catch(reject => {
+ createAndAppend('div', root, { text: reject.message, class: 'alert-error' });
+ })
+ .then(data => {
+ createAndAppend('header', root, { id: 'topBoxID', class: 'topBoxClass' });
+ const topBoxID = document.getElementById('topBoxID');
+ createAndAppend('p', topBoxID, {
+ id: 'topTextID',
+ class: 'topTextClass',
+ text: 'HYF Repositories',
+ });
+
+ createAndAppend('div', root, { id: 'mainContainerID', class: 'mainContainerClass' });
+
+ const mainContainerID = document.getElementById('mainContainerID');
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ createAndAppend('select', topBoxID, { id: 'repsSelectID', Class: 'repsSelectClass' });
+ data.sort((a, b) => a.name.localeCompare(b.name));
+
+ const repsSelectID = document.getElementById('repsSelectID');
+ for (let index = 0; index < data.length; index++) {
+ createAndAppend('option', repsSelectID, {
+ value: index,
+ text: data[index].name,
+ id: 'optionID',
+ class: 'optionClass',
+ });
+ }
+ const selector = document.getElementById('repsSelectID');
+
+ loadDetail(data[0]);
+ loadContributor(data[0]);
+
+ selector.onchange = () => {
+ const leftDetail = document.getElementById('leftID');
+ leftDetail.parentNode.removeChild(leftDetail);
+
+ const rightDetail = document.getElementById('rightID');
+ rightDetail.parentNode.removeChild(rightDetail);
+
+ const i = selector.value;
+
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ loadDetail(data[i]);
+ loadContributor(data[i]);
+ };
+ });
+ }
+
+ const HYF_REPS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
+
+ window.onload = () => main(HYF_REPS_URL);
+}
diff --git a/Week2/style.css b/Week2/style.css
new file mode 100644
index 000000000..c9040ac64
--- /dev/null
+++ b/Week2/style.css
@@ -0,0 +1,119 @@
+.alert-error {
+ color: #721c24;
+ background-color: #f8d7da;
+}
+
+body {
+ margin-left: auto;
+ margin-right: auto;
+ font-family: Arial, Helvetica, sans-serif;
+ color: black;
+ margin-top: 0;
+ background-color: #f8f8f8;
+ width: 900px;
+}
+
+.mainContainerClass {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+}
+
+@media (max-width: 767px) {
+ body {
+ width: 100%;
+ }
+ #mainContainerClass {
+ margin: 0;
+ flex-direction: column;
+ align-items: stretch;
+ }
+}
+
+.topBoxClass {
+ color: white;
+ background-color: #3f51b5;
+ padding: 8px 16px;
+ margin-bottom: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.topTextClass {
+ margin-left: 40px;
+ font-size: 30px;
+ font-family: 'Trebuchet MS';
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.repsSelectClass {
+ margin-left: 30px;
+ font-size: 18px;
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.leftClass, .rightClass {
+ background-color: white;
+ flex: 1;
+ padding: 16px;
+ margin-right: 16px;
+ margin-bottom: 8px;
+ border: none;
+ border-radius: 2px;
+ background-color: white;
+ box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.2), 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.12)
+}
+
+.leftDetailClass {
+ table-layout: fixed;
+ color: rgb(0, 0, 0, 81%);
+}
+
+@media (max-width: 767px) {
+ .leftClass {
+ margin: 0;
+ }
+}
+
+#contTextID {
+ font-size: 0.9rem;
+ color: rgb(0, 0, 0, 54%);
+ padding: 8px 16px 4px 16px;
+}
+
+.contDataClass {
+ border-bottom: solid 1px rgb(0, 0, 0, 12%);
+ padding: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ cursor: pointer;
+}
+
+.contImgClass {
+ border-radius: 3px;
+ margin-right: 16px;
+ height: 48px;
+}
+
+.contDetailClass {
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-content: center;
+}
+
+.contBadgeClass {
+ font-size: 12px;
+ padding: 2px 8px;
+ line-height: 1rem;
+ background-color: gray;
+ color: white;
+ border-radius: 4px;
+}
\ No newline at end of file
diff --git a/Week3/index.html b/Week3/index.html
new file mode 100644
index 000000000..9c8f80c1a
--- /dev/null
+++ b/Week3/index.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HYF-GITHUB
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week3/index.js b/Week3/index.js
new file mode 100644
index 000000000..5d80712f8
--- /dev/null
+++ b/Week3/index.js
@@ -0,0 +1,168 @@
+'use strict';
+
+{
+ function fetchJSON(URL) {
+ return new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', URL);
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status < 400) {
+ resolve(xhr.response);
+ } else {
+ reject(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
+ }
+ };
+ xhr.send();
+ });
+ }
+
+ function createAndAppend(name, parent, options = {}) {
+ const elem = document.createElement(name);
+ parent.appendChild(elem);
+ Object.keys(options).forEach(key => {
+ const value = options[key];
+ if (key === 'text') {
+ elem.textContent = value;
+ } else {
+ elem.setAttribute(key, value);
+ }
+ });
+ return elem;
+ }
+ function loadDetail(element) {
+ const leftID = document.getElementById('leftID');
+ createAndAppend('ul', leftID, { id: 'leftDetailID', class: 'leftDetailClass' });
+
+ const leftDetailID = document.getElementById('leftDetailID');
+ createAndAppend('li', leftDetailID, {
+ id: 'leftListID',
+ class: 'leftListClass',
+ text: 'Repository: ',
+ });
+
+ const leftListID = document.getElementById('leftListID');
+ createAndAppend('a', leftListID, {
+ text: element.name,
+ href: element.html_url,
+ id: 'repositoryNameID',
+ class: 'repositoryNameClass',
+ });
+
+ createAndAppend('li', leftDetailID, {
+ id: 'descList',
+ text: `Description: ${element.description}`,
+ });
+ createAndAppend('li', leftDetailID, { text: `Forks: ${element.forks}` });
+ const updatedAt = new Date(element.updated_at).toLocaleString();
+ createAndAppend('li', leftDetailID, { text: `Updated: ${updatedAt}` });
+ }
+ async function loadContributor(element) {
+ const root = document.getElementById('root');
+ try {
+ const data = await fetchJSON(element.contributors_url);
+ const rightID = document.getElementById('rightID');
+ createAndAppend('p', rightID, { id: 'contTextID', text: 'Contributors' });
+ createAndAppend('ul', rightID, { id: 'contListID', class: 'contListClass' });
+
+ let contURL;
+ let contData;
+ let contDetail;
+ const contListID = document.getElementById('contListID');
+ for (let i = 0; i < data.length; i++) {
+ contURL = createAndAppend('a', contListID, {
+ href: data[i].html_url,
+ target: '_blank',
+ id: 'contUrlID',
+ class: 'contUrlClass',
+ });
+ contData = createAndAppend('li', contURL, {
+ id: 'contDataID',
+ class: 'contDataClass',
+ });
+
+ createAndAppend('img', contData, {
+ src: data[i].avatar_url,
+ id: 'contImgID',
+ class: 'contImgClass',
+ });
+
+ contDetail = createAndAppend('div', contData, {
+ id: 'contDetailID',
+ class: 'contDetailClass',
+ });
+ createAndAppend('div', contDetail, { text: data[i].login });
+ createAndAppend('div', contDetail, {
+ text: data[i].contributions,
+ id: 'contBadgeID',
+ class: 'contBadgeClass',
+ });
+ }
+ } catch (err) {
+ createAndAppend('div', root, {
+ id: 'err.message',
+ class: 'alert-error',
+ });
+ }
+ }
+
+ async function main(url) {
+ const root = document.getElementById('root');
+ try {
+ const data = await fetchJSON(url);
+ createAndAppend('header', root, {
+ id: 'topBoxID',
+ class: 'topBoxClass',
+ });
+ const topBoxID = document.getElementById('topBoxID');
+ createAndAppend('p', topBoxID, {
+ id: 'topTextID',
+ class: 'topTextClass',
+ text: 'HYF Repositories',
+ });
+
+ createAndAppend('div', root, { id: 'mainContainerID', class: 'mainContainerClass' });
+
+ const mainContainerID = document.getElementById('mainContainerID');
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ createAndAppend('select', topBoxID, { id: 'repsSelectID', Class: 'repsSelectClass' });
+ data.sort((a, b) => a.name.localeCompare(b.name));
+
+ const repsSelectID = document.getElementById('repsSelectID');
+ for (let index = 0; index < data.length; index++) {
+ createAndAppend('option', repsSelectID, {
+ value: index,
+ text: data[index].name,
+ id: 'optionID',
+ class: 'optionClass',
+ });
+ }
+ const selector = document.getElementById('repsSelectID');
+
+ loadDetail(data[0]);
+ loadContributor(data[0]);
+
+ selector.onchange = () => {
+ const leftID = document.getElementById('leftID');
+ leftID.parentNode.removeChild(leftID);
+
+ const rightID = document.getElementById('rightID');
+ rightID.parentNode.removeChild(rightID);
+
+ const i = selector.value;
+
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ loadDetail(data[i]);
+ loadContributor(data[i]);
+ };
+ } catch (error) {
+ createAndAppend('div', root, { text: error.message, class: 'alert-error' });
+ }
+ }
+
+ const HYF_REPS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
+
+ window.onload = () => main(HYF_REPS_URL);
+}
diff --git a/Week3/style.css b/Week3/style.css
new file mode 100644
index 000000000..c9040ac64
--- /dev/null
+++ b/Week3/style.css
@@ -0,0 +1,119 @@
+.alert-error {
+ color: #721c24;
+ background-color: #f8d7da;
+}
+
+body {
+ margin-left: auto;
+ margin-right: auto;
+ font-family: Arial, Helvetica, sans-serif;
+ color: black;
+ margin-top: 0;
+ background-color: #f8f8f8;
+ width: 900px;
+}
+
+.mainContainerClass {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+}
+
+@media (max-width: 767px) {
+ body {
+ width: 100%;
+ }
+ #mainContainerClass {
+ margin: 0;
+ flex-direction: column;
+ align-items: stretch;
+ }
+}
+
+.topBoxClass {
+ color: white;
+ background-color: #3f51b5;
+ padding: 8px 16px;
+ margin-bottom: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.topTextClass {
+ margin-left: 40px;
+ font-size: 30px;
+ font-family: 'Trebuchet MS';
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.repsSelectClass {
+ margin-left: 30px;
+ font-size: 18px;
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.leftClass, .rightClass {
+ background-color: white;
+ flex: 1;
+ padding: 16px;
+ margin-right: 16px;
+ margin-bottom: 8px;
+ border: none;
+ border-radius: 2px;
+ background-color: white;
+ box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.2), 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.12)
+}
+
+.leftDetailClass {
+ table-layout: fixed;
+ color: rgb(0, 0, 0, 81%);
+}
+
+@media (max-width: 767px) {
+ .leftClass {
+ margin: 0;
+ }
+}
+
+#contTextID {
+ font-size: 0.9rem;
+ color: rgb(0, 0, 0, 54%);
+ padding: 8px 16px 4px 16px;
+}
+
+.contDataClass {
+ border-bottom: solid 1px rgb(0, 0, 0, 12%);
+ padding: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ cursor: pointer;
+}
+
+.contImgClass {
+ border-radius: 3px;
+ margin-right: 16px;
+ height: 48px;
+}
+
+.contDetailClass {
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-content: center;
+}
+
+.contBadgeClass {
+ font-size: 12px;
+ padding: 2px 8px;
+ line-height: 1rem;
+ background-color: gray;
+ color: white;
+ border-radius: 4px;
+}
\ No newline at end of file
diff --git a/homework/App.js b/homework/App.js
index 32b71e34b..914da3df5 100644
--- a/homework/App.js
+++ b/homework/App.js
@@ -72,6 +72,7 @@ class App {
* @param {Error} error An Error object describing the error.
*/
renderError(error) {
+ // eslint-disable-next-line no-console
console.log(error); // TODO: replace with your own code
}
}
diff --git a/homework/index.js b/homework/index.js
index d3a97645e..5d80712f8 100644
--- a/homework/index.js
+++ b/homework/index.js
@@ -1,19 +1,20 @@
'use strict';
{
- function fetchJSON(url, cb) {
- const xhr = new XMLHttpRequest();
- xhr.open('GET', url);
- xhr.responseType = 'json';
- xhr.onload = () => {
- if (xhr.status < 400) {
- 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 fetchJSON(URL) {
+ return new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', URL);
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status < 400) {
+ resolve(xhr.response);
+ } else {
+ reject(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
+ }
+ };
+ xhr.send();
+ });
}
function createAndAppend(name, parent, options = {}) {
@@ -29,19 +30,139 @@
});
return elem;
}
+ function loadDetail(element) {
+ const leftID = document.getElementById('leftID');
+ createAndAppend('ul', leftID, { id: 'leftDetailID', class: 'leftDetailClass' });
- function main(url) {
- fetchJSON(url, (err, data) => {
- const root = document.getElementById('root');
- if (err) {
- createAndAppend('div', root, { text: err.message, class: 'alert-error' });
- } else {
- createAndAppend('pre', root, { text: JSON.stringify(data, null, 2) });
- }
+ const leftDetailID = document.getElementById('leftDetailID');
+ createAndAppend('li', leftDetailID, {
+ id: 'leftListID',
+ class: 'leftListClass',
+ text: 'Repository: ',
+ });
+
+ const leftListID = document.getElementById('leftListID');
+ createAndAppend('a', leftListID, {
+ text: element.name,
+ href: element.html_url,
+ id: 'repositoryNameID',
+ class: 'repositoryNameClass',
});
+
+ createAndAppend('li', leftDetailID, {
+ id: 'descList',
+ text: `Description: ${element.description}`,
+ });
+ createAndAppend('li', leftDetailID, { text: `Forks: ${element.forks}` });
+ const updatedAt = new Date(element.updated_at).toLocaleString();
+ createAndAppend('li', leftDetailID, { text: `Updated: ${updatedAt}` });
+ }
+ async function loadContributor(element) {
+ const root = document.getElementById('root');
+ try {
+ const data = await fetchJSON(element.contributors_url);
+ const rightID = document.getElementById('rightID');
+ createAndAppend('p', rightID, { id: 'contTextID', text: 'Contributors' });
+ createAndAppend('ul', rightID, { id: 'contListID', class: 'contListClass' });
+
+ let contURL;
+ let contData;
+ let contDetail;
+ const contListID = document.getElementById('contListID');
+ for (let i = 0; i < data.length; i++) {
+ contURL = createAndAppend('a', contListID, {
+ href: data[i].html_url,
+ target: '_blank',
+ id: 'contUrlID',
+ class: 'contUrlClass',
+ });
+ contData = createAndAppend('li', contURL, {
+ id: 'contDataID',
+ class: 'contDataClass',
+ });
+
+ createAndAppend('img', contData, {
+ src: data[i].avatar_url,
+ id: 'contImgID',
+ class: 'contImgClass',
+ });
+
+ contDetail = createAndAppend('div', contData, {
+ id: 'contDetailID',
+ class: 'contDetailClass',
+ });
+ createAndAppend('div', contDetail, { text: data[i].login });
+ createAndAppend('div', contDetail, {
+ text: data[i].contributions,
+ id: 'contBadgeID',
+ class: 'contBadgeClass',
+ });
+ }
+ } catch (err) {
+ createAndAppend('div', root, {
+ id: 'err.message',
+ class: 'alert-error',
+ });
+ }
+ }
+
+ async function main(url) {
+ const root = document.getElementById('root');
+ try {
+ const data = await fetchJSON(url);
+ createAndAppend('header', root, {
+ id: 'topBoxID',
+ class: 'topBoxClass',
+ });
+ const topBoxID = document.getElementById('topBoxID');
+ createAndAppend('p', topBoxID, {
+ id: 'topTextID',
+ class: 'topTextClass',
+ text: 'HYF Repositories',
+ });
+
+ createAndAppend('div', root, { id: 'mainContainerID', class: 'mainContainerClass' });
+
+ const mainContainerID = document.getElementById('mainContainerID');
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ createAndAppend('select', topBoxID, { id: 'repsSelectID', Class: 'repsSelectClass' });
+ data.sort((a, b) => a.name.localeCompare(b.name));
+
+ const repsSelectID = document.getElementById('repsSelectID');
+ for (let index = 0; index < data.length; index++) {
+ createAndAppend('option', repsSelectID, {
+ value: index,
+ text: data[index].name,
+ id: 'optionID',
+ class: 'optionClass',
+ });
+ }
+ const selector = document.getElementById('repsSelectID');
+
+ loadDetail(data[0]);
+ loadContributor(data[0]);
+
+ selector.onchange = () => {
+ const leftID = document.getElementById('leftID');
+ leftID.parentNode.removeChild(leftID);
+
+ const rightID = document.getElementById('rightID');
+ rightID.parentNode.removeChild(rightID);
+
+ const i = selector.value;
+
+ createAndAppend('div', mainContainerID, { id: 'leftID', class: 'leftClass' });
+ createAndAppend('div', mainContainerID, { id: 'rightID', class: 'rightClass' });
+ loadDetail(data[i]);
+ loadContributor(data[i]);
+ };
+ } catch (error) {
+ createAndAppend('div', root, { text: error.message, class: 'alert-error' });
+ }
}
- const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
+ const HYF_REPS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
- window.onload = () => main(HYF_REPOS_URL);
+ window.onload = () => main(HYF_REPS_URL);
}
diff --git a/homework/style.css b/homework/style.css
index a8985a8a5..c9040ac64 100644
--- a/homework/style.css
+++ b/homework/style.css
@@ -1,3 +1,119 @@
.alert-error {
- color: red;
+ color: #721c24;
+ background-color: #f8d7da;
+}
+
+body {
+ margin-left: auto;
+ margin-right: auto;
+ font-family: Arial, Helvetica, sans-serif;
+ color: black;
+ margin-top: 0;
+ background-color: #f8f8f8;
+ width: 900px;
+}
+
+.mainContainerClass {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+}
+
+@media (max-width: 767px) {
+ body {
+ width: 100%;
+ }
+ #mainContainerClass {
+ margin: 0;
+ flex-direction: column;
+ align-items: stretch;
+ }
+}
+
+.topBoxClass {
+ color: white;
+ background-color: #3f51b5;
+ padding: 8px 16px;
+ margin-bottom: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.topTextClass {
+ margin-left: 40px;
+ font-size: 30px;
+ font-family: 'Trebuchet MS';
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.repsSelectClass {
+ margin-left: 30px;
+ font-size: 18px;
+ width: 350px;
+ height: 32px;
+ padding: 2px;
+}
+
+.leftClass, .rightClass {
+ background-color: white;
+ flex: 1;
+ padding: 16px;
+ margin-right: 16px;
+ margin-bottom: 8px;
+ border: none;
+ border-radius: 2px;
+ background-color: white;
+ box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.2), 0 3px 4px 0 rgba(0, 0, 0, 0.14), 0 3px 3px -2px rgba(0, 0, 0, 0.12)
+}
+
+.leftDetailClass {
+ table-layout: fixed;
+ color: rgb(0, 0, 0, 81%);
+}
+
+@media (max-width: 767px) {
+ .leftClass {
+ margin: 0;
+ }
+}
+
+#contTextID {
+ font-size: 0.9rem;
+ color: rgb(0, 0, 0, 54%);
+ padding: 8px 16px 4px 16px;
+}
+
+.contDataClass {
+ border-bottom: solid 1px rgb(0, 0, 0, 12%);
+ padding: 16px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ cursor: pointer;
+}
+
+.contImgClass {
+ border-radius: 3px;
+ margin-right: 16px;
+ height: 48px;
+}
+
+.contDetailClass {
+ flex: 1;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-content: center;
+}
+
+.contBadgeClass {
+ font-size: 12px;
+ padding: 2px 8px;
+ line-height: 1rem;
+ background-color: gray;
+ color: white;
+ border-radius: 4px;
}
\ No newline at end of file