@realiizlabs/admin 0.15.8 → 0.16.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/dist/git/index.cjs +4 -5
- package/dist/git/index.cjs.map +1 -1
- package/dist/git/index.d.cts +4 -0
- package/dist/git/index.d.ts +4 -0
- package/dist/git/index.js +4 -5
- package/dist/git/index.js.map +1 -1
- package/dist/shell/index.cjs +22 -17
- package/dist/shell/index.cjs.map +1 -1
- package/dist/shell/index.d.cts +1 -1
- package/dist/shell/index.d.ts +1 -1
- package/dist/shell/index.js +22 -17
- package/dist/shell/index.js.map +1 -1
- package/dist/studio/index.cjs +17 -10
- package/dist/studio/index.cjs.map +1 -1
- package/dist/studio/index.d.cts +7 -0
- package/dist/studio/index.d.ts +7 -0
- package/dist/studio/index.js +17 -10
- package/dist/studio/index.js.map +1 -1
- package/dist/studio-ui/index.cjs +34 -23
- package/dist/studio-ui/index.cjs.map +1 -1
- package/dist/studio-ui/index.d.cts +17 -3
- package/dist/studio-ui/index.d.ts +17 -3
- package/dist/studio-ui/index.js +35 -24
- package/dist/studio-ui/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -67,6 +67,8 @@ interface PublishInput {
|
|
|
67
67
|
branch: string;
|
|
68
68
|
} | null;
|
|
69
69
|
images?: ImagePayload[];
|
|
70
|
+
/** The slug this item was opened as (edits only) — lets a save that changes the file name rename rather than duplicate. */
|
|
71
|
+
replaces?: string | null;
|
|
70
72
|
}
|
|
71
73
|
/** The pending Studio update, as Studio.readers.studioUpdate() returns it (serialisable). */
|
|
72
74
|
interface StudioUpdate {
|
|
@@ -172,21 +174,31 @@ type PendingSummary = {
|
|
|
172
174
|
removal: boolean;
|
|
173
175
|
};
|
|
174
176
|
|
|
177
|
+
/** Per type, per field — the choices for a reference field, e.g. { events: { venue: ["soundplex"] } }. */
|
|
178
|
+
type StudioOptions = Record<string, Record<string, string[]>>;
|
|
175
179
|
interface StudioContextValue {
|
|
176
180
|
contentTypes: Record<string, ContentTypeEntry>;
|
|
177
181
|
actions: StudioActions;
|
|
178
182
|
/** Who to ask when something needs the agency — "your web team" by default. */
|
|
179
183
|
supportName: string;
|
|
180
184
|
siteName: string;
|
|
185
|
+
/**
|
|
186
|
+
* Option lists the server resolved for this request (an event's venue is one of the
|
|
187
|
+
* site's venues). The registry is imported client-side and can't read the repo, so a
|
|
188
|
+
* layout computes these with Studio.readers.listSlugs and passes them here.
|
|
189
|
+
*/
|
|
190
|
+
options: StudioOptions;
|
|
181
191
|
}
|
|
182
|
-
declare function StudioProvider({ contentTypes, actions, supportName, siteName, children }: {
|
|
192
|
+
declare function StudioProvider({ contentTypes, actions, supportName, siteName, options, children }: {
|
|
183
193
|
contentTypes: Record<string, ContentTypeEntry>;
|
|
184
194
|
actions: StudioActions;
|
|
185
195
|
supportName?: string;
|
|
186
196
|
siteName?: string;
|
|
197
|
+
options?: StudioOptions;
|
|
187
198
|
children: ReactNode;
|
|
188
199
|
}): react.JSX.Element;
|
|
189
200
|
declare function useStudio(): StudioContextValue;
|
|
201
|
+
/** The registry entry, with any server-resolved option lists merged over the entry's own. */
|
|
190
202
|
declare function useEntry(typeId: string): ContentTypeEntry | null;
|
|
191
203
|
/** Pictures for a type live under public/<last folder segment>/. */
|
|
192
204
|
declare function publicDirOf(entry: {
|
|
@@ -307,11 +319,13 @@ declare function StudioAccount({ me, manages, team, branding, myUserId, myRole,
|
|
|
307
319
|
* zod schema, so it can't cross the server→client boundary — the page passes
|
|
308
320
|
* the type id and this component looks the entry up on the client.
|
|
309
321
|
*/
|
|
310
|
-
declare function ContentEditor({ typeId, initialValues, initialBody, existing, isNew, footer }: {
|
|
322
|
+
declare function ContentEditor({ typeId, initialValues, initialBody, existing, isNew, replaces, footer }: {
|
|
311
323
|
typeId: string;
|
|
312
324
|
initialValues?: Record<string, unknown>;
|
|
313
325
|
/** A brand-new item: the web address follows the title until it's edited by hand. */
|
|
314
326
|
isNew?: boolean;
|
|
327
|
+
/** The slug this item was opened as; lets a save that changes the file name rename rather than duplicate. */
|
|
328
|
+
replaces?: string | null;
|
|
315
329
|
initialBody?: string;
|
|
316
330
|
/** An open change for this file; saves go onto its branch (05c). */
|
|
317
331
|
existing?: {
|
|
@@ -485,4 +499,4 @@ declare function searchHelp(query: string, articles?: HelpArticle[]): HelpHit[];
|
|
|
485
499
|
/** Every article as plain text, section by section — what STUDIO_FACTS carries to the assistant. */
|
|
486
500
|
declare function helpAsText(vars?: HelpVars): string;
|
|
487
501
|
|
|
488
|
-
export { ACTION_NAMES, type ActionResult, ContentEditor, type DiscardOutcome, GLOSSARY, HELP_ARTICLES, HELP_SECTIONS, type HelpArticle, type HelpSection, type HelpSectionId, type ImagePayload, InstallTracker, type Installing, Jargon, type ListRow, type MergeOutcome, type NudgeOutcome, type PendingSummary, type PublishInput, PublishPanel, RemoveItem, STUDIO_CSS, STUDIO_FACTS, StudioAcceptInvite, StudioAccount, type StudioActions, type StudioContextValue, StudioDashboard, StudioEdit, StudioHelp, StudioList, StudioNew, StudioNoAccess, StudioNotConfigured, StudioProvider, StudioPullRequest, StudioShellFrame, StudioSignIn, StudioTerm, type StudioUpdate, type TeamState, UpdateBody, UpdateStrip, canSeeUpdates, copyFor, fillVars, helpAsText, joinTypes, publicDirOf, searchHelp, useEntry, useInstalling, useStudio };
|
|
502
|
+
export { ACTION_NAMES, type ActionResult, ContentEditor, type DiscardOutcome, GLOSSARY, HELP_ARTICLES, HELP_SECTIONS, type HelpArticle, type HelpSection, type HelpSectionId, type ImagePayload, InstallTracker, type Installing, Jargon, type ListRow, type MergeOutcome, type NudgeOutcome, type PendingSummary, type PublishInput, PublishPanel, RemoveItem, STUDIO_CSS, STUDIO_FACTS, StudioAcceptInvite, StudioAccount, type StudioActions, type StudioContextValue, StudioDashboard, StudioEdit, StudioHelp, StudioList, StudioNew, StudioNoAccess, StudioNotConfigured, type StudioOptions, StudioProvider, StudioPullRequest, StudioShellFrame, StudioSignIn, StudioTerm, type StudioUpdate, type TeamState, UpdateBody, UpdateStrip, canSeeUpdates, copyFor, fillVars, helpAsText, joinTypes, publicDirOf, searchHelp, useEntry, useInstalling, useStudio };
|
|
@@ -67,6 +67,8 @@ interface PublishInput {
|
|
|
67
67
|
branch: string;
|
|
68
68
|
} | null;
|
|
69
69
|
images?: ImagePayload[];
|
|
70
|
+
/** The slug this item was opened as (edits only) — lets a save that changes the file name rename rather than duplicate. */
|
|
71
|
+
replaces?: string | null;
|
|
70
72
|
}
|
|
71
73
|
/** The pending Studio update, as Studio.readers.studioUpdate() returns it (serialisable). */
|
|
72
74
|
interface StudioUpdate {
|
|
@@ -172,21 +174,31 @@ type PendingSummary = {
|
|
|
172
174
|
removal: boolean;
|
|
173
175
|
};
|
|
174
176
|
|
|
177
|
+
/** Per type, per field — the choices for a reference field, e.g. { events: { venue: ["soundplex"] } }. */
|
|
178
|
+
type StudioOptions = Record<string, Record<string, string[]>>;
|
|
175
179
|
interface StudioContextValue {
|
|
176
180
|
contentTypes: Record<string, ContentTypeEntry>;
|
|
177
181
|
actions: StudioActions;
|
|
178
182
|
/** Who to ask when something needs the agency — "your web team" by default. */
|
|
179
183
|
supportName: string;
|
|
180
184
|
siteName: string;
|
|
185
|
+
/**
|
|
186
|
+
* Option lists the server resolved for this request (an event's venue is one of the
|
|
187
|
+
* site's venues). The registry is imported client-side and can't read the repo, so a
|
|
188
|
+
* layout computes these with Studio.readers.listSlugs and passes them here.
|
|
189
|
+
*/
|
|
190
|
+
options: StudioOptions;
|
|
181
191
|
}
|
|
182
|
-
declare function StudioProvider({ contentTypes, actions, supportName, siteName, children }: {
|
|
192
|
+
declare function StudioProvider({ contentTypes, actions, supportName, siteName, options, children }: {
|
|
183
193
|
contentTypes: Record<string, ContentTypeEntry>;
|
|
184
194
|
actions: StudioActions;
|
|
185
195
|
supportName?: string;
|
|
186
196
|
siteName?: string;
|
|
197
|
+
options?: StudioOptions;
|
|
187
198
|
children: ReactNode;
|
|
188
199
|
}): react.JSX.Element;
|
|
189
200
|
declare function useStudio(): StudioContextValue;
|
|
201
|
+
/** The registry entry, with any server-resolved option lists merged over the entry's own. */
|
|
190
202
|
declare function useEntry(typeId: string): ContentTypeEntry | null;
|
|
191
203
|
/** Pictures for a type live under public/<last folder segment>/. */
|
|
192
204
|
declare function publicDirOf(entry: {
|
|
@@ -307,11 +319,13 @@ declare function StudioAccount({ me, manages, team, branding, myUserId, myRole,
|
|
|
307
319
|
* zod schema, so it can't cross the server→client boundary — the page passes
|
|
308
320
|
* the type id and this component looks the entry up on the client.
|
|
309
321
|
*/
|
|
310
|
-
declare function ContentEditor({ typeId, initialValues, initialBody, existing, isNew, footer }: {
|
|
322
|
+
declare function ContentEditor({ typeId, initialValues, initialBody, existing, isNew, replaces, footer }: {
|
|
311
323
|
typeId: string;
|
|
312
324
|
initialValues?: Record<string, unknown>;
|
|
313
325
|
/** A brand-new item: the web address follows the title until it's edited by hand. */
|
|
314
326
|
isNew?: boolean;
|
|
327
|
+
/** The slug this item was opened as; lets a save that changes the file name rename rather than duplicate. */
|
|
328
|
+
replaces?: string | null;
|
|
315
329
|
initialBody?: string;
|
|
316
330
|
/** An open change for this file; saves go onto its branch (05c). */
|
|
317
331
|
existing?: {
|
|
@@ -485,4 +499,4 @@ declare function searchHelp(query: string, articles?: HelpArticle[]): HelpHit[];
|
|
|
485
499
|
/** Every article as plain text, section by section — what STUDIO_FACTS carries to the assistant. */
|
|
486
500
|
declare function helpAsText(vars?: HelpVars): string;
|
|
487
501
|
|
|
488
|
-
export { ACTION_NAMES, type ActionResult, ContentEditor, type DiscardOutcome, GLOSSARY, HELP_ARTICLES, HELP_SECTIONS, type HelpArticle, type HelpSection, type HelpSectionId, type ImagePayload, InstallTracker, type Installing, Jargon, type ListRow, type MergeOutcome, type NudgeOutcome, type PendingSummary, type PublishInput, PublishPanel, RemoveItem, STUDIO_CSS, STUDIO_FACTS, StudioAcceptInvite, StudioAccount, type StudioActions, type StudioContextValue, StudioDashboard, StudioEdit, StudioHelp, StudioList, StudioNew, StudioNoAccess, StudioNotConfigured, StudioProvider, StudioPullRequest, StudioShellFrame, StudioSignIn, StudioTerm, type StudioUpdate, type TeamState, UpdateBody, UpdateStrip, canSeeUpdates, copyFor, fillVars, helpAsText, joinTypes, publicDirOf, searchHelp, useEntry, useInstalling, useStudio };
|
|
502
|
+
export { ACTION_NAMES, type ActionResult, ContentEditor, type DiscardOutcome, GLOSSARY, HELP_ARTICLES, HELP_SECTIONS, type HelpArticle, type HelpSection, type HelpSectionId, type ImagePayload, InstallTracker, type Installing, Jargon, type ListRow, type MergeOutcome, type NudgeOutcome, type PendingSummary, type PublishInput, PublishPanel, RemoveItem, STUDIO_CSS, STUDIO_FACTS, StudioAcceptInvite, StudioAccount, type StudioActions, type StudioContextValue, StudioDashboard, StudioEdit, StudioHelp, StudioList, StudioNew, StudioNoAccess, StudioNotConfigured, type StudioOptions, StudioProvider, StudioPullRequest, StudioShellFrame, StudioSignIn, StudioTerm, type StudioUpdate, type TeamState, UpdateBody, UpdateStrip, canSeeUpdates, copyFor, fillVars, helpAsText, joinTypes, publicDirOf, searchHelp, useEntry, useInstalling, useStudio };
|
package/dist/studio-ui/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { createContext, useContext, useState, useEffect, useId, useTransition, Suspense,
|
|
2
|
+
import { createContext, useContext, useMemo, useState, useEffect, useId, useTransition, Suspense, useRef, useCallback, useSyncExternalStore, Fragment as Fragment$1 } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
5
5
|
import { createBrowserClient } from '@supabase/ssr';
|
|
@@ -7,8 +7,8 @@ import Link3 from 'next/link';
|
|
|
7
7
|
|
|
8
8
|
// src/studio-ui/context.tsx
|
|
9
9
|
var Ctx = createContext(null);
|
|
10
|
-
function StudioProvider({ contentTypes, actions, supportName = "your web team", siteName = "Studio", children }) {
|
|
11
|
-
return /* @__PURE__ */ jsx(Ctx.Provider, { value: { contentTypes, actions, supportName, siteName }, children });
|
|
10
|
+
function StudioProvider({ contentTypes, actions, supportName = "your web team", siteName = "Studio", options = {}, children }) {
|
|
11
|
+
return /* @__PURE__ */ jsx(Ctx.Provider, { value: { contentTypes, actions, supportName, siteName, options }, children });
|
|
12
12
|
}
|
|
13
13
|
function useStudio() {
|
|
14
14
|
const v = useContext(Ctx);
|
|
@@ -16,7 +16,10 @@ function useStudio() {
|
|
|
16
16
|
return v;
|
|
17
17
|
}
|
|
18
18
|
function useEntry(typeId) {
|
|
19
|
-
|
|
19
|
+
const { contentTypes, options } = useStudio();
|
|
20
|
+
const entry = contentTypes[typeId] ?? null;
|
|
21
|
+
const served = options[typeId];
|
|
22
|
+
return useMemo(() => entry && served ? { ...entry, options: { ...entry.options, ...served } } : entry, [entry, served]);
|
|
20
23
|
}
|
|
21
24
|
function publicDirOf(entry) {
|
|
22
25
|
return `/${entry.folder.split("/").filter(Boolean).pop() ?? "images"}/`;
|
|
@@ -307,20 +310,22 @@ function AccountMenu({ user, role, theme, onTheme, signOutPath, accountHref, hel
|
|
|
307
310
|
}
|
|
308
311
|
function TopBar({ siteName, productName, logoUrl, homeHref, siteUrl, user, role, theme, onTheme, signOutPath, accountHref, helpHref, version }) {
|
|
309
312
|
return /* @__PURE__ */ jsxs("header", { className: "rz-topbar", children: [
|
|
310
|
-
/* @__PURE__ */ jsxs(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
313
|
+
/* @__PURE__ */ jsxs("div", { className: "rz-topbar__brand", children: [
|
|
314
|
+
/* @__PURE__ */ jsxs(
|
|
315
|
+
"a",
|
|
316
|
+
{
|
|
317
|
+
href: siteUrl || homeHref,
|
|
318
|
+
className: "rz-topbar__site",
|
|
319
|
+
...siteUrl ? { target: "_blank", rel: "noreferrer", title: "Open the live website in a new tab" } : {},
|
|
320
|
+
children: [
|
|
321
|
+
logoUrl && /* @__PURE__ */ jsx("img", { src: logoUrl, alt: "", className: "rz-topbar__logo" }),
|
|
322
|
+
/* @__PURE__ */ jsx("span", { children: siteName }),
|
|
323
|
+
siteUrl && /* @__PURE__ */ jsx(OutboundArrow, {})
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
/* @__PURE__ */ jsx("span", { className: "rz-topbar__product", children: productName })
|
|
328
|
+
] }),
|
|
324
329
|
user && role && /* @__PURE__ */ jsxs("div", { className: "rz-topbar__right", children: [
|
|
325
330
|
/* @__PURE__ */ jsxs("span", { className: "rz-topbar__greeting", "data-testid": "rz-greeting", children: [
|
|
326
331
|
"Welcome back, ",
|
|
@@ -383,11 +388,14 @@ var SHELL_CSS = `
|
|
|
383
388
|
|
|
384
389
|
/* ---- frame ---------------------------------------------------------- */
|
|
385
390
|
.rz-topbar { height: var(--rz-topbar); display: flex; align-items: center; gap: 1rem; padding: 0 1.25rem; border-bottom: 1px solid var(--border); background: var(--surface-1); flex-shrink: 0; }
|
|
386
|
-
.rz-topbar__brand { display: flex; align-items: center; gap: .6rem; font-weight: 600; font-size: .9375rem;
|
|
391
|
+
.rz-topbar__brand { display: flex; align-items: center; gap: .6rem; font-weight: 600; font-size: .9375rem; }
|
|
392
|
+
.rz-topbar__site { display: inline-flex; align-items: center; gap: .6rem; color: inherit; text-decoration: none; }
|
|
393
|
+
.rz-topbar__site:hover { color: var(--signal); }
|
|
387
394
|
.rz-topbar__logo { height: 22px; width: auto; display: block; }
|
|
388
395
|
.rz-topbar__product { font-weight: 400; color: var(--text-secondary); }
|
|
389
|
-
|
|
390
|
-
.rz-
|
|
396
|
+
/* The arrow's width is reserved, so "Studio" never shifts when it fades in. */
|
|
397
|
+
.rz-topbar__site .rz-arrow { color: var(--text-muted); opacity: 0; margin-left: -.25rem; transition: opacity .15s, transform .15s; }
|
|
398
|
+
.rz-topbar__site:hover .rz-arrow { opacity: 1; color: var(--signal); }
|
|
391
399
|
.rz-topbar__right { margin-left: auto; display: flex; align-items: center; gap: 1rem; }
|
|
392
400
|
.rz-topbar__greeting { color: var(--text-secondary); font-size: .8rem; }
|
|
393
401
|
.rz-body { display: flex; flex: 1; min-height: 0; }
|
|
@@ -733,7 +741,7 @@ function Tabs({ options, value, onChange, label = "Sections" }) {
|
|
|
733
741
|
}
|
|
734
742
|
|
|
735
743
|
// src/version.ts
|
|
736
|
-
var ADMIN_VERSION = "0.
|
|
744
|
+
var ADMIN_VERSION = "0.16.0" ;
|
|
737
745
|
|
|
738
746
|
// src/studio-ui/css.ts
|
|
739
747
|
var STUDIO_CSS = `
|
|
@@ -3115,7 +3123,7 @@ function toBase64(blob) {
|
|
|
3115
3123
|
r.readAsDataURL(blob);
|
|
3116
3124
|
});
|
|
3117
3125
|
}
|
|
3118
|
-
function ContentEditor({ typeId, initialValues, initialBody, existing = null, isNew = false, footer }) {
|
|
3126
|
+
function ContentEditor({ typeId, initialValues, initialBody, existing = null, isNew = false, replaces = null, footer }) {
|
|
3119
3127
|
const entry = useEntry(typeId);
|
|
3120
3128
|
const { publishContent, previewBody } = useStudio().actions;
|
|
3121
3129
|
const [error, setError] = useState(null);
|
|
@@ -3133,7 +3141,7 @@ function ContentEditor({ typeId, initialValues, initialBody, existing = null, is
|
|
|
3133
3141
|
startTransition(async () => {
|
|
3134
3142
|
setError(null);
|
|
3135
3143
|
const images = await pictures.toPayload(s.images, s.body);
|
|
3136
|
-
const result = await publishContent({ type: typeId, frontmatter: s.frontmatter, body: s.body, images, existing: existing ? { number: existing.number, branch: existing.branch } : null });
|
|
3144
|
+
const result = await publishContent({ type: typeId, frontmatter: s.frontmatter, body: s.body, images, existing: existing ? { number: existing.number, branch: existing.branch } : null, replaces });
|
|
3137
3145
|
if (result && result.ok === false) setError(result.error);
|
|
3138
3146
|
resolve();
|
|
3139
3147
|
});
|
|
@@ -3671,6 +3679,7 @@ function StudioEdit({ typeId, slug, frontmatter, body, pending }) {
|
|
|
3671
3679
|
typeId: entry.id,
|
|
3672
3680
|
initialValues: frontmatter,
|
|
3673
3681
|
initialBody: body,
|
|
3682
|
+
replaces: slug,
|
|
3674
3683
|
existing: pending ? { number: pending.number, branch: pending.branch, state: pending.state } : null,
|
|
3675
3684
|
footer: !pending ? /* @__PURE__ */ jsx(RemoveItem, { typeId: entry.id, slug }) : void 0
|
|
3676
3685
|
}
|
|
@@ -4986,6 +4995,8 @@ The old listing shows "Rescheduled" with a link to the new date. The new one is
|
|
|
4986
4995
|
|
|
4987
4996
|
You can, for small corrections. But once people have shared the link or put it in a calendar, a visible "moved" trail avoids no-shows on the wrong day.
|
|
4988
4997
|
|
|
4998
|
+
On sites where the date is part of the event's web address, changing the date moves the event to a new address and the old one stops working \u2014 Studio handles the move cleanly (one file, not two), but any link already shared points at nothing. That's the real reason to prefer **Moved to**.
|
|
4999
|
+
|
|
4989
5000
|
## After it's over
|
|
4990
5001
|
|
|
4991
5002
|
Nothing to do. Past events move to the **Past** section automatically the day after they end.
|