Compare commits
3 commits
625fcb5986
...
1fba9c2620
Author | SHA1 | Date | |
---|---|---|---|
1fba9c2620 | |||
5dfea373a9 | |||
4e7ab8a432 |
16 changed files with 227 additions and 28 deletions
|
@ -1,21 +1,100 @@
|
||||||
<script>
|
<script>
|
||||||
import "$lib/css/base.css";
|
import "$lib/css/base.css";
|
||||||
import "$lib/css/hover-card.css"
|
import "$lib/css/hover-card.css";
|
||||||
|
|
||||||
|
import anime from "animejs";
|
||||||
|
import SvgIcon from "@jamescoyle/svelte-icon";
|
||||||
|
import { mdiEye } from "@mdi/js";
|
||||||
|
import { popupComponent } from "$lib/ts/popup.ts";
|
||||||
|
import HoverCardPopup from "$lib/components/popup/hover-card.svelte";
|
||||||
|
|
||||||
|
import text from "$lib/json/hover-card.json";
|
||||||
|
|
||||||
export let picture;
|
export let picture;
|
||||||
export let title = "Title";
|
export let title = "Title";
|
||||||
export let description = "This is a description, you can add some explaination to your picture in here!";
|
export let description =
|
||||||
|
"This is a description, you can add some explaination to your picture in here!";
|
||||||
|
|
||||||
|
let divHoverCardOverlay;
|
||||||
|
let divHoverCardMetadata = {
|
||||||
|
div: null,
|
||||||
|
title: null,
|
||||||
|
description: null,
|
||||||
|
tip: null,
|
||||||
|
};
|
||||||
|
function animateCard(isEntering) {
|
||||||
|
const opacityValues = [0, 1];
|
||||||
|
let translateValues = [-30, 0];
|
||||||
|
|
||||||
|
if (!isEntering) {
|
||||||
|
opacityValues.reverse();
|
||||||
|
translateValues.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
anime({
|
||||||
|
targets: [divHoverCardOverlay, divHoverCardMetadata.div],
|
||||||
|
opacity: opacityValues,
|
||||||
|
duration: 400,
|
||||||
|
easing: "easeInOutQuad",
|
||||||
|
});
|
||||||
|
anime({
|
||||||
|
targets: [divHoverCardMetadata.title, divHoverCardMetadata.tip],
|
||||||
|
opacity: opacityValues,
|
||||||
|
translateX: translateValues,
|
||||||
|
delay: 100,
|
||||||
|
duration: 500,
|
||||||
|
easing: "easeInOutQuad",
|
||||||
|
});
|
||||||
|
translateValues = translateValues.map((e) => -e);
|
||||||
|
anime({
|
||||||
|
targets: [divHoverCardMetadata.description],
|
||||||
|
opacity: opacityValues,
|
||||||
|
translateY: translateValues,
|
||||||
|
delay: 100,
|
||||||
|
duration: 500,
|
||||||
|
easing: "easeInOutQuad",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPopup() {
|
||||||
|
popupComponent.set({
|
||||||
|
component: HoverCardPopup,
|
||||||
|
props: { title: "Hello", description: "This is a custom Popup" },
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="hover-card-container">
|
<div
|
||||||
|
class="hover-card-container"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
on:mouseenter={() => {
|
||||||
|
animateCard(true);
|
||||||
|
}}
|
||||||
|
on:mouseleave={() => {
|
||||||
|
animateCard(false);
|
||||||
|
}}
|
||||||
|
on:click={showPopup}
|
||||||
|
on:keydown={(e) => e.key === "Enter" && showPopup()}
|
||||||
|
>
|
||||||
<div class="hover-card">
|
<div class="hover-card">
|
||||||
<img alt="hover-card" src={picture} />
|
<img alt="hover-card" src={picture} />
|
||||||
</div>
|
</div>
|
||||||
<div class="hover-card-overlay"></div>
|
<div class="hover-card-overlay" bind:this={divHoverCardOverlay}></div>
|
||||||
<div class="hover-card flex-row">
|
<div class="hover-card flex-col">
|
||||||
<div class="hover-card-metadata margin-bot-force">
|
<div
|
||||||
<h1>{title}</h1>
|
class="hover-card-tip flex-row"
|
||||||
<p>{description}</p>
|
bind:this={divHoverCardMetadata.tip}
|
||||||
|
>
|
||||||
|
<SvgIcon type="mdi" path={mdiEye}></SvgIcon>
|
||||||
|
<span>{text.seemore}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="hover-card-metadata margin-bot-force"
|
||||||
|
bind:this={divHoverCardMetadata.div}
|
||||||
|
>
|
||||||
|
<h1 bind:this={divHoverCardMetadata.title}>{title}</h1>
|
||||||
|
<p bind:this={divHoverCardMetadata.description}>{description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
26
src/lib/components/popup.svelte
Normal file
26
src/lib/components/popup.svelte
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<script>
|
||||||
|
import "$lib/css/popup.css";
|
||||||
|
import { popupComponent } from "$lib/ts/popup.ts";
|
||||||
|
|
||||||
|
let component = null;
|
||||||
|
|
||||||
|
popupComponent.subscribe((value) => {
|
||||||
|
component = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
popupComponent.set(null);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if component}
|
||||||
|
<div
|
||||||
|
class="popup"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
on:click={close}
|
||||||
|
on:keydown={(e) => e.key === "Escape" && close()}
|
||||||
|
>
|
||||||
|
<svelte:component this={component.component} {...component.props} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
11
src/lib/components/popup/hover-card.svelte
Normal file
11
src/lib/components/popup/hover-card.svelte
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<script>
|
||||||
|
import "$lib/css/hover-card.css"
|
||||||
|
|
||||||
|
export let title=""
|
||||||
|
export let description=""
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="hover-card-popup-container">
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<p>{description}</p>
|
||||||
|
</div>
|
|
@ -44,6 +44,7 @@ h2 {
|
||||||
--background-dark: linear-gradient(180deg, rgba(248, 241, 241, 1) 0%, rgba(224, 217, 217, 1) 100%);
|
--background-dark: linear-gradient(180deg, rgba(248, 241, 241, 1) 0%, rgba(224, 217, 217, 1) 100%);
|
||||||
--shadow: rgba(79, 50, 93, 0.25) 0px 30px 60px -12px, rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
|
--shadow: rgba(79, 50, 93, 0.25) 0px 30px 60px -12px, rgba(0, 0, 0, 0.3) 0px 18px 36px -18px;
|
||||||
--shadow-hover: rgba(43, 33, 48, 0.5) 0px 22px 70px 4px;
|
--shadow-hover: rgba(43, 33, 48, 0.5) 0px 22px 70px 4px;
|
||||||
|
--shadow-active: #2c1235a0 0px 20px 30px -10px;
|
||||||
--z-index-last: -1;
|
--z-index-last: -1;
|
||||||
--z-index-normal: 0;
|
--z-index-normal: 0;
|
||||||
--z-index-front: 1;
|
--z-index-front: 1;
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-image: linear-gradient(to right, var(--navbar-dark) 0%, var(--navbar-light) 100%);
|
background-image: linear-gradient(to right, var(--navbar-dark) 0%, var(--navbar-light) 100%);
|
||||||
box-shadow: 0px 8px 18px -1px #33283760;
|
|
||||||
padding: 0.2rem;
|
padding: 0.2rem;
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:active {
|
.button:active {
|
||||||
box-shadow: 0px 4px 10px 0px #2c1235b0;
|
box-shadow: var(--shadow-active);
|
||||||
transform: translateY(3px);
|
transform: translateY(3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
box-shadow: #00000040 0px 8px 18px -1px;
|
box-shadow: #00000040 0px 8px 18px -1px;
|
||||||
transition: all .1s ease 0s;
|
transition: all .1s ease 0s;
|
||||||
background-color: var(--color-background);
|
background-color: var(--color-background);
|
||||||
z-index: 2;
|
z-index: var(--z-index-normal);
|
||||||
margin-right: 1rem;
|
margin-right: 1rem;
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
|
|
|
@ -15,13 +15,13 @@
|
||||||
background: linear-gradient(0deg, #00000000, #261C2C40 50%, #261c2c80 100%);
|
background: linear-gradient(0deg, #00000000, #261C2C40 50%, #261c2c80 100%);
|
||||||
height: calc(var(--navbar-height)*2);
|
height: calc(var(--navbar-height)*2);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 0;
|
z-index: var(--z-index-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover-img-text {
|
.cover-img-text {
|
||||||
grid-area: overlay;
|
grid-area: overlay;
|
||||||
padding: 4rem;
|
padding: 4rem;
|
||||||
z-index: 1;
|
z-index: var(--z-index-normal);
|
||||||
max-width: 50rem;
|
max-width: 50rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
.cover-img-darken {
|
.cover-img-darken {
|
||||||
grid-area: overlay;
|
grid-area: overlay;
|
||||||
background-color: rgb(0, 0, 0, 0.35);
|
background-color: rgb(0, 0, 0, 0.35);
|
||||||
z-index: 0;
|
z-index: var(--z-index-normal);
|
||||||
border-bottom-left-radius: 2rem;
|
border-bottom-left-radius: 2rem;
|
||||||
border-bottom-right-radius: 2rem;
|
border-bottom-right-radius: 2rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
box-shadow: var(--shadow-hover);
|
box-shadow: var(--shadow-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hover-card-container:active {
|
||||||
|
transform: translateY(0.3rem) scale(100%);
|
||||||
|
box-shadow: var(--shadow-active);
|
||||||
|
}
|
||||||
|
|
||||||
.hover-card-container img {
|
.hover-card-container img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -37,15 +42,44 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-image: linear-gradient(0deg, #120e14 0%, #120e14dc 30%, #120e1491 35%, rgba(0, 0, 0, 0) 45%);
|
background-image: linear-gradient(0deg, #120e14 0%, #120e14dc 30%, #120e1491 35%, rgba(0, 0, 0, 0) 45%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-card-tip {
|
||||||
|
color: var(--color-background);
|
||||||
|
background-color: #120e14b0;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0.4rem;
|
||||||
|
padding: 0.4rem;
|
||||||
|
padding-right: 0.6rem;
|
||||||
|
padding-left: 0.6rem;
|
||||||
|
border-radius: 3rem;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-card-tip svg {
|
||||||
|
width: 1.4rem;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-card-tip span {
|
||||||
|
font-family: 'JetBrains Mono';
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hover-card-metadata {
|
.hover-card-metadata {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 7rem;
|
height: 7rem;
|
||||||
color: var(--color-background);
|
color: var(--color-background);
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hover-card-metadata h1 {
|
.hover-card-metadata h1 {
|
||||||
|
/* Animation */
|
||||||
|
opacity: 0;
|
||||||
font-family: 'JetBrains Mono';
|
font-family: 'JetBrains Mono';
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
|
@ -62,6 +96,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.hover-card-metadata p {
|
.hover-card-metadata p {
|
||||||
|
/* Animation */
|
||||||
|
opacity: 0;
|
||||||
font-family: 'JetBrains Mono';
|
font-family: 'JetBrains Mono';
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
@ -76,3 +112,15 @@
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 2;
|
||||||
line-clamp: 2;
|
line-clamp: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pop-up Hover Card */
|
||||||
|
|
||||||
|
.hover-card-popup-container {
|
||||||
|
width: calc(100% - 12rem);
|
||||||
|
height: calc(100% - 12rem);
|
||||||
|
margin: 5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background-image: var(--background-dark);
|
||||||
|
border-radius: 1rem;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ nav {
|
||||||
height: var(--navbar-height);
|
height: var(--navbar-height);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 5;
|
z-index: var(--z-index-navbar);
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ a {
|
||||||
|
|
||||||
.navbar-content {
|
.navbar-content {
|
||||||
grid-area: overlay;
|
grid-area: overlay;
|
||||||
z-index: 1;
|
z-index: var(--z-index-normal);
|
||||||
width: inherit;
|
width: inherit;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
15
src/lib/css/popup.css
Normal file
15
src/lib/css/popup.css
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
:root {
|
||||||
|
--popup-blur: blur(1rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup {
|
||||||
|
width: 100dvw;
|
||||||
|
height: 100dvh;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
background-color: #150f1aa0;
|
||||||
|
z-index: var(--z-index-popup);
|
||||||
|
-webkit-backdrop-filter: var(--popup-blur);
|
||||||
|
backdrop-filter: var(--popup-blur);
|
||||||
|
}
|
|
@ -40,7 +40,7 @@
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
z-index: 1;
|
z-index: var(--z-index-normal);
|
||||||
transform: translateX(-1rem);
|
transform: translateX(-1rem);
|
||||||
display: none;
|
display: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
3
src/lib/json/hover-card.json
Normal file
3
src/lib/json/hover-card.json
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"seemore": "Voir plus"
|
||||||
|
}
|
|
@ -50,13 +50,19 @@
|
||||||
},
|
},
|
||||||
"photos": [
|
"photos": [
|
||||||
{
|
{
|
||||||
"url": "https://share.etheryo.fr/rando/2024.07.28/IMG20240728150532.jpg"
|
"url": "https://share.etheryo.fr/rando/2024.07.28/IMG20240728150532.jpg",
|
||||||
|
"title": "Tarnished Peak (afterwar)",
|
||||||
|
"description": "Photo prise à Ben More, Écosse"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://share.etheryo.fr/rando/2024.07.28/IMG20240728142327.jpg"
|
"url": "https://share.etheryo.fr/rando/2024.07.28/IMG20240728142327.jpg",
|
||||||
|
"title": "Whitewashed",
|
||||||
|
"description": "Photo prise à Ben More, Écosse"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "https://share.etheryo.fr/rando/2023.11.01/Groupe%20Ombre%20Lac%20Montagne%20Rouge%20Bleu.jpg"
|
"url": "https://share.etheryo.fr/rando/2023.11.01/Groupe%20Ombre%20Lac%20Montagne%20Rouge%20Bleu.jpg",
|
||||||
|
"title": "Compagnons",
|
||||||
|
"description": "Photo prise au Lac d'Oô, France"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
3
src/lib/ts/popup.ts
Normal file
3
src/lib/ts/popup.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const popupComponent = writable(null);
|
|
@ -1,14 +1,17 @@
|
||||||
<script>
|
<script>
|
||||||
import { page } from '$app/stores';
|
import { page } from "$app/stores";
|
||||||
import '$lib/css/base.css';
|
import "$lib/css/base.css";
|
||||||
import '$lib/css/navbar.css';
|
import "$lib/css/navbar.css";
|
||||||
|
import "$lib/css/popup.css";
|
||||||
|
|
||||||
import Navbar from '$lib/components/navbar.svelte';
|
import Navbar from "$lib/components/navbar.svelte";
|
||||||
import Footer from '$lib/components/footer.svelte';
|
import Footer from "$lib/components/footer.svelte";
|
||||||
|
import Popup from "$lib/components/popup.svelte";
|
||||||
|
|
||||||
// $: pageUrl = $page.url.pathname;
|
// $: pageUrl = $page.url.pathname;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<Popup />
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<div class="base">
|
<div class="base">
|
||||||
<slot />
|
<slot />
|
||||||
|
|
|
@ -70,7 +70,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex w-100 justify-center">
|
<div class="flex w-100 justify-center">
|
||||||
{#each hubjson.photos as photo}
|
{#each hubjson.photos as photo}
|
||||||
<HoverCard picture={photo.url} />
|
<HoverCard
|
||||||
|
picture={photo.url}
|
||||||
|
title={photo.title}
|
||||||
|
description={photo.description}
|
||||||
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue