@websline/cms-view-utils 0.1.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/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@websline/cms-view-utils",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": "./src/index.js"
7
+ },
8
+ "files": [
9
+ "src"
10
+ ],
11
+ "sideEffects": false,
12
+ "peerDependencies": {
13
+ "astro": "^5.8.0",
14
+ "svelte": "^5.33.0"
15
+ },
16
+ "scripts": {}
17
+ }
@@ -0,0 +1,28 @@
1
+ ---
2
+ import { fetchPageData } from "../data/pageData";
3
+
4
+ const { lang, slug } = Astro.params;
5
+ const url = new URL(Astro.request.url);
6
+ const searchParams = url.searchParams;
7
+
8
+ // const isPreviewMode = searchParams.get("editable") === "true";
9
+
10
+ await fetchPageData(Astro.locals, lang, slug);
11
+ ---
12
+
13
+ <slot />
14
+
15
+ <!--
16
+ {isPreviewMode && (
17
+
18
+ <style>
19
+ .cms-block-dropzones {
20
+ padding: 2rem;
21
+ border: 2px dashed #999;
22
+ min-height: 50px;
23
+ }
24
+ .cms-block-dropzones.highlight {
25
+ border-color: rgb(106, 106, 255);
26
+ }
27
+ </style>
28
+ )} -->
@@ -0,0 +1 @@
1
+ export * from "./pageData";
@@ -0,0 +1,37 @@
1
+ export async function fetchPageData(locals, lang, slug) {
2
+ const API_BASE = import.meta.env.PUBLIC_API_URL?.replace(/\/+$/, ""); // Remove trailing slashes
3
+ if (!API_BASE) throw new Error("PUBLIC_API_URL ist nicht gesetzt.");
4
+
5
+ const key = `__pageData__${lang}__${slug}`;
6
+
7
+ if (!locals[key]) {
8
+ console.log("from fetch");
9
+ const url = `${API_BASE}/${lang}/pages/${slug}`;
10
+ const res = await fetch(url);
11
+
12
+ if (!res.ok) {
13
+ throw new Error(
14
+ `Fehler beim Abrufen der Seite: ${res.status} ${res.statusText}`
15
+ );
16
+ }
17
+
18
+ locals[key] = await res.json();
19
+ }
20
+
21
+ locals.__currentPageKey = key;
22
+ return locals[key];
23
+ }
24
+
25
+ export function getPageData(locals) {
26
+ const key = locals.__currentPageKey;
27
+
28
+ if (!key || !locals[key]) {
29
+ throw new Error(
30
+ "getPageData() wurde aufgerufen, bevor fetchPageData() ausgeführt wurde."
31
+ );
32
+ }
33
+
34
+ console.log("from cache");
35
+
36
+ return locals[key];
37
+ }
package/src/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { default as PageRenderer } from "./components/PageRenderer.astro";
2
+ export * from "./data";
3
+ export * from "./utils";
@@ -0,0 +1,190 @@
1
+ // Handler for mouse follower behavior inside the iframe
2
+ class IframeDragHandler {
3
+ constructor() {
4
+ this.mouseFollowerWidth = 48;
5
+ this.mouseFollowerHeight = 48;
6
+
7
+ this.handleMouseMove = (event) => {
8
+ this.updateMouseFollowerPosition(event);
9
+ this.checkMouseLeaveFrame();
10
+ };
11
+
12
+ window.addEventListener("message", (event) => {
13
+ const { owner, type } = event.data;
14
+ if (owner !== "dragging") return;
15
+
16
+ if (type === "startDragging") {
17
+ this.enableDragging();
18
+ }
19
+
20
+ if (type === "stopDragging") {
21
+ this.disableDragging();
22
+ }
23
+
24
+ if (type === "enterIframeWhileDragging") {
25
+ this.showMouseFollower();
26
+ }
27
+
28
+ if (type === "leaveIframeWhileDragging") {
29
+ this.hideMouseFollower();
30
+ }
31
+ });
32
+ }
33
+
34
+ // Enables drag mode inside the iframe
35
+ enableDragging() {
36
+ this.addStopDraggingHandler();
37
+ this.addMouseFollowerToDOM();
38
+ this.addMouseFollowerHandler();
39
+ this.highlightDropzone();
40
+ }
41
+
42
+ // Disables drag mode
43
+ disableDragging() {
44
+ this.removeStopDraggingHandler();
45
+ this.removeMouseFollowerFromDOM();
46
+ this.removeMouseFollowerHandler();
47
+ this.unhighlightDropzone();
48
+ }
49
+
50
+ // Adds a listener for mouseup to stop dragging
51
+ addStopDraggingHandler() {
52
+ window.addEventListener("mouseup", this.stopDragging);
53
+ }
54
+
55
+ // Removes the mouseup listener
56
+ removeStopDraggingHandler() {
57
+ window.removeEventListener("mouseup", this.stopDragging);
58
+ }
59
+
60
+ // Stops dragging and notifies the parent
61
+ stopDragging = () => {
62
+ this.sendParentMessage({
63
+ owner: "iframe",
64
+ type: "stopDragging",
65
+ });
66
+ this.removeStopDraggingHandler();
67
+ };
68
+
69
+ // Adds mouse follower element to the DOM
70
+ addMouseFollowerToDOM() {
71
+ if (this.mouseFollowerInDOM()) return;
72
+
73
+ const div = document.createElement("div");
74
+ div.className = "mouse-follower";
75
+
76
+ Object.assign(div.style, {
77
+ position: "absolute",
78
+ zIndex: "9999",
79
+ pointerEvents: "none",
80
+ left: `-${this.mouseFollowerWidth}px`,
81
+ top: `-${this.mouseFollowerHeight}px`,
82
+ width: this.mouseFollowerWidth + "px",
83
+ height: this.mouseFollowerHeight + "px",
84
+ background: "url(/drag-component.svg) no-repeat center center",
85
+ });
86
+
87
+ document.body.appendChild(div);
88
+ }
89
+
90
+ // Adds the mousemove listener
91
+ addMouseFollowerHandler() {
92
+ window.addEventListener("mousemove", this.handleMouseMove);
93
+ }
94
+
95
+ // Removes the mousemove listener
96
+ removeMouseFollowerHandler() {
97
+ window.removeEventListener("mousemove", this.handleMouseMove);
98
+ }
99
+
100
+ // Updates mouse follower position on mouse move
101
+ updateMouseFollowerPosition(event) {
102
+ const div = this.getMouseFollower();
103
+ if (div) {
104
+ div.style.left = `${event.clientX - this.mouseFollowerWidth / 2}px`;
105
+ div.style.top = `${event.clientY - this.mouseFollowerHeight / 2}px`;
106
+ }
107
+ }
108
+
109
+ // Checks if the mouse follower is outside the viewport
110
+ checkMouseLeaveFrame() {
111
+ const follower = this.getMouseFollower();
112
+ if (!follower) return;
113
+
114
+ const rect = follower.getBoundingClientRect();
115
+ const margin = 1;
116
+
117
+ const outOfBounds =
118
+ rect.left < -margin ||
119
+ rect.top < -margin ||
120
+ rect.right > window.innerWidth + margin ||
121
+ rect.bottom > window.innerHeight + margin;
122
+
123
+ if (outOfBounds && !follower.dataset._wasOutside) {
124
+ follower.dataset._wasOutside = "true";
125
+ this.hideMouseFollower();
126
+ this.sendParentMessage({ owner: "iframe", type: "leaveIframe" });
127
+ } else if (!outOfBounds && follower.dataset._wasOutside === "true") {
128
+ delete follower.dataset._wasOutside;
129
+ }
130
+ }
131
+
132
+ // Hides the mouse follower
133
+ hideMouseFollower() {
134
+ const div = this.getMouseFollower();
135
+ if (div) {
136
+ div.style.display = "none";
137
+ }
138
+ }
139
+
140
+ // Shows the mouse follower
141
+ showMouseFollower() {
142
+ const div = this.getMouseFollower();
143
+ if (div) {
144
+ div.style.display = "block";
145
+ }
146
+ }
147
+
148
+ // Removes the mouse follower from DOM
149
+ removeMouseFollowerFromDOM() {
150
+ const div = this.getMouseFollower();
151
+ if (div) {
152
+ div.remove();
153
+ }
154
+ }
155
+
156
+ // Checks whether the follower is in the DOM
157
+ mouseFollowerInDOM() {
158
+ return !!this.getMouseFollower();
159
+ }
160
+
161
+ // Gets the follower element
162
+ getMouseFollower() {
163
+ return document.querySelector(".mouse-follower");
164
+ }
165
+
166
+ // Sends a message to the parent window
167
+ sendParentMessage(message) {
168
+ window.parent.postMessage(message, "*");
169
+ }
170
+
171
+ // Highlights the dropzone
172
+ highlightDropzone() {
173
+ const dropzones = document.querySelectorAll(".cms-block-dropzones");
174
+
175
+ dropzones.forEach((dropzone) => {
176
+ dropzone.classList.add("highlight");
177
+ });
178
+ }
179
+
180
+ // Removes highlight from dropzone
181
+ unhighlightDropzone() {
182
+ const dropzones = document.querySelectorAll(".cms-block-dropzones");
183
+
184
+ dropzones.forEach((dropzone) => {
185
+ dropzone.classList.remove("highlight");
186
+ });
187
+ }
188
+ }
189
+
190
+ export default IframeDragHandler;
@@ -0,0 +1 @@
1
+ export * from "./iframeDragHandler";