@agence-zef/astro 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Popover.astro +9 -2
- package/dist/index.d.ts +11 -0
- package/dist/index.js +15 -1
- package/dist/reveal.d.ts +2 -0
- package/dist/reveal.js +75 -0
- package/package.json +7 -3
- package/styles.css +127 -0
package/components/Popover.astro
CHANGED
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* - un autre bouton du même popover pendant qu'il est ouvert : le popover se déplace vers lui
|
|
9
9
|
* tout de suite, sans se fermer ni se rouvrir (le site met son contenu à jour dans son propre
|
|
10
10
|
* `click`) ; le même bouton : il se ferme ;
|
|
11
|
-
* - clic en dehors ou Échap : il se ferme (sauf `manual`)
|
|
11
|
+
* - clic en dehors ou Échap : il se ferme (sauf `manual`) ;
|
|
12
|
+
* - `popovertargetaction="hide"` (croix de fermeture, placée dans le popover ou ailleurs) : il se
|
|
13
|
+
* ferme ; `popovertargetaction="show"` : il s'ouvre contre ce bouton sans jamais se fermer.
|
|
12
14
|
*/
|
|
13
15
|
interface Props {
|
|
14
16
|
id: string;
|
|
@@ -59,7 +61,12 @@ const { id, manual = false, placement = "bottom", class: className } = Astro.pro
|
|
|
59
61
|
if (trigger && pop?.hasAttribute("data-zef-popover")) {
|
|
60
62
|
// Le comportement natif (basculer) est remplacé : déplacer plutôt que fermer.
|
|
61
63
|
event.preventDefault();
|
|
62
|
-
|
|
64
|
+
const action = trigger.getAttribute("popovertargetaction");
|
|
65
|
+
if (action === "hide") {
|
|
66
|
+
if (isOpen(pop)) pop.hidePopover();
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (action !== "show" && isOpen(pop) && opener.get(pop) === trigger) return pop.hidePopover();
|
|
63
70
|
anchorTo(pop, trigger);
|
|
64
71
|
if (!isOpen(pop)) pop.showPopover();
|
|
65
72
|
return;
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,17 @@ export type ZefOptions = {
|
|
|
32
32
|
checkout?: string;
|
|
33
33
|
confirmation?: string;
|
|
34
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Apparitions au défilement (`data-reveal` dans les sections, styles dans `styles.css`) :
|
|
37
|
+
* actives par défaut. `false` les coupe sur tout le site ; `once: false` les rejoue à chaque
|
|
38
|
+
* entrée dans l'écran ; `threshold` (part visible, 0 à 1) et `rootMargin` règlent le moment
|
|
39
|
+
* où elles partent.
|
|
40
|
+
*/
|
|
41
|
+
animations?: false | {
|
|
42
|
+
once?: boolean;
|
|
43
|
+
threshold?: number;
|
|
44
|
+
rootMargin?: string;
|
|
45
|
+
};
|
|
35
46
|
};
|
|
36
47
|
/**
|
|
37
48
|
* Intégration Astro du CMS ZEF (cahier des charges § 10) : route attrape-tout des pages
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,15 @@ export * from "./accounts.js";
|
|
|
7
7
|
export * from "./helpers.js";
|
|
8
8
|
export * from "./seo.js";
|
|
9
9
|
export * from "./shop.js";
|
|
10
|
+
/**
|
|
11
|
+
* Script en tête de page : active les apparitions (`data-zef-reveal` sur `<html>`, avec leurs
|
|
12
|
+
* réglages) avant le premier affichage, sauf dans les routes de l'éditeur (`/__zef/…`). Filet de
|
|
13
|
+
* sécurité : si le script des apparitions n'a pas démarré après 2,5 s, tout redevient visible.
|
|
14
|
+
*/
|
|
15
|
+
function revealHead(animations) {
|
|
16
|
+
const settings = JSON.stringify(animations || {});
|
|
17
|
+
return `(function(){var d=document.documentElement;if(location.pathname.indexOf("/__zef/")===0)return;d.setAttribute("data-zef-reveal",${JSON.stringify(settings)});setTimeout(function(){if(!window.__zefReveal)d.removeAttribute("data-zef-reveal")},2500)})();`;
|
|
18
|
+
}
|
|
10
19
|
const MEDIA_URL = "https://medias.agence-zef.fr";
|
|
11
20
|
/** `rendering` de `zef.config.ts` (lu comme la CLI, avec jiti) ; `static` en cas de doute. */
|
|
12
21
|
async function readRendering(file) {
|
|
@@ -72,7 +81,7 @@ export default function zef(options = {}) {
|
|
|
72
81
|
return {
|
|
73
82
|
name: "@agence-zef/astro",
|
|
74
83
|
hooks: {
|
|
75
|
-
"astro:config:setup": async ({ config, command, injectRoute, updateConfig, addWatchFile, addMiddleware, logger, }) => {
|
|
84
|
+
"astro:config:setup": async ({ config, command, injectRoute, injectScript, updateConfig, addWatchFile, addMiddleware, logger, }) => {
|
|
76
85
|
const root = fileURLToPath(config.root);
|
|
77
86
|
loadZefEnv(root);
|
|
78
87
|
// Redirections du CMS (C-17 : slugs modifiés, pages déplacées, redirections manuelles).
|
|
@@ -104,6 +113,11 @@ export default function zef(options = {}) {
|
|
|
104
113
|
if (config.build.inlineStylesheets === "auto") {
|
|
105
114
|
updateConfig({ build: { inlineStylesheets: "always" } });
|
|
106
115
|
}
|
|
116
|
+
// Apparitions au défilement (`data-reveal`) : actives sauf `animations: false`.
|
|
117
|
+
if (options.animations !== false) {
|
|
118
|
+
injectScript("head-inline", revealHead(options.animations));
|
|
119
|
+
injectScript("page", 'import "@agence-zef/astro/reveal";');
|
|
120
|
+
}
|
|
107
121
|
addWatchFile(join(root, ".env"));
|
|
108
122
|
const layout = join(root, options.layout ?? "src/layouts/Page.astro");
|
|
109
123
|
const configFile = join(root, "zef.config.ts");
|
package/dist/reveal.d.ts
ADDED
package/dist/reveal.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Apparitions au défilement (`data-reveal`), chargé sur chaque page par l'intégration (option
|
|
3
|
+
* `animations`). Le visuel est dans `styles.css` ; ce script pose seulement `data-zef-visible`
|
|
4
|
+
* quand un élément entre dans l'écran, puis `data-zef-done` une fois l'effet joué (l'élément
|
|
5
|
+
* retrouve alors ses propres transitions). Ne fait rien sans `data-zef-reveal` sur `<html>`
|
|
6
|
+
* (aperçu de l'éditeur, animations coupées).
|
|
7
|
+
*
|
|
8
|
+
* Attributs : `data-reveal` (effet), `data-reveal-delay` (ms), `data-reveal-stagger` sur un
|
|
9
|
+
* parent (ses `data-reveal` arrivent en cascade), `data-reveal-scroll` (100 % CSS, ignoré ici).
|
|
10
|
+
*/
|
|
11
|
+
const root = document.documentElement;
|
|
12
|
+
const observed = new WeakSet();
|
|
13
|
+
let observer = null;
|
|
14
|
+
let options = { once: true, threshold: 0.15, rootMargin: "0px 0px -5% 0px" };
|
|
15
|
+
/** Fin de l'effet : l'élément ne porte plus la transition d'apparition. */
|
|
16
|
+
function done(el) {
|
|
17
|
+
const style = getComputedStyle(el);
|
|
18
|
+
const seconds = (v) => Math.max(...v.split(",").map((s) => Number.parseFloat(s) || 0));
|
|
19
|
+
const ms = (seconds(style.transitionDuration) + seconds(style.transitionDelay)) * 1000;
|
|
20
|
+
window.setTimeout(() => el.setAttribute("data-zef-done", ""), ms + 50);
|
|
21
|
+
}
|
|
22
|
+
function onIntersect(entries) {
|
|
23
|
+
for (const { target, isIntersecting } of entries) {
|
|
24
|
+
const el = target;
|
|
25
|
+
if (isIntersecting) {
|
|
26
|
+
el.setAttribute("data-zef-visible", "");
|
|
27
|
+
if (options.once) {
|
|
28
|
+
observer?.unobserve(el);
|
|
29
|
+
done(el);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (!options.once) {
|
|
33
|
+
el.removeAttribute("data-zef-visible");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Observe les nouveaux `data-reveal` de la page (rang dans la cascade, délai). */
|
|
38
|
+
export function scanReveals(scope = document) {
|
|
39
|
+
if (!observer)
|
|
40
|
+
return;
|
|
41
|
+
for (const parent of scope.querySelectorAll("[data-reveal-stagger]")) {
|
|
42
|
+
let index = 0;
|
|
43
|
+
for (const el of parent.querySelectorAll("[data-reveal]")) {
|
|
44
|
+
if (el.closest("[data-reveal-stagger]") !== parent)
|
|
45
|
+
continue;
|
|
46
|
+
el.style.setProperty("--zef-reveal-index", String(index++));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const el of scope.querySelectorAll("[data-reveal]:not([data-reveal-scroll])")) {
|
|
50
|
+
if (observed.has(el))
|
|
51
|
+
continue;
|
|
52
|
+
observed.add(el);
|
|
53
|
+
const delay = Number(el.dataset.revealDelay);
|
|
54
|
+
if (delay > 0)
|
|
55
|
+
el.style.setProperty("--zef-reveal-delay", `${delay}ms`);
|
|
56
|
+
observer.observe(el);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function start() {
|
|
60
|
+
const raw = root.getAttribute("data-zef-reveal");
|
|
61
|
+
if (raw === null || observer)
|
|
62
|
+
return;
|
|
63
|
+
window.__zefReveal = true;
|
|
64
|
+
try {
|
|
65
|
+
options = { ...options, ...JSON.parse(raw || "{}") };
|
|
66
|
+
}
|
|
67
|
+
catch { }
|
|
68
|
+
observer = new IntersectionObserver(onIntersect, {
|
|
69
|
+
threshold: options.threshold,
|
|
70
|
+
rootMargin: options.rootMargin,
|
|
71
|
+
});
|
|
72
|
+
scanReveals();
|
|
73
|
+
}
|
|
74
|
+
start();
|
|
75
|
+
document.addEventListener("astro:page-load", () => scanReveals());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agence-zef/astro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Intégration Astro du CMS ZEF : routes, rendu des sections, aperçu, composants réutilisables sans style.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -65,6 +65,10 @@
|
|
|
65
65
|
"types": "./dist/ui.d.ts",
|
|
66
66
|
"import": "./dist/ui.js"
|
|
67
67
|
},
|
|
68
|
+
"./reveal": {
|
|
69
|
+
"types": "./dist/reveal.d.ts",
|
|
70
|
+
"import": "./dist/reveal.js"
|
|
71
|
+
},
|
|
68
72
|
"./routes/page-cached.astro": "./components/routes/page-cached.astro",
|
|
69
73
|
"./routes/revalidate.ts": "./components/routes/revalidate.ts"
|
|
70
74
|
},
|
|
@@ -86,8 +90,8 @@
|
|
|
86
90
|
"dependencies": {
|
|
87
91
|
"jiti": "^2.6.1",
|
|
88
92
|
"vanilla-cookieconsent": "3.1.0",
|
|
89
|
-
"@agence-zef/schema": "0.
|
|
90
|
-
"@agence-zef/sdk": "0.
|
|
93
|
+
"@agence-zef/schema": "0.11.0",
|
|
94
|
+
"@agence-zef/sdk": "0.11.0"
|
|
91
95
|
},
|
|
92
96
|
"homepage": "https://agence-zef.fr",
|
|
93
97
|
"scripts": {
|
package/styles.css
CHANGED
|
@@ -686,3 +686,130 @@
|
|
|
686
686
|
flex-basis: 100%;
|
|
687
687
|
}
|
|
688
688
|
}
|
|
689
|
+
|
|
690
|
+
/*
|
|
691
|
+
* Apparitions au défilement (`data-reveal`) : le visuel est ici, en CSS ; le script de
|
|
692
|
+
* l'intégration (`src/reveal.ts`) pose seulement `data-zef-visible` quand l'élément entre dans
|
|
693
|
+
* l'écran. L'état masqué ne s'applique que sous `:root[data-zef-reveal]`, posé en tête de page
|
|
694
|
+
* par l'intégration (option `animations`) : sans JavaScript, dans l'aperçu de l'éditeur ou si le
|
|
695
|
+
* script ne se charge pas, tout reste visible.
|
|
696
|
+
*
|
|
697
|
+
* Réglages par site : les variables `--zef-reveal-*` dans le `:root` du site ; un effet maison
|
|
698
|
+
* se déclare avec les variables `--zef-reveal-from-*` (voir `CLAUDE.md` du kit).
|
|
699
|
+
*/
|
|
700
|
+
:where(:root) {
|
|
701
|
+
--zef-reveal-duration: 0.7s;
|
|
702
|
+
--zef-reveal-easing: cubic-bezier(0.22, 1, 0.36, 1);
|
|
703
|
+
--zef-reveal-distance: 1.5rem;
|
|
704
|
+
--zef-reveal-scale: 0.94;
|
|
705
|
+
--zef-reveal-blur: 8px;
|
|
706
|
+
--zef-reveal-stagger: 80ms;
|
|
707
|
+
--zef-reveal-scroll-range: entry 0% cover 35%;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/* Point de départ de chaque effet (fade-up par défaut) */
|
|
711
|
+
:where([data-reveal]) {
|
|
712
|
+
--zef-reveal-from-opacity: 0;
|
|
713
|
+
--zef-reveal-from-translate: 0 var(--zef-reveal-distance);
|
|
714
|
+
--zef-reveal-from-scale: none;
|
|
715
|
+
--zef-reveal-from-filter: none;
|
|
716
|
+
}
|
|
717
|
+
:where([data-reveal="fade"]) {
|
|
718
|
+
--zef-reveal-from-translate: none;
|
|
719
|
+
}
|
|
720
|
+
:where([data-reveal="fade-down"]) {
|
|
721
|
+
--zef-reveal-from-translate: 0 calc(var(--zef-reveal-distance) * -1);
|
|
722
|
+
}
|
|
723
|
+
:where([data-reveal="slide-left"]) {
|
|
724
|
+
--zef-reveal-from-translate: var(--zef-reveal-distance) 0;
|
|
725
|
+
}
|
|
726
|
+
:where([data-reveal="slide-right"]) {
|
|
727
|
+
--zef-reveal-from-translate: calc(var(--zef-reveal-distance) * -1) 0;
|
|
728
|
+
}
|
|
729
|
+
:where([data-reveal="zoom"]) {
|
|
730
|
+
--zef-reveal-from-translate: none;
|
|
731
|
+
--zef-reveal-from-scale: var(--zef-reveal-scale);
|
|
732
|
+
}
|
|
733
|
+
:where([data-reveal="blur"]) {
|
|
734
|
+
--zef-reveal-from-translate: none;
|
|
735
|
+
--zef-reveal-from-filter: blur(var(--zef-reveal-blur));
|
|
736
|
+
}
|
|
737
|
+
:where([data-reveal="clip"]) {
|
|
738
|
+
--zef-reveal-from-opacity: 1;
|
|
739
|
+
--zef-reveal-from-translate: none;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/* Déclenché à l'entrée dans l'écran : transition de l'état de départ à l'état normal */
|
|
743
|
+
:root[data-zef-reveal] [data-reveal]:not([data-reveal-scroll], [data-zef-done]) {
|
|
744
|
+
transition-property: opacity, translate, scale, filter, clip-path;
|
|
745
|
+
transition-duration: var(--zef-reveal-duration);
|
|
746
|
+
transition-timing-function: var(--zef-reveal-easing);
|
|
747
|
+
transition-delay: calc(
|
|
748
|
+
var(--zef-reveal-delay, 0ms) +
|
|
749
|
+
var(--zef-reveal-index, 0) *
|
|
750
|
+
var(--zef-reveal-stagger)
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
:root[data-zef-reveal] [data-reveal]:not([data-reveal-scroll], [data-zef-visible]) {
|
|
754
|
+
opacity: var(--zef-reveal-from-opacity);
|
|
755
|
+
translate: var(--zef-reveal-from-translate);
|
|
756
|
+
scale: var(--zef-reveal-from-scale);
|
|
757
|
+
filter: var(--zef-reveal-from-filter);
|
|
758
|
+
}
|
|
759
|
+
/* Dévoilement par masque : seul effet qui touche à clip-path (les autres gardent celui du site) */
|
|
760
|
+
:root[data-zef-reveal] [data-reveal="clip"]:not([data-reveal-scroll], [data-zef-visible]) {
|
|
761
|
+
clip-path: inset(0 100% 0 0);
|
|
762
|
+
}
|
|
763
|
+
:root[data-zef-reveal] [data-reveal="clip"][data-zef-visible]:not([data-zef-done]) {
|
|
764
|
+
clip-path: inset(0 0 0 0);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/*
|
|
768
|
+
* Variante 100 % CSS liée au défilement (`data-reveal-scroll`) : l'effet avance et recule avec
|
|
769
|
+
* le défilement. Navigateurs sans `animation-timeline` : rien n'est animé, tout est visible.
|
|
770
|
+
*/
|
|
771
|
+
@keyframes zef-reveal {
|
|
772
|
+
from {
|
|
773
|
+
opacity: var(--zef-reveal-from-opacity);
|
|
774
|
+
translate: var(--zef-reveal-from-translate);
|
|
775
|
+
scale: var(--zef-reveal-from-scale);
|
|
776
|
+
filter: var(--zef-reveal-from-filter);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
@keyframes zef-reveal-clip {
|
|
780
|
+
from {
|
|
781
|
+
clip-path: inset(0 100% 0 0);
|
|
782
|
+
}
|
|
783
|
+
to {
|
|
784
|
+
clip-path: inset(0 0 0 0);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
@supports (animation-timeline: view()) {
|
|
788
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
789
|
+
:root[data-zef-reveal] [data-reveal][data-reveal-scroll] {
|
|
790
|
+
animation: zef-reveal linear both;
|
|
791
|
+
animation-timeline: view();
|
|
792
|
+
animation-range: var(--zef-reveal-scroll-range);
|
|
793
|
+
}
|
|
794
|
+
:root[data-zef-reveal] [data-reveal="clip"][data-reveal-scroll] {
|
|
795
|
+
animation-name: zef-reveal-clip;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/* Mouvement réduit : un fondu court, sans déplacement ni flou */
|
|
801
|
+
@media (prefers-reduced-motion: reduce) {
|
|
802
|
+
:where([data-reveal]) {
|
|
803
|
+
--zef-reveal-from-translate: none;
|
|
804
|
+
--zef-reveal-from-scale: none;
|
|
805
|
+
--zef-reveal-from-filter: none;
|
|
806
|
+
--zef-reveal-stagger: 0ms;
|
|
807
|
+
--zef-reveal-duration: 0.3s;
|
|
808
|
+
}
|
|
809
|
+
:where([data-reveal="clip"]) {
|
|
810
|
+
--zef-reveal-from-opacity: 0;
|
|
811
|
+
}
|
|
812
|
+
:root[data-zef-reveal] [data-reveal="clip"]:not([data-reveal-scroll], [data-zef-visible]) {
|
|
813
|
+
clip-path: none;
|
|
814
|
+
}
|
|
815
|
+
}
|