diff --git a/.gitignore b/.gitignore index b512c09..34977ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +.idea \ No newline at end of file diff --git a/src/assets/js-heroes-bear.png b/src/assets/js-heroes-bear.png new file mode 100644 index 0000000..0a21525 Binary files /dev/null and b/src/assets/js-heroes-bear.png differ diff --git a/src/index.html b/src/index.html index b6f9767..548ce7f 100644 --- a/src/index.html +++ b/src/index.html @@ -1,21 +1,60 @@ - - - + + + JSHeroes Bootcamp + + + +
-

Welcome to the JSHeroes Bootcamp!

+
+

Welcome to the JSHeroes Bootcamp!

+
+
-
- +
+
+
+ + +
+
+
+

Repositories

+ + +
    + +
    - - \ No newline at end of file + diff --git a/src/script.js b/src/script.js index 956632b..d6c102c 100644 --- a/src/script.js +++ b/src/script.js @@ -1,23 +1,75 @@ -// TODO: Add some sample repositories as a static array +const repoCardTemplate = document.querySelector("[data-repo-template]"); +const repoCardContainer = document.querySelector("[data-repo-cards-container]"); +const searchInput = document.querySelector("[data-search]"); +const loadingText = document.querySelector("[data-loading]") +const searchButton = document.getElementById('search-repos-btn') -function createRepositoryCard() { - // Implement string template HTML builder for repo card -} -function renderRepositories() { - // Implement DOM manipulation function to add list items in the repo list +// form submission +searchButton.addEventListener("click", async (event) => { + event.preventDefault() + const searchValue = searchInput.value; + + if (!searchValue) { + alert("Please type something") + return; + } + + clearRepos() + await fetchRepos(searchValue) + +}); + +// fetch initial repos when clearing the input +searchInput.addEventListener('input', async (event) => { + const searchValue = event.target.value; + + if (!searchValue) { + clearRepos() + await fetchRepos() + } +}) + +function clearRepos() { + // loadingText.classList.remove('hide') + repoCardContainer.textContent = null; } -// Comment this out when you start working on the search functionality -renderRepositories(); +// we can commented these out, if we use :empty +// function hideLoadingMessage() { +// loadingText.classList.add('hide'); +// } -function handleSearch() { - // Implement form submit event handler +function renderRepositories(repository) { + // get the content inside the template / card + const card = repoCardTemplate.content.cloneNode(true).children[0]; + + const header = card.querySelector('[data-header]'); + const description = card.querySelector('[data-description]'); + const stars = card.querySelector('[data-stars]'); + const forks = card.querySelector('[data-forks]'); + + header.textContent = repository.full_name; + description.textContent = repository.description; + stars.textContent = `Stars: ${repository.stargazers_count}`; + forks.textContent = `Forks: ${repository.forks}`; + + repoCardContainer.append(card) } -async function fetchRepositories() { - // Pass parameter to the search endpoint - return fetch("https://api.github.com/legacy/repos/search/") - .then((res) => res.json()) - .then((res) => res.repositories); +function fetchRepos(searchParam = '') { + const API_URL = `https://api.github.com/search/repositories${searchParam ? '?q=' + searchParam : '?q=stars:>10000'}`; + + return fetch(API_URL) + .then((response) => response.json()) + .then(data => { + // hideLoadingMessage(); + + data.items.map((repo) => { + return renderRepositories(repo) + }) + }) } + +fetchRepos(); + diff --git a/src/style.css b/src/style.css index 3039c87..405f3f4 100644 --- a/src/style.css +++ b/src/style.css @@ -1,10 +1,247 @@ -body { +/* Reset https://www.joshwcomeau.com/css/custom-css-reset/ */ + +/* + 1. Use a more-intuitive box-sizing model. +*/ +*, +*::before, +*::after { + box-sizing: border-box; +} +/* + 2. Remove default margin +*/ +* { margin: 0; - font-family: system-ui, sans-serif; +} +/* + 3. Allow percentage-based heights in the application +*/ +html, +body { + height: 100%; +} +/* + Typographic tweaks! + 4. Add accessible line-height + 5. Improve text rendering +*/ +body { + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} +/* + 6. Improve media defaults +*/ +img, +picture, +video, +canvas, +svg { + display: block; + max-width: 100%; +} +/* + 7. Remove built-in form typography styles +*/ +input, +button, +textarea, +select { + font: inherit; +} +/* + 8. Avoid text overflows +*/ +p, +h1, +h2, +h3, +h4, +h5, +h6 { + overflow-wrap: break-word; } -ul { - list-style: none; - margin: 0; +/* color variables */ +:root { + --color-primary: #0b1b44; + --color-background: #fff; + --color-border: #bbb; + --color-text: #202022; + --color-accent: #0098ff; + --color-accent-hover: #0b1b44; + + --font-family-base: system-ui, sans-serif; + --font-family-display: "Ubuntu", sans-serif; + + --drop-shadow: 0 2px 8px 1px rgba(18, 18, 18, 0.3); + --animation-fade: all 0.1s ease-out; +} + +body { + font-family: var(--font-family-base); + color: var(--color-text); +} + +h1 { + font-size: 1.67rem; + font-family: var(--font-family-display); +} + +header { + background: var(--color-primary); + color: var(--color-background); + position: relative; +} + +.content-wrapper { + max-width: 75rem; + margin-inline: auto; + padding: 3rem 2rem; + position: relative; + z-index: 1; +} + +.bear { + position: absolute; + top: 0; + left: 0; + height: 100%; +} + +@media (max-width: 1400px) { + .bear { + left: auto; + right: 0; + transform: scaleX(-1); + } +} + +/* Search form component styles */ + +.search-form { + display: flex; + margin-bottom: 3rem; +} + +.input { + border-radius: 8px 0 0 8px; + border: 1px solid var(--color-border); + border-right: 0; + font-size: 1.2rem; + padding: 1rem 2rem; + flex: 1 1 auto; + transition: var(--animation-fade); + min-width: 8rem; +} + +.input:focus { + border-radius: 0; + outline: none; + border-color: var(--color-accent); +} + +.button { + border: 0; + font-size: 1.2rem; + font-family: var(--font-family-display); + appearance: none; + background: var(--color-accent); + color: var(--color-background); + padding: 1rem 2rem; + border-radius: 0 8px 8px 0; + height: 4rem; + transition: var(--animation-fade); +} + +.button:hover { + background: var(--color-accent-hover); + border-radius: 0; +} + +/* Repo card component styles */ +.repo-cards { + padding: 0; + display: grid; + gap: 1rem; + grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); +} + +.repo-cards:empty::before { + display: block; + content: "Loading..."; + width: 100%; + text-align: center; +} + +.repo-card { + display: block; + border: 1px solid var(--color-border); + transition: var(--animation-fade); + padding: 1rem 1.5rem; + border-radius: 8px; +} + +.repo-card:hover { + box-shadow: var(--drop-shadow); + /* + border-left: 4px solid var(--color-accent); + padding-left: 1rem; + */ + /* maintain size of content/ move without text reflow */ + background: linear-gradient( + 90deg, + var(--color-accent) 0, + var(--color-accent) 4px, + transparent 5px + ); + transform: scale(1.025); +} + +.title { + display: block; + font-family: var(--font-family-display); + font-weight: 700; + font-size: 1.2rem; + margin-bottom: 0.5rem; +} + +.description { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.footer { + display: flex; + align-items: center; + gap: 1rem; + margin-top: 0.5rem; +} + +/* utility classes */ + +/* i would prefix them with u- + we would heve to do that in the js */ +.hide { + display: none; +} + +.show { + display: block; +} + +.u-screen-reader-text { + border: 0; + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(50%); + height: 1px; + margin: -1px; + overflow: hidden; padding: 0; + position: absolute !important; + width: 1px; + word-wrap: normal !important; }