@bygghammar/cms-platform 0.90.0-m7.10 → 0.90.0-m7.11
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/CHANGELOG.md +17 -0
- package/package.json +1 -1
- package/src/backoffice/PageBuilderView.tsx +57 -22
- package/src/backoffice/routes/host.ts +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,23 @@ matches `package.json` exactly. See
|
|
|
8
8
|
Versions 0.1.0 through 0.78.0 predate this repository and were reconstructed
|
|
9
9
|
from the published npm tarballs.
|
|
10
10
|
|
|
11
|
+
## 0.90.0-m7.11
|
|
12
|
+
|
|
13
|
+
- The page builder no longer invents a public URL for a locale with no
|
|
14
|
+
configured public domain. An empty `publicHost(locale)` means no public URL
|
|
15
|
+
exists, and is no longer read as a relative one.
|
|
16
|
+
- For an unmapped locale the page path is shown as plain, non-clickable
|
|
17
|
+
information, saying that no domain is configured for that language. The
|
|
18
|
+
public-link anchor and the Copy URL action are omitted rather than pointed
|
|
19
|
+
somewhere else: no relative href, no backoffice or request hostname, no other
|
|
20
|
+
locale's domain.
|
|
21
|
+
- Draft Preview keeps working for an unmapped locale. Previewing is a
|
|
22
|
+
backoffice operation and has never needed a public hostname.
|
|
23
|
+
- The `publicHost`, `publicPath` and `usePageUrl` host contracts document this,
|
|
24
|
+
so a host knows what the empty string means before it implements one.
|
|
25
|
+
- No migration and no database change. Nothing in this release concerns a
|
|
26
|
+
host's own integration code.
|
|
27
|
+
|
|
11
28
|
## 0.90.0-m7.10
|
|
12
29
|
|
|
13
30
|
- Code & tracking drafts survive a refetch. A background reload replaced the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bygghammar/cms-platform",
|
|
3
|
-
"version": "0.90.0-m7.
|
|
3
|
+
"version": "0.90.0-m7.11",
|
|
4
4
|
"description": "Shared CMS platform: blocks, block types, i18n core, UI primitives and design-token contract used by every Bygghammar/Voyara site.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -64,9 +64,23 @@ export type PageBuilderDeps<TBlock> = {
|
|
|
64
64
|
locales: readonly string[];
|
|
65
65
|
localeLabels: Record<string, string>;
|
|
66
66
|
defaultLocale: string;
|
|
67
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Site-relative path for this page in the given locale.
|
|
69
|
+
*
|
|
70
|
+
* A path on its own is not a public address. It only becomes one when
|
|
71
|
+
* `publicHost` supplies the hostname it belongs to.
|
|
72
|
+
*/
|
|
68
73
|
publicPath: (locale: string) => string;
|
|
69
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* The public hostname for this locale, or `""` when there is none.
|
|
76
|
+
*
|
|
77
|
+
* Since m7.10 a deployment's locale-to-domain table is explicit: a locale
|
|
78
|
+
* that is not in it has no public site. `""` is that answer — NO PUBLIC URL
|
|
79
|
+
* EXISTS — and it must never be read as "use a relative URL" or "fall back
|
|
80
|
+
* to the current host". Doing so hands the browser a path it resolves
|
|
81
|
+
* against whatever hostname the backoffice happens to be served from,
|
|
82
|
+
* inventing a public address for a locale the deployment does not publish.
|
|
83
|
+
*/
|
|
70
84
|
publicHost: (locale: string) => string;
|
|
71
85
|
|
|
72
86
|
versions: BuilderVersion[] | undefined;
|
|
@@ -156,7 +170,11 @@ export function PageBuilderView<TBlock>({ deps }: { deps: PageBuilderDeps<TBlock
|
|
|
156
170
|
|
|
157
171
|
const slugPath = deps.publicPath(locale);
|
|
158
172
|
const host = deps.publicHost(locale);
|
|
159
|
-
|
|
173
|
+
// No hostname, no public URL. A relative href here would be resolved against
|
|
174
|
+
// the backoffice hostname, which is not where this page is published — and
|
|
175
|
+
// for an unmapped locale it is not published anywhere.
|
|
176
|
+
const publicUrl = host ? `https://${host}${slugPath}` : null;
|
|
177
|
+
const localeName = localeLabels[locale] ?? locale;
|
|
160
178
|
|
|
161
179
|
const togglePanel = (panel: "history" | "schedule") => {
|
|
162
180
|
if (panel === "history") {
|
|
@@ -171,8 +189,9 @@ export function PageBuilderView<TBlock>({ deps }: { deps: PageBuilderDeps<TBlock
|
|
|
171
189
|
};
|
|
172
190
|
|
|
173
191
|
const onCopyUrl = async () => {
|
|
192
|
+
if (!publicUrl) return;
|
|
174
193
|
try {
|
|
175
|
-
await navigator.clipboard.writeText(
|
|
194
|
+
await navigator.clipboard.writeText(publicUrl);
|
|
176
195
|
setCopied(true);
|
|
177
196
|
setTimeout(() => setCopied(false), 1500);
|
|
178
197
|
} catch {
|
|
@@ -329,24 +348,40 @@ export function PageBuilderView<TBlock>({ deps }: { deps: PageBuilderDeps<TBlock
|
|
|
329
348
|
</div>
|
|
330
349
|
)}
|
|
331
350
|
<div className="mt-2 flex flex-wrap items-center gap-2">
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
351
|
+
{publicUrl ? (
|
|
352
|
+
<>
|
|
353
|
+
<a
|
|
354
|
+
href={publicUrl}
|
|
355
|
+
target="_blank"
|
|
356
|
+
rel="noreferrer"
|
|
357
|
+
title={`Open ${publicUrl}`}
|
|
358
|
+
className="inline-flex items-center gap-1.5 border border-ink/15 bg-white px-2.5 py-1 font-mono text-xs text-ink hover:border-sea"
|
|
359
|
+
>
|
|
360
|
+
{slugPath}
|
|
361
|
+
<ExternalLink className="size-3 text-ink/40" />
|
|
362
|
+
</a>
|
|
363
|
+
<button
|
|
364
|
+
onClick={onCopyUrl}
|
|
365
|
+
title="Copy full URL"
|
|
366
|
+
className="inline-flex items-center gap-1.5 border border-ink/15 px-2 py-1 text-xs text-ink/60 hover:border-sea hover:text-ink"
|
|
367
|
+
>
|
|
368
|
+
{copied ? <Check className="size-3" /> : <Copy className="size-3" />}
|
|
369
|
+
{copied ? "Copied" : "Copy URL"}
|
|
370
|
+
</button>
|
|
371
|
+
</>
|
|
372
|
+
) : (
|
|
373
|
+
/* Not a link and not a copy target: there is no address to open
|
|
374
|
+
or to paste into a message. The path is still shown, because
|
|
375
|
+
it is the one true thing here — where this page would live if
|
|
376
|
+
the locale were given a domain. */
|
|
377
|
+
<span
|
|
378
|
+
className="inline-flex items-center gap-1.5 border border-dashed border-ink/20 px-2.5 py-1 font-mono text-xs text-ink/50"
|
|
379
|
+
title={`${localeName} has no public domain, so this page has no public address.`}
|
|
380
|
+
>
|
|
381
|
+
{slugPath}
|
|
382
|
+
<span className="font-sans">· No domain configured for {localeName}</span>
|
|
383
|
+
</span>
|
|
384
|
+
)}
|
|
350
385
|
{locales.length > 1 && (
|
|
351
386
|
<div className="flex items-center gap-1">
|
|
352
387
|
{locales.map((loc) => (
|
|
@@ -239,6 +239,14 @@ export type BackofficeHost = {
|
|
|
239
239
|
/**
|
|
240
240
|
* React hook returning a resolver for a page's public URL. Implemented as a
|
|
241
241
|
* hook so a site can read its slug overrides and locale domains.
|
|
242
|
+
*
|
|
243
|
+
* `path` is site-relative. `host` is the public hostname for that locale,
|
|
244
|
+
* or `""` when the locale has no public hostname — since m7.10 the
|
|
245
|
+
* locale-to-domain table is explicit, so a locale missing from it has no
|
|
246
|
+
* public site at all. An empty `host` therefore means NO PUBLIC URL
|
|
247
|
+
* EXISTS; it is not a signal to use `path` on its own, and a host must
|
|
248
|
+
* not answer it by borrowing the current hostname or another locale's
|
|
249
|
+
* domain. Screens are expected to offer no public link in that case.
|
|
242
250
|
*/
|
|
243
251
|
usePageUrl: () => (
|
|
244
252
|
pageKey: string,
|