From 6d8c2859541d87fb793b99f6b6c9d72b818d14e6 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 3 Jan 2025 12:42:36 +0000 Subject: [PATCH 1/8] complete level 100 1. All episodes must be shown 2. For each episode, _at least_ following must be displayed: 1. The name of the episode 2. The season number 3. The episode number 4. The medium-sized image for the episode 5. The summary text of the episode 3. Combine season number and episode number into an **episode code**: 1. Each part should be zero-padded to two digits. 2. Example: `S02E07` would be the code for the 7th episode of the 2nd season. `S2E7` would be incorrect. 4. Link back to TV Maze. See [tvmaze.com/api#licensing](https://www.tvmaze.com/api#licensing). --- index.html | 30 +++++++++++++++++++--- script.js | 60 +++++++++++++++++++++++++++++++++++++++---- style.css | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 154 insertions(+), 10 deletions(-) diff --git a/index.html b/index.html index 9a400d1..ec0cb9c 100644 --- a/index.html +++ b/index.html @@ -3,14 +3,38 @@ - TV Show Project | My Name (My GitHub username) + TV Show Project | SallyMcGrath -
-
+
+

TV Show Project

+

By Sample Solution

+
+
+ + + diff --git a/script.js b/script.js index 87a7de8..0e68a36 100644 --- a/script.js +++ b/script.js @@ -1,12 +1,62 @@ //You can edit ALL of the code here function setup() { const allEpisodes = getAllEpisodes(); - makePageForEpisodes(allEpisodes); + const root = document.getElementById("root"); + /* JSDoc + * @param {object[]} allEpisodes - The episodes + * @param {Element} root - The root element + */ + const episodeCards = allEpisodes.map((episode) => + episodeCard("episode-template", episode) + ); + /* JSDoc + * @param {Element[]} episodeCards - The episode cards + */ + episodeCards.forEach((card) => { + root.appendChild(card); + }); } +/* JSDoc + * @param {string} template - The template to clone + * @param {object} episode - The episode object + * @returns {Element} - The card element + */ +const episodeCard = ( + template, + {id, image: {medium}, name, summary, season, number} +) => { + const card = document.getElementById(template).content.cloneNode(true); + card.querySelector('[data-episode="title"]').textContent = name; + card.querySelector('[data-episode="code"]').textContent = makeEpisodeCode( + season, + number + ); + card.querySelector('[data-episode="summary"]').textContent = + parseFromAPI(summary).body.textContent; + card.querySelector('[data-episode="image"]').src = medium; -function makePageForEpisodes(episodeList) { - const rootElem = document.getElementById("root"); - rootElem.textContent = `Got ${episodeList.length} episode(s)`; -} + return card; +}; + +/* JSDoc + * @param {number} number - The number to pad + * @returns {string} - The padded number + */ +const pad = (number) => number.toString().padStart(2, "0"); + +/* JSDoc + * @param {number} season - The season number + * @param {number} episode - The episode number + * @returns {string} - The episode code + */ +const makeEpisodeCode = (season, episode) => `S${pad(season)}E${pad(episode)}`; +/* JSDoc + * @param {string} html - The HTML to parse + * @returns {Document} - The parsed HTML + */ +const parseFromAPI = (html) => { + const parser = new DOMParser(); + return parser.parseFromString(html, "text/html"); +}; window.onload = setup; diff --git a/style.css b/style.css index 77cb8d4..2d00be2 100644 --- a/style.css +++ b/style.css @@ -1,3 +1,73 @@ -#root { - color: red; +/* Design palette */ +:root { + --font: ui-sans-serif, system-ui, sans-serif; + --paper: hsla(275, 100%, 95%, 0.985); + --ink: hsla(257, 61%, 9%, 0.85); + --spacing-s: 4px; + --spacing-m: 8px; + --spacing-l: 24px; + --container: 1280px; + --box: 410px; +} +/* Base element styles */ +html { + margin: 0; + background: linear-gradient(var(--ink), var(--paper), var(--ink), var(--ink)); +} +body { + font-family: var(--font); + background: linear-gradient(var(--ink), var(--ink), var(--ink), transparent); + color: var(--paper); + margin: 0; + padding: var(--spacing-l); +} + +a:any-link { + color: currentColor; +} + +img { + width: 100%; + object-fit: cover; + aspect-ratio: 16/9; +} + +h1 { + font-size: 3rem; +} +/* Whole Page Layout */ +.container { + max-width: var(--container); + margin: auto; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(auto, var(--box))); + gap: calc(var(--spacing-l) * 2) var(--spacing-l); + justify-content: center; +} +/* Card component */ +.card { + display: grid; + grid-template: + "image image image image" 140px + ". title code ......" auto + ". summary summary ." 1fr + ". ....... ....... ." var(--spacing-l) + / var(--spacing-l) 1fr min-content var(--spacing-l); + border: 1px solid var(--ink); + box-shadow: var(--spacing-s) var(--spacing-s) var(--spacing-l) var(--ink); +} +.card__title { + grid-area: title; +} +.card__code { + grid-area: code; +} +.card__summary { + grid-area: summary; +} +.card__image { + grid-area: image; } From 5d46eb0ea6a5e705f001377445032361e501f9ae Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 3 Jan 2025 15:37:48 +0000 Subject: [PATCH 2/8] add new templates --- index.html | 63 +++++++++++++++++++++++++++++++++++------------------- script.js | 62 ----------------------------------------------------- style.css | 23 +++++++++++++------- 3 files changed, 56 insertions(+), 92 deletions(-) delete mode 100644 script.js diff --git a/index.html b/index.html index ec0cb9c..e277408 100644 --- a/index.html +++ b/index.html @@ -11,35 +11,54 @@

TV Show Project

-

By Sample Solution

+

Sample Solution

+
+ + + +
-
- - +
+
+ +
- + - + diff --git a/script.js b/script.js deleted file mode 100644 index 0e68a36..0000000 --- a/script.js +++ /dev/null @@ -1,62 +0,0 @@ -//You can edit ALL of the code here -function setup() { - const allEpisodes = getAllEpisodes(); - const root = document.getElementById("root"); - /* JSDoc - * @param {object[]} allEpisodes - The episodes - * @param {Element} root - The root element - */ - const episodeCards = allEpisodes.map((episode) => - episodeCard("episode-template", episode) - ); - /* JSDoc - * @param {Element[]} episodeCards - The episode cards - */ - episodeCards.forEach((card) => { - root.appendChild(card); - }); -} -/* JSDoc - * @param {string} template - The template to clone - * @param {object} episode - The episode object - * @returns {Element} - The card element - */ -const episodeCard = ( - template, - {id, image: {medium}, name, summary, season, number} -) => { - const card = document.getElementById(template).content.cloneNode(true); - card.querySelector('[data-episode="title"]').textContent = name; - card.querySelector('[data-episode="code"]').textContent = makeEpisodeCode( - season, - number - ); - card.querySelector('[data-episode="summary"]').textContent = - parseFromAPI(summary).body.textContent; - card.querySelector('[data-episode="image"]').src = medium; - - return card; -}; - -/* JSDoc - * @param {number} number - The number to pad - * @returns {string} - The padded number - */ -const pad = (number) => number.toString().padStart(2, "0"); - -/* JSDoc - * @param {number} season - The season number - * @param {number} episode - The episode number - * @returns {string} - The episode code - */ -const makeEpisodeCode = (season, episode) => `S${pad(season)}E${pad(episode)}`; -/* JSDoc - * @param {string} html - The HTML to parse - * @returns {Document} - The parsed HTML - */ -const parseFromAPI = (html) => { - const parser = new DOMParser(); - return parser.parseFromString(html, "text/html"); -}; - -window.onload = setup; diff --git a/style.css b/style.css index 2d00be2..7313cd6 100644 --- a/style.css +++ b/style.css @@ -35,6 +35,16 @@ img { h1 { font-size: 3rem; } +form { + display: flex; + align-items: center; + gap: var(--spacing-m); + padding: var(--spacing-l) 0; +} +input, +select { + padding: var(--spacing-m); +} /* Whole Page Layout */ .container { max-width: var(--container); @@ -51,20 +61,17 @@ h1 { .card { display: grid; grid-template: - "image image image image" 140px - ". title code ......" auto - ". summary summary ." 1fr - ". ....... ....... ." var(--spacing-l) - / var(--spacing-l) 1fr min-content var(--spacing-l); + "image image image" 140px + ". title ." auto + ". summary ." 1fr + ". ....... ." var(--spacing-l) + / var(--spacing-l) 1fr var(--spacing-l); border: 1px solid var(--ink); box-shadow: var(--spacing-s) var(--spacing-s) var(--spacing-l) var(--ink); } .card__title { grid-area: title; } -.card__code { - grid-area: code; -} .card__summary { grid-area: summary; } From 1ebacd2b116e700391101f76859c8eea92b00ac3 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 3 Jan 2025 15:38:36 +0000 Subject: [PATCH 3/8] split up functions into modules based state and render off https://programming.codeyourfuture.io/data-flows/sprints/2/ --- lib/card.mjs | 20 ++++++++++++++++ episodes.js => lib/episodes.js | 0 lib/helpers.mjs | 15 ++++++++++++ lib/main.mjs | 44 ++++++++++++++++++++++++++++++++++ lib/search.mjs | 15 ++++++++++++ lib/select.mjs | 21 ++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 lib/card.mjs rename episodes.js => lib/episodes.js (100%) create mode 100644 lib/helpers.mjs create mode 100644 lib/main.mjs create mode 100644 lib/search.mjs create mode 100644 lib/select.mjs diff --git a/lib/card.mjs b/lib/card.mjs new file mode 100644 index 0000000..0860ed6 --- /dev/null +++ b/lib/card.mjs @@ -0,0 +1,20 @@ +import {pad, makeEpisodeTitle, parseFromAPI} from "./helpers.mjs"; + +const createCard = ( + template, + {id, image: {medium}, name, summary, season, number} +) => { + const card = document.getElementById(template).content.cloneNode(true); + card.querySelector('[data-episode="title"]').textContent = makeEpisodeTitle( + name, + season, + number + ); + card.querySelector('[data-episode="summary"]').textContent = + parseFromAPI(summary).body.textContent; + card.querySelector('[data-episode="image"]').src = medium; + + return card; +}; + +export {createCard}; diff --git a/episodes.js b/lib/episodes.js similarity index 100% rename from episodes.js rename to lib/episodes.js diff --git a/lib/helpers.mjs b/lib/helpers.mjs new file mode 100644 index 0000000..1d78864 --- /dev/null +++ b/lib/helpers.mjs @@ -0,0 +1,15 @@ +// utility functions to +// help with formatting and parsing data + +const pad = (number) => number.toString().padStart(2, "0"); + +const makeEpisodeCode = (season, episode) => `S${pad(season)}E${pad(episode)}`; +const makeEpisodeTitle = (name, season, episode) => + `${name} - ${makeEpisodeCode(season, episode)}`; + +const parseFromAPI = (html) => { + const parser = new DOMParser(); + return parser.parseFromString(html, "text/html"); +}; + +export {pad, makeEpisodeTitle, parseFromAPI}; diff --git a/lib/main.mjs b/lib/main.mjs new file mode 100644 index 0000000..b826485 --- /dev/null +++ b/lib/main.mjs @@ -0,0 +1,44 @@ +import {createCard} from "./card.mjs"; +import {handleSearch} from "./search.mjs"; +import {createOption, handleSelect} from "./select.mjs"; + +// State and Render + +const state = {episodes: []}; + +function updateEpisodeState(newEpisodes) { + state.episodes = newEpisodes; +} + +const getCardContainer = () => document.getElementById("card-container"); + +// a generalised render function +// based on https://programming.codeyourfuture.io/data-flows/sprints/2/prep/#refactoring-to-state%2brender + +const render = (container, template, creator) => { + container.textContent = ""; // remember we clear up first + const fragment = state.episodes.map((episode) => creator(template, episode)); + container.append(...fragment); +}; + +const init = () => { + // set out the initial html nodes + const episodes = getAllEpisodes(); + const search = document.getElementById("episode-search"); + const select = document.getElementById("episode-select"); + + // events + search.addEventListener("input", handleSearch); + select.addEventListener("change", handleSelect); + + // here's our state + state.episodes = episodes; + + // render the UI + render(getCardContainer(), "episode-card", createCard); + render(select, "option-template", createOption); +}; + +window.onload = init; + +export {state, render, updateEpisodeState, getCardContainer}; diff --git a/lib/search.mjs b/lib/search.mjs new file mode 100644 index 0000000..06eff0f --- /dev/null +++ b/lib/search.mjs @@ -0,0 +1,15 @@ +import {state, render, updateEpisodeState, getCardContainer} from "./main.mjs"; +import {createCard} from "./card.mjs"; + +function handleSearch(event) { + const searchTerm = event.target.value.toLowerCase(); + const filteredEpisodes = state.episodes.filter( + (episode) => + episode.name.toLowerCase().includes(searchTerm) || + episode.summary.toLowerCase().includes(searchTerm) + ); + updateEpisodeState(filteredEpisodes); + render(getCardContainer(), "episode-card", createCard); +} + +export {handleSearch}; diff --git a/lib/select.mjs b/lib/select.mjs new file mode 100644 index 0000000..9980aa1 --- /dev/null +++ b/lib/select.mjs @@ -0,0 +1,21 @@ +import {state, render, updateEpisodeState, getCardContainer} from "./main.mjs"; +import {pad, makeEpisodeTitle} from "./helpers.mjs"; +import {createCard} from "./card.mjs"; + +function createOption(template, {name, season, number}) { + console.log(template); + const option = document.getElementById(template).content.cloneNode(true); + const title = `${makeEpisodeTitle(name, season, number)}`; + option.querySelector("option").textContent = title; + return option; +} + +function handleSelect(event) { + const filteredEpisodes = state.episodes.filter((episode) => + event.target.value.includes(episode.name) + ); + updateEpisodeState(filteredEpisodes); + render(getCardContainer(), "episode-card", createCard); +} + +export {createOption, handleSelect}; From 1273c2c9f631145d7cda22e00084f076e68927b8 Mon Sep 17 00:00:00 2001 From: Sally McGrath Date: Fri, 3 Jan 2025 16:34:27 +0000 Subject: [PATCH 4/8] meet all level 300 conditions --- index.html | 27 +- lib/api.mjs | 13 + lib/episodes.js | 1855 ----------------------------------------------- lib/main.mjs | 47 +- lib/search.mjs | 2 +- lib/select.mjs | 3 +- style.css | 10 + 7 files changed, 74 insertions(+), 1883 deletions(-) create mode 100644 lib/api.mjs delete mode 100644 lib/episodes.js diff --git a/index.html b/index.html index e277408..99229bf 100644 --- a/index.html +++ b/index.html @@ -31,7 +31,28 @@

Sample Solution

-
+
+ + + + Loading + +