@phis/ui 0.4.0 → 0.4.2
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/components/controls/phi-table-control.d.ts +6 -1
- package/components/controls/phi-table-control.js +16 -4
- package/components/layouts/layout-definitions.d.ts +2 -2
- package/components/layouts/layout-definitions.js +6 -1
- package/components/shell/use-phi-shell-sticky-top.d.ts +5 -0
- package/components/shell/use-phi-shell-sticky-top.js +78 -0
- package/components/widgets/helpers/semantic-html-translation.d.ts +3 -1
- package/components/widgets/helpers/semantic-html-translation.js +8 -3
- package/components/widgets/navigation-descriptor-resolver.server.js +6 -1
- package/components/widgets/shared/markdown-body-client.d.ts +2 -1
- package/components/widgets/shared/markdown-body-client.js +3 -1
- package/components/widgets/shared/markdown-render.js +23 -6
- package/helpers/text-source.d.ts +19 -0
- package/helpers/text-source.js +20 -0
- package/next/config.mjs +1 -1
- package/package.json +1 -1
- package/plugins/runtime-modules/auth/trees/phi-default-pub-confirm-page-tree.js +3 -0
- package/plugins/runtime-modules/auth/trees/phi-default-pub-login-page-tree.js +2 -0
- package/plugins/runtime-modules/auth/trees/phi-default-pub-registration-page-tree.js +3 -0
- package/plugins/runtime-modules/auth/trees/phi-default-pub-reset-password-page-tree.js +3 -0
- package/plugins/runtime-modules/builder/clients/widget-inspector.js +9 -0
- package/plugins/runtime-modules/builder/trees/phi-default-builder-area-preset-tree.js +4 -0
- package/plugins/runtime-modules/core/widgets/card/server.js +4 -2
- package/plugins/runtime-modules/core/widgets/description/config.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/description/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/description/server.js +10 -12
- package/plugins/runtime-modules/core/widgets/entry-list/server.js +2 -2
- package/plugins/runtime-modules/core/widgets/html/server.js +1 -1
- package/plugins/runtime-modules/core/widgets/markdown/config.d.ts +3 -1
- package/plugins/runtime-modules/core/widgets/markdown/config.js +14 -0
- package/plugins/runtime-modules/core/widgets/markdown-toc/server.js +7 -2
- package/plugins/runtime-modules/core/widgets/quick-links/config.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/quick-links/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/quick-links/plugin.js +4 -2
- package/plugins/runtime-modules/core/widgets/quick-links/server.d.ts +5 -1
- package/plugins/runtime-modules/core/widgets/quick-links/server.js +4 -2
- package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +3 -0
- package/plugins/runtime-modules/core/widgets/simple-text/config.js +2 -0
- package/plugins/runtime-modules/core/widgets/simple-text/plugin.js +1 -1
- package/plugins/runtime-modules/core/widgets/simple-text/server.d.ts +4 -1
- package/plugins/runtime-modules/core/widgets/simple-text/server.js +3 -3
- package/plugins/runtime-modules/core/widgets/table/client.js +1 -1
- package/plugins/runtime-modules/core/widgets/table/config.d.ts +1 -0
- package/plugins/runtime-modules/core/widgets/table/config.js +3 -0
- package/plugins/runtime-modules/phi-default-site-area-preset-tree.js +12 -4
- package/plugins/runtime-modules/public/trees/phi-default-pub-contact-page-tree.js +2 -0
- package/plugins/runtime-modules/public/trees/phi-default-pub-unsubscribe-page-tree.js +3 -0
- package/plugins/runtime-modules/public/trees/phi-default-pub-welcome-page-tree.js +2 -1
- package/plugins/runtime-modules/revisions/trees/phi-default-builder-revisions-page-tree.js +4 -0
- package/server-helpers/translate.d.ts +9 -0
- package/server-helpers/translate.js +14 -0
- package/styles/controls.css +41 -1
- package/styles/root.css +20 -19
- package/types/core-widget-placements.d.ts +8 -0
- package/types/table-widget.d.ts +2 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { trWidgetText } from "../../../../../server-helpers/translate";
|
|
3
3
|
import { maskPhiTextPlaceholders, resolvePhiTextPlaceholders } from "../../../../../helpers/text-placeholders";
|
|
4
4
|
import { PhiBulletListControl } from "../../../../../components/controls/phi-bullet-list-control";
|
|
5
5
|
import { buildPhiBulletListTree, resolvePhiBulletListStyle, } from "../../../../../components/widgets/shared/bullet-list-vocabulary";
|
|
@@ -12,17 +12,15 @@ import { PHI_COLOR, PHI_FONT_SIZE, PHI_LINE_HEIGHT, PHI_SPACE, } from "../../../
|
|
|
12
12
|
* `{year}` out of the translator's hands, which would otherwise hand back `{Jahr}`.
|
|
13
13
|
*/
|
|
14
14
|
async function translateLabel(locale, value, runtime, translate,
|
|
15
|
+
/** Whose words these are, which decides the store (`helpers/text-source.ts`). */
|
|
16
|
+
textSource,
|
|
15
17
|
/** The text's own values, which stand in it as `%1` onwards and are never translated. */
|
|
16
18
|
values = []) {
|
|
17
19
|
if (!value) {
|
|
18
20
|
return undefined;
|
|
19
21
|
}
|
|
20
22
|
const masked = maskPhiTextPlaceholders(value, values.length);
|
|
21
|
-
const translated =
|
|
22
|
-
? masked.text
|
|
23
|
-
: locale
|
|
24
|
-
? await trGlobalForLocale(locale, masked.text)
|
|
25
|
-
: await trGlobal(masked.text);
|
|
23
|
+
const translated = translate ? await trWidgetText(locale, masked.text, textSource) : masked.text;
|
|
26
24
|
return resolvePhiTextPlaceholders(translated, masked.names, runtime, values);
|
|
27
25
|
}
|
|
28
26
|
function resolveDescriptionToneColor(tone) {
|
|
@@ -39,15 +37,15 @@ function resolveDescriptionToneColor(tone) {
|
|
|
39
37
|
}
|
|
40
38
|
export async function PhiDescriptionWidget({ labels, config, runtime, translate, }) {
|
|
41
39
|
const locale = runtime?.locale.current;
|
|
42
|
-
const eyebrow = await translateLabel(locale, labels.eyebrow ?? config?.eyebrow, runtime, translate);
|
|
43
|
-
const title = await translateLabel(locale, labels.title ?? config?.title, runtime, translate);
|
|
44
|
-
const description = await translateLabel(locale, labels.description ?? config?.description, runtime, translate);
|
|
45
|
-
const asideTitle = await translateLabel(locale, labels.asideTitle ?? config?.asideTitle, runtime, translate);
|
|
40
|
+
const eyebrow = await translateLabel(locale, labels.eyebrow ?? config?.eyebrow, runtime, translate, config?.textSource);
|
|
41
|
+
const title = await translateLabel(locale, labels.title ?? config?.title, runtime, translate, config?.textSource);
|
|
42
|
+
const description = await translateLabel(locale, labels.description ?? config?.description, runtime, translate, config?.textSource);
|
|
43
|
+
const asideTitle = await translateLabel(locale, labels.asideTitle ?? config?.asideTitle, runtime, translate, config?.textSource);
|
|
46
44
|
const asideEntries = await Promise.all((labels.asideItems ?? config?.asideItems ?? []).map(async (entry) => ({
|
|
47
45
|
...entry,
|
|
48
|
-
text: await translateLabel(locale, entry.text, runtime, translate, entry.values),
|
|
46
|
+
text: await translateLabel(locale, entry.text, runtime, translate, config?.textSource, entry.values),
|
|
49
47
|
})));
|
|
50
|
-
const footer = await translateLabel(locale, labels.footer ?? config?.footer, runtime, translate);
|
|
48
|
+
const footer = await translateLabel(locale, labels.footer ?? config?.footer, runtime, translate, config?.textSource);
|
|
51
49
|
const resolvedAsideItems = buildPhiBulletListTree(asideEntries.filter((entry) => Boolean(entry.text)), (entry) => entry.text);
|
|
52
50
|
const stackStyle = {
|
|
53
51
|
display: "grid",
|
|
@@ -5,7 +5,7 @@ import { getPhiContentEntryReaderLabels } from "../../../../../components/widget
|
|
|
5
5
|
import { PhiCmsWidgetType } from "../../../../../constants/cms-widget-types";
|
|
6
6
|
import { fetchPhiSiteContentEntries } from "../../../../../gateway/content-entries";
|
|
7
7
|
import { phiRuntime } from "../../../../../server-helpers/phi-runtime";
|
|
8
|
-
import {
|
|
8
|
+
import { trBulkForLocale } from "../../../../../server-helpers/translate";
|
|
9
9
|
import { readPhiBoundContentEntry } from "../../content-entries/record-source.server";
|
|
10
10
|
import { buildPhiEntryViews } from "./view.server";
|
|
11
11
|
import { normalizePhiEntryListWidgetConfig } from "./config";
|
|
@@ -74,7 +74,7 @@ export async function PhiEntryListWidget({ config, runtime, registry, links, tra
|
|
|
74
74
|
// A stacked entry's title is an `h2`; its text's headings start under it.
|
|
75
75
|
headingOffset: 2,
|
|
76
76
|
});
|
|
77
|
-
const [title] = settings.title && translate ? await
|
|
77
|
+
const [title] = settings.title && translate ? await trBulkForLocale(locale, [settings.title]) : [settings.title];
|
|
78
78
|
return (_jsx(PhiRuntimeModuleRenderClientHost, { type: PhiCmsWidgetType.EntryList, componentProps: {
|
|
79
79
|
entries: views,
|
|
80
80
|
labels,
|
|
@@ -52,7 +52,7 @@ export async function PhiHtmlWidget({ blockId, config, runtime, }) {
|
|
|
52
52
|
}
|
|
53
53
|
const translatedHtml = (sourceMode !== "url" && config?.resolvedContent != null) || config?.preferSource === true
|
|
54
54
|
? sourceHtml
|
|
55
|
-
: await translateSemanticHtml(sourceHtml, sourceMode === "url" ? config?.sourceLocale?.trim() : undefined);
|
|
55
|
+
: await translateSemanticHtml(sourceHtml, sourceMode === "url" ? config?.sourceLocale?.trim() : undefined, runtime.locale.current);
|
|
56
56
|
if (!translatedHtml) {
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PhiMarkdownTextAlign } from "../../../../../types/core-widget-placements";
|
|
1
|
+
import type { PhiMarkdownImageFloat, PhiMarkdownTextAlign } from "../../../../../types/core-widget-placements";
|
|
2
2
|
import { type PhiSpacingScaleKey } from "../../../../../components/widgets/config/spacing-options";
|
|
3
3
|
import type { PhiCmsResolvedContent } from "../../../../../types/cms";
|
|
4
4
|
import { type PhiBulletListStyle } from "../../../../../components/widgets/shared/bullet-list-vocabulary";
|
|
@@ -13,6 +13,8 @@ export type PhiCmsMarkdownWidgetConfig = PhiCmsWidgetConfigBase & {
|
|
|
13
13
|
/** Set at render from the node's `NoTranslate` flag, or by a caller that knows; never authored. */
|
|
14
14
|
translate?: boolean;
|
|
15
15
|
textAlign?: PhiMarkdownTextAlign;
|
|
16
|
+
/** Pictures stand at this edge and the text flows past them; absent, a picture is a line of its own. */
|
|
17
|
+
imageFloat?: PhiMarkdownImageFloat;
|
|
16
18
|
textBlockSpacingBefore?: PhiSpacingScaleKey;
|
|
17
19
|
textBlockSpacingAfter?: PhiSpacingScaleKey;
|
|
18
20
|
headingBlockSpacingBefore?: PhiSpacingScaleKey;
|
|
@@ -9,6 +9,13 @@ const PHI_MARKDOWN_TEXT_ALIGN_OPTIONS = [
|
|
|
9
9
|
{ value: "end", label: "End" },
|
|
10
10
|
{ value: "justify", label: "Justify" },
|
|
11
11
|
];
|
|
12
|
+
const PHI_MARKDOWN_IMAGE_FLOAT_OPTIONS = [
|
|
13
|
+
{ value: "start", label: "Start" },
|
|
14
|
+
{ value: "end", label: "End" },
|
|
15
|
+
];
|
|
16
|
+
function readMarkdownImageFloat(value) {
|
|
17
|
+
return value === "start" || value === "end" ? value : undefined;
|
|
18
|
+
}
|
|
12
19
|
// The one spacing scale every padding and gap speaks (`theme/phi-tokens.ts`), stored by its key.
|
|
13
20
|
const PHI_MARKDOWN_SPACING_OPTIONS = PHI_SPACING_SCALE_KEYS.map((key) => ({ value: key, label: key }));
|
|
14
21
|
function readMarkdownSourceMode(value) {
|
|
@@ -41,6 +48,7 @@ export function parsePhiCmsMarkdownWidgetConfig(config) {
|
|
|
41
48
|
sourceLocale: readString(config.sourceLocale),
|
|
42
49
|
revalidateSeconds: readNumber(config.revalidateSeconds),
|
|
43
50
|
textAlign: readMarkdownTextAlign(config.textAlign),
|
|
51
|
+
imageFloat: readMarkdownImageFloat(config.imageFloat),
|
|
44
52
|
textBlockSpacingBefore: readMarkdownSpacingKey(config.textBlockSpacingBefore),
|
|
45
53
|
textBlockSpacingAfter: readMarkdownSpacingKey(config.textBlockSpacingAfter),
|
|
46
54
|
headingBlockSpacingBefore: readMarkdownSpacingKey(config.headingBlockSpacingBefore),
|
|
@@ -115,6 +123,12 @@ export const PHI_MARKDOWN_WIDGET_DEFINITION = {
|
|
|
115
123
|
label: "Align",
|
|
116
124
|
options: PHI_MARKDOWN_TEXT_ALIGN_OPTIONS,
|
|
117
125
|
},
|
|
126
|
+
{
|
|
127
|
+
key: "imageFloat",
|
|
128
|
+
type: "choice",
|
|
129
|
+
label: "Image Float",
|
|
130
|
+
options: PHI_MARKDOWN_IMAGE_FLOAT_OPTIONS,
|
|
131
|
+
},
|
|
118
132
|
{
|
|
119
133
|
key: "textBlockSpacingBefore",
|
|
120
134
|
type: "choice",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { PhiCmsFlags } from "../../../../../constants/phi-cms";
|
|
3
3
|
import { hasPhiFlag } from "../../../../../helpers/flags";
|
|
4
|
-
import {
|
|
4
|
+
import { trForLocale } from "../../../../../server-helpers/translate";
|
|
5
5
|
import { PhiCmsWidgetType } from "../../../../../constants/cms-widget-types";
|
|
6
6
|
import { parsePhiCmsMarkdownWidgetConfig } from "../markdown/config";
|
|
7
7
|
import { PhiRuntimeModuleRenderClientHost } from "../../../../../components/runtime/runtime-module-render-client-manifest";
|
|
@@ -25,7 +25,12 @@ function filterHeadings(headings, config) {
|
|
|
25
25
|
return headings.filter((heading) => heading.level >= minLevel && heading.level <= maxLevel);
|
|
26
26
|
}
|
|
27
27
|
export async function PhiMarkdownTocWidget({ config, defaultLabels, tree, runtime, }) {
|
|
28
|
-
|
|
28
|
+
/*
|
|
29
|
+
* The author's title in the render's locale; the default is a label set's and arrives translated, so
|
|
30
|
+
* asking for it again would hand a translator text that is no longer in the source language.
|
|
31
|
+
*/
|
|
32
|
+
const ownTitle = config?.title?.trim();
|
|
33
|
+
const title = ownTitle ? await trForLocale(runtime.locale.current, ownTitle) : defaultLabels.title;
|
|
29
34
|
const targetWidget = resolveTargetMarkdownWidget(tree, config);
|
|
30
35
|
if (!targetWidget) {
|
|
31
36
|
return (_jsx(PhiRuntimeModuleRenderClientHost, { type: PhiCmsWidgetType.MarkdownToc, componentProps: { config: { ...config, title, headings: [] } } }));
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { type PhiTextSource } from "../../../../../helpers/text-source";
|
|
1
2
|
import { type PhiCmsWidgetConfigBase } from "../../../../../components/widgets/config/parser-primitives";
|
|
2
3
|
export type PhiCmsQuickLinksWidgetConfig = PhiCmsWidgetConfigBase & {
|
|
3
4
|
navKey?: string;
|
|
4
5
|
title?: string;
|
|
5
6
|
columns?: 1 | 2 | 3;
|
|
6
7
|
separator?: boolean;
|
|
8
|
+
/** `"preset"` while the words are a Preset's and translated globally (`helpers/text-source.ts`). */
|
|
9
|
+
textSource?: PhiTextSource;
|
|
7
10
|
};
|
|
8
11
|
declare function parsePhiCmsQuickLinksWidgetConfig(config: Record<string, unknown>): PhiCmsQuickLinksWidgetConfig;
|
|
9
12
|
export declare const PHI_QUICK_LINKS_WIDGET_DEFINITION: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolvePhiCmsWidgetPluginKey } from "../../../../../constants/cms-widget-types";
|
|
2
|
+
import { readPhiTextSource } from "../../../../../helpers/text-source";
|
|
2
3
|
import { PhiCmsWidgetType } from "../../../../../constants/cms-widget-types";
|
|
3
4
|
import { PHI_AUTHORING_OPTION_PROVIDER_KEYS } from "../../../../../constants/authoring-option-provider-keys";
|
|
4
5
|
import { readBoolean, readNumber, readRenderableBlockConfig, readString, } from "../../../../../components/widgets/config/parser-primitives";
|
|
@@ -11,6 +12,7 @@ function parsePhiCmsQuickLinksWidgetConfig(config) {
|
|
|
11
12
|
title: readString(config.title),
|
|
12
13
|
columns: columns === 1 || columns === 3 ? columns : 2,
|
|
13
14
|
separator: readBoolean(config.separator) ?? true,
|
|
15
|
+
textSource: readPhiTextSource(config.textSource),
|
|
14
16
|
};
|
|
15
17
|
}
|
|
16
18
|
export const PHI_QUICK_LINKS_WIDGET_DEFINITION = {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PhiCmsFlags } from "../../../../../constants/phi-cms";
|
|
3
|
+
import { hasPhiFlag } from "../../../../../helpers/flags";
|
|
2
4
|
import { PhiQuickLinksWidget } from "./server";
|
|
3
5
|
import { PHI_QUICK_LINKS_WIDGET_DEFINITION, PHI_QUICK_LINKS_WIDGET_PLUGIN_TYPE, } from "./config";
|
|
4
6
|
export const PHI_QUICK_LINKS_WIDGET_PLUGIN = {
|
|
5
7
|
...PHI_QUICK_LINKS_WIDGET_DEFINITION,
|
|
6
|
-
render: ({ widget, runtime, config }) => (_jsx(PhiQuickLinksWidget, { runtime: runtime, navKey: config.navKey, title: config.title, columns: config.columns, separator: config.separator }, `widget-${widget.id}`)),
|
|
7
|
-
renderPreview: ({ widget, runtime, config }) => (_jsx(PhiQuickLinksWidget, { runtime: runtime, navKey: config.navKey, title: config.title, columns: config.columns, separator: config.separator, interactive: false }, `widget-${widget.id}`)),
|
|
8
|
+
render: ({ widget, runtime, config }) => (_jsx(PhiQuickLinksWidget, { runtime: runtime, navKey: config.navKey, title: config.title, textSource: config.textSource, translate: !hasPhiFlag(widget.flags, PhiCmsFlags.NoTranslate), columns: config.columns, separator: config.separator }, `widget-${widget.id}`)),
|
|
9
|
+
renderPreview: ({ widget, runtime, config }) => (_jsx(PhiQuickLinksWidget, { runtime: runtime, navKey: config.navKey, title: config.title, textSource: config.textSource, translate: !hasPhiFlag(widget.flags, PhiCmsFlags.NoTranslate), columns: config.columns, separator: config.separator, interactive: false }, `widget-${widget.id}`)),
|
|
8
10
|
};
|
|
9
11
|
export { PHI_QUICK_LINKS_WIDGET_PLUGIN_TYPE };
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { PhiBlockRuntime } from "../../../../../types";
|
|
2
|
+
import type { PhiTextSource } from "../../../../../helpers/text-source";
|
|
2
3
|
export type PhiQuickLinksWidgetProps = {
|
|
3
4
|
runtime: Pick<PhiBlockRuntime, "site" | "locale" | "area" | "viewer" | "request">;
|
|
4
5
|
navKey?: string;
|
|
5
6
|
title?: string;
|
|
7
|
+
/** Whose words the title is, which decides the store that translates it. */
|
|
8
|
+
textSource?: PhiTextSource;
|
|
9
|
+
translate?: boolean;
|
|
6
10
|
columns?: 1 | 2 | 3;
|
|
7
11
|
separator?: boolean;
|
|
8
12
|
interactive?: boolean;
|
|
9
13
|
};
|
|
10
|
-
export declare function PhiQuickLinksWidget({ runtime, navKey, title, columns, separator, interactive, }: PhiQuickLinksWidgetProps): Promise<import("react").JSX.Element | null>;
|
|
14
|
+
export declare function PhiQuickLinksWidget({ runtime, navKey, title, textSource, translate, columns, separator, interactive, }: PhiQuickLinksWidgetProps): Promise<import("react").JSX.Element | null>;
|
|
@@ -3,15 +3,17 @@ import { PhiCmsWidgetType } from "../../../../../constants/cms-widget-types";
|
|
|
3
3
|
import { PhiRuntimeModuleRenderClientHost } from "../../../../../components/runtime/runtime-module-render-client-manifest";
|
|
4
4
|
import { resolvePhiNavigationItems } from "../../../../../components/widgets/server/navigation-request";
|
|
5
5
|
import { mapPhiNavItemsToQuickLinksItems } from "./items";
|
|
6
|
-
|
|
6
|
+
import { trWidgetText } from "../../../../../server-helpers/translate";
|
|
7
|
+
export async function PhiQuickLinksWidget({ runtime, navKey, title, textSource, translate = true, columns = 2, separator = true, interactive = true, }) {
|
|
7
8
|
const resolvedNavKey = navKey?.trim() ||
|
|
8
9
|
`${runtime.area}:footer`;
|
|
9
10
|
const resolvedNavigationItems = (await resolvePhiNavigationItems(runtime, resolvedNavKey)) ?? [];
|
|
10
11
|
if (resolvedNavigationItems.length === 0) {
|
|
11
12
|
return null;
|
|
12
13
|
}
|
|
14
|
+
const ownTitle = title?.trim();
|
|
13
15
|
const labels = {
|
|
14
|
-
title,
|
|
16
|
+
title: ownTitle && translate ? await trWidgetText(runtime.locale.current, ownTitle, textSource) : title,
|
|
15
17
|
};
|
|
16
18
|
const config = {
|
|
17
19
|
columns,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PhiTextSource } from "../../../../../helpers/text-source";
|
|
1
2
|
import { type PhiSimpleTextMark } from "../../../../../types/core-widget-placements";
|
|
2
3
|
import type { PhiCmsResolvedContent } from "../../../../../types";
|
|
3
4
|
import type { PhiWidgetFontFamilyKey, PhiWidgetFontSizeKey } from "../../../../../types/site-theme";
|
|
@@ -15,6 +16,8 @@ export type PhiCmsSimpleTextWidgetConfig = PhiCmsWidgetConfigBase & {
|
|
|
15
16
|
tone?: PhiTextTone;
|
|
16
17
|
marks?: PhiSimpleTextMark[];
|
|
17
18
|
disabled?: boolean;
|
|
19
|
+
/** `"preset"` while the words are a Preset's and translated globally (`helpers/text-source.ts`). */
|
|
20
|
+
textSource?: PhiTextSource;
|
|
18
21
|
};
|
|
19
22
|
declare function parsePhiCmsSimpleTextWidgetConfig(config: Record<string, unknown>): PhiCmsSimpleTextWidgetConfig;
|
|
20
23
|
export type PhiSimpleTextWidgetRenderableConfig = PhiCmsSimpleTextWidgetConfig & {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolvePhiCmsWidgetPluginKey } from "../../../../../constants/cms-widget-types";
|
|
2
|
+
import { readPhiTextSource } from "../../../../../helpers/text-source";
|
|
2
3
|
import { PHI_SIMPLE_TEXT_MARKS } from "../../../../../types/core-widget-placements";
|
|
3
4
|
import { PhiCmsWidgetType } from "../../../../../constants/cms-widget-types";
|
|
4
5
|
import { PHI_RENDERABLE_BLOCK_GEOMETRY_FIELDS } from "../../../../../helpers/renderable-block-plugin-fields";
|
|
@@ -27,6 +28,7 @@ function parsePhiCmsSimpleTextWidgetConfig(config) {
|
|
|
27
28
|
tone: readPhiTextTone(config.tone),
|
|
28
29
|
marks: readSimpleTextMarks(config.marks),
|
|
29
30
|
disabled: readBoolean(config.disabled),
|
|
31
|
+
textSource: readPhiTextSource(config.textSource),
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
export const PHI_SIMPLE_TEXT_WIDGET_DEFINITION = {
|
|
@@ -9,7 +9,7 @@ export const PHI_SIMPLE_TEXT_WIDGET_PLUGIN = {
|
|
|
9
9
|
const noTranslate = hasPhiFlag(widget.flags, PhiCmsFlags.NoTranslate);
|
|
10
10
|
// A record's text is already translated; only the Widget's own still has to be.
|
|
11
11
|
const hasResolvedText = Boolean(widget.resolvedContent?.textFields.text);
|
|
12
|
-
return (_jsx(PhiSimpleTextWidget, { blockId: widget.id, translate: !noTranslate && !hasResolvedText, labels: {
|
|
12
|
+
return (_jsx(PhiSimpleTextWidget, { blockId: widget.id, translate: !noTranslate && !hasResolvedText, textSource: config.textSource, labels: {
|
|
13
13
|
text: resolvePhiSimpleTextWidgetText({
|
|
14
14
|
...config,
|
|
15
15
|
label: widget.label ?? undefined,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PhiTextSource } from "../../../../../helpers/text-source";
|
|
1
2
|
import type { PhiCmsInstanceId, PhiRenderableBlockBase, PhiServerBlockBaseProps } from "../../../../../types";
|
|
2
3
|
import type { PhiSimpleTextWidgetClientConfig } from "./client";
|
|
3
4
|
export type PhiSimpleTextWidgetLabels = {
|
|
@@ -6,6 +7,8 @@ export type PhiSimpleTextWidgetLabels = {
|
|
|
6
7
|
export type PhiSimpleTextWidgetConfig = PhiSimpleTextWidgetClientConfig & PhiRenderableBlockBase;
|
|
7
8
|
export type PhiSimpleTextWidgetProps = PhiServerBlockBaseProps<PhiSimpleTextWidgetLabels, PhiSimpleTextWidgetConfig> & {
|
|
8
9
|
blockId: PhiCmsInstanceId;
|
|
10
|
+
/** Whose words the text is, which decides the store that translates it (`helpers/text-source.ts`). */
|
|
11
|
+
textSource?: PhiTextSource;
|
|
9
12
|
/**
|
|
10
13
|
* Whether the text still has to be translated, which is true only where it is the Widget's own.
|
|
11
14
|
*
|
|
@@ -16,4 +19,4 @@ export type PhiSimpleTextWidgetProps = PhiServerBlockBaseProps<PhiSimpleTextWidg
|
|
|
16
19
|
*/
|
|
17
20
|
translate?: boolean;
|
|
18
21
|
};
|
|
19
|
-
export declare function PhiSimpleTextWidget({ blockId, labels, config, translate, runtime, }: PhiSimpleTextWidgetProps): Promise<import("react").JSX.Element>;
|
|
22
|
+
export declare function PhiSimpleTextWidget({ blockId, labels, config, translate, textSource, runtime, }: PhiSimpleTextWidgetProps): Promise<import("react").JSX.Element>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { trWidgetText } from "../../../../../server-helpers/translate";
|
|
3
3
|
import { maskPhiTextPlaceholders, resolvePhiTextPlaceholders } from "../../../../../helpers/text-placeholders";
|
|
4
4
|
import { PhiCmsWidgetType } from "../../../../../constants/cms-widget-types";
|
|
5
5
|
import { PhiRuntimeModuleRenderClientHost } from "../../../../../components/runtime/runtime-module-render-client-manifest";
|
|
6
|
-
export async function PhiSimpleTextWidget({ blockId, labels, config, translate, runtime, }) {
|
|
6
|
+
export async function PhiSimpleTextWidget({ blockId, labels, config, translate, textSource, runtime, }) {
|
|
7
7
|
const locale = runtime?.locale.current;
|
|
8
8
|
/*
|
|
9
9
|
* Masked before the translation and filled after it.
|
|
@@ -14,7 +14,7 @@ export async function PhiSimpleTextWidget({ blockId, labels, config, translate,
|
|
|
14
14
|
*/
|
|
15
15
|
const masked = maskPhiTextPlaceholders(labels.text);
|
|
16
16
|
const translated = translate && masked.text
|
|
17
|
-
?
|
|
17
|
+
? await trWidgetText(locale, masked.text, textSource)
|
|
18
18
|
: masked.text;
|
|
19
19
|
const text = resolvePhiTextPlaceholders(translated, masked.names, runtime);
|
|
20
20
|
return (_jsx(PhiRuntimeModuleRenderClientHost, { type: PhiCmsWidgetType.SimpleText, componentProps: {
|
|
@@ -913,7 +913,7 @@ export function PhiTableWidgetClient({ config: inputConfig, externalSearch, exte
|
|
|
913
913
|
afterRowIdentity: null,
|
|
914
914
|
}).catch(() => undefined).finally(clearPhiDataDragPayload);
|
|
915
915
|
}
|
|
916
|
-
: undefined, loading: effectiveLoading, bordered: presentation.borders, striped: presentation.row?.striped, showHeader: presentation.header, size: resolvedControlSize, emptyText: (_jsxs(PhiFlexControl, { vertical: true, gap: "small", children: [_jsx(PhiTypographyControl, { strong: true, children: presentation.emptyState?.title ?? labels.emptyTitle }), _jsx(PhiTypographyControl, { type: "secondary", children: presentation.emptyState?.description ?? labels.emptyDescription })] })), layout: presentation.layout, footer: footer, summary: tableSummary })] }));
|
|
916
|
+
: undefined, loading: effectiveLoading, bordered: presentation.borders, striped: presentation.row?.striped, showHeader: presentation.header, stickyHeader: presentation.stickyHeader !== false, size: resolvedControlSize, emptyText: (_jsxs(PhiFlexControl, { vertical: true, gap: "small", children: [_jsx(PhiTypographyControl, { strong: true, children: presentation.emptyState?.title ?? labels.emptyTitle }), _jsx(PhiTypographyControl, { type: "secondary", children: presentation.emptyState?.description ?? labels.emptyDescription })] })), layout: presentation.layout, footer: footer, summary: tableSummary })] }));
|
|
917
917
|
}
|
|
918
918
|
function TableAction({ action, disabled = false, disabledReason, templateValue, size, onActivate }) {
|
|
919
919
|
const icon = action.icon ? resolvePhiButtonIcon(action.icon) : null;
|
|
@@ -537,6 +537,7 @@ export function parsePhiTableWidgetConfig(config) {
|
|
|
537
537
|
},
|
|
538
538
|
borders: readBoolean(presentation.borders),
|
|
539
539
|
header: readBoolean(presentation.header),
|
|
540
|
+
stickyHeader: readBoolean(presentation.stickyHeader),
|
|
540
541
|
footer: readTableFooter(presentation.footer),
|
|
541
542
|
summary: readTableSummary(presentation.summary),
|
|
542
543
|
row: {
|
|
@@ -1153,6 +1154,7 @@ export const PHI_TABLE_WIDGET_DEFINITION = {
|
|
|
1153
1154
|
{ ...PHI_CONTROL_SIZE_FIELD, key: "presentation.controlSize" },
|
|
1154
1155
|
{ key: "presentation.borders", type: "boolean", label: "Borders" },
|
|
1155
1156
|
{ key: "presentation.header", type: "boolean", label: "Header" },
|
|
1157
|
+
{ key: "presentation.stickyHeader", type: "boolean", label: "Sticky Header" },
|
|
1156
1158
|
{ key: "presentation.row.striped", type: "boolean", label: "Striped Rows" },
|
|
1157
1159
|
...buildPhiTableConditionExpressionConfigFields("presentation.row.mutedWhen", "Muted Row Conditions", "any", "No muted rows"),
|
|
1158
1160
|
],
|
|
@@ -1162,6 +1164,7 @@ export const PHI_TABLE_WIDGET_DEFINITION = {
|
|
|
1162
1164
|
layout: { mode: "auto", overflowX: "auto" },
|
|
1163
1165
|
borders: false,
|
|
1164
1166
|
header: true,
|
|
1167
|
+
stickyHeader: true,
|
|
1165
1168
|
row: { striped: false },
|
|
1166
1169
|
},
|
|
1167
1170
|
features: {
|
|
@@ -4,8 +4,7 @@ import { PhiCmsFlags, PhiCmsRegionType } from "../../constants/phi-cms";
|
|
|
4
4
|
import { resolvePhiCmsWidgetPluginKey } from "../../constants/cms-widget-types";
|
|
5
5
|
import { buildPhiCmsLayoutNamespacedTypeKey } from "../../constants/cms-layout-types";
|
|
6
6
|
import { resolvePhiCmsLayoutPluginKey } from "../../constants/cms-layout-type-keys";
|
|
7
|
-
import {
|
|
8
|
-
import { PHI_TR_CTX_WEB_UI_LABEL } from "../../gateway/tr";
|
|
7
|
+
import { PHI_TEXT_SOURCE_PRESET } from "../../helpers/text-source";
|
|
9
8
|
import { PHI_SPACE } from "../../theme/antd-css-var-contract";
|
|
10
9
|
import { buildPhiCmsWidgetNamespacedTypeKey } from "../../constants/cms-widget-types";
|
|
11
10
|
import { createPhiCmsPresetNodes } from "../../helpers/cms-preset-nodes";
|
|
@@ -44,7 +43,12 @@ export async function buildPhiDefaultSiteAreaPresetTree({ page, runtime, presetK
|
|
|
44
43
|
const footerTopRegion = PHI_DEFAULT_PUB_AREA_PRESET.regions.find((region) => region.key === "footer_top");
|
|
45
44
|
const footerBottomRegion = PHI_DEFAULT_PUB_AREA_PRESET.regions.find((region) => region.key === "footer_bottom");
|
|
46
45
|
const { label: contactLabel, href: contactHref, icon: contactIcon, } = resolvePhiBrandContact(runtime);
|
|
47
|
-
|
|
46
|
+
/*
|
|
47
|
+
* The Preset's words stay in the source language and say they are the Preset's; the Widgets translate
|
|
48
|
+
* them through the global store (`helpers/text-source.ts`). The contact label is the Preset's only
|
|
49
|
+
* while the Site's theme names none.
|
|
50
|
+
*/
|
|
51
|
+
const contactLabelIsPreset = !runtime.site.theme?.contact?.label?.trim();
|
|
48
52
|
/*
|
|
49
53
|
* A template rather than a finished sentence, and left untranslated here.
|
|
50
54
|
*
|
|
@@ -477,6 +481,7 @@ export async function buildPhiDefaultSiteAreaPresetTree({ page, runtime, presetK
|
|
|
477
481
|
label: "pub header top right",
|
|
478
482
|
config: {
|
|
479
483
|
text: contactLabel,
|
|
484
|
+
...(contactLabelIsPreset ? { textSource: PHI_TEXT_SOURCE_PRESET } : {}),
|
|
480
485
|
href: contactHref,
|
|
481
486
|
icon: contactIcon,
|
|
482
487
|
},
|
|
@@ -581,7 +586,8 @@ export async function buildPhiDefaultSiteAreaPresetTree({ page, runtime, presetK
|
|
|
581
586
|
visibilityMask: page.visibilityMask,
|
|
582
587
|
label: "pub footer main quick links",
|
|
583
588
|
config: {
|
|
584
|
-
title:
|
|
589
|
+
title: "Quick Links",
|
|
590
|
+
textSource: PHI_TEXT_SOURCE_PRESET,
|
|
585
591
|
navKey: `${navigationArea}:footer`,
|
|
586
592
|
columns: 2,
|
|
587
593
|
separator: true,
|
|
@@ -601,6 +607,7 @@ export async function buildPhiDefaultSiteAreaPresetTree({ page, runtime, presetK
|
|
|
601
607
|
label: "pub footer main right",
|
|
602
608
|
config: {
|
|
603
609
|
text: contactLabel,
|
|
610
|
+
...(contactLabelIsPreset ? { textSource: PHI_TEXT_SOURCE_PRESET } : {}),
|
|
604
611
|
href: contactHref,
|
|
605
612
|
icon: contactIcon,
|
|
606
613
|
},
|
|
@@ -623,6 +630,7 @@ export async function buildPhiDefaultSiteAreaPresetTree({ page, runtime, presetK
|
|
|
623
630
|
label: "pub footer bottom text",
|
|
624
631
|
config: {
|
|
625
632
|
text: footerBottomText,
|
|
633
|
+
textSource: PHI_TEXT_SOURCE_PRESET,
|
|
626
634
|
tone: "secondary",
|
|
627
635
|
},
|
|
628
636
|
contentVersionId: null,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PHI_TEXT_SOURCE_PRESET } from "../../../../helpers/text-source";
|
|
1
2
|
import { createPhiPresetCmsInstanceIdMap } from "../../../../types/cms-instance-id";
|
|
2
3
|
import { PHI_SPACE } from "../../../../theme/antd-css-var-contract";
|
|
3
4
|
import { PHI_PUBLIC_RUNTIME_MODULE_ID } from "../ids";
|
|
@@ -73,6 +74,7 @@ export async function buildPhiDefaultPubContactPageTree({ page, }) {
|
|
|
73
74
|
sortOrder: 0,
|
|
74
75
|
label: "pub contact description widget",
|
|
75
76
|
config: {
|
|
77
|
+
textSource: PHI_TEXT_SOURCE_PRESET,
|
|
76
78
|
eyebrow: "Contact",
|
|
77
79
|
title: "Get in touch",
|
|
78
80
|
description: "Send us your question, project request, or product inquiry and we will get back to you.",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PHI_TEXT_SOURCE_PRESET } from "../../../../helpers/text-source";
|
|
1
2
|
import { createPhiPresetCmsInstanceIdMap } from "../../../../types/cms-instance-id";
|
|
2
3
|
import { PHI_PUBLIC_RUNTIME_MODULE_ID } from "../ids";
|
|
3
4
|
import { PhiCmsPageType } from "../../../../constants/phi-cms";
|
|
@@ -58,6 +59,7 @@ export async function buildPhiDefaultPubUnsubscribePageTree({ page, presetKey, }
|
|
|
58
59
|
sortOrder: 0,
|
|
59
60
|
label: "pub unsubscribe intro widget",
|
|
60
61
|
config: {
|
|
62
|
+
textSource: PHI_TEXT_SOURCE_PRESET,
|
|
61
63
|
title: "Stop receiving updates",
|
|
62
64
|
description: "Press the button below and this site will send you no further updates.",
|
|
63
65
|
visibleWhen: withToken,
|
|
@@ -75,6 +77,7 @@ export async function buildPhiDefaultPubUnsubscribePageTree({ page, presetKey, }
|
|
|
75
77
|
sortOrder: 0,
|
|
76
78
|
label: "pub unsubscribe incomplete widget",
|
|
77
79
|
config: {
|
|
80
|
+
textSource: PHI_TEXT_SOURCE_PRESET,
|
|
78
81
|
title: "This link is incomplete",
|
|
79
82
|
description: "Open the unsubscribe link from the message itself, or use the most recent one you received.",
|
|
80
83
|
tone: "secondary",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PHI_TEXT_SOURCE_PRESET } from "../../../../helpers/text-source";
|
|
1
2
|
import { createPhiPresetCmsInstanceIdMap } from "../../../../types/cms-instance-id";
|
|
2
3
|
import { PHI_PUBLIC_RUNTIME_MODULE_ID } from "../ids";
|
|
3
4
|
import { PHI_PUBLIC_BASE_PAGE_REFERENCES } from "../../public-base-page-references";
|
|
@@ -125,7 +126,7 @@ export async function buildPhiDefaultPubWelcomePageTree({ page, runtime, }) {
|
|
|
125
126
|
sortOrder: 0,
|
|
126
127
|
label: "pub welcome greeting",
|
|
127
128
|
// English source, like every Preset sentence: the Site translator makes it "Herzlich willkommen".
|
|
128
|
-
config: { text: "A warm welcome" },
|
|
129
|
+
config: { textSource: PHI_TEXT_SOURCE_PRESET, text: "A warm welcome" },
|
|
129
130
|
}),
|
|
130
131
|
nodes.widget({
|
|
131
132
|
typeKey: "markdown",
|
|
@@ -265,6 +265,8 @@ export async function buildPhiDefaultBuilderRevisionsPageTree({ page, runtime, }
|
|
|
265
265
|
*/
|
|
266
266
|
nodes.widget({
|
|
267
267
|
typeKey: "simple-text",
|
|
268
|
+
/* Label set text, translated already; a second pass would hand the translator a non-source text. */
|
|
269
|
+
flags: PhiCmsFlags.NoTranslate,
|
|
268
270
|
id: PHI_REVISIONS_DELETE_AREA_WIDGET_IDS.deleteAreaWarning,
|
|
269
271
|
parentLayoutNodeId: PHI_REVISIONS_DELETE_AREA_LAYOUT_IDS.deleteAreaBody,
|
|
270
272
|
slotIndex: PHI_CMS_DEFAULT_SLOT_INDEX,
|
|
@@ -279,6 +281,8 @@ export async function buildPhiDefaultBuilderRevisionsPageTree({ page, runtime, }
|
|
|
279
281
|
}),
|
|
280
282
|
nodes.widget({
|
|
281
283
|
typeKey: "simple-text",
|
|
284
|
+
/* Label set text, translated already; a second pass would hand the translator a non-source text. */
|
|
285
|
+
flags: PhiCmsFlags.NoTranslate,
|
|
282
286
|
id: PHI_REVISIONS_DELETE_AREA_WIDGET_IDS.deleteAreaSurvives,
|
|
283
287
|
parentLayoutNodeId: PHI_REVISIONS_DELETE_AREA_LAYOUT_IDS.deleteAreaBody,
|
|
284
288
|
slotIndex: PHI_CMS_SEQUENTIAL_LAYOUT_SLOTS[1].slotIndex,
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
import { type PhiTranslationParams } from "../helpers/translation-format";
|
|
3
3
|
import { PHI_TR_CTX_WEB_UI_LABEL, type PhiTranslationFormat } from "../gateway/tr";
|
|
4
|
+
import { type PhiTextSource } from "../helpers/text-source";
|
|
4
5
|
export { PHI_TR_CTX_WEB_UI_LABEL };
|
|
5
6
|
export type { PhiTranslationParams } from "../helpers/translation-format";
|
|
6
7
|
export declare function tr(msg: string, params?: PhiTranslationParams, ctx?: string | number, format?: PhiTranslationFormat): Promise<string>;
|
|
7
8
|
export declare function trGlobal(msg: string, params?: PhiTranslationParams, ctx?: string | number, format?: PhiTranslationFormat): Promise<string>;
|
|
9
|
+
/**
|
|
10
|
+
* A text Widget's own words in the render's locale, from the store their source names.
|
|
11
|
+
*
|
|
12
|
+
* `textSource: "preset"` is a Preset's sentence and the platform's, so the global store answers it;
|
|
13
|
+
* anything else an author wrote and the Site's store does (`helpers/text-source.ts`). The locale is the
|
|
14
|
+
* render's where there is one: a static render has no request to read it from.
|
|
15
|
+
*/
|
|
16
|
+
export declare function trWidgetText(locale: string | undefined, msg: string, textSource: PhiTextSource | undefined): Promise<string>;
|
|
8
17
|
export declare function trForLocale(localeInput: string, msg: string, params?: PhiTranslationParams, ctx?: string | number, format?: PhiTranslationFormat,
|
|
9
18
|
/** The language `msg` is written in, when it is not the Site's own -- a Module's text. */
|
|
10
19
|
sourceLocale?: string): Promise<string>;
|
|
@@ -6,6 +6,7 @@ import { PHI_TR_CTX_WEB_UI_LABEL, trBulk as requestInternalTranslationBulk, tr a
|
|
|
6
6
|
import { getPhiRequestRuntime } from "./request-runtime";
|
|
7
7
|
import { resolvePhiRequestLocale } from "./request-locale";
|
|
8
8
|
import { readPhiServerApiCredentials } from "../helpers/phis-server-credentials";
|
|
9
|
+
import { PHI_TEXT_SOURCE_PRESET } from "../helpers/text-source";
|
|
9
10
|
export { PHI_TR_CTX_WEB_UI_LABEL };
|
|
10
11
|
function buildTranslatorOptions(locale, sourceLocale) {
|
|
11
12
|
const requestRuntime = getPhiRequestRuntime();
|
|
@@ -46,6 +47,19 @@ export async function trGlobal(msg, params = 0, ctx = 0, format = "text") {
|
|
|
46
47
|
const locale = await resolvePhiRequestLocale();
|
|
47
48
|
return trGlobalForLocale(locale, msg, params, ctx, format);
|
|
48
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* A text Widget's own words in the render's locale, from the store their source names.
|
|
52
|
+
*
|
|
53
|
+
* `textSource: "preset"` is a Preset's sentence and the platform's, so the global store answers it;
|
|
54
|
+
* anything else an author wrote and the Site's store does (`helpers/text-source.ts`). The locale is the
|
|
55
|
+
* render's where there is one: a static render has no request to read it from.
|
|
56
|
+
*/
|
|
57
|
+
export async function trWidgetText(locale, msg, textSource) {
|
|
58
|
+
if (textSource === PHI_TEXT_SOURCE_PRESET) {
|
|
59
|
+
return locale ? trGlobalForLocale(locale, msg) : trGlobal(msg);
|
|
60
|
+
}
|
|
61
|
+
return locale ? trForLocale(locale, msg) : tr(msg);
|
|
62
|
+
}
|
|
49
63
|
/**
|
|
50
64
|
* Trimmed, one per message and in order: an empty message stays in its place, and `trBulk` answers it
|
|
51
65
|
* with an empty text, so every answer lines up with the message it belongs to.
|
package/styles/controls.css
CHANGED
|
@@ -492,10 +492,24 @@ h5.phi-typography, .phi-typography h5 {
|
|
|
492
492
|
* as a Table closed with one instead of with a footer. Clipping the Table is what both cases want, which
|
|
493
493
|
* is why the rule names neither.
|
|
494
494
|
*/
|
|
495
|
+
/*
|
|
496
|
+
* A sticky header row sticks under the Shell's Header, which publishes where it ends right now
|
|
497
|
+
* (`components/shell/use-phi-shell-sticky-top.ts`), and at the top edge of an Overlay's body,
|
|
498
|
+
* which scrolls on its own. Ant Design writes the offset inline, so the position is stated over it.
|
|
499
|
+
*/
|
|
500
|
+
.phi-table-control.phi-table-control--sticky-header [class~="ant-table-sticky-holder"] {
|
|
501
|
+
top: var(--phi-table-sticky-top, var(--phi-shell-sticky-top, 0px)) !important;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
:is([data-phi-modal-body-content], [data-phi-drawer-body-content]) {
|
|
505
|
+
--phi-table-sticky-top: 0px;
|
|
506
|
+
}
|
|
507
|
+
|
|
495
508
|
.phi-table-control.phi-table-control--closing-block [class~="ant-table"] {
|
|
496
509
|
border-end-start-radius: var(--phi-surface-radius, var(--ant-border-radius-lg));
|
|
497
510
|
border-end-end-radius: var(--phi-surface-radius, var(--ant-border-radius-lg));
|
|
498
|
-
|
|
511
|
+
/* `clip`, not `hidden`, so the corners are cut without making this the sticky header's scroller. */
|
|
512
|
+
overflow: clip;
|
|
499
513
|
}
|
|
500
514
|
|
|
501
515
|
/*
|
|
@@ -584,3 +598,29 @@ h5.phi-typography, .phi-typography h5 {
|
|
|
584
598
|
.phi-plain-table tbody tr:last-child td {
|
|
585
599
|
border-block-end: none;
|
|
586
600
|
}
|
|
601
|
+
|
|
602
|
+
/*
|
|
603
|
+
* Markdown pictures the text flows past (`imageFloat` on the Markdown Widget).
|
|
604
|
+
*
|
|
605
|
+
* Only where there is room for both: below 560px a picture beside the words leaves each of them a column
|
|
606
|
+
* nobody reads, so there the picture stands on its own line at full width, as an unfloated one does. The
|
|
607
|
+
* width is a share of the text with a ceiling, so a wide column does not grow the picture past a glance.
|
|
608
|
+
*/
|
|
609
|
+
.phi-markdown-body :is(img) {
|
|
610
|
+
display: block;
|
|
611
|
+
margin-block-end: var(--ant-margin, 16px);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
@container (min-width: 560px) {
|
|
615
|
+
.phi-markdown-body--float-start :is(img) {
|
|
616
|
+
float: inline-start;
|
|
617
|
+
width: min(45%, 440px);
|
|
618
|
+
margin-inline-end: var(--ant-margin-lg, 24px);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
.phi-markdown-body--float-end :is(img) {
|
|
622
|
+
float: inline-end;
|
|
623
|
+
width: min(45%, 440px);
|
|
624
|
+
margin-inline-start: var(--ant-margin-lg, 24px);
|
|
625
|
+
}
|
|
626
|
+
}
|