diff --git a/fetch/programmer-humour/index.html b/fetch/programmer-humour/index.html new file mode 100644 index 000000000..3794041da --- /dev/null +++ b/fetch/programmer-humour/index.html @@ -0,0 +1,19 @@ + + + + + + + + + Programmer humour + + + +
+

Progammer humour image below

+ Loading XKCD comic +
+ + + \ No newline at end of file diff --git a/fetch/programmer-humour/script.js b/fetch/programmer-humour/script.js new file mode 100644 index 000000000..16a90098b --- /dev/null +++ b/fetch/programmer-humour/script.js @@ -0,0 +1,64 @@ +const imageElement = document.querySelector("img"); +const endpoint = `https://xkcd.now.sh/?comic=latest`; + +let imageCache = null; +let imagePromise = null; + +const state = { + imgData: {}, +}; + +async function fetchImageData() { + if (imageCache) return imageCache; + if (!imagePromise) { + imagePromise = fetch(endpoint) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then((data) => { + imageCache = data; + return imageCache; + }); + } + return imagePromise; +} + +async function setup() { + try { + const fetchedImgData = await fetchImageData(); + state.imgData = fetchedImgData; + renderImage(); + const loadingMessage = document.querySelector(".app-message"); + if (loadingMessage) { + loadingMessage.remove(); + } + } catch (error) { + showMessage("Sorry, we could not load the image right now."); + } +} + +function renderImage() { + if (imageElement && state.imgData.img) { + imageElement.src = state.imgData.img; + imageElement.alt = state.imgData.alt || "Comic image"; + } +} + +function showMessage(message, duration = 3000) { + const existingMessage = document.querySelector(".app-message"); + if (existingMessage) existingMessage.remove(); + + const messageBox = document.createElement("div"); + messageBox.className = "app-message"; + messageBox.textContent = message; + document.body.appendChild(messageBox); + + setTimeout(() => { + messageBox.remove(); + }, duration); +} + +window.addEventListener("DOMContentLoaded", setup); diff --git a/fetch/programmer-humour/style.css b/fetch/programmer-humour/style.css new file mode 100644 index 000000000..c966dfd97 --- /dev/null +++ b/fetch/programmer-humour/style.css @@ -0,0 +1,63 @@ +/* CSS Reset */ + +*, +*::before, +*::after { + box-sizing: border-box; +} + +* { + margin: 0; + padding: 0; +} + +html { + font-size: 100%; + line-height: 1.5; +} + +img { + display: block; + width: 100%; + height: auto; +} + +body { + min-height: 100vh; + display: grid; + place-items: center; + font-family: Arial, sans-serif; + background: #f4f4f4; + color: #222; +} + +main { + width: 90%; + max-width: 600px; +} + +h1 { + text-align: center; + font-size: 1em; + margin: 1rem 0; +} + +/* shows loading message */ +.app-message { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: #b53a3a; + color: white; + padding: 0.8rem 1rem; + border-radius: 6px; + z-index: 1000; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +@media (min-width: 600px) { + h1 { + font-size: 1.8em; + } +}