@websline/cms-view-utils 1.0.0-alpha.5 → 1.0.1

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.
@@ -1 +1 @@
1
- (()=>{(function(){var c;if(typeof window>"u")return;let u=150,a=60,t=document.currentScript||[...document.querySelectorAll("script[data-slug]")].pop(),n=(c=t==null?void 0:t.dataset)==null?void 0:c.slug;if(!n){console.warn("[editScroll] Missing data-slug");return}let s=`preview-scroll:${n}`,r=null,l=0,i=()=>{let e=window.scrollY;e!==l&&(l=e,sessionStorage.setItem(s,String(e)))},d=()=>{clearTimeout(r),r=setTimeout(i,u)},w=()=>{let e=sessionStorage.getItem(s);if(!e)return;let o=Number(e);Number.isNaN(o)||requestAnimationFrame(()=>{window.scrollTo(0,o),setTimeout(()=>{window.scrollTo(0,o)},a)})};window.addEventListener("scroll",d,{passive:!0}),window.addEventListener("beforeunload",i),window.addEventListener("load",w)})();})();
1
+ (()=>{(function(){var c;if(typeof window>"u")return;let a=150,d=60,e=document.currentScript||[...document.querySelectorAll("script[data-path]")].pop(),n=(c=e==null?void 0:e.dataset)==null?void 0:c.path;if(!n){console.warn("[editScroll] Missing data-path");return}let r=`preview-scroll:${n}`,s=null,i=0,l=()=>{let t=window.scrollY;t!==i&&(i=t,sessionStorage.setItem(r,String(t)))},u=()=>{clearTimeout(s),s=setTimeout(l,a)},w=()=>{let t=sessionStorage.getItem(r);if(!t)return;let o=Number(t);Number.isNaN(o)||requestAnimationFrame(()=>{window.scrollTo(0,o),setTimeout(()=>{window.scrollTo(0,o)},d)})};window.addEventListener("scroll",u,{passive:!0}),window.addEventListener("beforeunload",l),window.addEventListener("load",w)})();})();
@@ -1 +1 @@
1
- (()=>{var e={BLOCK_ADD:"BLOCK_ADD",BLOCK_DELETE:"BLOCK_DELETE",BLOCK_EDIT:"BLOCK_EDIT",BLOCK_POSITION:"BLOCK_POSITION",BLOCK_SHOW:"BLOCK_SHOW",BLOCK_HIDE:"BLOCK_HIDE",SLUG_CHANGED:"SLUG_CHANGED",SLUG_ON_LOAD:"SLUG_ON_LOAD",IFRAME_DOM_LOADED:"IFRAME_DOM_LOADED",CURRENT_BLOCK_EDIT:"CURRENT_BLOCK_EDIT",SCROLL_TO_BLOCK:"SCROLL_TO_BLOCK"},_=(r,L={})=>{r&&window.parent!==window&&window.parent.postMessage({type:r,payload:L},"*")};(function(){if(window.parent===window||window.__PREVIEW_BRIDGE_INITIALIZED__)return;window.__PREVIEW_BRIDGE_INITIALIZED__=!0;let r=t=>t.metaKey||t.ctrlKey||t.shiftKey,L=t=>{let n=t.target.closest("a[href]");if(!n||n.target==="_blank"||r(t))return;let o=new URL(n.href,window.location.origin);o.origin===window.location.origin&&(t.preventDefault(),t.stopPropagation(),_(e.SLUG_CHANGED,{slug:o.pathname}))};document.addEventListener("click",L,!0),_(e.SLUG_ON_LOAD,{slug:window.location.pathname}),window.addEventListener("load",()=>{_(e.IFRAME_DOM_LOADED)});let E=t=>{let n=`[data-cms-block-id="${t}"]`,o=0,i=10,O=setInterval(()=>{let a=document.querySelector(n);a&&(a.scrollIntoView({behavior:"smooth",block:"center"}),clearInterval(O)),++o>=i&&clearInterval(O)},100)};window.addEventListener("message",t=>{let{type:n,payload:o}=t.data||{};if(n&&n===e.SCROLL_TO_BLOCK){let{draftBlockUuid:i}=o||{};if(!i)return;E(i)}})})();})();
1
+ (()=>{var r={BLOCK_ADD:"BLOCK_ADD",BLOCK_DELETE:"BLOCK_DELETE",BLOCK_EDIT:"BLOCK_EDIT",BLOCK_POSITION:"BLOCK_POSITION",BLOCK_SHOW:"BLOCK_SHOW",BLOCK_HIDE:"BLOCK_HIDE",PATH_CHANGED:"PATH_CHANGED",PATH_ON_LOAD:"PATH_ON_LOAD",IFRAME_DOM_LOADED:"IFRAME_DOM_LOADED",CURRENT_BLOCK_EDIT:"CURRENT_BLOCK_EDIT",SCROLL_TO_BLOCK:"SCROLL_TO_BLOCK"},_=(i,a={})=>{i&&window.parent!==window&&window.parent.postMessage({type:i,payload:a},"*")};(function(){if(window.parent===window||window.__PREVIEW_BRIDGE_INITIALIZED__)return;window.__PREVIEW_BRIDGE_INITIALIZED__=!0;let i=t=>t.metaKey||t.ctrlKey||t.shiftKey,a=t=>{let n=t.target.closest("a[href]");if(!n||n.target==="_blank"||i(t))return;let o=new URL(n.href,window.location.origin);o.origin===window.location.origin&&(t.preventDefault(),t.stopPropagation(),_(r.PATH_CHANGED,{path:o.pathname}))};document.addEventListener("click",a,!0),_(r.PATH_ON_LOAD,{path:window.location.pathname}),window.addEventListener("load",()=>{_(r.IFRAME_DOM_LOADED)});let L=t=>{let n=`[data-cms-block-id="${t}"]`,o=0,e=10,O=setInterval(()=>{let E=document.querySelector(n);E&&(E.scrollIntoView({behavior:"smooth",block:"start"}),clearInterval(O)),++o>=e&&clearInterval(O)},100)};window.addEventListener("message",t=>{let{type:n,payload:o}=t.data||{};if(n&&n===r.SCROLL_TO_BLOCK){let{draftBlockUuid:e}=o||{};if(!e)return;L(e)}})})();})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websline/cms-view-utils",
3
- "version": "1.0.0-alpha.5",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -19,6 +19,15 @@
19
19
  "jsonwebtoken": "^9.0.3"
20
20
  },
21
21
  "devDependencies": {
22
+ "@eslint/compat": "^2.0.5",
23
+ "@eslint/js": "^10.0.1",
24
+ "eslint": "^10.3.0",
25
+ "eslint-config-prettier": "^10.1.8",
26
+ "eslint-plugin-svelte": "^3.17.1",
27
+ "globals": "^17.6.0",
28
+ "prettier": "^3.8.3",
29
+ "prettier-plugin-svelte": "^3.5.1",
30
+ "prettier-plugin-tailwindcss": "^0.8.0",
22
31
  "tsup": "^8.5.1"
23
32
  },
24
33
  "peerDependencies": {
@@ -26,6 +35,8 @@
26
35
  },
27
36
  "sideEffects": false,
28
37
  "scripts": {
29
- "build": "tsup"
38
+ "build": "tsup",
39
+ "format": "prettier --write .",
40
+ "lint": "prettier --check . && eslint ."
30
41
  }
31
42
  }
@@ -9,11 +9,40 @@
9
9
  textColor = "#121110",
10
10
  iconBackgroundColor = "#FFFFFF",
11
11
  iconColor = "#121110",
12
- label = "Hier das erste Element einfügen",
13
- sublabel = "Füge über den Button einen neuen Block hinzu,um mit dem Bearbeiten der Page zu beginnen.",
14
12
  sublabelColor = "#92908D",
13
+ locale = "de",
14
+ isFirst = true,
15
15
  } = $props();
16
16
 
17
+ const i18n = {
18
+ de: {
19
+ first: {
20
+ label: "Block hinzufügen",
21
+ sublabel:
22
+ "Füge über den Button einen neuen Block hinzu, um mit dem Bearbeiten der Page zu beginnen.",
23
+ },
24
+ additional: {
25
+ label: "Weiteren Block hinzufügen",
26
+ sublabel:
27
+ "Füge einen weiteren Block unterhalb der bestehenden Inhalte hinzu.",
28
+ },
29
+ },
30
+ en: {
31
+ first: {
32
+ label: "Add block",
33
+ sublabel: "Use the button to add a new block and start editing the page.",
34
+ },
35
+ additional: {
36
+ label: "Add another block",
37
+ sublabel: "Add another block below the existing content.",
38
+ },
39
+ },
40
+ };
41
+
42
+ const texts = $derived(
43
+ (i18n[locale] ?? i18n["de"])[isFirst ? "first" : "additional"],
44
+ );
45
+
17
46
  const handleClick = () => {
18
47
  notifyCMS(EVENTS.BLOCK_ADD);
19
48
  };
@@ -25,7 +54,7 @@
25
54
  style={`--block-color: ${color}; --block-hover-color: ${hoverColor}; --block-hover-border-color: ${hoverBorderColor}; --block-text: ${textColor}; --block-icon-background: ${iconBackgroundColor}; --block-icon-color: ${iconColor}; --sublabel-color: ${sublabelColor};`}
26
55
  onclick={handleClick}>
27
56
  <div
28
- class="relative mx-auto flex max-w-md flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed border-[var(--block-color)] px-6 py-8 text-center transition-colors duration-300 group-hover:border-[var(--block-hover-border-color)] group-hover:bg-[var(--block-hover-color)]">
57
+ class="relative mx-auto flex max-w-md flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed border-(--block-color) px-6 py-8 text-center transition-colors duration-300 group-hover:border-(--block-hover-border-color) group-hover:bg-(--block-hover-color)">
29
58
  <svg
30
59
  width="24"
31
60
  height="24"
@@ -33,11 +62,11 @@
33
62
  fill="none"
34
63
  xmlns="http://www.w3.org/2000/svg">
35
64
  <path
36
- class="fill-[var(--block-icon-background)]"
65
+ class="fill-(--block-icon-background)"
37
66
  d="M0 12C0 5.37258 5.37258 0 12 0C18.6274 0 24 5.37258 24 12C24 18.6274 18.6274 24 12 24C5.37258 24 0 18.6274 0 12Z"
38
67
  fill="#FFFFFF" />
39
68
  <path
40
- class="stroke-[var(--block-icon-color)]"
69
+ class="stroke-(--block-icon-color)"
41
70
  d="M12.0231 6.6665L12.0092 17.3332M6.66675 11.9998H17.3334"
42
71
  stroke="#121110"
43
72
  stroke-width="1.5"
@@ -46,12 +75,12 @@
46
75
  </svg>
47
76
 
48
77
  <span
49
- class="text-sm text-[var(--block-text)] transition-opacity duration-300 group-hover:opacity-100">
50
- {label}
78
+ class="text-sm text-(--block-text) transition-opacity duration-300 group-hover:opacity-100">
79
+ {texts.label}
51
80
  </span>
52
81
  <span
53
- class="text-sm text-[var(--sublabel-color)] transition-opacity duration-300 group-hover:opacity-100">
54
- {sublabel}
82
+ class="text-sm text-(--sublabel-color) transition-opacity duration-300 group-hover:opacity-100">
83
+ {texts.sublabel}
55
84
  </span>
56
85
  </div>
57
86
  </button>
@@ -8,6 +8,7 @@
8
8
  import ImageText from "./skeleton/ImageText.svelte";
9
9
 
10
10
  let {
11
+ barPosition,
11
12
  block,
12
13
  children,
13
14
  color = "#000fff",
@@ -16,6 +17,14 @@
16
17
  textColor = "#F1F1F2",
17
18
  } = $props();
18
19
 
20
+ let calcBarPosition = $derived.by(() => {
21
+ if (typeof barPosition === "string") return barPosition;
22
+
23
+ if (position === 0) return "inside";
24
+
25
+ return "outside";
26
+ });
27
+
19
28
  const debounce = (fn, delay = 150) => {
20
29
  let timer;
21
30
 
@@ -100,6 +109,20 @@
100
109
  window.removeEventListener("message", handler);
101
110
  };
102
111
  });
112
+
113
+ const isOutside = $derived(calcBarPosition === "outside");
114
+
115
+ const containerShape = $derived(
116
+ isOutside ? "rounded-t-lg -top-8" : "rounded-b-lg top-1.5",
117
+ );
118
+
119
+ const cornerEdges = $derived(
120
+ isOutside
121
+ ? "before:bottom-1 before:-left-4 before:shadow-[6px_6px_0_0_var(--block-color)] " +
122
+ "after:bottom-1 after:-right-4 after:shadow-[-6px_6px_0_0_var(--block-color)]"
123
+ : "before:top-0 before:-left-4 before:shadow-[6px_-6px_0_0_var(--block-color)] " +
124
+ "after:top-0 after:-right-4 after:shadow-[-6px_-6px_0_0_var(--block-color)]",
125
+ );
103
126
  </script>
104
127
 
105
128
  <div
@@ -111,14 +134,14 @@
111
134
  onmouseleave={handleLeave}
112
135
  role="group">
113
136
  <div
114
- class="pointer-events-none absolute inset-0 z-20 border-6 transition-opacity duration-100"
137
+ class="pointer-events-none absolute inset-0 z-[9998] border-6 transition-opacity duration-100"
115
138
  style="border-color: var(--block-color)"
116
139
  class:opacity-100={toolbarVisible}
117
140
  class:opacity-0={!toolbarVisible}>
118
141
  </div>
119
142
 
120
143
  <div
121
- class="absolute top-1.5 left-1/2 z-10 flex h-9 -translate-x-1/2 items-center justify-center gap-1.5 rounded-b-lg px-3 pb-1 transition-opacity duration-100 before:absolute before:top-0 before:-left-4 before:h-4 before:w-4 before:rounded-full before:bg-transparent before:shadow-[6px_-6px_0_0_var(--block-color)] before:content-[''] after:absolute after:top-0 after:-right-4 after:h-4 after:w-4 after:rounded-full after:bg-transparent after:shadow-[-6px_-6px_0_0_var(--block-color)] after:content-['']"
144
+ class="absolute left-1/2 z-[9999] flex h-9 -translate-x-1/2 items-center justify-center gap-1.5 px-3 transition-opacity duration-100 before:absolute before:h-4 before:w-4 before:rounded-full before:bg-transparent before:content-[''] after:absolute after:h-4 after:w-4 after:rounded-full after:bg-transparent after:content-[''] {containerShape} {cornerEdges}"
122
145
  style="background: var(--block-color); color: var(--block-text);"
123
146
  class:opacity-100={toolbarVisible}
124
147
  class:opacity-0={!toolbarVisible}>
@@ -196,7 +219,7 @@
196
219
  </button>
197
220
  {/if} -->
198
221
 
199
- <button
222
+ <!-- <button
200
223
  aria-label="copy block"
201
224
  class="cursor-pointer"
202
225
  onclick={() => handleClick(CMS_ACTIONS.copy)}>
@@ -213,7 +236,7 @@
213
236
  d="M10 4.5H22C22.2761 4.50011 22.5 4.72392 22.5 5V19C22.5 19.2761 22.2761 19.4999 22 19.5H18.5V22.999C18.5 23.2731 18.2763 23.4999 17.9932 23.5H6.00684C5.72308 23.5 5.5 23.2754 5.5 22.999L5.50293 9.00098C5.50298 8.72676 5.72665 8.5 6.00977 8.5H9.5V5C9.5 4.72386 9.72386 4.5 10 4.5ZM6.50195 10L6.5 22V22.5H17.5V9.5H6.50293L6.50195 10ZM10.5 8.5H18.5V18.5H21.5V5.5H10.5V8.5Z"
214
237
  stroke="var(--block-text)"></path>
215
238
  </svg>
216
- </button>
239
+ </button> -->
217
240
 
218
241
  <button
219
242
  aria-label="position block"
@@ -2,6 +2,8 @@
2
2
  let { children, class: className } = $props();
3
3
  </script>
4
4
 
5
- <section class={`grid${className ? ` ${className}` : ""}`} data-cms-page-content>
5
+ <section
6
+ class={`grid grid-cols-1${className ? ` ${className}` : ""}`}
7
+ data-cms-page-content>
6
8
  {@render children?.()}
7
9
  </section>
@@ -6,16 +6,16 @@
6
6
 
7
7
  const script =
8
8
  document.currentScript ||
9
- [...document.querySelectorAll("script[data-slug]")].pop();
9
+ [...document.querySelectorAll("script[data-path]")].pop();
10
10
 
11
- const slug = script?.dataset?.slug;
11
+ const path = script?.dataset?.path;
12
12
 
13
- if (!slug) {
14
- console.warn("[editScroll] Missing data-slug");
13
+ if (!path) {
14
+ console.warn("[editScroll] Missing data-path");
15
15
  return;
16
16
  }
17
17
 
18
- const storageKey = `preview-scroll:${slug}`;
18
+ const storageKey = `preview-scroll:${path}`;
19
19
 
20
20
  let timeout = null;
21
21
  let lastY = 0;
@@ -4,20 +4,21 @@ import { buildCmsHeaders } from "./headers.js";
4
4
  import { HttpError } from "./errors.js";
5
5
 
6
6
  const fetchPage = async (context) => {
7
- let { slug = "" } = context.params;
7
+ let { path = "" } = context.params;
8
+
8
9
  const request = context.request;
9
10
  const url = new URL(request.url);
10
11
  const isCMSPreviewRoute = url.pathname.startsWith("/preview_");
11
12
 
12
13
  if (isCMSPreviewRoute) {
13
- slug = slug.replace(/^preview_/, "");
14
+ path = path.replace(/^preview_/, "");
14
15
  }
15
16
 
16
17
  const editorToken = url.searchParams.get("editorToken");
17
18
  const draftUuid = resolveDraftUuidFromToken(editorToken);
18
19
  const isCMSEditRoute = editorToken && draftUuid;
19
20
 
20
- const cmsUrl = buildCmsPageUrl({ slug, draftUuid });
21
+ const cmsUrl = buildCmsPageUrl({ draftUuid, path });
21
22
 
22
23
  const response = await fetch(cmsUrl, {
23
24
  method: "GET",
@@ -5,8 +5,8 @@ const EVENTS = {
5
5
  BLOCK_POSITION: "BLOCK_POSITION",
6
6
  BLOCK_SHOW: "BLOCK_SHOW",
7
7
  BLOCK_HIDE: "BLOCK_HIDE",
8
- SLUG_CHANGED: "SLUG_CHANGED",
9
- SLUG_ON_LOAD: "SLUG_ON_LOAD",
8
+ PATH_CHANGED: "PATH_CHANGED",
9
+ PATH_ON_LOAD: "PATH_ON_LOAD",
10
10
  IFRAME_DOM_LOADED: "IFRAME_DOM_LOADED",
11
11
  CURRENT_BLOCK_EDIT: "CURRENT_BLOCK_EDIT",
12
12
  SCROLL_TO_BLOCK: "SCROLL_TO_BLOCK",
@@ -21,15 +21,15 @@ import { EVENTS, notifyCMS } from "./notify.js";
21
21
  event.preventDefault();
22
22
  event.stopPropagation();
23
23
 
24
- notifyCMS(EVENTS.SLUG_CHANGED, {
25
- slug: url.pathname,
24
+ notifyCMS(EVENTS.PATH_CHANGED, {
25
+ path: url.pathname,
26
26
  });
27
27
  };
28
28
 
29
29
  document.addEventListener("click", handleClick, true);
30
30
 
31
- notifyCMS(EVENTS.SLUG_ON_LOAD, {
32
- slug: window.location.pathname,
31
+ notifyCMS(EVENTS.PATH_ON_LOAD, {
32
+ path: window.location.pathname,
33
33
  });
34
34
 
35
35
  window.addEventListener("load", () => {
@@ -46,7 +46,7 @@ import { EVENTS, notifyCMS } from "./notify.js";
46
46
  const el = document.querySelector(selector);
47
47
 
48
48
  if (el) {
49
- el.scrollIntoView({ behavior: "smooth", block: "center" });
49
+ el.scrollIntoView({ behavior: "smooth", block: "start" });
50
50
  clearInterval(interval);
51
51
  }
52
52
 
@@ -1,13 +1,13 @@
1
- const buildCmsPageUrl = ({ slug, draftUuid }) => {
1
+ const buildCmsPageUrl = ({ draftUuid, path }) => {
2
2
  const base = import.meta.env.CMS_URL;
3
3
 
4
4
  if (draftUuid) {
5
5
  return `${base}/api/public/pages/preview/${draftUuid}`;
6
6
  }
7
7
 
8
- const normalizedSlug = slug.startsWith("/") ? slug : `/${slug}`;
8
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
9
9
 
10
- return `${base}/api/public/pages${normalizedSlug}`;
10
+ return `${base}/api/public/pages${normalizedPath}`;
11
11
  };
12
12
 
13
13
  export { buildCmsPageUrl };