@realiizlabs/admin 0.15.0 → 0.15.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.
@@ -20,26 +20,55 @@ function editHrefFor(pathname, routes, adminPath = "/admin") {
20
20
  }
21
21
  return null;
22
22
  }
23
+ function usePathname() {
24
+ const [path, setPath] = react.useState("");
25
+ react.useEffect(() => {
26
+ const read = () => setPath(window.location.pathname);
27
+ read();
28
+ window.addEventListener("popstate", read);
29
+ const h = window.history;
30
+ if (!h.__rzWrapped) {
31
+ h.__rzWrapped = true;
32
+ for (const m of ["pushState", "replaceState"]) {
33
+ const orig = h[m].bind(h);
34
+ h[m] = ((...args) => {
35
+ orig(...args);
36
+ window.dispatchEvent(new Event("rz:navigate"));
37
+ });
38
+ }
39
+ }
40
+ window.addEventListener("rz:navigate", read);
41
+ return () => {
42
+ window.removeEventListener("popstate", read);
43
+ window.removeEventListener("rz:navigate", read);
44
+ };
45
+ }, []);
46
+ return path;
47
+ }
23
48
  function StudioBar({ routes = {}, adminPath = "/admin", label = "Studio" }) {
24
- const [state, setState] = react.useState({ show: false, path: "" });
49
+ const path = usePathname();
50
+ const [show, setShow] = react.useState(false);
25
51
  react.useEffect(() => {
26
- const path = window.location.pathname;
27
- if (path === adminPath || path.startsWith(`${adminPath}/`)) return;
52
+ if (!path) return;
53
+ if (path === adminPath || path.startsWith(`${adminPath}/`)) {
54
+ setShow(false);
55
+ return;
56
+ }
28
57
  let hidden = false;
29
58
  try {
30
59
  hidden = sessionStorage.getItem(HIDE_KEY) === "1";
31
60
  } catch {
32
61
  }
33
- if (!hidden && hasStudioMarker()) setState({ show: true, path });
34
- }, [adminPath]);
35
- if (!state.show) return null;
36
- const edit = editHrefFor(state.path, routes, adminPath);
62
+ setShow(!hidden && hasStudioMarker());
63
+ }, [path, adminPath]);
64
+ if (!show) return null;
65
+ const edit = editHrefFor(path, routes, adminPath);
37
66
  const close = () => {
38
67
  try {
39
68
  sessionStorage.setItem(HIDE_KEY, "1");
40
69
  } catch {
41
70
  }
42
- setState({ show: false, path: "" });
71
+ setShow(false);
43
72
  };
44
73
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: S.wrap, role: "region", "aria-label": "Studio", "data-studio-bar": true, children: [
45
74
  /* @__PURE__ */ jsxRuntime.jsxs("span", { style: S.brand, children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bar/StudioBar.tsx"],"names":["useState","useEffect","jsxs","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["\"use client\";\n\nimport { useEffect, useState, type CSSProperties } from \"react\";\n\nexport const STUDIO_MARKER_COOKIE = \"rz-studio\";\nconst HIDE_KEY = \"rz-bar-hidden\";\n\nexport interface StudioBarProps {\n /** Public URL prefix → content type id, e.g. { \"/blog/\": \"posts\", \"/events/\": \"events\" }. */\n routes?: Record<string, string>;\n /** Where Studio lives. Default \"/admin\". */\n adminPath?: string;\n /** Shown on the pill. Default \"Studio\". */\n label?: string;\n}\n\n/** True when Studio's marker cookie is present (someone signed in to Studio in this browser). */\nexport function hasStudioMarker(cookie: string = typeof document === \"undefined\" ? \"\" : document.cookie): boolean {\n return cookie.split(\";\").some((c) => c.trim().startsWith(`${STUDIO_MARKER_COOKIE}=1`));\n}\n\n/** The Studio edit page for a public path, or null when the path isn't an item Studio manages. */\nexport function editHrefFor(pathname: string, routes: Record<string, string>, adminPath = \"/admin\"): string | null {\n for (const [prefix, typeId] of Object.entries(routes)) {\n if (!pathname.startsWith(prefix)) continue;\n const rest = pathname.slice(prefix.length).replace(/\\/+$/, \"\");\n if (!rest || rest.includes(\"/\")) continue; // the index page, or something nested — not an item\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(rest)) continue;\n return `${adminPath}/${typeId}/${rest}`;\n }\n return null;\n}\n\nexport function StudioBar({ routes = {}, adminPath = \"/admin\", label = \"Studio\" }: StudioBarProps) {\n const [state, setState] = useState<{ show: boolean; path: string }>({ show: false, path: \"\" });\n\n useEffect(() => {\n const path = window.location.pathname;\n if (path === adminPath || path.startsWith(`${adminPath}/`)) return;\n let hidden = false;\n try { hidden = sessionStorage.getItem(HIDE_KEY) === \"1\"; } catch { /* private mode */ }\n if (!hidden && hasStudioMarker()) setState({ show: true, path });\n }, [adminPath]);\n\n if (!state.show) return null;\n const edit = editHrefFor(state.path, routes, adminPath);\n const close = () => { try { sessionStorage.setItem(HIDE_KEY, \"1\"); } catch { /* private mode */ } setState({ show: false, path: \"\" }); };\n\n return (\n <div style={S.wrap} role=\"region\" aria-label=\"Studio\" data-studio-bar>\n <span style={S.brand}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M12 3l7 3v5c0 5-3.5 8.5-7 10-3.5-1.5-7-5-7-10V6z\" /></svg>\n {label}\n </span>\n {edit && <a href={edit} style={S.link}>Edit this page</a>}\n <a href={adminPath} style={S.link}>Dashboard</a>\n <button type=\"button\" onClick={close} style={S.close} aria-label=\"Hide the Studio bar for this tab\">×</button>\n </div>\n );\n}\n\n/* Self-contained styles: no dependency on the site's CSS, fonts or theme. */\nconst S: Record<string, CSSProperties> = {\n wrap: {\n position: \"fixed\", left: 16, bottom: 16, zIndex: 2147483000,\n display: \"flex\", alignItems: \"center\", gap: 2,\n padding: \"4px 6px 4px 10px\", borderRadius: 999,\n background: \"#0b1220\", color: \"#e5e7eb\", boxShadow: \"0 6px 24px rgba(0,0,0,.28)\",\n font: \"500 13px/1 system-ui, -apple-system, Segoe UI, Roboto, sans-serif\", letterSpacing: \".01em\",\n WebkitFontSmoothing: \"antialiased\",\n },\n brand: { display: \"inline-flex\", alignItems: \"center\", gap: 6, paddingRight: 8, marginRight: 4, borderRight: \"1px solid rgba(255,255,255,.18)\", color: \"#a5b4fc\", fontWeight: 600 },\n link: { color: \"#e5e7eb\", textDecoration: \"none\", padding: \"6px 8px\", borderRadius: 999 },\n close: { marginLeft: 2, width: 26, height: 26, border: 0, borderRadius: 999, background: \"transparent\", color: \"#9ca3af\", fontSize: 16, lineHeight: 1, cursor: \"pointer\" },\n};\n"]}
1
+ {"version":3,"sources":["../../src/bar/StudioBar.tsx"],"names":["useState","useEffect","jsxs","jsx"],"mappings":"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","file":"index.cjs","sourcesContent":["\"use client\";\n\nimport { useEffect, useState, type CSSProperties } from \"react\";\n\nexport const STUDIO_MARKER_COOKIE = \"rz-studio\";\nconst HIDE_KEY = \"rz-bar-hidden\";\n\nexport interface StudioBarProps {\n /** Public URL prefix → content type id, e.g. { \"/blog/\": \"posts\", \"/events/\": \"events\" }. */\n routes?: Record<string, string>;\n /** Where Studio lives. Default \"/admin\". */\n adminPath?: string;\n /** Shown on the pill. Default \"Studio\". */\n label?: string;\n}\n\n/** True when Studio's marker cookie is present (someone signed in to Studio in this browser). */\nexport function hasStudioMarker(cookie: string = typeof document === \"undefined\" ? \"\" : document.cookie): boolean {\n return cookie.split(\";\").some((c) => c.trim().startsWith(`${STUDIO_MARKER_COOKIE}=1`));\n}\n\n/** The Studio edit page for a public path, or null when the path isn't an item Studio manages. */\nexport function editHrefFor(pathname: string, routes: Record<string, string>, adminPath = \"/admin\"): string | null {\n for (const [prefix, typeId] of Object.entries(routes)) {\n if (!pathname.startsWith(prefix)) continue;\n const rest = pathname.slice(prefix.length).replace(/\\/+$/, \"\");\n if (!rest || rest.includes(\"/\")) continue; // the index page, or something nested — not an item\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(rest)) continue;\n return `${adminPath}/${typeId}/${rest}`;\n }\n return null;\n}\n\n/** The current pathname, kept in step with client-side navigation (Next's router uses pushState). */\nfunction usePathname(): string {\n const [path, setPath] = useState(\"\");\n useEffect(() => {\n const read = () => setPath(window.location.pathname);\n read();\n window.addEventListener(\"popstate\", read);\n // pushState/replaceState fire no event; wrap them once per page so every router notifies us.\n const h = window.history as History & { __rzWrapped?: boolean };\n if (!h.__rzWrapped) {\n h.__rzWrapped = true;\n for (const m of [\"pushState\", \"replaceState\"] as const) {\n const orig = h[m].bind(h);\n h[m] = ((...args: Parameters<History[\"pushState\"]>) => { orig(...args); window.dispatchEvent(new Event(\"rz:navigate\")); }) as History[\"pushState\"];\n }\n }\n window.addEventListener(\"rz:navigate\", read);\n return () => { window.removeEventListener(\"popstate\", read); window.removeEventListener(\"rz:navigate\", read); };\n }, []);\n return path;\n}\n\nexport function StudioBar({ routes = {}, adminPath = \"/admin\", label = \"Studio\" }: StudioBarProps) {\n const path = usePathname();\n const [show, setShow] = useState(false);\n\n useEffect(() => {\n if (!path) return;\n if (path === adminPath || path.startsWith(`${adminPath}/`)) { setShow(false); return; }\n let hidden = false;\n try { hidden = sessionStorage.getItem(HIDE_KEY) === \"1\"; } catch { /* private mode */ }\n setShow(!hidden && hasStudioMarker());\n }, [path, adminPath]);\n\n if (!show) return null;\n const edit = editHrefFor(path, routes, adminPath);\n const close = () => { try { sessionStorage.setItem(HIDE_KEY, \"1\"); } catch { /* private mode */ } setShow(false); };\n\n return (\n <div style={S.wrap} role=\"region\" aria-label=\"Studio\" data-studio-bar>\n <span style={S.brand}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M12 3l7 3v5c0 5-3.5 8.5-7 10-3.5-1.5-7-5-7-10V6z\" /></svg>\n {label}\n </span>\n {edit && <a href={edit} style={S.link}>Edit this page</a>}\n <a href={adminPath} style={S.link}>Dashboard</a>\n <button type=\"button\" onClick={close} style={S.close} aria-label=\"Hide the Studio bar for this tab\">×</button>\n </div>\n );\n}\n\n/* Self-contained styles: no dependency on the site's CSS, fonts or theme. */\nconst S: Record<string, CSSProperties> = {\n wrap: {\n position: \"fixed\", left: 16, bottom: 16, zIndex: 2147483000,\n display: \"flex\", alignItems: \"center\", gap: 2,\n padding: \"4px 6px 4px 10px\", borderRadius: 999,\n background: \"#0b1220\", color: \"#e5e7eb\", boxShadow: \"0 6px 24px rgba(0,0,0,.28)\",\n font: \"500 13px/1 system-ui, -apple-system, Segoe UI, Roboto, sans-serif\", letterSpacing: \".01em\",\n WebkitFontSmoothing: \"antialiased\",\n },\n brand: { display: \"inline-flex\", alignItems: \"center\", gap: 6, paddingRight: 8, marginRight: 4, borderRight: \"1px solid rgba(255,255,255,.18)\", color: \"#a5b4fc\", fontWeight: 600 },\n link: { color: \"#e5e7eb\", textDecoration: \"none\", padding: \"6px 8px\", borderRadius: 999 },\n close: { marginLeft: 2, width: 26, height: 26, border: 0, borderRadius: 999, background: \"transparent\", color: \"#9ca3af\", fontSize: 16, lineHeight: 1, cursor: \"pointer\" },\n};\n"]}
package/dist/bar/index.js CHANGED
@@ -18,26 +18,55 @@ function editHrefFor(pathname, routes, adminPath = "/admin") {
18
18
  }
19
19
  return null;
20
20
  }
21
+ function usePathname() {
22
+ const [path, setPath] = useState("");
23
+ useEffect(() => {
24
+ const read = () => setPath(window.location.pathname);
25
+ read();
26
+ window.addEventListener("popstate", read);
27
+ const h = window.history;
28
+ if (!h.__rzWrapped) {
29
+ h.__rzWrapped = true;
30
+ for (const m of ["pushState", "replaceState"]) {
31
+ const orig = h[m].bind(h);
32
+ h[m] = ((...args) => {
33
+ orig(...args);
34
+ window.dispatchEvent(new Event("rz:navigate"));
35
+ });
36
+ }
37
+ }
38
+ window.addEventListener("rz:navigate", read);
39
+ return () => {
40
+ window.removeEventListener("popstate", read);
41
+ window.removeEventListener("rz:navigate", read);
42
+ };
43
+ }, []);
44
+ return path;
45
+ }
21
46
  function StudioBar({ routes = {}, adminPath = "/admin", label = "Studio" }) {
22
- const [state, setState] = useState({ show: false, path: "" });
47
+ const path = usePathname();
48
+ const [show, setShow] = useState(false);
23
49
  useEffect(() => {
24
- const path = window.location.pathname;
25
- if (path === adminPath || path.startsWith(`${adminPath}/`)) return;
50
+ if (!path) return;
51
+ if (path === adminPath || path.startsWith(`${adminPath}/`)) {
52
+ setShow(false);
53
+ return;
54
+ }
26
55
  let hidden = false;
27
56
  try {
28
57
  hidden = sessionStorage.getItem(HIDE_KEY) === "1";
29
58
  } catch {
30
59
  }
31
- if (!hidden && hasStudioMarker()) setState({ show: true, path });
32
- }, [adminPath]);
33
- if (!state.show) return null;
34
- const edit = editHrefFor(state.path, routes, adminPath);
60
+ setShow(!hidden && hasStudioMarker());
61
+ }, [path, adminPath]);
62
+ if (!show) return null;
63
+ const edit = editHrefFor(path, routes, adminPath);
35
64
  const close = () => {
36
65
  try {
37
66
  sessionStorage.setItem(HIDE_KEY, "1");
38
67
  } catch {
39
68
  }
40
- setState({ show: false, path: "" });
69
+ setShow(false);
41
70
  };
42
71
  return /* @__PURE__ */ jsxs("div", { style: S.wrap, role: "region", "aria-label": "Studio", "data-studio-bar": true, children: [
43
72
  /* @__PURE__ */ jsxs("span", { style: S.brand, children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bar/StudioBar.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport { useEffect, useState, type CSSProperties } from \"react\";\n\nexport const STUDIO_MARKER_COOKIE = \"rz-studio\";\nconst HIDE_KEY = \"rz-bar-hidden\";\n\nexport interface StudioBarProps {\n /** Public URL prefix → content type id, e.g. { \"/blog/\": \"posts\", \"/events/\": \"events\" }. */\n routes?: Record<string, string>;\n /** Where Studio lives. Default \"/admin\". */\n adminPath?: string;\n /** Shown on the pill. Default \"Studio\". */\n label?: string;\n}\n\n/** True when Studio's marker cookie is present (someone signed in to Studio in this browser). */\nexport function hasStudioMarker(cookie: string = typeof document === \"undefined\" ? \"\" : document.cookie): boolean {\n return cookie.split(\";\").some((c) => c.trim().startsWith(`${STUDIO_MARKER_COOKIE}=1`));\n}\n\n/** The Studio edit page for a public path, or null when the path isn't an item Studio manages. */\nexport function editHrefFor(pathname: string, routes: Record<string, string>, adminPath = \"/admin\"): string | null {\n for (const [prefix, typeId] of Object.entries(routes)) {\n if (!pathname.startsWith(prefix)) continue;\n const rest = pathname.slice(prefix.length).replace(/\\/+$/, \"\");\n if (!rest || rest.includes(\"/\")) continue; // the index page, or something nested — not an item\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(rest)) continue;\n return `${adminPath}/${typeId}/${rest}`;\n }\n return null;\n}\n\nexport function StudioBar({ routes = {}, adminPath = \"/admin\", label = \"Studio\" }: StudioBarProps) {\n const [state, setState] = useState<{ show: boolean; path: string }>({ show: false, path: \"\" });\n\n useEffect(() => {\n const path = window.location.pathname;\n if (path === adminPath || path.startsWith(`${adminPath}/`)) return;\n let hidden = false;\n try { hidden = sessionStorage.getItem(HIDE_KEY) === \"1\"; } catch { /* private mode */ }\n if (!hidden && hasStudioMarker()) setState({ show: true, path });\n }, [adminPath]);\n\n if (!state.show) return null;\n const edit = editHrefFor(state.path, routes, adminPath);\n const close = () => { try { sessionStorage.setItem(HIDE_KEY, \"1\"); } catch { /* private mode */ } setState({ show: false, path: \"\" }); };\n\n return (\n <div style={S.wrap} role=\"region\" aria-label=\"Studio\" data-studio-bar>\n <span style={S.brand}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M12 3l7 3v5c0 5-3.5 8.5-7 10-3.5-1.5-7-5-7-10V6z\" /></svg>\n {label}\n </span>\n {edit && <a href={edit} style={S.link}>Edit this page</a>}\n <a href={adminPath} style={S.link}>Dashboard</a>\n <button type=\"button\" onClick={close} style={S.close} aria-label=\"Hide the Studio bar for this tab\">×</button>\n </div>\n );\n}\n\n/* Self-contained styles: no dependency on the site's CSS, fonts or theme. */\nconst S: Record<string, CSSProperties> = {\n wrap: {\n position: \"fixed\", left: 16, bottom: 16, zIndex: 2147483000,\n display: \"flex\", alignItems: \"center\", gap: 2,\n padding: \"4px 6px 4px 10px\", borderRadius: 999,\n background: \"#0b1220\", color: \"#e5e7eb\", boxShadow: \"0 6px 24px rgba(0,0,0,.28)\",\n font: \"500 13px/1 system-ui, -apple-system, Segoe UI, Roboto, sans-serif\", letterSpacing: \".01em\",\n WebkitFontSmoothing: \"antialiased\",\n },\n brand: { display: \"inline-flex\", alignItems: \"center\", gap: 6, paddingRight: 8, marginRight: 4, borderRight: \"1px solid rgba(255,255,255,.18)\", color: \"#a5b4fc\", fontWeight: 600 },\n link: { color: \"#e5e7eb\", textDecoration: \"none\", padding: \"6px 8px\", borderRadius: 999 },\n close: { marginLeft: 2, width: 26, height: 26, border: 0, borderRadius: 999, background: \"transparent\", color: \"#9ca3af\", fontSize: 16, lineHeight: 1, cursor: \"pointer\" },\n};\n"]}
1
+ {"version":3,"sources":["../../src/bar/StudioBar.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\n\nimport { useEffect, useState, type CSSProperties } from \"react\";\n\nexport const STUDIO_MARKER_COOKIE = \"rz-studio\";\nconst HIDE_KEY = \"rz-bar-hidden\";\n\nexport interface StudioBarProps {\n /** Public URL prefix → content type id, e.g. { \"/blog/\": \"posts\", \"/events/\": \"events\" }. */\n routes?: Record<string, string>;\n /** Where Studio lives. Default \"/admin\". */\n adminPath?: string;\n /** Shown on the pill. Default \"Studio\". */\n label?: string;\n}\n\n/** True when Studio's marker cookie is present (someone signed in to Studio in this browser). */\nexport function hasStudioMarker(cookie: string = typeof document === \"undefined\" ? \"\" : document.cookie): boolean {\n return cookie.split(\";\").some((c) => c.trim().startsWith(`${STUDIO_MARKER_COOKIE}=1`));\n}\n\n/** The Studio edit page for a public path, or null when the path isn't an item Studio manages. */\nexport function editHrefFor(pathname: string, routes: Record<string, string>, adminPath = \"/admin\"): string | null {\n for (const [prefix, typeId] of Object.entries(routes)) {\n if (!pathname.startsWith(prefix)) continue;\n const rest = pathname.slice(prefix.length).replace(/\\/+$/, \"\");\n if (!rest || rest.includes(\"/\")) continue; // the index page, or something nested — not an item\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(rest)) continue;\n return `${adminPath}/${typeId}/${rest}`;\n }\n return null;\n}\n\n/** The current pathname, kept in step with client-side navigation (Next's router uses pushState). */\nfunction usePathname(): string {\n const [path, setPath] = useState(\"\");\n useEffect(() => {\n const read = () => setPath(window.location.pathname);\n read();\n window.addEventListener(\"popstate\", read);\n // pushState/replaceState fire no event; wrap them once per page so every router notifies us.\n const h = window.history as History & { __rzWrapped?: boolean };\n if (!h.__rzWrapped) {\n h.__rzWrapped = true;\n for (const m of [\"pushState\", \"replaceState\"] as const) {\n const orig = h[m].bind(h);\n h[m] = ((...args: Parameters<History[\"pushState\"]>) => { orig(...args); window.dispatchEvent(new Event(\"rz:navigate\")); }) as History[\"pushState\"];\n }\n }\n window.addEventListener(\"rz:navigate\", read);\n return () => { window.removeEventListener(\"popstate\", read); window.removeEventListener(\"rz:navigate\", read); };\n }, []);\n return path;\n}\n\nexport function StudioBar({ routes = {}, adminPath = \"/admin\", label = \"Studio\" }: StudioBarProps) {\n const path = usePathname();\n const [show, setShow] = useState(false);\n\n useEffect(() => {\n if (!path) return;\n if (path === adminPath || path.startsWith(`${adminPath}/`)) { setShow(false); return; }\n let hidden = false;\n try { hidden = sessionStorage.getItem(HIDE_KEY) === \"1\"; } catch { /* private mode */ }\n setShow(!hidden && hasStudioMarker());\n }, [path, adminPath]);\n\n if (!show) return null;\n const edit = editHrefFor(path, routes, adminPath);\n const close = () => { try { sessionStorage.setItem(HIDE_KEY, \"1\"); } catch { /* private mode */ } setShow(false); };\n\n return (\n <div style={S.wrap} role=\"region\" aria-label=\"Studio\" data-studio-bar>\n <span style={S.brand}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\"><path d=\"M12 3l7 3v5c0 5-3.5 8.5-7 10-3.5-1.5-7-5-7-10V6z\" /></svg>\n {label}\n </span>\n {edit && <a href={edit} style={S.link}>Edit this page</a>}\n <a href={adminPath} style={S.link}>Dashboard</a>\n <button type=\"button\" onClick={close} style={S.close} aria-label=\"Hide the Studio bar for this tab\">×</button>\n </div>\n );\n}\n\n/* Self-contained styles: no dependency on the site's CSS, fonts or theme. */\nconst S: Record<string, CSSProperties> = {\n wrap: {\n position: \"fixed\", left: 16, bottom: 16, zIndex: 2147483000,\n display: \"flex\", alignItems: \"center\", gap: 2,\n padding: \"4px 6px 4px 10px\", borderRadius: 999,\n background: \"#0b1220\", color: \"#e5e7eb\", boxShadow: \"0 6px 24px rgba(0,0,0,.28)\",\n font: \"500 13px/1 system-ui, -apple-system, Segoe UI, Roboto, sans-serif\", letterSpacing: \".01em\",\n WebkitFontSmoothing: \"antialiased\",\n },\n brand: { display: \"inline-flex\", alignItems: \"center\", gap: 6, paddingRight: 8, marginRight: 4, borderRight: \"1px solid rgba(255,255,255,.18)\", color: \"#a5b4fc\", fontWeight: 600 },\n link: { color: \"#e5e7eb\", textDecoration: \"none\", padding: \"6px 8px\", borderRadius: 999 },\n close: { marginLeft: 2, width: 26, height: 26, border: 0, borderRadius: 999, background: \"transparent\", color: \"#9ca3af\", fontSize: 16, lineHeight: 1, cursor: \"pointer\" },\n};\n"]}
@@ -1116,7 +1116,7 @@ function makeHandlers(ctx) {
1116
1116
  }
1117
1117
 
1118
1118
  // src/version.ts
1119
- var ADMIN_VERSION = "0.15.0" ;
1119
+ var ADMIN_VERSION = "0.15.1" ;
1120
1120
 
1121
1121
  // src/studio/update.ts
1122
1122
  var PACKAGE_NAME = "@realiizlabs/admin";
@@ -1104,7 +1104,7 @@ function makeHandlers(ctx) {
1104
1104
  }
1105
1105
 
1106
1106
  // src/version.ts
1107
- var ADMIN_VERSION = "0.15.0" ;
1107
+ var ADMIN_VERSION = "0.15.1" ;
1108
1108
 
1109
1109
  // src/studio/update.ts
1110
1110
  var PACKAGE_NAME = "@realiizlabs/admin";
@@ -5453,7 +5453,7 @@ function BackArrow() {
5453
5453
  }
5454
5454
 
5455
5455
  // src/version.ts
5456
- var ADMIN_VERSION = "0.15.0" ;
5456
+ var ADMIN_VERSION = "0.15.1" ;
5457
5457
 
5458
5458
  // src/studio-ui/types.ts
5459
5459
  var ACTION_NAMES = [
@@ -5447,7 +5447,7 @@ function BackArrow() {
5447
5447
  }
5448
5448
 
5449
5449
  // src/version.ts
5450
- var ADMIN_VERSION = "0.15.0" ;
5450
+ var ADMIN_VERSION = "0.15.1" ;
5451
5451
 
5452
5452
  // src/studio-ui/types.ts
5453
5453
  var ACTION_NAMES = [
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@realiizlabs/admin",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "description": "Realiiz Studio — the publishing dashboard for websites built on site-starter-pro.",
5
- "releaseNotes": "Update Studio from Studio: when a new version is out, owners see a strip with what's new, a preview and an Update button. A small Studio pill on the public site takes you straight to Edit this page or the Dashboard. The brand at the top left opens the live site.",
5
+ "releaseNotes": "The Studio pill now follows you as you move around the site: Edit this page appears the moment you open a post or event and steps aside on other pages, no reload needed.",
6
6
  "license": "SEE LICENSE IN LICENSE",
7
7
  "type": "module",
8
8
  "main": "./dist/index.cjs",