smoodly 0.0.52 → 0.0.54

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.
Files changed (79) hide show
  1. package/dist/admin/client-ops.js +1 -1
  2. package/dist/admin/editor/CanvasOverlay.d.ts +3 -1
  3. package/dist/admin/editor/CanvasOverlay.js +2 -2
  4. package/dist/admin/editor/EditorView.js +243 -63
  5. package/dist/admin/editor/InsertPicker.d.ts +8 -1
  6. package/dist/admin/editor/InsertPicker.js +2 -2
  7. package/dist/admin/editor/InspectorFields.js +1 -1
  8. package/dist/admin/editor/Outline.d.ts +2 -3
  9. package/dist/admin/editor/PageInspector.js +1 -1
  10. package/dist/admin/editor/StructureView.d.ts +31 -0
  11. package/dist/admin/editor/StructureView.js +58 -0
  12. package/dist/admin/editor/card-preview.d.ts +10 -0
  13. package/dist/admin/editor/card-preview.js +50 -0
  14. package/dist/admin/editor/global-edit.js +29 -22
  15. package/dist/admin/editor/history.d.ts +39 -0
  16. package/dist/admin/editor/history.js +64 -0
  17. package/dist/admin/editor/section-clipboard.d.ts +40 -0
  18. package/dist/admin/editor/section-clipboard.js +106 -0
  19. package/dist/admin/editor/undo-keys.d.ts +19 -0
  20. package/dist/admin/editor/undo-keys.js +27 -0
  21. package/dist/admin/editor/useInlineSession.d.ts +4 -1
  22. package/dist/admin/editor/useInlineSession.js +11 -2
  23. package/dist/admin/editor/view-memory.d.ts +9 -0
  24. package/dist/admin/editor/view-memory.js +17 -0
  25. package/dist/admin/files.generated.js +1 -1
  26. package/dist/admin/handler.d.ts +1 -1
  27. package/dist/admin/index.d.ts +2 -2
  28. package/dist/admin/ops.d.ts +4 -10
  29. package/dist/admin/page-data.d.ts +1 -1
  30. package/dist/admin/session-flow.d.ts +24 -2
  31. package/dist/admin/session-flow.js +29 -2
  32. package/dist/admin/shell/AdminApp.d.ts +1 -1
  33. package/dist/admin/shell/IconRail.js +5 -4
  34. package/dist/admin/shell/presence.d.ts +1 -1
  35. package/dist/admin/shell/session.d.ts +1 -2
  36. package/dist/admin/shell/session.js +10 -9
  37. package/dist/admin/ui/ActionMenu.d.ts +2 -0
  38. package/dist/admin/ui/ActionMenu.js +1 -1
  39. package/dist/admin/ui/primitives.d.ts +1 -0
  40. package/dist/admin/ui/primitives.js +3 -2
  41. package/dist/admin/ui/theme.js +70 -0
  42. package/dist/admin/ui/useSortable.js +3 -1
  43. package/dist/api-client.js +1 -1
  44. package/dist/assemble.js +1 -1
  45. package/dist/astro/cache.d.ts +1 -1
  46. package/dist/astro/index.js +11 -6
  47. package/dist/astro/runtime.d.ts +1 -1
  48. package/dist/astro/runtime.js +1 -1
  49. package/dist/astro/shell.d.ts +1 -1
  50. package/dist/astro/shell.js +1 -1
  51. package/dist/content/content-api.d.ts +1 -0
  52. package/dist/content/content-api.js +3 -1
  53. package/dist/css.js +1 -1
  54. package/dist/entry-store.d.ts +5 -5
  55. package/dist/entry-store.js +7 -7
  56. package/dist/image/markup.js +1 -1
  57. package/dist/index.d.ts +2 -2
  58. package/dist/index.js +1 -1
  59. package/dist/media-cut.d.ts +1 -1
  60. package/dist/media-cut.js +2 -2
  61. package/dist/media.d.ts +1 -1
  62. package/dist/media.js +2 -2
  63. package/dist/member-store.d.ts +0 -29
  64. package/dist/member-store.js +0 -4
  65. package/dist/paths.d.ts +1 -1
  66. package/dist/paths.js +1 -1
  67. package/dist/revalidate.d.ts +1 -1
  68. package/dist/revalidate.js +1 -1
  69. package/dist/space-transfer.d.ts +1 -1
  70. package/dist/space-transfer.js +1 -1
  71. package/dist/version.d.ts +1 -1
  72. package/dist/version.js +1 -1
  73. package/package.json +1 -1
  74. package/dist/admin/auth-config.d.ts +0 -7
  75. package/dist/admin/auth-config.js +0 -1
  76. package/dist/admin/browser/fetch-op.d.ts +0 -10
  77. package/dist/admin/browser/fetch-op.js +0 -45
  78. package/dist/admin/browser/main.d.ts +0 -1
  79. package/dist/admin/browser/main.js +0 -27
@@ -1,4 +1,4 @@
1
- // One image markup for both frameworks (spec 2026-10-18 media on R2 and Images §7; plan (c) decision 5): what
1
+ // One image markup for both frameworks (spec 2026-10-18 media on R2 and Images §7): what
2
2
  // <SmoodlyImage> (React) and <Image> (Astro) render, decided here so both are only markup and a test holds them equal.
3
3
  // Plain HTML, no optimizer and no Smoodly JavaScript: a box, an <img> whose srcset lists the cut's widths, or a
4
4
  // <picture> with one <source> per crop the view places. Without a cut (locally, an SVG) the original is framed in CSS
package/dist/index.d.ts CHANGED
@@ -30,8 +30,8 @@ export { assetErrors, kindOf, extensionFor, objectPath, PAGE_SIZE as ASSET_PAGE_
30
30
  export type { AssetStore, UploadTicket, FinishInput, AssetQuery, AssetPage, BeginUploadInput, CreateAssetInput } from "./asset-store.ts";
31
31
  export { imageDimensions } from "./image-dimensions.ts";
32
32
  export type { ImageQuality } from "./media-cut.ts";
33
- export { sortMembers, memberErrors } from "./member-store.ts";
34
- export type { MemberStore, MemberRecord, InviteInput, InviteResult } from "./member-store.ts";
33
+ export { sortMembers } from "./member-store.ts";
34
+ export type { MemberStore, MemberRecord } from "./member-store.ts";
35
35
  export { MEMBER_ROLES, can, normalizeRole, isMemberRole } from "./permissions.ts";
36
36
  export type { MemberRole, Capability } from "./permissions.ts";
37
37
  export { collectEntryRefs, collectTreeRefs } from "./refs.ts";
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ export { defineConfig } from "./config.js";
21
21
  export { draftToken, sameToken, isDraftToken, assertFresh, StaleDraftError } from "./draft-token.js";
22
22
  export { assetErrors, kindOf, extensionFor, objectPath, PAGE_SIZE as ASSET_PAGE_SIZE } from "./asset-store.js";
23
23
  export { imageDimensions } from "./image-dimensions.js";
24
- export { sortMembers, memberErrors } from "./member-store.js";
24
+ export { sortMembers } from "./member-store.js";
25
25
  export { MEMBER_ROLES, can, normalizeRole, isMemberRole } from "./permissions.js";
26
26
  export { collectEntryRefs, collectTreeRefs } from "./refs.js";
27
27
  export { richtextBlocks, elementSchemas, IMAGE_NODE, ELEMENT_NODE } from "./richtext-walk.js";
@@ -6,7 +6,7 @@ export type PixelRect = {
6
6
  height: number;
7
7
  };
8
8
  /** The qualities a cut is made at: unsigned in the address like the width, so a list bounds what Images is asked to
9
- * make (spec 2026-10-18 image quality and max width §2). 75 matched Vercel's optimizer in step 6's speed round. */
9
+ * make (spec 2026-10-18 image quality and max width §2). 75 matched Vercel's optimizer in the 2026-10-18 speed round. */
10
10
  export declare const IMAGE_QUALITIES: readonly [50, 60, 75, 85, 95, 100];
11
11
  export type ImageQuality = (typeof IMAGE_QUALITIES)[number];
12
12
  export declare const DEFAULT_QUALITY: ImageQuality;
package/dist/media-cut.js CHANGED
@@ -1,10 +1,10 @@
1
1
  /** The widths a cut is served at, plus the cut's own width; a wider one is never served (upscaling sells nothing).
2
2
  * From 640 to 1080 they are Next's device sizes, so a phone gets what `next/image` gave it (a 412-pixel screen at 1.75
3
- * finds 750, not 960; step 6 plan (d)'s speed round); 1536 spares a 1366- or 1440-wide laptop the 1920 (spec 2026-10-18
3
+ * finds 750, not 960; the 2026-10-18 speed round); 1536 spares a 1366- or 1440-wide laptop the 1920 (spec 2026-10-18
4
4
  * image quality and max width §5). */
5
5
  const CUT_WIDTHS = [320, 640, 750, 828, 1080, 1280, 1536, 1920, 2560];
6
6
  /** The qualities a cut is made at: unsigned in the address like the width, so a list bounds what Images is asked to
7
- * make (spec 2026-10-18 image quality and max width §2). 75 matched Vercel's optimizer in step 6's speed round. */
7
+ * make (spec 2026-10-18 image quality and max width §2). 75 matched Vercel's optimizer in the 2026-10-18 speed round. */
8
8
  export const IMAGE_QUALITIES = [50, 60, 75, 85, 95, 100];
9
9
  export const DEFAULT_QUALITY = 75;
10
10
  export const isImageQuality = (n) => IMAGE_QUALITIES.includes(n);
package/dist/media.d.ts CHANGED
@@ -115,7 +115,7 @@ export declare const ASSET_COLLECTION = "asset";
115
115
  export declare const MEDIA_TYPES: ReadonlySet<string>;
116
116
  /** Cache lifetime of a media object, in seconds — a year. Objects are
117
117
  * immutable (no upsert; Replace picks a new id), so the CDN, the browser
118
- * and next/image may keep one for as long as they like. */
118
+ * may keep one for as long as they like. */
119
119
  export declare const MEDIA_CACHE_SECONDS = 31536000;
120
120
  /** The largest file a space may accept (spec 2026-10-18 media on R2 and Images §4): Cloudflare's request body limit on
121
121
  * Free and Pro, since every upload streams through the Worker; a pushed `media.maxSize` over it is refused. */
package/dist/media.js CHANGED
@@ -5,7 +5,7 @@ export const ASSET_COLLECTION = "asset";
5
5
  export const MEDIA_TYPES = new Set(["image", "video", "file"]);
6
6
  /** Cache lifetime of a media object, in seconds — a year. Objects are
7
7
  * immutable (no upsert; Replace picks a new id), so the CDN, the browser
8
- * and next/image may keep one for as long as they like. */
8
+ * may keep one for as long as they like. */
9
9
  export const MEDIA_CACHE_SECONDS = 31536000;
10
10
  /** The largest file a space may accept (spec 2026-10-18 media on R2 and Images §4): Cloudflare's request body limit on
11
11
  * Free and Pro, since every upload streams through the Worker; a pushed `media.maxSize` over it is refused. */
@@ -113,7 +113,7 @@ const namedCropsOf = (d) => d.crops && typeof d.crops === "object" && Object.key
113
113
  * `crop` saved before the field declared crops (under `aspect`) is the first crop's when its ratio is the first's
114
114
  * within 1%, else ignored. The first crop's cut is the image's. */
115
115
  /** A stored crop counts only at the ratio its field declares now, within 1%: a ratio changed in code makes it follow
116
- * the hotspot at the new one, so the box, the cut and the crop window agree (the final review of plan (c)). */
116
+ * the hotspot at the new one, so the box, the cut and the crop window agree. */
117
117
  const atRatio = (crop, ratio, imageAspect) => Math.abs(cropAspect(crop, imageAspect) / parseAspect(ratio) - 1) <= 0.01;
118
118
  /** A named crop's framed rectangle, or undefined when it follows the hotspot: its stored entry, or for the first crop a
119
119
  * `crop` saved under `aspect`, at the crop's ratio (spec §6; the resolver and the crop window agree). */
@@ -1,42 +1,13 @@
1
- import type { MemberRole } from "./permissions.ts";
2
1
  export type MemberRecord = {
3
2
  userId: string;
4
3
  email: string | null;
5
4
  role: string;
6
5
  };
7
- export type InviteInput = {
8
- email: string;
9
- role: MemberRole;
10
- redirectTo: string;
11
- };
12
- /** `invited` false = the email already had a confirmed account, so no mail was sent; the row was added. (A pending invitee is re-invited: same account, mail again, `invited` true.) */
13
- export type InviteResult = {
14
- member: MemberRecord;
15
- invited: boolean;
16
- };
17
6
  export interface MemberStore {
18
7
  /** Every member of the current space, by email then user id. */
19
8
  list(): Promise<MemberRecord[]>;
20
- /** The space's console URL when the control plane manages its members; null in self-host. */
21
- consoleUrl(): Promise<string | null>;
22
- /** Creates or finds the Auth user for the email, mails the invite when it created one, upserts the row (spec 2026-09-25 members management §3). */
23
- invite(input: InviteInput): Promise<InviteResult>;
24
- /** Creates the Auth user with a password (confirmed, no mail) and upserts the row — the installer's first editor, `add-admin`.
25
- * An existing account keeps its password and only gains the membership. */
26
- createAccount(input: {
27
- email: string;
28
- password: string;
29
- role: MemberRole;
30
- }): Promise<MemberRecord>;
31
- setRole(userId: string, role: MemberRole): Promise<MemberRecord>;
32
- /** Deletes the member row only; the Auth account stays. */
33
- remove(userId: string): Promise<void>;
34
9
  /** The whole list at once, as the management API sets it (spec 2026-10-16 the control plane §3). */
35
10
  replaceAll(members: MemberRecord[]): Promise<void>;
36
11
  }
37
- export declare const memberErrors: {
38
- notFound: (userId: string) => Error;
39
- managed: () => Error;
40
- };
41
12
  /** Email first (case-insensitive), rows without one last, ties by user id. */
42
13
  export declare function sortMembers(rows: MemberRecord[]): MemberRecord[];
@@ -1,7 +1,3 @@
1
- export const memberErrors = {
2
- notFound: (userId) => new Error(`smoodly: no member "${userId}".`),
3
- managed: () => new Error("smoodly: members are managed at smoodly.io."),
4
- };
5
1
  /** Email first (case-insensitive), rows without one last, ties by user id. */
6
2
  export function sortMembers(rows) {
7
3
  return [...rows].sort((a, b) => {
package/dist/paths.d.ts CHANGED
@@ -102,7 +102,7 @@ export declare function collectionSegment(path: string | Record<string, string>
102
102
  * it is a non-empty string — absent, null, or `""` all mean "no URL".
103
103
  * There is no sibling-slug index: sibling uniqueness is the primary key
104
104
  * of `paths` plus the pre-check each store makes per locale before it
105
- * writes (spec 2026-09-06 §12), so Postgres and memory agree on which
105
+ * writes (spec 2026-09-06 §12), so every store agrees on which
106
106
  * entries can collide. */
107
107
  export declare const slugOf: (fields: Record<string, unknown>) => string | null;
108
108
  /** The entry's segment in one locale: its row's slug. An absent locale
package/dist/paths.js CHANGED
@@ -162,7 +162,7 @@ export function collectionSegment(path, locale, set) {
162
162
  * it is a non-empty string — absent, null, or `""` all mean "no URL".
163
163
  * There is no sibling-slug index: sibling uniqueness is the primary key
164
164
  * of `paths` plus the pre-check each store makes per locale before it
165
- * writes (spec 2026-09-06 §12), so Postgres and memory agree on which
165
+ * writes (spec 2026-09-06 §12), so every store agrees on which
166
166
  * entries can collide. */
167
167
  export const slugOf = (fields) => {
168
168
  const slug = fields.slug;
@@ -26,7 +26,7 @@ export declare const addressesTag: () => string;
26
26
  /** Every published response of a space carries it (spec 2026-10-16 the control plane §4): a push that changed the
27
27
  * registry purges this one tag, and the new schema applies on the next read. */
28
28
  export declare const spaceTag: (space: string) => string;
29
- /** An asset's original and every cut of it at the edge (plan 2026-10-18 media (c) decision 4): its delete purges it. */
29
+ /** An asset's original and every cut of it at the edge (spec 2026-10-18 media on R2 and Images §5): its delete purges it. */
30
30
  export declare const mediaTag: (asset: string) => string;
31
31
  /** Every media file of a space at the edge: the space's delete purges it. Never a content tag, so a publish purges no bytes. */
32
32
  export declare const mediaSpaceTag: (space: string) => string;
@@ -25,7 +25,7 @@ export const addressesTag = () => "addresses";
25
25
  /** Every published response of a space carries it (spec 2026-10-16 the control plane §4): a push that changed the
26
26
  * registry purges this one tag, and the new schema applies on the next read. */
27
27
  export const spaceTag = (space) => `space:${space}`;
28
- /** An asset's original and every cut of it at the edge (plan 2026-10-18 media (c) decision 4): its delete purges it. */
28
+ /** An asset's original and every cut of it at the edge (spec 2026-10-18 media on R2 and Images §5): its delete purges it. */
29
29
  export const mediaTag = (asset) => `media:${asset}`;
30
30
  /** Every media file of a space at the edge: the space's delete purges it. Never a content tag, so a publish purges no bytes. */
31
31
  export const mediaSpaceTag = (space) => `media-space:${space}`;
@@ -27,7 +27,7 @@ export type Manifest = {
27
27
  export declare const INSERT_ORDER: readonly ContentTable[];
28
28
  /** A row's identity inside one space: its primary key without `space_id`. */
29
29
  export declare const ROW_KEY: Record<ContentTable, readonly string[]>;
30
- /** The primary key as Postgres declares it — what "on conflict do nothing" names. */
30
+ /** The primary key, in column order — what the import's skip-duplicates names. */
31
31
  export declare const CONFLICT_COLUMNS: Record<ContentTable, string>;
32
32
  export declare const rowKey: (table: ContentTable, row: Row) => string;
33
33
  /** Sorted by key, so two exports of an unchanged space diff cleanly (spec §7). */
@@ -37,7 +37,7 @@ export const ROW_KEY = {
37
37
  paths: ["locale", "anchor", "path"],
38
38
  assets: ["id"],
39
39
  };
40
- /** The primary key as Postgres declares it — what "on conflict do nothing" names. */
40
+ /** The primary key, in column order — what the import's skip-duplicates names. */
41
41
  export const CONFLICT_COLUMNS = Object.fromEntries(CONTENT_TABLES.map((t) => [t, (t === "paths" ? ["space_id", ...ROW_KEY[t]] : ROW_KEY[t]).join(",")]));
42
42
  export const rowKey = (table, row) => JSON.stringify(ROW_KEY[table].map((c) => row[c]));
43
43
  /** Sorted by key, so two exports of an unchanged space diff cleanly (spec §7). */
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SMOODLY_VERSION = "0.0.52";
1
+ export declare const SMOODLY_VERSION = "0.0.54";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/write-version.mjs from package.json — do not edit.
2
- export const SMOODLY_VERSION = "0.0.52";
2
+ export const SMOODLY_VERSION = "0.0.54";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoodly",
3
- "version": "0.0.52",
3
+ "version": "0.0.54",
4
4
  "description": "Open-source, code-first CMS for Astro and Next.js: define a component once, it becomes a typed, editable building block.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,7 +0,0 @@
1
- /** Where the admin sends a person to sign in, and the dashboard its account menu and Members page link to (spec
2
- * 2026-10-16 sign-in and the dashboard §1, §6): `GET /v1/auth` answers it from the Worker's env; the handler and the
3
- * page data carry it. Public values only. */
4
- export type SignInConfig = {
5
- signInUrl: string;
6
- consoleUrl: string;
7
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,10 +0,0 @@
1
- import type { AdminOpAction } from "../ops.ts";
2
- /** JSON has no `undefined`: in an array it becomes null, which several ops read as a value (`expected:
3
- * null` is "no draft", `undefined` is "skip the check"). Trailing ones are dropped; one between two
4
- * arguments cannot be sent and is named here. */
5
- export declare function wireArgs(args: unknown[]): unknown[];
6
- /** `fetcher` is the test seam. A network failure rejects; every answer resolves to a typed result.
7
- * One operation at a time, in call order: Next queued server actions per browser, and the admin's reads
8
- * and writes rely on it (a read sent after a save must see that save's token; a save typed during a
9
- * publish must follow the publish). A call that fails does not hold the ones behind it. */
10
- export declare function fetchOp(url: string, fetcher?: typeof fetch): AdminOpAction;
@@ -1,45 +0,0 @@
1
- /** JSON has no `undefined`: in an array it becomes null, which several ops read as a value (`expected:
2
- * null` is "no draft", `undefined` is "skip the check"). Trailing ones are dropped; one between two
3
- * arguments cannot be sent and is named here. */
4
- export function wireArgs(args) {
5
- let end = args.length;
6
- while (end > 0 && args[end - 1] === undefined)
7
- end--;
8
- const out = args.slice(0, end);
9
- if (out.some((a) => a === undefined)) {
10
- throw new Error("smoodly: an operation argument is undefined between two others — pass null or a value; JSON cannot carry undefined.");
11
- }
12
- return out;
13
- }
14
- const noResult = (status) => ({ ok: false, code: "internal", message: `smoodly: the admin API answered ${status} without a result — see the server log.` });
15
- /** `fetcher` is the test seam. A network failure rejects; every answer resolves to a typed result.
16
- * One operation at a time, in call order: Next queued server actions per browser, and the admin's reads
17
- * and writes rely on it (a read sent after a save must see that save's token; a save typed during a
18
- * publish must follow the publish). A call that fails does not hold the ones behind it. */
19
- export function fetchOp(url, fetcher = fetch) {
20
- const send = async (call) => {
21
- const res = await fetcher(url, {
22
- method: "POST",
23
- // The endpoint is the service's origin; the session rides the header, no cookie crosses.
24
- credentials: "omit",
25
- headers: { "content-type": "application/json", ...(call.token ? { authorization: `Bearer ${call.token}` } : {}) },
26
- body: JSON.stringify({ path: call.path, args: wireArgs(call.args) }),
27
- });
28
- let body;
29
- try {
30
- body = await res.json();
31
- }
32
- catch {
33
- return noResult(res.status);
34
- }
35
- if (typeof body === "object" && body !== null && typeof body.ok === "boolean")
36
- return body;
37
- return noResult(res.status);
38
- };
39
- let last = Promise.resolve();
40
- return (call) => {
41
- const run = last.then(() => send(call));
42
- last = run.catch(() => { });
43
- return run;
44
- };
45
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,27 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- // packages/smoodly/src/admin/browser/main.tsx
3
- // The prebuilt admin's entry (spec 2026-10-02 astro cloud fit §4): reads the page's data, writes the
4
- // stylesheet into the document and mounts the shell. Bundled by scripts/build-admin.ts; no app compiles it.
5
- import { createRoot } from "react-dom/client";
6
- import { ADMIN_DATA_ID, ADMIN_ROOT_ID } from "../page-data.js";
7
- import { setCanvasMarks, setPreviewBase, setPreviewUrl } from "../editor/canvas-address.js";
8
- import { setDelivery } from "../delivery-mode.js";
9
- import { AdminApp } from "../shell/AdminApp.js";
10
- import { setConsole } from "../shell/console-links.js";
11
- import { fontFaceCss } from "../ui/fonts.js";
12
- import { ADMIN_CSS } from "../ui/theme.js";
13
- import { fetchOp } from "./fetch-op.js";
14
- const data = JSON.parse(document.getElementById(ADMIN_DATA_ID).textContent ?? "");
15
- setPreviewBase(data.previewBase ?? "");
16
- setCanvasMarks(data.canvasMarks ?? "query");
17
- setPreviewUrl(data.previewUrl ?? "");
18
- setDelivery(data.delivery ?? "live");
19
- setConsole(data.signIn.consoleUrl, data.spaceId);
20
- // One <style>, fonts first: the canvas copies this element's text into the site's frame (editor/useInlineSession.ts).
21
- const style = document.createElement("style");
22
- style.setAttribute("data-smoodly-admin-styles", "");
23
- style.textContent = `${fontFaceCss(data.filesBase)}\n${ADMIN_CSS}`;
24
- document.head.appendChild(style);
25
- // The page's own background rules did their job (admin/page.ts): the stylesheet owns the look now.
26
- document.querySelector("style[data-smoodly-boot]")?.remove();
27
- createRoot(document.getElementById(ADMIN_ROOT_ID)).render(_jsx(AdminApp, { registry: data.registry, op: fetchOp(data.opUrl), signIn: data.signIn, api: { apiUrl: data.apiUrl, spaceId: data.spaceId }, presenceConfig: data.presence ?? undefined }));