diff --git a/README.md b/README.md index 1613a3b0..96c65513 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ # GitHub Tracker -Replace this readme with your own information about your project. - -Start by briefly describing the assignment in a sentence or two. Keep it short and to the point. +They assignment was to make a Github tracker with information fetched from githubs apis. ## The problem -Describe how you approached to problem, and what tools and techniques you used to solve it. How did you plan? What technologies did you use? If you had more time, what would be next? +Initially I didnt split up the fetch and the actual rendering of the content on my site. After doing a couple of functions I realised that it would probably be a better solution to split the fetching of the data and the rendering up into different functions. ## View it live -Every project should be deployed somewhere. Be sure to include the link to the deployed project so that the viewer can click around and see what it's all about. +https://zancotti-githubtracker.netlify.app/ diff --git a/code/chart.js b/code/chart.js index 92e85a30..e2a2f133 100644 --- a/code/chart.js +++ b/code/chart.js @@ -1,4 +1,22 @@ -//DOM-selector for the canvas 👇 -const ctx = document.getElementById('chart').getContext('2d') +const renderChart = (finishedProjects) => { + //DOM-selector + const ctx = document.getElementById("chart").getContext("2d"); -//"Draw" the chart here 👇 + //Chart + const config = { + type: "pie", + data: { + labels: ["Finished projects", "Projects left"], + datasets: [ + { + label: "My First Dataset", + data: [finishedProjects, 19 - finishedProjects], + backgroundColor: ["rgb(0,250,154,0.20)", "rgb(228, 228, 228)"], + hoverOffset: 4, + }, + ], + }, + }; + + const myChart = new Chart(ctx, config); +}; diff --git a/code/index.html b/code/index.html index 2fb5e0ae..9da7519f 100644 --- a/code/index.html +++ b/code/index.html @@ -1,21 +1,47 @@ - - - - - Project GitHub Tracker - - - -

GitHub Tracker

-

Projects:

-
+ + + + + Project GitHub Tracker + + + + - - - - - - - \ No newline at end of file + +
+ +
+
+
Projects at Technigo:
+
+
+ +
+
+ + + + diff --git a/code/script.js b/code/script.js index e69de29b..4831aa0b 100644 --- a/code/script.js +++ b/code/script.js @@ -0,0 +1,262 @@ +//Global variables +let username = "Zancotti"; +let filteredRepos = []; +let global__UserData, global__ReposData; + +// ------------Functions-------------------- + +// Function in which I toggleMenu to to put on an active class for the commits accordion. +const toggleMenu = (menuName) => { + let menu = document.getElementById(`${menuName}-menu`); + menu.classList.toggle( + "projects__commit-pulls-container__commits-accordion__active" + ); +}; + +// Function in which I toggleMenu to to put on an active class for the comments accordion. +const toggleMenuComments = (menuName) => { + let menu = document.getElementById(`${menuName}-comments-menu`); + menu.classList.toggle( + "projects__commit-comments-container__comments-accordion__active" + ); +}; + +// a filter function to function out repos depending on the language of them. +const filter = (type) => { + if (type === `js`) { + const projects = document.getElementsByClassName(`projects__HTML`); + + Array.from(projects).forEach((project) => { + project.style.display = "none"; + }); + } else if (type === `html`) { + const projects = document.getElementsByClassName(`projects__JavaScript`); + + Array.from(projects).forEach((project) => { + project.style.display = "none"; + }); + } else { + const projects = document.getElementsByClassName( + `projects__repo-container` + ); + Array.from(projects).forEach((project) => { + project.style.display = "flex"; + }); + } +}; + +// A function to make the first character in a string into a capital letter. +const toCapitalLetter = (str) => { + return str.charAt(0).toUpperCase() + str.slice(1); +}; + +//Function in which I fetch data from the json and save the data from the json into a global variable. +const getUsernameAndPicture = () => { + const usernamePictureAndBioApi = `https://api.github.com/users/${username}`; + fetch(usernamePictureAndBioApi) + .then((res) => res.json()) + .then((data) => { + global__UserData = data; + }) + .then(() => renderUsernameAndPicture()); +}; + +// Function in which i render the information based on the data that i saved to the global variable. +const renderUsernameAndPicture = () => { + const pictureOfUser = global__UserData.avatar_url; + const userBio = global__UserData.bio; + + userInformation.innerHTML += ` + Picture of gitHub-user +
+
${username}
+
${userBio}
+
`; +}; + +// Function in which I fetch the repository data and save it into a global variable. I also after the data has been fetched +// call for the functions renderrepos, get commits and getpullrequests. +const getRepos = () => { + const myReposApi = `https://api.github.com/users/${username}/repos`; + fetch(myReposApi) + .then((res) => res.json()) + .then((data) => { + global__ReposData = data; + }) + .then(() => renderRepos()) + .then(() => getCommits()) + .then(() => getPullRequests()); +}; + +// Function in which I filter the repodata. +const renderRepos = () => { + global__ReposData.forEach((e) => { + if (e.fork === true && e.name.includes(`project`)) { + filteredRepos.push(e); + } + }); + + renderChart(filteredRepos.length - 1); + + // I sort the filtered repoList after creation dates and then reverse it. + filteredRepos.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); + filteredRepos = filteredRepos.reverse(); + + // ForEach function over filteredRepos which picks up repoName, default branch, html Url and repoLanguage. + filteredRepos.forEach((e) => { + const repoName = e.name; + const repoNameDisplay = toCapitalLetter(repoName); + const repoDefaultBranch = e.default_branch; + const htmlUrl = e.html_url; + let repoLanguage = e.language; + + if (repoLanguage === null) { + repoLanguage = ""; + } + + // change the inner html and put the id of the projects__repo-container to the repoName. And make content with the values which we saved. + projects.innerHTML += ` +
+
+
+
${repoNameDisplay} ${repoDefaultBranch}
+ +
Programming language: ${repoLanguage}
+
+
+
+
+
+
`; + }); +}; + +// function that fetches the commits from the repo data and saved the data unto a global variable. It also sends data through to the new function +// renderCommits. +const getCommits = () => { + filteredRepos.forEach((repo) => { + const repoName = repo.name; + const commitsUrl = repo.commits_url.slice(0, -6); + + fetch(commitsUrl) + .then((res) => res.json()) + .then((data) => { + return data; + }) + .then((data) => renderCommits(data, repoName)); + }); +}; + +// A function which filter the amount of commits into just counting the ones that I have made in my name. +const renderCommits = (data, repoName) => { + const commitMessage = toCapitalLetter(data[0].commit.message); + const amountOfCommits = data.filter( + (element) => element.author && element.author.login === username + ).length; + + // Set the containerToChange into the dynamic reponame-commit-pulls-container and then switch the inner html of that container. + let containerToChange = document.getElementById( + `${repoName}-commit-pulls-container` + ); + + containerToChange.innerHTML += ` +
${commitMessage} + +
`; + + // Change the innerhtml of to registrer amount of commits on the website. + const amountCommitmessages = document.getElementById( + `${repoName}-amountCommitmessages` + ); + amountCommitmessages.innerHTML += `${amountOfCommits}`; + + let menu = document.getElementById(`${repoName}-menu`); + // I slice,filter and make a foreach and then change the innerhtml of menu (the commit message accordion) + data + .slice(1) + .filter((element) => element.author && element.author.login === username) + .forEach((element) => { + menu.innerHTML += `
  • ${toCapitalLetter( + element.commit.message + )}
  • `; + }); +}; + +// function that for each repo set default branch and repo name and then fetch the pullrequests. +const getPullRequests = () => { + filteredRepos.forEach((repo) => { + const repoDefaultBranch = repo.default_branch; + const repoName = repo.name; + + finishedProjects = filteredRepos.length - 1; + + // add reponame username and repodefault branch to the api to get into the right api adress depending on repo. + const pullRequestsApi = `https://api.github.com/repos/technigo/${repoName}/pulls?head=${username}:${repoDefaultBranch}`; + + fetch(pullRequestsApi) + .then((res) => res.json()) + .then((data) => { + return data; + }) + .then((data) => { + renderPullRequest(data, repoName); + return data; + }) + .then((data) => getCommentsOnPullRequest(data, repoName)); + }); +}; + +// Function that renderPullrequest and changes the innerhtml of the dynamic containerToChange. +const renderPullRequest = (data, repoName) => { + if (data.length > 0) { + const prTitle = data[0].title; + const prUrl = data[0].html_url; + let containerToChange = document.getElementById( + `${repoName}-commit-pulls-container` + ); + containerToChange.innerHTML += `
    Pull request:
    ${prTitle}
    `; + } else { + let containerToChange = document.getElementById( + `${repoName}-commit-pulls-container` + ); + containerToChange.innerHTML += `
    No pull request made
    `; + } +}; + +// function that fetches the comments of the PR and then wait for the data and sends it through to the renderCommentsOnPullRequest function. +const getCommentsOnPullRequest = (data, repoName) => { + if (data.length > 0) { + const commentsOnPrApi = data[0].review_comments_url; + + fetch(commentsOnPrApi) + .then((res) => res.json()) + .then((data) => { + return data; + }) + .then((data) => renderCommentsOnPullRequest(data, repoName)); + } +}; + +// Function that renders the information on the of the container to change and pick up the information through a foreach. +const renderCommentsOnPullRequest = (data, repoName) => { + const containerToChange = document.getElementById( + `${repoName}-commit-comments-container` + ); + + containerToChange.innerHTML += ` +
    Show all PR comments: + +
    `; + + const commentsContainer = document.getElementById( + `${repoName}-comments-menu` + ); + + data.forEach((comment) => { + commentsContainer.innerHTML += `
  • ${comment.user.login}: ${comment.body}
  • `; + }); +}; + +// Start the website by calling these functions. +getUsernameAndPicture(); +getRepos(); diff --git a/code/style.css b/code/style.css index 7c8ad447..2cb939d5 100644 --- a/code/style.css +++ b/code/style.css @@ -1,3 +1,330 @@ +@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"); + body { - background: #FFECE9; -} \ No newline at end of file + background: rgb(246, 248, 250); + margin: 0; + padding: 0; + font-family: "Roboto", sans-serif; + box-sizing: border-box; + min-width: 325px; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +/* ------------------------- Navbar container------------------------*/ + +.navbar__container { + display: grid; + grid-template-columns: 1fr auto auto auto; + column-gap: 10px; + padding: 10px 20px; + align-items: center; + color: white; + background-color: rgb(14, 16, 18, 0.8); + position: fixed; + top: 0; + width: 100%; + height: 60px; +} + +.icon { + margin-right: auto; + font-size: 18px; +} + +.icon:hover { + cursor: pointer; +} + +h1 { + font-size: 18px; + font-weight: 100; + margin: 0; +} + +/* ---------------------- User information-content-----------------------*/ + +.user-information { + display: flex; + margin-top: 64px; + padding: 20px 20px 0 20px; + justify-content: center; +} + +.user-information__picture { + border-radius: 50%; + width: 30%; + height: 30%; +} + +.user-information__username-bio-container { + padding-left: 20px; +} + +.user-information__username-bio-container__username { + font-size: 40px; + font-weight: 200; +} + +.user-information__username-bio-container__bio { + font-size: 16px; +} + +/* ------------------------- Main projects section------------------------*/ + +.projects { + display: flex; + flex-direction: column; + padding: 0 20px 20px 20px; +} + +.projects__title { + font-size: 1.25em; + font-weight: bold; + margin: 1em 0; +} + +.projects__repo-container { + display: flex; + flex-direction: column; + border: 1px solid lightgrey; + border-radius: 10px; + margin-bottom: 10px; + padding: 0 0 10px 0; +} + +.projects__repo-container__header { + display: flex; + flex-direction: row; + background-color: rgb(228, 228, 228); + border-radius: 10px 10px 0 0; + padding: 5px 10px; + order: 1; +} + +.projects__repo-container__header__flex-box { + width: 100%; +} + +.projects__repo-container__header__flex-box__repo-name { + font-weight: 500; + margin: 4px 0; +} + +.projects__repo-container__header__flex-box__html-url { + text-decoration: none; + margin: 4px 0; + font-size: 15px; +} + +.projects__repo-container__header__flex-box__html-url a { + text-decoration: none; + margin: 4px 0; + font-size: 15px; + cursor: pointer; + color: #218bff; +} + +.projects__repo-container__header__amount-commitmessages { + display: flex; + align-self: center; + justify-content: center; + padding: 10px; + border-radius: 50%; + border: 1px solid lightgrey; + min-width: 40px; + background-color: rgb(0, 250, 154, 0.2); +} + +.projects__commit-pulls-container { + display: flex; + flex-direction: column; + order: 2; + padding: 0px 6px; +} + +/*-----------------------Commits Accordion----------------------------*/ + +.projects__commit-pulls-container__commits-accordion { + padding: 5px 10px; + background-color: rgb(0, 250, 154, 0.2); + border: 1px solid lightgrey; + border-radius: 10px; + order: 1; + margin: 4px 0 0 0; + cursor: pointer; +} + +.projects__commit-pulls-container__commits-accordion__menu { + order: 2; + flex-direction: column; + row-gap: 6px; + min-width: 250px; + max-height: 0px; + margin: 0; + overflow: hidden; + list-style-position: outside; +} + +.projects__commit-pulls-container__commits-accordion__active { + display: flex; + max-height: 2000px; + transition: max-height 400ms ease-in-out; +} + +.option { + padding: 10px 0px; +} + +.projects__commit-pulls-container__pull-request { + padding: 5px 5px; + order: 2; +} + +.projects__commit-pulls-container__pull-request a { + text-decoration: none; + color: #218bff; +} + +.projects__commit-comments-container { + padding: 0px 6px; + border-radius: 10px; + order: 3; + cursor: pointer; +} + +/*-----------------------Comments Accordion----------------------------*/ + +.projects__commit-comments-container__comments-accordion { + padding: 5px 10px; + background-color: rgba(0, 137, 250, 0.2); + border: 1px solid lightgrey; + border-radius: 10px; + order: 1; + margin: 4px 0 0 0; + cursor: pointer; +} + +.projects__commit-comments-container__comments-accordion__menu { + order: 2; + flex-direction: column; + row-gap: 6px; + min-width: 250px; + max-height: 0px; + margin: 0; + overflow: hidden; + list-style-position: outside; +} + +.projects__commit-comments-container__comments-accordion__active { + display: flex; + max-height: 2000px; + transition: max-height 400ms ease-in-out; +} + +/* ------------------------- Chart container------------------------*/ + +.chart { + margin: auto; + width: 80%; + margin-bottom: 40px; +} + +/* ------------------------- iPad Alterations------------------------*/ + +@media (min-width: 668px) and (max-width: 1024px) { + .user-information { + margin-top: 100px; + justify-content: center; + } + + .user-information__username-bio-container { + display: flex; + flex-direction: column; + justify-content: center; + } + + .user-information__username-bio-container__username { + font-size: 60px; + } + + .user-information__username-bio-container__bio { + font-size: 20px; + } + + .projects__commit-pulls-container { + flex-direction: row; + } + + .projects__commit-pulls-container__commits-accordion { + width: 50%; + } + + .projects__commit-pulls-container__pull-request { + width: 50%; + } + + .chart { + width: 50%; + } +} + +/* ------------------------- Desktop Alterations------------------------*/ + +@media (min-width: 1025px) { + body { + display: flex; + flex-direction: column; + align-items: center; + } + .navbar__container { + max-width: 1024px; + } + + .wrapper { + max-width: 1024px; + display: flex; + flex-direction: column; + margin: 0; + } + + .user-information { + display: flex; + flex-direction: row; + margin-top: 100px; + justify-content: center; + } + + .user-information__username-bio-container { + display: flex; + flex-direction: column; + justify-content: center; + } + + .user-information__username-bio-container__username { + font-size: 60px; + } + + .user-information__username-bio-container__bio { + font-size: 20px; + } + + .projects__commit-pulls-container { + flex-direction: row; + } + + .projects__commit-pulls-container__commits-accordion { + width: 50%; + } + + .projects__commit-pulls-container__pull-request { + width: 50%; + } + .chart { + width: 50%; + } +}