Skip to content

Instantly share code, notes, and snippets.

@MarceauKa
Created June 26, 2022 15:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MarceauKa/3708bdfe4bce74fd73181ac4ef9556b7 to your computer and use it in GitHub Desktop.
Save MarceauKa/3708bdfe4bce74fd73181ac4ef9556b7 to your computer and use it in GitHub Desktop.
Grid, data labels and favorites
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Data labels, Favorites and Grid</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
<style type="text/css">
/** Base styles **/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-size: 16px;
line-height: 20px;
font-family: Roboto, sans-serif;
color: black;
}
.wrapper {
width: 100%;
max-width: 1024px;
margin: 0 auto;
padding: 2rem 1rem;
display: grid;
grid-template-columns: 1fr;
gap: 2rem;
}
/** Cards **/
.card {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
overflow: hidden;
box-shadow: 0 1rem 2rem 1rem rgba(0, 0, 0, .125);
border-radius: 1rem;
}
.card img {
width: 100%;
max-height: 240px;
object-fit: cover;
flex-grow: 1;
}
.card .content {
position: relative;
padding: .75rem;
display: flex;
flex-direction: column;
gap: .5rem;
}
.card .content h2 {}
.card .content p {}
.card[data-new]::before {
content: "Nouveau";
position: absolute;
top: 1rem;
right: 1rem;
background-color: #b3ffb3;
color: green;
padding: .25rem .5rem;
font-size: .75rem;
}
.card button {
position: absolute;
right: 1rem;
top: 1.25rem;
width: 2rem;
height: 2rem;
border-radius: 100%;
border: 0;
background: none;
}
.card button svg {
fill: transparent;
stroke: black;
transition: all 200ms linear;
stroke-width: 1;
pointer-events: none;
}
.card button:hover svg,
.card button.active svg {
fill: #dcdc1e;
stroke: #dcdc1e;
}
/** Responsive MD **/
@media screen and (min-width: 660px) {
.wrapper {
grid-template-columns: 1fr 1fr;
}
}
/** Responsive LG **/
@media screen and (min-width: 900px) {
.wrapper {
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
.card.full-h {
grid-row: span 2;
}
.card img {
max-height: 100%;
}
}
</style>
</head>
<body>
<div class="wrapper">
<div class="card">
<img src="https://images.unsplash.com/photo-1567767292278-a4f21aa2d36e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80" />
<div class="content">
<h2>Toulouse</h2>
<p>188 000 €</p>
<button id="toulouse" data-favorite>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" /></svg>
</button>
</div>
</div>
<div class="card" data-new>
<img src="https://images.unsplash.com/photo-1585412727339-54e4bae3bbf9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80" />
<div class="content">
<h2>Paris</h2>
<p>163 000 €</p>
<button id="paris" data-favorite>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" /></svg>
</button>
</div>
</div>
<div class="card full-h">
<img src="https://images.unsplash.com/photo-1589834390005-5d4fb9bf3d32?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80" />
<div class="content">
<h2>Montpellier</h2>
<p>293 000 €</p>
<button id="montpellier" data-favorite>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" /></svg>
</button>
</div>
</div>
<div class="card">
<img src="https://images.unsplash.com/photo-1554995207-c18c203602cb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80" />
<div class="content">
<h2>Rennes</h2>
<p>201 000 €</p>
<button id="rennes" data-favorite>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" /></svg>
</button>
</div>
</div>
<div class="card">
<img src="https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80" />
<div class="content">
<h2>Bordeaux</h2>
<p>234 000 €</p>
<button id="bordeaux" data-favorite>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" /></svg>
</button>
</div>
</div>
</div>
<script type="text/javascript">
class Favorites {
constructor(selector, className) {
this.className = className
this.els = Array.from(document.querySelectorAll(selector))
this.readStorage()
this.bindEvents()
}
bindEvents() {
this.els.forEach(item => {
let id = item.getAttribute('id')
if (this.favorites.includes(id)) {
item.classList.toggle(this.className)
}
item.addEventListener('click', (event) => {
event.preventDefault()
this.toggleElement(event.target)
})
})
}
toggleElement(element) {
element.classList.toggle(this.className)
let id = element.getAttribute('id')
if (this.favorites.includes(id)) {
this.favorites.splice(this.favorites.indexOf(id), 1)
} else {
this.favorites.push(id)
}
this.writeStorage()
}
readStorage() {
let favorites = window.localStorage.getItem('favorites')
this.favorites = favorites ? JSON.parse(favorites) : []
}
writeStorage() {
window.localStorage.setItem('favorites', JSON.stringify(this.favorites))
}
}
new Favorites('[data-favorite]', 'active')
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment