temp: transfert entre ordinateurs

This commit is contained in:
gcch 2025-12-23 16:18:28 +01:00
commit d81acac380
46 changed files with 18652 additions and 1328 deletions

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
#page-a-propos{--images-longueur-maximale:1300px;--page-marges-bloc-debut:var(--en-tete-hauteur);--images-marges-ligne:var(--espace-xl)*2;margin-top:var(--page-marges-bloc-debut);flex-flow:column;display:flex}#page-a-propos .storytelling{padding:var(--espace-xl)0;color:var(--couleur-gris-fonce)}#page-a-propos .storytelling__conteneur{width:min(var(--images-longueur-maximale),100% - var(--images-marges-ligne));margin:auto;position:relative}#page-a-propos .storytelling picture{position:relative}#page-a-propos .storytelling picture:before{content:"";filter:opacity(0%);background-image:url(/app/themes/haiku-atelier-2024/assets/img/icons/cloud-gris.svg);background-position:50%;background-repeat:space;background-size:contain;width:100%;height:100%;animation:1s linear infinite alternate both clignotement;position:absolute;top:0;left:0}#page-a-propos .storytelling img{object-fit:contain;background:0 0;width:max-content;height:auto;position:relative}#page-a-propos .storytelling .epingle{position:absolute;right:46.5%}#page-a-propos .storytelling .epingle img{pointer-events:none;width:1.75rem;display:block}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="1"]{top:1%;right:60%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="2"]{top:25%;right:70%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="3"]{top:37%;right:20%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="4"]{top:58%;right:70%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="5"]{top:76%;right:14%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="6"]{top:95.5%;right:75%}#page-a-propos .storytelling .boite-texte{top:0;right:calc(46.5% - (15rem + var(--espace-l))/2);padding:var(--espace-l);border:1px solid var(--couleur-noir);color:var(--couleur-noir);visibility:hidden;opacity:0;background:var(--couleur-fond);flex-flow:column;font-size:.8rem;font-style:italic;transition:opacity .2s,visibility .2s;display:flex;position:absolute}#page-a-propos .storytelling .boite-texte button{top:0;right:calc(-1.5rem - var(--espace-m) - var(--espace-xs));padding:var(--espace-xs);align-self:end;position:absolute}#page-a-propos .storytelling .boite-texte button img{pointer-events:none;aspect-ratio:1;width:1.5rem}#page-a-propos .storytelling .boite-texte button:active{background:var(--couleur-jaune)}#page-a-propos .storytelling .boite-texte p{max-width:15rem}#page-a-propos .storytelling .boite-texte p+p{margin-top:var(--espace-m)}#page-a-propos .storytelling .boite-texte[data-ensemble-epingle-boite-actif]{visibility:visible;opacity:1}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="2"]{--hauteur-boite:calc(7lh + 1rem + var(--espace-l)*2);top:calc(23% - var(--hauteur-boite)/2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="3"]{--hauteur-boite:calc(7lh + 1rem + var(--espace-l)*2);top:calc(35% - var(--hauteur-boite)/2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="3"] button{left:calc(-1.5rem - var(--espace-m) - var(--espace-xs))}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="4"]{--hauteur-boite:calc(8lh + 2rem + var(--espace-l)*2);top:calc(58% - var(--hauteur-boite)/2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="5"]{--hauteur-boite:calc(12lh + 2rem + var(--espace-l)*2);top:calc(76% - var(--hauteur-boite)/2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="6"]{--hauteur-boite:calc(7lh + 1rem + var(--espace-l)*2);top:calc(95.5% - var(--hauteur-boite)/2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="6"] button{left:calc(-1.5rem - var(--espace-m) - var(--espace-xs))}@media (width<=700px){#page-a-propos{--images-marges-ligne:var(--espace-m)}}@keyframes clignotement{to{filter:opacity(30%)}}
#page-a-propos{--images-longueur-maximale:1300px;--page-marges-bloc-debut:var(--en-tete-hauteur);--images-marges-ligne:var(--espace-xl) * 2;margin-top:var(--page-marges-bloc-debut);flex-flow:column;display:flex}#page-a-propos .storytelling{padding:var(--espace-xl) 0;color:var(--couleur-gris-fonce)}#page-a-propos .storytelling__conteneur{width:min(var(--images-longueur-maximale), 100% - var(--images-marges-ligne));margin:auto;position:relative}#page-a-propos .storytelling picture{position:relative}#page-a-propos .storytelling picture:before{content:"";filter:opacity(0%);background-image:url(/app/themes/haiku-atelier-2024/assets/img/icons/cloud-gris.svg);background-position:50%;background-repeat:space;background-size:contain;width:100%;height:100%;animation:1s linear infinite alternate both clignotement;position:absolute;top:0;left:0}#page-a-propos .storytelling img{object-fit:contain;background:0 0;width:max-content;height:auto;position:relative}#page-a-propos .storytelling .epingle{position:absolute;right:46.5%}#page-a-propos .storytelling .epingle img{pointer-events:none;width:1.75rem;display:block}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="1"]{top:1%;right:60%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="2"]{top:25%;right:70%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="3"]{top:37%;right:20%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="4"]{top:58%;right:70%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="5"]{top:76%;right:14%}#page-a-propos .storytelling .epingle[data-id-ensemble-epingle-boite="6"]{top:95.5%;right:75%}#page-a-propos .storytelling .boite-texte{top:0;right:calc(46.5% - (15rem + var(--espace-l)) / 2);padding:var(--espace-l);border:1px solid var(--couleur-noir);color:var(--couleur-noir);visibility:hidden;opacity:0;background:var(--couleur-fond);flex-flow:column;font-size:.8rem;font-style:italic;transition:opacity .2s,visibility .2s;display:flex;position:absolute}#page-a-propos .storytelling .boite-texte button{top:0;right:calc(-1.5rem - var(--espace-m) - var(--espace-xs));padding:var(--espace-xs);align-self:end;position:absolute}#page-a-propos .storytelling .boite-texte button img{pointer-events:none;aspect-ratio:1;width:1.5rem}#page-a-propos .storytelling .boite-texte button:active{background:var(--couleur-jaune)}#page-a-propos .storytelling .boite-texte p{max-width:15rem}#page-a-propos .storytelling .boite-texte p+p{margin-top:var(--espace-m)}#page-a-propos .storytelling .boite-texte[data-ensemble-epingle-boite-actif]{visibility:visible;opacity:1}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="2"]{--hauteur-boite:calc(7lh + 1rem + var(--espace-l) * 2);top:calc(23% - var(--hauteur-boite) / 2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="3"]{--hauteur-boite:calc(7lh + 1rem + var(--espace-l) * 2);top:calc(35% - var(--hauteur-boite) / 2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="3"] button{left:calc(-1.5rem - var(--espace-m) - var(--espace-xs))}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="4"]{--hauteur-boite:calc(8lh + 2rem + var(--espace-l) * 2);top:calc(58% - var(--hauteur-boite) / 2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="5"]{--hauteur-boite:calc(12lh + 2rem + var(--espace-l) * 2);top:calc(76% - var(--hauteur-boite) / 2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="6"]{--hauteur-boite:calc(7lh + 1rem + var(--espace-l) * 2);top:calc(95.5% - var(--hauteur-boite) / 2)}#page-a-propos .storytelling .boite-texte[data-id-ensemble-epingle-boite="6"] button{left:calc(-1.5rem - var(--espace-m) - var(--espace-xs))}@media (width<=700px){#page-a-propos{--images-marges-ligne:var(--espace-m)}}@keyframes clignotement{to{filter:opacity(30%)}}

View file

@ -1 +1 @@
#page-accueil{--hauteur-conteneur:var(--contenu-page-hauteur-minimale-sans-categories);--page-marges-bloc-debut:var(--en-tete-hauteur);--conteneur-marges-internes-ligne:var(--espace-xl);min-block-size:var(--hauteur-conteneur);max-block-size:var(--hauteur-conteneur);margin-top:var(--page-marges-bloc-debut);flex-flow:column;display:flex;overflow:hidden}#page-accueil .storytelling{overscroll-behavior:none;min-block-size:inherit;max-block-size:inherit;overflow-y:scroll}#page-accueil .storytelling__conteneur{overscroll-behavior:inherit;min-block-size:calc(var(--hauteur-conteneur)*13);padding:0 var(--conteneur-marges-internes-ligne);flex-flow:column;place-items:center;display:flex}#page-accueil .storytelling__animation{--hauteur-animation:90px;--taille-police:calc(var(--espace-xl)*2.5);pointer-events:none;z-index:3;visibility:visible;opacity:1;block-size:100%;mask-image:linear-gradient(var(--mask-direction,to right),#0000,#000 20%,#000 80%,#0000);place-content:center;place-items:center;margin:auto;transition:opacity 1s ease-in-out,visibility 1s ease-in-out;display:grid;position:absolute;top:0;left:0;right:0;overflow:hidden}#page-accueil .storytelling__animation[hidden]{visibility:hidden;opacity:0;transition:opacity 1s ease-in-out,visibility 1s ease-in-out;display:grid!important}#page-accueil .storytelling__animation.no-js{visibility:hidden;opacity:0;transition:opacity 1s ease-in-out,visibility 1s ease-in-out}#page-accueil .storytelling__animation .animation-conteneur{width:120vw;block-size:var(--hauteur-animation);overflow:visible}#page-accueil .storytelling__animation .animation-texte{font-size:var(--taille-police);text-shadow:4px 4px 0 var(--couleur-blanc);text-transform:uppercase;letter-spacing:var(--espacement-inter-lettres-rapproche-s);font-weight:600;overflow:visible}#page-accueil .storytelling__image{inline-size:max-content;max-inline-size:100%;min-block-size:var(--hauteur-conteneur);max-block-size:var(--hauteur-conteneur);align-content:center;position:sticky;top:0}#page-accueil .storytelling__image[data-caché]{display:none!important}#page-accueil .storytelling__image picture{max-block-size:inherit}#page-accueil .storytelling__image img{max-block-size:inherit;object-fit:contain;background:0 0;margin:auto;scale:.95}@media (scripting:none){#page-accueil .storytelling__animation{visibility:hidden}}@media (width<=700px){#page-accueil{--conteneur-marges-internes-ligne:var(--espace-l)}}@media (width<=500px){#page-accueil{--conteneur-marges-internes-ligne:var(--espace-m)}}@supports ((-moz-appearance:none)){#page-accueil .storytelling__animation{--taille-police:calc(var(--espace-xl)*2.2)}}
#page-accueil{--hauteur-conteneur:var(--contenu-page-hauteur-minimale-sans-categories);--page-marges-bloc-debut:var(--en-tete-hauteur);--conteneur-marges-internes-ligne:var(--espace-xl);min-block-size:var(--hauteur-conteneur);max-block-size:var(--hauteur-conteneur);margin-top:var(--page-marges-bloc-debut);flex-flow:column;display:flex;overflow:hidden}#page-accueil .storytelling{overscroll-behavior:none;min-block-size:inherit;max-block-size:inherit;overflow-y:scroll}#page-accueil .storytelling__conteneur{overscroll-behavior:inherit;min-block-size:calc(var(--hauteur-conteneur) * 13);padding:0 var(--conteneur-marges-internes-ligne);flex-flow:column;place-items:center;display:flex}#page-accueil .storytelling__animation{--hauteur-animation:90px;--taille-police:calc(var(--espace-xl) * 2.5);pointer-events:none;z-index:3;visibility:visible;opacity:1;block-size:100%;mask-image:linear-gradient(var(--mask-direction,to right), #0000, #000 20%, #000 80%, #0000);place-content:center;place-items:center;margin:auto;transition:opacity 1s ease-in-out,visibility 1s ease-in-out;display:grid;position:absolute;top:0;left:0;right:0;overflow:hidden}#page-accueil .storytelling__animation[hidden]{visibility:hidden;opacity:0;transition:opacity 1s ease-in-out,visibility 1s ease-in-out;display:grid!important}#page-accueil .storytelling__animation.no-js{visibility:hidden;opacity:0;transition:opacity 1s ease-in-out,visibility 1s ease-in-out}#page-accueil .storytelling__animation .animation-conteneur{width:120vw;block-size:var(--hauteur-animation);overflow:visible}#page-accueil .storytelling__animation .animation-texte{font-size:var(--taille-police);text-shadow:4px 4px 0 var(--couleur-blanc);text-transform:uppercase;letter-spacing:var(--espacement-inter-lettres-rapproche-s);font-weight:600;overflow:visible}#page-accueil .storytelling__image{inline-size:max-content;max-inline-size:100%;min-block-size:var(--hauteur-conteneur);max-block-size:var(--hauteur-conteneur);align-content:center;position:sticky;top:0}#page-accueil .storytelling__image[data-caché]{display:none!important}#page-accueil .storytelling__image picture{max-block-size:inherit}#page-accueil .storytelling__image img{max-block-size:inherit;object-fit:contain;background:0 0;margin:auto;scale:.95}@media (scripting:none){#page-accueil .storytelling__animation{visibility:hidden}}@media (width<=700px){#page-accueil{--conteneur-marges-internes-ligne:var(--espace-l)}}@media (width<=500px){#page-accueil{--conteneur-marges-internes-ligne:var(--espace-m)}}@supports ((-moz-appearance:none)){#page-accueil .storytelling__animation{--taille-police:calc(var(--espace-xl) * 2.2)}}

View file

@ -1 +1 @@
#page-boutique .actions{text-align:center;align-content:center;width:100%}#page-boutique .actions button{height:initial;padding:var(--espace-xl)0;margin:auto}
#page-boutique .actions{text-align:center;align-content:center;width:100%}#page-boutique .actions button{height:initial;padding:var(--espace-xl) 0;margin:auto}

View file

@ -1 +1 @@
.page-modele-simple{--page-hauteur-minimale:calc(100svh - var(--en-tete-hauteur) - var(--pied-de-page-hauteur) - var(--espace-xl) - 1px);--page-marges-bloc-debut:var(--en-tete-hauteur);margin-top:var(--page-marges-bloc-debut);margin-bottom:var(--espace-xl);border-bottom:1px solid var(--couleur-noir);flex-flow:column;display:flex}.page-modele-simple .contenu{width:min(50rem,100%);min-height:var(--page-hauteur-minimale);border:1px solid var(--couleur-noir);border-bottom:initial;flex-flow:column;place-items:center;margin:auto;font-style:italic;font-weight:400;display:flex}.page-modele-simple .contenu__en-tete{width:100%;padding:var(--espace-m)var(--espace-xl);color:var(--couleur-blanc);background:var(--couleur-noir)}.page-modele-simple .contenu__en-tete h2{text-transform:uppercase;width:fit-content;letter-spacing:var(--espacement-inter-lettres-etendu-l);margin:auto}.page-modele-simple .contenu__textuel{max-width:34rem;height:100%;padding:0 var(--espace-xl);text-wrap:pretty;flex-flow:column;flex:1;place-content:center;display:flex}.page-modele-simple .contenu__textuel p+p{margin-top:var(--espace-m)}.page-modele-simple#page-cgv .contenu{font-style:normal}.page-modele-simple#page-cgv .contenu header{font-style:italic}.page-modele-simple#page-cgv .contenu__textuel{max-width:initial;padding:0}.page-modele-simple#page-cgv .contenu__textuel__section{width:100%}.page-modele-simple#page-cgv .contenu__textuel__section:first-of-type header{border-top:initial}.page-modele-simple#page-cgv .contenu__textuel__section header{width:100%;margin-bottom:var(--espace-l);padding:var(--espace-m)var(--espace-xl);border-top:1px solid var(--couleur-noir);border-bottom:1px solid var(--couleur-noir)}.page-modele-simple#page-cgv .contenu__textuel__section header h3{text-transform:uppercase;width:fit-content;letter-spacing:var(--espacement-inter-lettres-etendu-l);margin:auto}.page-modele-simple#page-cgv .contenu__textuel__section ul{padding:0 var(--espace-xl);margin-bottom:1lh;list-style:inside square}.page-modele-simple#page-cgv .contenu__textuel__section p{padding:0 var(--espace-xl)}.page-modele-simple#page-cgv .contenu__textuel__section p:last-of-type{margin-bottom:var(--espace-xl)}@media (width<=50rem){.page-modele-simple .contenu{border-right:initial;border-left:initial}}
.page-modele-simple{--page-hauteur-minimale:calc(100svh - var(--en-tete-hauteur) - var(--pied-de-page-hauteur) - var(--espace-xl) - 1px);--page-marges-bloc-debut:var(--en-tete-hauteur);margin-top:var(--page-marges-bloc-debut);margin-bottom:var(--espace-xl);border-bottom:1px solid var(--couleur-noir);flex-flow:column;display:flex}.page-modele-simple .contenu{width:min(50rem,100%);min-height:var(--page-hauteur-minimale);border:1px solid var(--couleur-noir);border-bottom:initial;flex-flow:column;place-items:center;margin:auto;font-style:italic;font-weight:400;display:flex}.page-modele-simple .contenu__en-tete{width:100%;padding:var(--espace-m) var(--espace-xl);color:var(--couleur-blanc);background:var(--couleur-noir)}.page-modele-simple .contenu__en-tete h2{text-transform:uppercase;width:fit-content;letter-spacing:var(--espacement-inter-lettres-etendu-l);margin:auto}.page-modele-simple .contenu__textuel{max-width:34rem;height:100%;padding:0 var(--espace-xl);text-wrap:pretty;flex-flow:column;flex:1;place-content:center;display:flex}.page-modele-simple .contenu__textuel p+p{margin-top:var(--espace-m)}.page-modele-simple#page-cgv .contenu{font-style:normal}.page-modele-simple#page-cgv .contenu header{font-style:italic}.page-modele-simple#page-cgv .contenu__textuel{max-width:initial;padding:0}.page-modele-simple#page-cgv .contenu__textuel__section{width:100%}.page-modele-simple#page-cgv .contenu__textuel__section:first-of-type header{border-top:initial}.page-modele-simple#page-cgv .contenu__textuel__section header{width:100%;margin-bottom:var(--espace-l);padding:var(--espace-m) var(--espace-xl);border-top:1px solid var(--couleur-noir);border-bottom:1px solid var(--couleur-noir)}.page-modele-simple#page-cgv .contenu__textuel__section header h3{text-transform:uppercase;width:fit-content;letter-spacing:var(--espacement-inter-lettres-etendu-l);margin:auto}.page-modele-simple#page-cgv .contenu__textuel__section ul{padding:0 var(--espace-xl);margin-bottom:1lh;list-style:inside square}.page-modele-simple#page-cgv .contenu__textuel__section p{padding:0 var(--espace-xl)}.page-modele-simple#page-cgv .contenu__textuel__section p:last-of-type{margin-bottom:var(--espace-xl)}@media (width<=50rem){.page-modele-simple .contenu{border-right:initial;border-left:initial}}

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
#page-succes-commande{--page-hauteur-minimale:calc(100svh - var(--en-tete-hauteur) - var(--pied-de-page-hauteur) - var(--espace-xl) - 1px);--page-marges-bloc-debut:var(--en-tete-hauteur);margin-top:var(--page-marges-bloc-debut);margin-bottom:var(--espace-xl);border-bottom:1px solid var(--couleur-noir);flex-flow:column;display:flex}#page-succes-commande .contenu{width:min(50rem,100%);min-height:var(--page-hauteur-minimale);border:1px solid var(--couleur-noir);border-bottom:initial;flex-flow:column;place-items:center;margin:auto;font-style:italic;font-weight:500;display:flex}#page-succes-commande .contenu__en-tete{width:100%;padding:var(--espace-m)var(--espace-xl);color:var(--couleur-blanc);background:var(--couleur-noir)}#page-succes-commande .contenu__en-tete h2{text-transform:uppercase;width:fit-content;letter-spacing:var(--espacement-inter-lettres-etendu-l);margin:auto}#page-succes-commande .contenu__textuel{max-width:34rem;height:100%;padding:var(--espace-xl);flex-flow:column;flex:1;place-content:center;font-style:normal;display:flex}#page-succes-commande .contenu__textuel p+p{margin-top:var(--espace-m)}#page-succes-commande .contenu__rappel-commande{border-top:1px solid var(--couleur-noir);flex-flow:column;display:flex}#page-succes-commande .contenu__rappel-commande__produit{border-bottom:1px solid var(--couleur-noir);grid-template-rows:1fr;grid-template-columns:1fr 1fr;display:grid}#page-succes-commande .contenu__rappel-commande__produit:only-child,#page-succes-commande .contenu__rappel-commande__produit:last-of-type{border-bottom:initial}#page-succes-commande .contenu__rappel-commande__produit__illustratif{border-right:1px solid var(--couleur-noir)}#page-succes-commande .contenu__rappel-commande__produit__illustratif picture{overflow:hidden}#page-succes-commande .contenu__rappel-commande__produit__illustratif img{aspect-ratio:1;height:auto}#page-succes-commande .contenu__rappel-commande .detail-produit{width:100%;padding:0 var(--espace-xl);flex-flow:column;place-content:center;font-style:italic;display:flex}#page-succes-commande .contenu__rappel-commande .detail-produit__nom-prix{column-gap:var(--espace-xl);margin-bottom:var(--espace-xs);font-size:var(--espace-l);line-height:var(--hauteur-ligne-moitie);flex-flow:row;justify-content:space-between;display:flex}#page-succes-commande .contenu__rappel-commande .detail-produit__nom-prix span{min-width:4rem;font-weight:600;font-style:initial;text-align:right}#page-succes-commande .contenu__rappel-commande .detail-produit__description{margin-bottom:var(--espace-l);line-height:var(--hauteur-ligne-moitie);text-transform:lowercase}@media (width<=50rem){#page-succes-commande .contenu{border-right:initial;border-left:initial}}
#page-succes-commande{--page-hauteur-minimale:calc(100svh - var(--en-tete-hauteur) - var(--pied-de-page-hauteur) - var(--espace-xl) - 1px);--page-marges-bloc-debut:var(--en-tete-hauteur);margin-top:var(--page-marges-bloc-debut);margin-bottom:var(--espace-xl);border-bottom:1px solid var(--couleur-noir);flex-flow:column;display:flex}#page-succes-commande .contenu{width:min(50rem,100%);min-height:var(--page-hauteur-minimale);border:1px solid var(--couleur-noir);border-bottom:initial;flex-flow:column;place-items:center;margin:auto;font-style:italic;font-weight:500;display:flex}#page-succes-commande .contenu__en-tete{width:100%;padding:var(--espace-m) var(--espace-xl);color:var(--couleur-blanc);background:var(--couleur-noir)}#page-succes-commande .contenu__en-tete h2{text-transform:uppercase;width:fit-content;letter-spacing:var(--espacement-inter-lettres-etendu-l);margin:auto}#page-succes-commande .contenu__textuel{max-width:34rem;height:100%;padding:var(--espace-xl);flex-flow:column;flex:1;place-content:center;font-style:normal;display:flex}#page-succes-commande .contenu__textuel p+p{margin-top:var(--espace-m)}#page-succes-commande .contenu__rappel-commande{border-top:1px solid var(--couleur-noir);flex-flow:column;display:flex}#page-succes-commande .contenu__rappel-commande__produit{border-bottom:1px solid var(--couleur-noir);grid-template-rows:1fr;grid-template-columns:1fr 1fr;display:grid}#page-succes-commande .contenu__rappel-commande__produit:only-child,#page-succes-commande .contenu__rappel-commande__produit:last-of-type{border-bottom:initial}#page-succes-commande .contenu__rappel-commande__produit__illustratif{border-right:1px solid var(--couleur-noir)}#page-succes-commande .contenu__rappel-commande__produit__illustratif picture{overflow:hidden}#page-succes-commande .contenu__rappel-commande__produit__illustratif img{aspect-ratio:1;height:auto}#page-succes-commande .contenu__rappel-commande .detail-produit{width:100%;padding:0 var(--espace-xl);flex-flow:column;place-content:center;font-style:italic;display:flex}#page-succes-commande .contenu__rappel-commande .detail-produit__nom-prix{column-gap:var(--espace-xl);margin-bottom:var(--espace-xs);font-size:var(--espace-l);line-height:var(--hauteur-ligne-moitie);flex-flow:row;justify-content:space-between;display:flex}#page-succes-commande .contenu__rappel-commande .detail-produit__nom-prix span{min-width:4rem;font-weight:600;font-style:initial;text-align:right}#page-succes-commande .contenu__rappel-commande .detail-produit__description{margin-bottom:var(--espace-l);line-height:var(--hauteur-ligne-moitie);text-transform:lowercase}@media (width<=50rem){#page-succes-commande .contenu{border-right:initial;border-left:initial}}

View file

@ -25,12 +25,12 @@ Timber::$dirname = ['views'];
// Charge les Scripts du thème (report d'erreurs)
function load_scripts(): void {
wp_enqueue_script_module(
id: 'haiku-atelier-2024-gaffe',
deps: [],
src: get_template_directory_uri() . '/assets/js/gaffe.js',
version: filemtime(get_template_directory() . '/assets/js/gaffe.js'),
);
// wp_enqueue_script_module(
// id: 'haiku-atelier-2024-gaffe',
// deps: [],
// src: get_template_directory_uri() . '/assets/js/gaffe.js',
// version: filemtime(get_template_directory() . '/assets/js/gaffe.js'),
// );
wp_enqueue_script_module(
id: 'haiku-atelier-2024-bouton-panier',
deps: [],

View file

@ -15,6 +15,23 @@ use Symfony\Component\Uid\Uuid;
header('Content-Type: application/json; charset=utf-8');
// TODO: Appliquer le bon calcul pour les montants vs. percentages
function get_discount_amount(WC_Coupon $coupon) {
if ($coupon->get_discount_type() === 'fixed_cart') {
return $coupon->get_amount() * 100;
} else {
return $coupon->get_amount();
}
}
function get_discount_duration(WC_Coupon $coupon): string {
if ($coupon->get_discount_type() === 'fixed_cart') {
return 'once';
} else {
return 'forever';
}
}
// Récupère les informations nécessaires
/** @var WC_Session_Handler $session_wc La Session WooCommerce contenant entre autre le Panier. */
$session_wc = WC()->session;
@ -101,28 +118,18 @@ if (empty($methode_livraison['nom'])) {
// Sélectionne la clé API Stripe
Stripe::setApiKey(Config::get('STRIPE_API_SECRET'));
// TODO: Appliquer le bon calcul pour les montants vs. percentages
function get_discount_amount(WC_Coupon $coupon) {
if ($coupon->get_discount_type() === 'amount_off') {
return $coupon->get_amount() * 100;
} else {
return $coupon->get_amount() * 100;
}
}
// Met à jour les Codes promos
$coupons_stripe = collect(Coupon::all()->data);
$coupons_wc = collect(WC()->cart->get_coupons())
->map(static fn(WC_Coupon $coupon): array => [
'currency' => 'EUR',
'duration' => 'forever',
'duration' => get_discount_duration($coupon),
'fixed_cart' === $coupon->get_discount_type() ? 'amount_off' : 'percent_off' => get_discount_amount($coupon),
'id' => $coupon->get_code(),
'name' => $coupon->get_code(),
])
->each(static function (array $item) use ($coupons_stripe): void {
// Si le code promo n'existe, le créer
// Si le code promo n'existe pas, le créer
if (!$coupons_stripe->contains('name', $item['name'])) {
Coupon::create($item);
}

View file

@ -4,9 +4,7 @@
* Le modèle de la Page d'un Produit.
*/
use function Crell\fp\pipe;
use HaikuAtelier\Data\Product;
use Timber\Timber;
require_once __DIR__ . '/src/inc/HTML.php';
@ -18,43 +16,16 @@ $templates = ['produit.twig'];
$product = wc_get_product();
// Le Produit DOIT exister.
if ($product === null || is_bool($product)) {
throw new Exception("Le Produit n'existe pas.");
}
// $donnees_produit = recupere_informations_produit_page_produit($product);
// Assemble les données d'intérêt pour la page au sein d'une Classe.
$donnees_produit = Product::new($product);
// Un tableau des informations d'affichage de chaque Variation du Produit
$variations_produit = pipe(
$product->get_children(),
// Récupère les Variations
static fn(/** @var list<int> */ $enfants): array => array_map(
callback: wc_get_product(...),
array: $enfants,
),
// Ne conserve que les Informations souhaitées.
static fn(/** @var list<WC_Product> */ $variations): array => array_map(
callback: static fn(WC_Product $variation): array => [
'id' => $variation->get_id(),
// Ne récupère que le titre de l'Attribut unique de la Variation.
'titre' => match (true) {
'' !== $variation->get_attribute('pa_side') => $variation->get_attribute('pa_side'),
'' !== $variation->get_attribute('pa_stone') => $variation->get_attribute('pa_stone'),
'' !== $variation->get_attribute('pa_size') => $variation->get_attribute('pa_size'),
'' !== $variation->get_attribute('pa_giftcard-amount') => $variation->get_attribute(
'pa_giftcard-amount',
),
default => '',
},
'prix' => $variation->get_price(),
],
array: $variations,
),
);
/** @var int $prix_maximal Le prix de la Variation la plus chère */
$prix_maximal = collect($variations_produit)->max('prix');
$prix_maximal = collect($donnees_produit->variations)->max('price');
$produits_meme_collection = array_map(
array: recupere_produits_meme_collection($donnees_produit->collection)($donnees_produit->id),
@ -62,8 +33,8 @@ $produits_meme_collection = array_map(
);
$context['produit'] = $donnees_produit;
$context['product_json'] = wp_json_encode($donnees_produit);
$context['prix_maximal'] = $prix_maximal;
$context['variations_produit'] = $variations_produit;
$context['produits_meme_collection'] = $produits_meme_collection;
/**
@ -86,12 +57,8 @@ function charge_scripts_page_produit(): void {
add_action('wp_enqueue_scripts', 'charge_scripts_page_produit');
// $lal = wp_json_encode($context);
// echo "<script>console.debug({$lal});</script>";
// $lol = wc_get_product()->get_children();
// $lol = wp_json_encode($lol);
// echo "<script>console.debug({$lol});</script>";
$lal = wp_json_encode($context);
echo "<script>console.debug({$lal});</script>";
// Rendu
Timber::render(

View file

@ -14,10 +14,10 @@ use WP_Term;
final readonly class Product {
/**
* @param list<Attribute> $attributes
* @param list<string> $left_column_photos
* @param list<string> $right_column_photos
* @param list<int> $variation_ids
* @param list<Attribute> $attributes
* @param list<string> $left_column_photos
* @param list<string> $right_column_photos
* @param list<ProductVariation> $variations
*/
private function __construct(
public array $attributes,
@ -33,7 +33,7 @@ final readonly class Product {
public string $hover_photo,
public string $slug,
public int $stock,
public array $variation_ids,
public array $variations,
public string $url,
) {}
@ -78,8 +78,9 @@ final readonly class Product {
$hover_photo = $right_column_photos[0] ?? genere_balise_img_multiformats('-1', true);
$slug = $product->get_slug();
$stock = $product->get_stock_quantity() ?? 1;
/** @var list<int> */
$variation_ids = $product->get_children();
$variations = $product->get_children()
|> (static fn($ids) => Arr::map($ids, wc_get_product(...)))
|> (static fn($products) => Arr::map($products, ProductVariation::new(...)));
$url = $product->get_permalink();
return new self(
@ -96,7 +97,7 @@ final readonly class Product {
hover_photo: $hover_photo,
slug: $slug,
stock: $stock,
variation_ids: $variation_ids,
variations: $variations,
url: $url,
);
}

View file

@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace HaikuAtelier\Data;
use WC_Product;
final readonly class ProductVariation {
/**
* @param int $id L'ID de la Variation
* @param string $price Le prix de la Variation
* @param list<ProductVariationAttribute> $attributes Les attributs appliqués à la Variation
*/
private function __construct(
public int $id,
public string $price,
public array $attributes,
) {}
/**
* Créé une nouvelle instance de `ProductVariation` à partir d'un `WC_Product`.
*/
public static function new(WC_Product $product): self {
$id = $product->get_id();
$price = $product->get_price();
/** @var list<ProductVariationAttribute> */
$attributes = array_map(
/** @phpstan-ignore argument.type (Impossible à satisfaire) */
static fn(string $key, string $value) => new ProductVariationAttribute($key, $value),
array_keys($product->get_attributes()),
array_values($product->get_attributes()),
);
return new self($id, $price, $attributes);
}
}

View file

@ -0,0 +1,14 @@
<?php declare(strict_types=1);
namespace HaikuAtelier\Data;
final readonly class ProductVariationAttribute {
/**
* @param string $attribute Le slug de l'Attribut
* @param string $value Le slug de la valeur de l'Attribut
*/
public function __construct(
public string $attribute,
public string $value,
) {}
}

View file

@ -197,9 +197,9 @@ function genere_prix_maximal_produit_variable_dans_reponse_rest(
}
// Assigne le prix de la Variation la plus chère dans la Réponse
$reponse->data['prix_maximal'] = collect($reponse->data['variations'])->map(wc_get_product(...))->map(
static fn($p) => $p->get_price(),
)->max();
$reponse->data['prix_maximal'] = collect($reponse->data['variations'])
->map(wc_get_product(...))
->map(static fn($p) => $p->get_price())->max();
return $reponse;
}

View file

@ -49,10 +49,10 @@ function genere_balise_img_multiformats(string $id, bool $lazy = false): string
'format' => pathinfo((string) $chemin_format)['extension'],
'taille' => filesize($chemin_format),
'url' => pathinfo($url)['dirname']
. '/'
. pathinfo($url)['filename']
. '.'
. pathinfo((string) $chemin_format)['extension'],
. '/'
. pathinfo($url)['filename']
. '.'
. pathinfo((string) $chemin_format)['extension'],
],
),
);
@ -72,18 +72,18 @@ function genere_balise_img_multiformats(string $id, bool $lazy = false): string
$loading = $lazy ? 'lazy' : 'eager';
return <<<EOD
{$sources}
{$sources}
<img
alt="{$alt}"
decoding="async"
height="{$dimensions[0]}"
loading="{$loading}"
onload="this.style.opacity=1"
src="{$url}"
width="{$dimensions[1]}"
/>
EOD;
<img
alt="{$alt}"
decoding="async"
height="{$dimensions[0]}"
loading="{$loading}"
onload="this.style.opacity=1"
src="{$url}"
width="{$dimensions[1]}"
/>
EOD;
}
/**

View file

@ -1,6 +1,11 @@
import type { InferOutput } from "valibot";
import type { WCV3ProductsArgsSchema, WCV3ProductsSchema } from "../../../schemas/api/v3/products.ts";
import type {
WCV3ProductsArgsSchema,
WCV3ProductSchema,
WCV3ProductsSchema,
} from "../../../schemas/api/v3/products.ts";
export type WCV3Product = InferOutput<typeof WCV3ProductSchema>;
export type WCV3Products = InferOutput<typeof WCV3ProductsSchema>;
export type WCV3ProductsArgs = InferOutput<typeof WCV3ProductsArgsSchema>;

View file

@ -67,6 +67,7 @@ const E = {
CONTENUS_ACCORDEON: mustGetElesInDocument<HTMLDivElement>(DOM_CONTENUS_ACCORDEON),
DOM_VARIATION: recupereElementDocumentEither<HTMLSelectElement>(DOM_DOM_QUANTITE),
PRIX_PRODUIT: mustGetEleInDocument<HTMLParagraphElement>(DOM_PRIX_PRODUIT),
PRODUCT_JSON: mustGetEleInDocument<HTMLScriptElement>("#product-json"),
VARIATION_CHOICE_FORM: mustGetEleInDocument<HTMLFormElement>("#variation-choice"),
};
@ -124,26 +125,51 @@ const gereAccordeonDetailsProduit = (): void => {
E.BOUTON_AJOUT_PANIER.addEventListener("click", (event: MouseEvent): void => ajouteProduitAuPanier(event));
};
const getAttributeValuesFromDom = () => {
const getAttributesFromDom = (): ReadonlyArray<WCStoreCartAddItemArgsItems> => {
const selectElements = epipe(
document.querySelectorAll<HTMLSelectElement>(".selecteur-produit select"),
Array.from<HTMLSelectElement>,
);
if (selectElements.length === 0) return [];
const attributeValues = selectElements.map(select => {
const attributes = selectElements.map((select: HTMLSelectElement) => {
return {
attribute: select.id.replace("selecteur-attribut-", ""),
attribute: select.id,
value: select.value,
} satisfies WCStoreCartAddItemArgsItems;
});
return attributeValues;
return attributes;
};
function areArraysEqual<T>(array1: Array<T>, array2: Array<T>): boolean {
if (array1 !== array2) {
const a1 = JSON.stringify(array1.toSorted());
const a2 = JSON.stringify(array2.toSorted());
return a1 === a2;
}
return true;
}
const updatePriceOnAttributeChange = (): void => {
E.VARIATION_CHOICE_FORM.addEventListener("change", (): void => {
if (!E.VARIATION_CHOICE_FORM.checkValidity()) {
return;
}
const productVariations: Array<unknown> = epipe(E.PRODUCT_JSON.textContent, JSON.parse)?.variations;
const chosenAttributes = getAttributesFromDom();
const chosenVariation = productVariations.find(v => areArraysEqual(v.attributes, chosenAttributes));
const newPrice: string = chosenVariation.price;
E.PRIX_PRODUIT.textContent = `${newPrice}`;
});
};
const ajouteProduitAuPanier = (event: MouseEvent): void => {
event.preventDefault();
console.debug("getAttributeValuesFromDom", getAttributeValuesFromDom());
console.debug("getAttributeValuesFromDom", getAttributesFromDom());
// Construis les arguments de la requête au backend
const argsRequete: WCStoreCartAddItemArgs = {
@ -153,7 +179,7 @@ const ajouteProduitAuPanier = (event: MouseEvent): void => {
// .orDefault(ETATS_PAGE.idProduit),
id: ETATS_PAGE.idProduit,
quantity: 1,
variation: getAttributeValuesFromDom(),
variation: getAttributesFromDom(),
};
// Réalise la Requête et traite sa Réponse
@ -234,19 +260,27 @@ const ajouteProduitAuPanier = (event: MouseEvent): void => {
};
const initAddToCartButtonActivationOnUserChoice = (): void => {
const isInStock = E.BOUTON_AJOUT_PANIER.hasAttribute("data-in-stock");
// S'il n'y a pas de stock, ne rien faire.
if (!isInStock) {
return;
}
// S'il n'y a pas de sélecteur de variation, activer le bouton.
const selectElements: ReadonlyArray<HTMLSelectElement> = epipe(
document.querySelectorAll<HTMLSelectElement>(".selecteur-produit select"),
Array.from<HTMLSelectElement>,
);
// S'il n'y a pas de sélecteur de variation, activer le bouton.
if (selectElements.length === 0) {
E.BOUTON_AJOUT_PANIER.removeAttribute(ATTRIBUT_DESACTIVE);
}
// (Dés)active le bouton d'ajout au panier en fonction de la validité du formulaire.
E.VARIATION_CHOICE_FORM.addEventListener("change", (): void => {
const formValidity = E.VARIATION_CHOICE_FORM.checkValidity();
const isFormValid = E.VARIATION_CHOICE_FORM.checkValidity();
if (formValidity) {
if (isFormValid) {
E.BOUTON_AJOUT_PANIER.removeAttribute(ATTRIBUT_DESACTIVE);
} else {
E.BOUTON_AJOUT_PANIER.setAttribute(ATTRIBUT_DESACTIVE, "");
@ -257,4 +291,8 @@ const initAddToCartButtonActivationOnUserChoice = (): void => {
document.addEventListener("DOMContentLoaded", (): void => {
gereAccordeonDetailsProduit();
initAddToCartButtonActivationOnUserChoice();
updatePriceOnAttributeChange();
// DEBUG
console.debug(JSON.parse(document.querySelector("#product-json")?.textContent));
});

View file

@ -1,12 +1,14 @@
{% extends 'base.twig' %}
{% block head %}
<script>
{{ include('parts/en-tetes-backend.twig') }}
<script id="injection">
// Injection d'états pour les Scripts de la page.
const _etats = {
nonce: "{{ nonce_wc }}",
authString: "{{ auth_string }}",
nonce: "{{ nonce_wc }}",
};
</script>
{% endblock head %}

View file

@ -1,7 +1,7 @@
{% extends 'base.twig' %}
{% block head %}
<script>
<script id="injection">
// Injection d'états pour les Scripts de la page.
const _etats = {

View file

@ -0,0 +1,6 @@
<script
id="injection-v2"
type="application/json"
>
{ "authString": "{{ auth_string }}", "nonce": "{{ nonce_wc }}" }
</script>

View file

@ -12,48 +12,48 @@
<h3 class="selecteur-produit__nom">{{ produit.name }}</h3>
<div class="selecteur-produit__attribut-variation">
{% if produit.attributes %}
{% for attribut in produit.attributes %}
<div class="test">
{{ include('parts/pages/produit/selecteur-attributs-produit.twig') }}
</div>
{% endfor %}
{% endif %}
{#
{% if produit.attributes %}
{% for attribut in produit.attributes %}
<div class="test">
{{ include('parts/pages/produit/selecteur-attributs-produit.twig') }}
</div>
{% endfor %}
{% if variations_produit|length > 1 %}
<label
for="selecteur-variation"
id="label-selecteur-variation"
>
Option:
</label>
<div class="selecteur-produit__attribut-variation__selecteurs">
<select
aria-labelledby="label-selecteur-variation"
id="selecteur-variation"
name="variations"
>
<option
disabled
selected
value=""
>
--
</option>
{% for variation in variations_produit %}
<option
data-prix="{{ variation.prix }}"
value="{{ variation.id }}"
>
{{ variation.titre }}
</option>
{% endfor %}
</select>
</div>
{% endif %}
#}
{% if variations_produit|length > 1 %}
<label
for="selecteur-variation"
id="label-selecteur-variation"
>
Option:
</label>
<div class="selecteur-produit__attribut-variation__selecteurs">
<select
aria-labelledby="label-selecteur-variation"
id="selecteur-variation"
name="variations"
>
<option
disabled
selected
value=""
>
--
</option>
{% for variation in variations_produit %}
<option
data-prix="{{ variation.prix }}"
value="{{ variation.id }}"
>
{{ variation.titre }}
</option>
{% endfor %}
</select>
</div>
{% endif %}
</div>
<p class="selecteur-produit__prix">{{ prix_maximal ?? produit.price }}€</p>
@ -126,6 +126,7 @@
<button
class="bouton-case-pleine"
disabled
data-in-stock
for="variation-choice"
id="bouton-ajout-panier"
type="submit"

View file

@ -1,15 +1,15 @@
<div class="selecteur-produit__attribut-variation__selecteurs">
<label
for="selecteur-attribut-{{ attribut.slug }}"
id="label-selecteur-attribut-{{ attribut.slug }}"
for="{{ attribut.slug }}"
id="label-{{ attribut.slug }}"
>
{{ attribut.name }}:
</label>
<select
aria-labelledby="label-selecteur-attribut-{{ atribut.slug }}"
id="selecteur-attribut-{{ attribut.slug }}"
name="attribut-{{ attribut.slug }}"
aria-labelledby="label-{{ atribut.slug }}"
id="{{ attribut.slug }}"
name="{{ attribut.slug }}"
required
>
<option

View file

@ -1,20 +1,30 @@
{% extends 'base.twig' %}
{% block head %}
<script>
<script id="injection">
// dprint-ignore-file
// Injection d'états pour les Scripts de la page.
// Injection d'états pour les Scripts de la page.
/**
* @typedef {Object} Etats - États utiles pour les scripts de la page.
* @property {number} idProduit - L'ID en base de données du Produit.
* @property {string} nonce - Un nonce pour l'authentification de requêtes API.
*/
/** @type {Etats} */
const _etats = {
idProduit: {{ produit.id }},
nonce: "{{ nonce_wc }}",
};
/**
* @typedef {Object} Etats - États utiles pour les scripts de la page.
* @property {number} idProduit - L'ID en base de données du Produit.
* @property {string} nonce - Un nonce pour l'authentification de requêtes API.
*/
/** @type {Etats} */
const _etats = {
idProduit: {{ produit.id }},
nonce: "{{ nonce_wc }}",
};
</script>
<!-- markup-fmt-ignore -->
<script
id="product-json"
type="application/json"
>
// dprint-ignore
{{ product_json }}
</script>
{% endblock head %}