Begin Store Front project using web components

This commit is contained in:
Andrea Fazzi 2024-09-26 10:13:29 +02:00
parent 4e61a13d5e
commit 1aeaed646e
6 changed files with 184 additions and 0 deletions

20
web-apps/main.go Normal file
View file

@ -0,0 +1,20 @@
package main
import (
"net/http"
"log"
)
func main() {
mux := http.NewServeMux()
mux.Handle("GET /store-front/", http.StripPrefix("/store-front", http.FileServer(http.Dir("store-front"))))
log.Println("Start the web server...")
err := http.ListenAndServe(":8080", mux)
if err != nil {
panic(err)
}
}

View file

@ -0,0 +1,24 @@
/**
* Grid Layout
*/
@media (min-width: 20em) {
grid-of-photos div {
display: grid;
grid-template-columns: 50% 50%;
}
}
@media (min-width: 32em) {
grid-of-photos div {
display: grid;
grid-template-columns: 33% 33% 33%;
}
}
@media (min-width: 42em) {
grid-of-photos div {
display: grid;
grid-template-columns: 20% 20% 20% 20% 20%;
}
}

4
web-apps/store-front/css/pico.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,34 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<link rel="stylesheet" href="css/pico.min.css">
<link rel="stylesheet" href="css/grid.css">
<title>Project - Store Front</title>
</head>
<body>
<div class="container">
<nav>
<ul>
<li><strong>Sparrow Photography</strong></li>
</ul>
<ul>
<li><a href="#">About</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Products</a></li>
</ul>
</nav>
</div>
<div class="container">
<grid-of-photos>
<p aria-busy="true">Loading...</p>
</grid-of-photos>
</div>
<div class="container">
<p><em>Photos by Jack Sparrow. All rights reserved.</em></p>
</div>
<script src="js/grid-of-photos.js"></script>
</body>
</html>

View file

@ -0,0 +1 @@
andrea@lv5.321700:1727085997

View file

@ -0,0 +1,101 @@
const endpoint = 'https://leanwebclub.com/course-apis/photos.json';
class GridOfPhotos extends HTMLElement {
/**
* Instantiate the component
*/
constructor () {
// Inherit parent class properties
super();
// LIsten for events
this.addEventListener('click', this);
}
/**
* Runs each time the element is appended to or moved in the DOM
*/
async connectedCallback () {
// Fetch the photos from the API
this.photos = await this.fetchPhotos();
// If there are no photos
if (!this.photos || !this.photos.length) {
this.innerHTML = '<p>There are no available photos at this time. Please try again later. Sorry!</p>';
}
// Render the element
this.innerHTML = `
<div>
${this.photos.map( (image) => { return `<img src="${image.url}" alt="${image.description}"></img>` } ).join('')}
</div>
`
}
/**
* Fetch photos from the API
* @return {Promise} response - The response from the API
*/
async fetchPhotos () {
try {
let response = await fetch(endpoint);
if (!response.ok) throw response.status;
let data = await response.json();
if (!data) throw 'No data!';
return data;
} catch (error) {
console.warn("ERR:", error);
}
}
/**
* Handle events
* @param {Event} event - The event object
*/
handleEvent (event) {
this[`on${event.type}`](event);
}
/**
* Handle the click event
* @param {Event} event - The event object
*/
onclick (event) {
if (!event.target.closest('img')) return;
let dialog = document.createElement('dialog');
dialog.setAttribute('open', '');
dialog.innerHTML = `
<article>
<h2>Confirm Your Membership</h2>
<p>
Thank you for signing up for a membership!
Please review the membership details below:
</p>
<ul>
<li>Membership: Individual</li>
<li>Price: $10</li>
</ul>
<footer>
<button class="secondary">
Close
</button>
</footer>
</article>
`
this.append(dialog);
}
}
// Define the new web component
if ('customElements' in window) {
customElements.define('grid-of-photos', GridOfPhotos);
}