@salesforcedevs/docs-components 1.34.1-redoc-latest-banner-2 → 1.34.3-final-alpha
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/package.json +2 -3
- package/src/modules/doc/contentActionToolbar/constants.ts +43 -0
- package/src/modules/doc/contentActionToolbar/contentActionToolbar.css +34 -6
- package/src/modules/doc/contentActionToolbar/contentActionToolbar.html +63 -28
- package/src/modules/doc/contentActionToolbar/contentActionToolbar.ts +372 -61
- package/src/modules/doc/contentActionToolbar/contentActionToolbarMocks.ts +1 -1
- package/src/modules/doc/contentLayout/contentLayout.ts +2 -1
- package/src/modules/doc/header/header.ts +14 -3
- package/src/modules/doc/redocReference/redocReference.ts +4 -3
- package/src/modules/doc/unifiedContentLayout/unifiedContentLayout.html +8 -0
- package/src/modules/doc/unifiedContentLayout/unifiedContentLayout.ts +88 -6
- package/src/modules/doc/versionPicker/versionPicker.css +10 -0
- package/src/modules/doc/versionPicker/versionPicker.html +1 -1
- package/src/modules/doc/versionPicker/versionPicker.ts +6 -0
- package/src/modules/docHelpers/contentLayoutStyle/contentLayoutStyle.css +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/docs-components",
|
|
3
|
-
"version": "1.34.
|
|
3
|
+
"version": "1.34.3-final-alpha",
|
|
4
4
|
"description": "Docs Lightning web components for DSC",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "index.js",
|
|
@@ -25,6 +25,5 @@
|
|
|
25
25
|
"@types/lodash.orderby": "4.6.9",
|
|
26
26
|
"@types/lodash.uniqby": "4.7.9"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "4629fdd9ca18a13480044ad43515b91945d16aad"
|
|
29
|
-
"stableVersion": "1.34.0"
|
|
28
|
+
"gitHead": "4629fdd9ca18a13480044ad43515b91945d16aad"
|
|
30
29
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const DEFAULT_TOOLTIP_LABEL = "Click to copy";
|
|
2
|
+
export const COPIED_TOOLTIP_LABEL = "Copied!";
|
|
3
|
+
export const COPIED_RESET_MS = 1000;
|
|
4
|
+
|
|
5
|
+
export const ANALYTICS_CONTENT_CATEGORY = "content action toolbar";
|
|
6
|
+
export const MORE_ACTIONS_LABEL = "More actions";
|
|
7
|
+
|
|
8
|
+
export const COPY_MARKDOWN_LABEL = "Copy as Markdown";
|
|
9
|
+
export const VIEW_MARKDOWN_LABEL = "View as Markdown";
|
|
10
|
+
export const COPY_MARKDOWN_URL_LABEL = "Copy URL to Markdown";
|
|
11
|
+
export const VIEW_LLMS_LABEL = "View llms.txt";
|
|
12
|
+
export const COPY_LLMS_URL_LABEL = "Copy URL to llms.txt";
|
|
13
|
+
export const OPEN_CHATGPT_LABEL = "Open in ChatGPT";
|
|
14
|
+
export const OPEN_CLAUDE_LABEL = "Open in Claude";
|
|
15
|
+
export const OPEN_PERPLEXITY_LABEL = "Open in Perplexity";
|
|
16
|
+
|
|
17
|
+
export const LLMS_TXT_PATH = "/docs/llms.txt";
|
|
18
|
+
export const CHATGPT_URL = "https://chatgpt.com/";
|
|
19
|
+
export const CLAUDE_URL = "https://claude.ai/new";
|
|
20
|
+
export const PERPLEXITY_URL = "https://www.perplexity.ai/search";
|
|
21
|
+
|
|
22
|
+
export const ACTION_COPY_MARKDOWN = "copy-markdown";
|
|
23
|
+
export const ACTION_VIEW_MARKDOWN = "view-markdown";
|
|
24
|
+
export const ACTION_COPY_MARKDOWN_URL = "copy-markdown-url";
|
|
25
|
+
export const ACTION_VIEW_LLMS = "view-llms";
|
|
26
|
+
export const ACTION_COPY_LLMS_URL = "copy-llms-url";
|
|
27
|
+
export const ACTION_OPEN_CHATGPT = "open-chatgpt";
|
|
28
|
+
export const ACTION_OPEN_CLAUDE = "open-claude";
|
|
29
|
+
export const ACTION_OPEN_PERPLEXITY = "open-perplexity";
|
|
30
|
+
|
|
31
|
+
export const AI_ASSISTANTS = [
|
|
32
|
+
{
|
|
33
|
+
action: ACTION_OPEN_CHATGPT,
|
|
34
|
+
base: CHATGPT_URL,
|
|
35
|
+
label: OPEN_CHATGPT_LABEL
|
|
36
|
+
},
|
|
37
|
+
{ action: ACTION_OPEN_CLAUDE, base: CLAUDE_URL, label: OPEN_CLAUDE_LABEL },
|
|
38
|
+
{
|
|
39
|
+
action: ACTION_OPEN_PERPLEXITY,
|
|
40
|
+
base: PERPLEXITY_URL,
|
|
41
|
+
label: OPEN_PERPLEXITY_LABEL
|
|
42
|
+
}
|
|
43
|
+
] as const;
|
|
@@ -2,16 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
:host {
|
|
4
4
|
display: block;
|
|
5
|
+
|
|
6
|
+
/* 4px gap below the trigger, and the same 4px gap above when the menu
|
|
7
|
+
flips */
|
|
8
|
+
--popover-container-open-transform: translateY(var(--dx-g-spacing-xs));
|
|
9
|
+
--popover-container-open-transform-up: translateY(
|
|
10
|
+
calc(-1 * var(--dx-g-spacing-xs))
|
|
11
|
+
);
|
|
5
12
|
}
|
|
6
13
|
|
|
7
14
|
.toolbar {
|
|
8
15
|
display: flex;
|
|
9
16
|
align-items: center;
|
|
10
|
-
flex-wrap:
|
|
17
|
+
flex-wrap: nowrap;
|
|
11
18
|
gap: var(--dx-g-spacing-smd);
|
|
12
19
|
margin-bottom: var(--dx-g-spacing-lg);
|
|
13
20
|
}
|
|
14
21
|
|
|
22
|
+
.toolbar > * {
|
|
23
|
+
flex-shrink: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
15
26
|
.toolbar-button {
|
|
16
27
|
--dx-c-button-font-weight: var(--dx-g-font-demi);
|
|
17
28
|
--dx-c-button-line-height: var(--dx-g-spacing-mlg);
|
|
@@ -24,9 +35,26 @@
|
|
|
24
35
|
background-color: var(--dx-g-gray-70);
|
|
25
36
|
}
|
|
26
37
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
38
|
+
.toolbar_no-markdown .divider_view-llms {
|
|
39
|
+
display: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.toolbar-menu {
|
|
43
|
+
--dx-c-popover-z-index: calc(var(--dx-g-z-index-100) + 6);
|
|
44
|
+
|
|
45
|
+
flex: 0 0 auto;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.menu-trigger {
|
|
49
|
+
white-space: nowrap;
|
|
50
|
+
flex-shrink: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.toolbar > [data-overflow="true"] {
|
|
54
|
+
display: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.toolbar > .divider_view-markdown[data-overflow="true"] ~ .divider_menu,
|
|
58
|
+
.toolbar_no-markdown .divider_menu {
|
|
59
|
+
display: none;
|
|
32
60
|
}
|
|
@@ -1,53 +1,88 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class=
|
|
3
|
-
<
|
|
2
|
+
<div class={toolbarClass}>
|
|
3
|
+
<template lwc:if={hasMarkdown}>
|
|
4
|
+
<dx-tooltip
|
|
5
|
+
placement="top-right"
|
|
6
|
+
label={copyMarkdownTooltipLabel}
|
|
7
|
+
visible={copyMarkdownTooltipVisible}
|
|
8
|
+
>
|
|
9
|
+
<dx-button
|
|
10
|
+
class="toolbar-button"
|
|
11
|
+
variant="inline"
|
|
12
|
+
size="small"
|
|
13
|
+
icon-sprite="utility"
|
|
14
|
+
icon-symbol="copy"
|
|
15
|
+
icon-size="medium"
|
|
16
|
+
icon-position="right"
|
|
17
|
+
aria-label={copyMarkdownButtonText}
|
|
18
|
+
onclick={handleCopyMarkdown}
|
|
19
|
+
>
|
|
20
|
+
{copyMarkdownButtonText}
|
|
21
|
+
</dx-button>
|
|
22
|
+
</dx-tooltip>
|
|
23
|
+
|
|
24
|
+
<div class="divider divider_view-markdown"></div>
|
|
25
|
+
|
|
4
26
|
<dx-button
|
|
5
|
-
class="toolbar-button"
|
|
27
|
+
class="toolbar-button toolbar-button_view-markdown"
|
|
6
28
|
variant="inline"
|
|
7
29
|
size="small"
|
|
8
30
|
icon-sprite="utility"
|
|
9
|
-
icon-symbol="
|
|
31
|
+
icon-symbol="new_window"
|
|
10
32
|
icon-size="medium"
|
|
11
33
|
icon-position="right"
|
|
12
|
-
aria-label={
|
|
13
|
-
onclick={
|
|
34
|
+
aria-label={viewMarkdownButtonText}
|
|
35
|
+
onclick={handleViewMarkdown}
|
|
14
36
|
>
|
|
15
|
-
{
|
|
37
|
+
{viewMarkdownButtonText}
|
|
16
38
|
</dx-button>
|
|
17
|
-
</
|
|
39
|
+
</template>
|
|
18
40
|
|
|
19
|
-
<div class="divider"></div>
|
|
41
|
+
<div class="divider divider_view-llms"></div>
|
|
20
42
|
|
|
21
43
|
<dx-button
|
|
22
|
-
class="toolbar-button"
|
|
44
|
+
class="toolbar-button toolbar-button_view-llms"
|
|
23
45
|
variant="inline"
|
|
24
46
|
size="small"
|
|
25
47
|
icon-sprite="utility"
|
|
26
48
|
icon-symbol="new_window"
|
|
27
49
|
icon-size="medium"
|
|
28
50
|
icon-position="right"
|
|
29
|
-
aria-label={
|
|
30
|
-
onclick={
|
|
51
|
+
aria-label={viewLlmsButtonText}
|
|
52
|
+
onclick={handleViewLlms}
|
|
31
53
|
>
|
|
32
|
-
{
|
|
54
|
+
{viewLlmsButtonText}
|
|
33
55
|
</dx-button>
|
|
34
56
|
|
|
35
|
-
<div class="divider
|
|
57
|
+
<div class="divider divider_menu"></div>
|
|
36
58
|
|
|
37
|
-
<dx-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
<dx-dropdown
|
|
60
|
+
class="toolbar-menu"
|
|
61
|
+
options={menuOptions}
|
|
62
|
+
placement="bottom-end"
|
|
63
|
+
width-mode="fit-content"
|
|
64
|
+
onchange={handleMenuSelect}
|
|
65
|
+
onopen={handleMenuOpen}
|
|
66
|
+
onclose={handleMenuClose}
|
|
67
|
+
>
|
|
68
|
+
<dx-tooltip
|
|
69
|
+
placement="top-right"
|
|
70
|
+
label={menuTooltipLabel}
|
|
71
|
+
visible={menuTooltipVisible}
|
|
72
|
+
suppressed={menuOpen}
|
|
48
73
|
>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
74
|
+
<dx-button
|
|
75
|
+
class="menu-trigger"
|
|
76
|
+
variant="secondary"
|
|
77
|
+
size="small"
|
|
78
|
+
icon-sprite="utility"
|
|
79
|
+
icon-symbol="threedots"
|
|
80
|
+
icon-size="medium"
|
|
81
|
+
icon-only
|
|
82
|
+
>
|
|
83
|
+
{moreActionsLabel}
|
|
84
|
+
</dx-button>
|
|
85
|
+
</dx-tooltip>
|
|
86
|
+
</dx-dropdown>
|
|
52
87
|
</div>
|
|
53
88
|
</template>
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
|
+
import cx from "classnames";
|
|
3
|
+
import { OptionWithNested } from "typings/custom";
|
|
2
4
|
import { track } from "dxUtils/analytics";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_TOOLTIP_LABEL,
|
|
7
|
+
COPIED_TOOLTIP_LABEL,
|
|
8
|
+
COPIED_RESET_MS,
|
|
9
|
+
ANALYTICS_CONTENT_CATEGORY,
|
|
10
|
+
MORE_ACTIONS_LABEL,
|
|
11
|
+
COPY_MARKDOWN_LABEL,
|
|
12
|
+
VIEW_MARKDOWN_LABEL,
|
|
13
|
+
COPY_MARKDOWN_URL_LABEL,
|
|
14
|
+
VIEW_LLMS_LABEL,
|
|
15
|
+
COPY_LLMS_URL_LABEL,
|
|
16
|
+
LLMS_TXT_PATH,
|
|
17
|
+
ACTION_COPY_MARKDOWN,
|
|
18
|
+
ACTION_VIEW_MARKDOWN,
|
|
19
|
+
ACTION_COPY_MARKDOWN_URL,
|
|
20
|
+
ACTION_VIEW_LLMS,
|
|
21
|
+
ACTION_COPY_LLMS_URL,
|
|
22
|
+
AI_ASSISTANTS
|
|
23
|
+
} from "./constants";
|
|
12
24
|
|
|
13
25
|
export default class ContentActionToolbar extends LightningElement {
|
|
14
26
|
@api
|
|
@@ -23,17 +35,18 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
23
35
|
}
|
|
24
36
|
private _pageUrl?: string;
|
|
25
37
|
|
|
26
|
-
|
|
27
|
-
copyUrlLabel: string = DEFAULT_COPY_TOOLTIP_LABEL;
|
|
38
|
+
@api pageTitle?: string;
|
|
28
39
|
|
|
29
|
-
|
|
40
|
+
copyMarkdownTooltipLabel: string = DEFAULT_TOOLTIP_LABEL;
|
|
41
|
+
copyMarkdownTooltipVisible: boolean = false;
|
|
42
|
+
menuTooltipLabel: string = MORE_ACTIONS_LABEL;
|
|
43
|
+
menuTooltipVisible: boolean = false;
|
|
44
|
+
menuOpen: boolean = false;
|
|
30
45
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
*/
|
|
36
|
-
get markdownUrl(): string | null {
|
|
46
|
+
private tooltipResetTimeout: number | null = null;
|
|
47
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
48
|
+
|
|
49
|
+
private get absolutePageUrl(): string | null {
|
|
37
50
|
if (!this.pageUrl) {
|
|
38
51
|
return null;
|
|
39
52
|
}
|
|
@@ -41,7 +54,15 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
41
54
|
const url = new URL(this.pageUrl, window.location.href);
|
|
42
55
|
url.hash = "";
|
|
43
56
|
url.search = "";
|
|
57
|
+
return url.toString();
|
|
58
|
+
}
|
|
44
59
|
|
|
60
|
+
get markdownUrl(): string | null {
|
|
61
|
+
if (!this.absolutePageUrl) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const url = new URL(this.absolutePageUrl);
|
|
45
66
|
if (!url.pathname.endsWith(".html")) {
|
|
46
67
|
return null;
|
|
47
68
|
}
|
|
@@ -50,6 +71,39 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
50
71
|
return url.toString();
|
|
51
72
|
}
|
|
52
73
|
|
|
74
|
+
get llmsUrl(): string {
|
|
75
|
+
return new URL(LLMS_TXT_PATH, window.location.href).toString();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private buildAiAssistantUrl(base: string): string | null {
|
|
79
|
+
if (!this.absolutePageUrl) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const title = this.pageTitle?.trim();
|
|
84
|
+
const intro = title
|
|
85
|
+
? `I'm reading "${title}" at ${this.absolutePageUrl}.`
|
|
86
|
+
: `I'm reading ${this.absolutePageUrl}.`;
|
|
87
|
+
|
|
88
|
+
const prompt = `${intro} Read this page so I can ask questions about it. For broader context, see ${this.llmsUrl}`;
|
|
89
|
+
|
|
90
|
+
const url = new URL(base);
|
|
91
|
+
url.searchParams.set("q", prompt);
|
|
92
|
+
return url.toString();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get hasMarkdown(): boolean {
|
|
96
|
+
return Boolean(this.markdownUrl);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get toolbarClass(): string {
|
|
100
|
+
return cx("toolbar", !this.hasMarkdown && "toolbar_no-markdown");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get moreActionsLabel(): string {
|
|
104
|
+
return MORE_ACTIONS_LABEL;
|
|
105
|
+
}
|
|
106
|
+
|
|
53
107
|
get copyMarkdownButtonText(): string {
|
|
54
108
|
return COPY_MARKDOWN_LABEL;
|
|
55
109
|
}
|
|
@@ -58,98 +112,355 @@ export default class ContentActionToolbar extends LightningElement {
|
|
|
58
112
|
return VIEW_MARKDOWN_LABEL;
|
|
59
113
|
}
|
|
60
114
|
|
|
61
|
-
get
|
|
62
|
-
return
|
|
115
|
+
get viewLlmsButtonText(): string {
|
|
116
|
+
return VIEW_LLMS_LABEL;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get menuOptions(): OptionWithNested[] {
|
|
120
|
+
const groups: OptionWithNested[] = [];
|
|
121
|
+
|
|
122
|
+
if (this.hasMarkdown) {
|
|
123
|
+
groups.push({
|
|
124
|
+
id: "this-page",
|
|
125
|
+
label: "This Page",
|
|
126
|
+
options: [
|
|
127
|
+
{
|
|
128
|
+
id: ACTION_COPY_MARKDOWN,
|
|
129
|
+
label: COPY_MARKDOWN_LABEL,
|
|
130
|
+
iconSprite: "utility",
|
|
131
|
+
iconSymbol: "copy"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: ACTION_VIEW_MARKDOWN,
|
|
135
|
+
label: VIEW_MARKDOWN_LABEL,
|
|
136
|
+
iconSprite: "utility",
|
|
137
|
+
iconSymbol: "new_window"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
id: ACTION_COPY_MARKDOWN_URL,
|
|
141
|
+
label: COPY_MARKDOWN_URL_LABEL,
|
|
142
|
+
iconSprite: "utility",
|
|
143
|
+
iconSymbol: "link"
|
|
144
|
+
},
|
|
145
|
+
...AI_ASSISTANTS.map(({ action, label }) => ({
|
|
146
|
+
id: action,
|
|
147
|
+
label,
|
|
148
|
+
iconSprite: "utility",
|
|
149
|
+
iconSymbol: "new_window"
|
|
150
|
+
}))
|
|
151
|
+
]
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
groups.push({
|
|
156
|
+
id: "all-documentation",
|
|
157
|
+
label: "All Documentation",
|
|
158
|
+
options: [
|
|
159
|
+
{
|
|
160
|
+
id: ACTION_VIEW_LLMS,
|
|
161
|
+
label: VIEW_LLMS_LABEL,
|
|
162
|
+
iconSprite: "utility",
|
|
163
|
+
iconSymbol: "new_window"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: ACTION_COPY_LLMS_URL,
|
|
167
|
+
label: COPY_LLMS_URL_LABEL,
|
|
168
|
+
iconSprite: "utility",
|
|
169
|
+
iconSymbol: "link"
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return groups;
|
|
63
175
|
}
|
|
64
176
|
|
|
65
177
|
async handleCopyMarkdown(event: Event) {
|
|
178
|
+
if (await this.copyMarkdown(event)) {
|
|
179
|
+
this.flashCopyMarkdownTooltip();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
handleViewMarkdown(event: Event) {
|
|
66
184
|
if (!this.markdownUrl) {
|
|
67
185
|
return;
|
|
68
186
|
}
|
|
69
187
|
|
|
70
|
-
this.trackToolbarEvent(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
188
|
+
this.trackToolbarEvent(event, VIEW_MARKDOWN_LABEL, this.markdownUrl);
|
|
189
|
+
window.open(this.markdownUrl, "_blank", "noopener,noreferrer");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
handleViewLlms(event: Event) {
|
|
193
|
+
this.trackToolbarEvent(event, VIEW_LLMS_LABEL, this.llmsUrl);
|
|
194
|
+
window.open(this.llmsUrl, "_blank", "noopener,noreferrer");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private handleOpenAiAssistant(
|
|
198
|
+
event: Event,
|
|
199
|
+
label: string,
|
|
200
|
+
url: string | null
|
|
201
|
+
) {
|
|
202
|
+
if (!url) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
this.trackToolbarEvent(event, label, url);
|
|
207
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
handleMenuOpen() {
|
|
211
|
+
this.menuOpen = true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
handleMenuClose() {
|
|
215
|
+
this.menuOpen = false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async handleMenuSelect(event: CustomEvent) {
|
|
219
|
+
switch (event.detail) {
|
|
220
|
+
case ACTION_COPY_MARKDOWN:
|
|
221
|
+
if (await this.copyMarkdown(event)) {
|
|
222
|
+
this.flashMenuCopied();
|
|
223
|
+
}
|
|
224
|
+
return;
|
|
225
|
+
case ACTION_VIEW_MARKDOWN:
|
|
226
|
+
this.handleViewMarkdown(event);
|
|
227
|
+
return;
|
|
228
|
+
case ACTION_COPY_MARKDOWN_URL:
|
|
229
|
+
await this.handleCopyMarkdownUrl(event);
|
|
230
|
+
return;
|
|
231
|
+
case ACTION_VIEW_LLMS:
|
|
232
|
+
this.handleViewLlms(event);
|
|
233
|
+
return;
|
|
234
|
+
case ACTION_COPY_LLMS_URL:
|
|
235
|
+
await this.handleCopyLlmsUrl(event);
|
|
236
|
+
return;
|
|
237
|
+
default: {
|
|
238
|
+
const assistant = AI_ASSISTANTS.find(
|
|
239
|
+
({ action }) => action === event.detail
|
|
240
|
+
);
|
|
241
|
+
if (assistant) {
|
|
242
|
+
this.handleOpenAiAssistant(
|
|
243
|
+
event,
|
|
244
|
+
assistant.label,
|
|
245
|
+
this.buildAiAssistantUrl(assistant.base)
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private async copyMarkdown(event: Event): Promise<boolean> {
|
|
253
|
+
if (!this.markdownUrl) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.trackToolbarEvent(event, COPY_MARKDOWN_LABEL, this.markdownUrl);
|
|
76
258
|
|
|
77
259
|
try {
|
|
78
260
|
const response = await fetch(this.markdownUrl);
|
|
79
261
|
if (!response.ok) {
|
|
80
|
-
return;
|
|
262
|
+
return false;
|
|
81
263
|
}
|
|
82
264
|
const markdown = await response.text();
|
|
83
265
|
await navigator.clipboard.writeText(markdown);
|
|
84
|
-
|
|
266
|
+
return true;
|
|
85
267
|
} catch (error) {
|
|
86
268
|
console.error(error);
|
|
269
|
+
return false;
|
|
87
270
|
}
|
|
88
271
|
}
|
|
89
272
|
|
|
90
|
-
|
|
273
|
+
private async handleCopyMarkdownUrl(event: Event) {
|
|
91
274
|
if (!this.markdownUrl) {
|
|
92
275
|
return;
|
|
93
276
|
}
|
|
94
277
|
|
|
95
278
|
this.trackToolbarEvent(
|
|
96
279
|
event,
|
|
97
|
-
|
|
98
|
-
VIEW_MARKDOWN_LABEL,
|
|
280
|
+
COPY_MARKDOWN_URL_LABEL,
|
|
99
281
|
this.markdownUrl
|
|
100
282
|
);
|
|
101
283
|
|
|
102
|
-
|
|
284
|
+
await this.copyToClipboard(this.markdownUrl);
|
|
103
285
|
}
|
|
104
286
|
|
|
105
|
-
async
|
|
106
|
-
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
287
|
+
private async handleCopyLlmsUrl(event: Event) {
|
|
288
|
+
this.trackToolbarEvent(event, COPY_LLMS_URL_LABEL, this.llmsUrl);
|
|
109
289
|
|
|
110
|
-
this.
|
|
111
|
-
|
|
112
|
-
"custEv_linkClick",
|
|
113
|
-
COPY_URL_LABEL,
|
|
114
|
-
this.markdownUrl
|
|
115
|
-
);
|
|
290
|
+
await this.copyToClipboard(this.llmsUrl);
|
|
291
|
+
}
|
|
116
292
|
|
|
293
|
+
private async copyToClipboard(text: string) {
|
|
117
294
|
try {
|
|
118
|
-
await navigator.clipboard.writeText(
|
|
119
|
-
this.
|
|
295
|
+
await navigator.clipboard.writeText(text);
|
|
296
|
+
this.flashMenuCopied();
|
|
120
297
|
} catch (error) {
|
|
121
298
|
console.error(error);
|
|
122
299
|
}
|
|
123
300
|
}
|
|
124
301
|
|
|
125
|
-
private trackToolbarEvent(
|
|
126
|
-
event
|
|
127
|
-
eventName: "custEv_linkClick",
|
|
128
|
-
label: string,
|
|
129
|
-
url: string
|
|
130
|
-
): void {
|
|
131
|
-
track(event.currentTarget!, eventName, {
|
|
302
|
+
private trackToolbarEvent(event: Event, label: string, url: string): void {
|
|
303
|
+
track(event.currentTarget!, "custEv_linkClick", {
|
|
132
304
|
click_text: label,
|
|
133
305
|
click_url: url,
|
|
134
306
|
element_type: "button_link",
|
|
135
307
|
element_title: label,
|
|
136
308
|
content_category: ANALYTICS_CONTENT_CATEGORY,
|
|
137
309
|
// Source page the CTA was clicked from; `click_url` above is the
|
|
138
|
-
//
|
|
310
|
+
// destination. Uses the same `page_path` expression as the
|
|
139
311
|
// amfReference doc_page_view events.
|
|
140
312
|
page_path: window.location.pathname + window.location.search
|
|
141
313
|
});
|
|
142
314
|
}
|
|
143
315
|
|
|
144
|
-
private
|
|
145
|
-
|
|
146
|
-
|
|
316
|
+
private flashCopyMarkdownTooltip() {
|
|
317
|
+
this.copyMarkdownTooltipLabel = COPIED_TOOLTIP_LABEL;
|
|
318
|
+
this.copyMarkdownTooltipVisible = true;
|
|
319
|
+
this.flashCopied();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private flashMenuCopied() {
|
|
323
|
+
this.menuTooltipLabel = COPIED_TOOLTIP_LABEL;
|
|
324
|
+
this.menuTooltipVisible = true;
|
|
325
|
+
this.flashCopied();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private flashCopied() {
|
|
329
|
+
if (this.tooltipResetTimeout !== null) {
|
|
330
|
+
window.clearTimeout(this.tooltipResetTimeout);
|
|
331
|
+
}
|
|
332
|
+
this.tooltipResetTimeout = window.setTimeout(() => {
|
|
333
|
+
this.copyMarkdownTooltipLabel = DEFAULT_TOOLTIP_LABEL;
|
|
334
|
+
this.copyMarkdownTooltipVisible = false;
|
|
335
|
+
this.menuTooltipVisible = false;
|
|
336
|
+
this.menuTooltipLabel = MORE_ACTIONS_LABEL;
|
|
337
|
+
this.tooltipResetTimeout = null;
|
|
338
|
+
}, COPIED_RESET_MS);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
renderedCallback(): void {
|
|
342
|
+
this.layoutToolbar();
|
|
343
|
+
this.ensureResizeObserver();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
disconnectedCallback(): void {
|
|
347
|
+
this.resizeObserver?.disconnect();
|
|
348
|
+
this.resizeObserver = null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* Keep every visible control on one row. The menu trigger stays at the
|
|
352
|
+
end; action buttons that no longer fit are hidden, last one first. */
|
|
353
|
+
private layoutToolbar(): void {
|
|
354
|
+
const toolbar = this.template.querySelector(
|
|
355
|
+
".toolbar"
|
|
356
|
+
) as HTMLElement | null;
|
|
357
|
+
if (!toolbar || toolbar.clientWidth <= 0) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const children = ([...toolbar.children] as HTMLElement[]).filter(
|
|
362
|
+
(node) => node instanceof HTMLElement
|
|
363
|
+
);
|
|
364
|
+
children.forEach((el) => {
|
|
365
|
+
delete el.dataset.overflow;
|
|
366
|
+
});
|
|
367
|
+
// Reading layout after clearing overflow flushes styles so the
|
|
368
|
+
// measurements below see the unhidden controls.
|
|
369
|
+
const availableWidth = toolbar.clientWidth;
|
|
370
|
+
|
|
371
|
+
const gap = this.readGap(toolbar);
|
|
372
|
+
const actionItems = children.filter(
|
|
373
|
+
(node) =>
|
|
374
|
+
!node.classList.contains("toolbar-menu") &&
|
|
375
|
+
!node.classList.contains("divider_menu") &&
|
|
376
|
+
this.isShown(node)
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
const menuDivider = toolbar.querySelector(
|
|
380
|
+
".divider_menu"
|
|
381
|
+
) as HTMLElement | null;
|
|
382
|
+
const menu = toolbar.querySelector(
|
|
383
|
+
".toolbar-menu"
|
|
384
|
+
) as HTMLElement | null;
|
|
385
|
+
const menuPieces = [menuDivider, menu].filter(
|
|
386
|
+
(el): el is HTMLElement => !!el && this.isShown(el)
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
let menuWidth = 0;
|
|
390
|
+
menuPieces.forEach((el, index) => {
|
|
391
|
+
menuWidth += el.offsetWidth + (index > 0 ? gap : 0);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
const groups = this.groupActions(actionItems);
|
|
395
|
+
let used = 0;
|
|
396
|
+
let fittedCount = 0;
|
|
397
|
+
|
|
398
|
+
for (const group of groups) {
|
|
399
|
+
let groupWidth = 0;
|
|
400
|
+
group.forEach((el, index) => {
|
|
401
|
+
groupWidth += el.offsetWidth + (index > 0 ? gap : 0);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const gapBefore = used > 0 ? gap : 0;
|
|
405
|
+
const gapBeforeMenu = menuWidth > 0 ? gap : 0;
|
|
406
|
+
const next =
|
|
407
|
+
used + gapBefore + groupWidth + gapBeforeMenu + menuWidth;
|
|
408
|
+
|
|
409
|
+
if (next <= availableWidth + 1) {
|
|
410
|
+
used += gapBefore + groupWidth;
|
|
411
|
+
fittedCount += group.length;
|
|
412
|
+
} else {
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
actionItems.slice(fittedCount).forEach((el) => {
|
|
418
|
+
el.dataset.overflow = "true";
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private ensureResizeObserver(): void {
|
|
423
|
+
if (this.resizeObserver || typeof ResizeObserver === "undefined") {
|
|
424
|
+
return;
|
|
147
425
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
426
|
+
|
|
427
|
+
const toolbar = this.template.querySelector(".toolbar");
|
|
428
|
+
if (!toolbar) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
433
|
+
this.layoutToolbar();
|
|
434
|
+
});
|
|
435
|
+
this.resizeObserver.observe(toolbar);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private groupActions(items: HTMLElement[]): HTMLElement[][] {
|
|
439
|
+
const groups: HTMLElement[][] = [];
|
|
440
|
+
let current: HTMLElement[] = [];
|
|
441
|
+
|
|
442
|
+
items.forEach((el) => {
|
|
443
|
+
if (el.classList.contains("divider") && current.length > 0) {
|
|
444
|
+
groups.push(current);
|
|
445
|
+
current = [el];
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
current.push(el);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
if (current.length > 0) {
|
|
452
|
+
groups.push(current);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return groups;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private isShown(el: HTMLElement): boolean {
|
|
459
|
+
return getComputedStyle(el).display !== "none";
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
private readGap(toolbar: HTMLElement): number {
|
|
463
|
+
const value = parseFloat(getComputedStyle(toolbar).columnGap);
|
|
464
|
+
return Number.isFinite(value) ? value : 0;
|
|
154
465
|
}
|
|
155
466
|
}
|
|
@@ -40,7 +40,7 @@ export function interceptWindowOpenForContentActionToolbar() {
|
|
|
40
40
|
const originalOpen = window.open.bind(window);
|
|
41
41
|
window.open = ((url?: string | URL, target?: string, features?: string) => {
|
|
42
42
|
const stringUrl = url?.toString() ?? "";
|
|
43
|
-
if (stringUrl.endsWith(".md")) {
|
|
43
|
+
if (stringUrl.endsWith(".md") || stringUrl.endsWith("/llms.txt")) {
|
|
44
44
|
return originalOpen(DUMMY_MARKDOWN_DATA_URL, target, features);
|
|
45
45
|
}
|
|
46
46
|
return originalOpen(url ?? "", target, features);
|
|
@@ -307,9 +307,10 @@ export default class ContentLayout extends LightningElement {
|
|
|
307
307
|
const toolbar = (this.contentActionToolbarElement ??
|
|
308
308
|
createElement(CONTENT_ACTION_TOOLBAR_TAG, {
|
|
309
309
|
is: ContentActionToolbar
|
|
310
|
-
})) as HTMLElement & { pageUrl?: string };
|
|
310
|
+
})) as HTMLElement & { pageUrl?: string; pageTitle?: string };
|
|
311
311
|
|
|
312
312
|
toolbar.pageUrl = this.sidebarValue;
|
|
313
|
+
toolbar.pageTitle = heading.textContent?.trim() || undefined;
|
|
313
314
|
|
|
314
315
|
if (toolbar.previousElementSibling !== heading) {
|
|
315
316
|
heading.parentNode?.insertBefore(toolbar, heading.nextSibling);
|
|
@@ -74,6 +74,13 @@ export default class Header extends HeaderBase {
|
|
|
74
74
|
return (this.hideDocHeader && !this.mobile) || this.showDocDivider;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
private get isDocsPath(): boolean {
|
|
78
|
+
return (
|
|
79
|
+
window.location.pathname.includes("/docs/") &&
|
|
80
|
+
window.location.pathname !== "/docs/apis"
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
77
84
|
connectedCallback(): void {
|
|
78
85
|
super.connectedCallback();
|
|
79
86
|
this.tabletMatchMedia = window.matchMedia(
|
|
@@ -83,9 +90,7 @@ export default class Header extends HeaderBase {
|
|
|
83
90
|
this.tabletMatchMedia.addEventListener("change", this.onTabletChange);
|
|
84
91
|
|
|
85
92
|
if (
|
|
86
|
-
(!this.shouldHideHeader &&
|
|
87
|
-
window.location.pathname.includes("/docs/") &&
|
|
88
|
-
window.location.pathname !== "/docs/apis") ||
|
|
93
|
+
(!this.shouldHideHeader && this.isDocsPath) ||
|
|
89
94
|
window.location.pathname ===
|
|
90
95
|
"/tableau/embedding-playground/overview" ||
|
|
91
96
|
isStorybook()
|
|
@@ -109,6 +114,12 @@ export default class Header extends HeaderBase {
|
|
|
109
114
|
);
|
|
110
115
|
}
|
|
111
116
|
|
|
117
|
+
renderedCallback(): void {
|
|
118
|
+
if (this.hideDocHeader) {
|
|
119
|
+
this.shouldRender = !this.shouldHideHeader && this.isDocsPath;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
112
123
|
private onTabletChange = (e: MediaQueryListEvent | MediaQueryList) =>
|
|
113
124
|
(this.tablet = e.matches);
|
|
114
125
|
|
|
@@ -790,7 +790,8 @@ export default class RedocReference extends LightningElement {
|
|
|
790
790
|
// "newer version" banner into a shared doc-phase-wrapper at container start
|
|
791
791
|
private insertStatusItems(container: HTMLElement): void {
|
|
792
792
|
const docPhaseInfo = this.getDocPhaseInfo();
|
|
793
|
-
|
|
793
|
+
const oldVersionInfo = this.oldVersionInfo;
|
|
794
|
+
if (!docPhaseInfo && !oldVersionInfo) {
|
|
794
795
|
return;
|
|
795
796
|
}
|
|
796
797
|
|
|
@@ -806,10 +807,10 @@ export default class RedocReference extends LightningElement {
|
|
|
806
807
|
wrapper.appendChild(docPhaseElement);
|
|
807
808
|
}
|
|
808
809
|
|
|
809
|
-
if (
|
|
810
|
+
if (oldVersionInfo) {
|
|
810
811
|
const versionBanner = createElement("doc-phase", { is: DocPhase });
|
|
811
812
|
Object.assign(versionBanner, {
|
|
812
|
-
docPhaseInfo:
|
|
813
|
+
docPhaseInfo: oldVersionInfo,
|
|
813
814
|
dismissible: true,
|
|
814
815
|
iconName: "warning"
|
|
815
816
|
});
|
|
@@ -24,6 +24,14 @@
|
|
|
24
24
|
lwc:if={docPhaseInfo}
|
|
25
25
|
doc-phase-info={docPhaseInfo}
|
|
26
26
|
></doc-phase>
|
|
27
|
+
<doc-phase
|
|
28
|
+
slot="version-banner"
|
|
29
|
+
lwc:if={showVersionBanner}
|
|
30
|
+
doc-phase-info={oldVersionInfo}
|
|
31
|
+
icon-name="warning"
|
|
32
|
+
dismissible="true"
|
|
33
|
+
ondismissphase={handleDismissVersionBanner}
|
|
34
|
+
></doc-phase>
|
|
27
35
|
<slot></slot>
|
|
28
36
|
</doc-content-layout>
|
|
29
37
|
</template>
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { LightningElement, api } from "lwc";
|
|
1
|
+
import { LightningElement, api, track } from "lwc";
|
|
2
2
|
import { toJson } from "dxUtils/normalizers";
|
|
3
|
-
import type {
|
|
3
|
+
import type { VersionedNode } from "dxUtils/topicVersion";
|
|
4
|
+
import {
|
|
5
|
+
findTopicVersionForCurrentPage,
|
|
6
|
+
latestHrefForCurrentPage
|
|
7
|
+
} from "dxUtils/topicVersion";
|
|
8
|
+
import { oldVersionDocInfo } from "docUtils/utils";
|
|
9
|
+
import type { DocPhaseInfo, OptionWithLink, TreeNode } from "typings/custom";
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
12
|
* Per-topic type emitted by the docs content-type parser
|
|
@@ -10,9 +16,36 @@ import type { OptionWithLink, TreeNode } from "typings/custom";
|
|
|
10
16
|
*/
|
|
11
17
|
const TOPIC_TYPE_SPEC = "spec";
|
|
12
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Walks down the first-child chain and returns the first markdown content
|
|
21
|
+
* page found, descending through nested content-less parents. Returns
|
|
22
|
+
* undefined if the chain breaks on a spec or external link before reaching a
|
|
23
|
+
* content page.
|
|
24
|
+
*/
|
|
25
|
+
function firstChildContentPage(node: TreeNode): TreeNode | undefined {
|
|
26
|
+
const firstChild = node.children?.[0];
|
|
27
|
+
if (!firstChild) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const isSpec =
|
|
32
|
+
(firstChild as { topicType?: string }).topicType === TOPIC_TYPE_SPEC;
|
|
33
|
+
const isExternal = firstChild.link?.target === "_blank";
|
|
34
|
+
if (isSpec || isExternal) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (firstChild.link?.href) {
|
|
39
|
+
return firstChild;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return firstChildContentPage(firstChild);
|
|
43
|
+
}
|
|
44
|
+
|
|
13
45
|
/**
|
|
14
46
|
* Translates per-topic `topicType` into the generic `showForwardArrow` flag
|
|
15
|
-
* that `dx-tree-tile` reads (spec topics get the forward arrow icon for Redoc)
|
|
47
|
+
* that `dx-tree-tile` reads (spec topics get the forward arrow icon for Redoc),
|
|
48
|
+
* and redirects content-less parent topics whose first child is a content page
|
|
16
49
|
*/
|
|
17
50
|
function decorateTopicsWithForwardArrow(
|
|
18
51
|
topics:
|
|
@@ -33,6 +66,21 @@ function decorateTopicsWithForwardArrow(
|
|
|
33
66
|
decorated.children
|
|
34
67
|
);
|
|
35
68
|
}
|
|
69
|
+
|
|
70
|
+
/** Redirect a parent that has no content of its own to its first child
|
|
71
|
+
* but only when that first child is itself a content page
|
|
72
|
+
*/
|
|
73
|
+
const isContentlessParent =
|
|
74
|
+
!!decorated.children?.length && !decorated.link?.href;
|
|
75
|
+
|
|
76
|
+
if (isContentlessParent) {
|
|
77
|
+
decorated.redirectToChild = true;
|
|
78
|
+
const firstChild = firstChildContentPage(topic);
|
|
79
|
+
if (firstChild?.link) {
|
|
80
|
+
decorated.link = { ...firstChild.link };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
36
84
|
return decorated;
|
|
37
85
|
});
|
|
38
86
|
}
|
|
@@ -67,6 +115,9 @@ export default class UnifiedContentLayout extends LightningElement {
|
|
|
67
115
|
|
|
68
116
|
private _docPhaseInfo: string | null = null;
|
|
69
117
|
private _sidebarContent: unknown = null;
|
|
118
|
+
private _oldVersionInfo: DocPhaseInfo | null = null;
|
|
119
|
+
|
|
120
|
+
@track showVersionBanner = false;
|
|
70
121
|
|
|
71
122
|
@api
|
|
72
123
|
get docPhaseInfo(): string | null {
|
|
@@ -83,9 +134,40 @@ export default class UnifiedContentLayout extends LightningElement {
|
|
|
83
134
|
}
|
|
84
135
|
|
|
85
136
|
set sidebarContent(value: string) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
);
|
|
137
|
+
const topics = decorateTopicsWithForwardArrow(toJson(value)?.topics);
|
|
138
|
+
this._sidebarContent = topics;
|
|
139
|
+
this.updateTopicVersionBanner(topics as VersionedNode[] | undefined);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get oldVersionInfo(): DocPhaseInfo | null {
|
|
143
|
+
return this._oldVersionInfo;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
handleDismissVersionBanner(): void {
|
|
147
|
+
this.showVersionBanner = false;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Same banner references use when the reader is on an older version.
|
|
152
|
+
* Topic versions are not a separate page property: the sidebar tree
|
|
153
|
+
* carries each version's switching URL, and the current pathname says
|
|
154
|
+
* which one is open.
|
|
155
|
+
*/
|
|
156
|
+
private updateTopicVersionBanner(
|
|
157
|
+
topics: VersionedNode[] | undefined
|
|
158
|
+
): void {
|
|
159
|
+
const match = findTopicVersionForCurrentPage(topics);
|
|
160
|
+
const latest = match?.node.versions?.[0];
|
|
161
|
+
const latestHref = latestHrefForCurrentPage(match?.node.versions);
|
|
162
|
+
|
|
163
|
+
if (match && latest && match.version.id !== latest.id && latestHref) {
|
|
164
|
+
this._oldVersionInfo = oldVersionDocInfo(latestHref);
|
|
165
|
+
this.showVersionBanner = true;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this._oldVersionInfo = null;
|
|
170
|
+
this.showVersionBanner = false;
|
|
89
171
|
}
|
|
90
172
|
|
|
91
173
|
private get enableFooter(): boolean {
|
|
@@ -120,6 +120,16 @@ dx-type-badge.not-latest-badge {
|
|
|
120
120
|
var(--dx-g-spacing-sm);
|
|
121
121
|
--dx-c-dropdown-option-border-radius: 0;
|
|
122
122
|
--dx-c-popover-border: none;
|
|
123
|
+
|
|
124
|
+
/* Hug the labels (down to the shortest) but never wider than the ToC
|
|
125
|
+
content: 296px on desktop, and on the smallest breakpoint the sidebar
|
|
126
|
+
variable grows with the viewport up to 720px. Long labels wrap inside
|
|
127
|
+
that cap. */
|
|
128
|
+
--dx-c-dropdown-menu-max-width: var(--doc-version-picker-width, 296px);
|
|
129
|
+
--dx-c-dropdown-fit-white-space: normal;
|
|
130
|
+
--dx-c-dropdown-fit-overflow: hidden;
|
|
131
|
+
--dx-c-dropdown-fit-text-overflow: clip;
|
|
132
|
+
--dx-c-dropdown-option-overflow-wrap: anywhere;
|
|
123
133
|
}
|
|
124
134
|
|
|
125
135
|
.version-picker-button-small {
|
|
@@ -124,6 +124,12 @@ export default class VersionPicker extends LightningElement {
|
|
|
124
124
|
return this.small ? "version-picker-dropdown-small" : undefined;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// "full" matches the trigger (ToC width). "fit-end" sizes to the labels,
|
|
128
|
+
// caps at the ToC width, and opens inward.
|
|
129
|
+
private get dropdownWidthMode(): "full" | "fit-end" {
|
|
130
|
+
return this.small ? "fit-end" : "full";
|
|
131
|
+
}
|
|
132
|
+
|
|
127
133
|
private get triggerClass(): string {
|
|
128
134
|
return cx(
|
|
129
135
|
"version-picker-button",
|
|
@@ -148,10 +148,6 @@ dx-toc {
|
|
|
148
148
|
.content-body {
|
|
149
149
|
margin-top: var(--dx-c-content-vertical-spacing);
|
|
150
150
|
}
|
|
151
|
-
|
|
152
|
-
.content-body-doc-phase-container {
|
|
153
|
-
border-left: 0;
|
|
154
|
-
}
|
|
155
151
|
}
|
|
156
152
|
|
|
157
153
|
@media screen and (max-width: 768px) {
|
|
@@ -163,6 +159,10 @@ dx-toc {
|
|
|
163
159
|
flex-direction: column;
|
|
164
160
|
}
|
|
165
161
|
|
|
162
|
+
.content-body-doc-phase-container {
|
|
163
|
+
border-left: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
166
|
.content-body-container {
|
|
167
167
|
padding-right: 0;
|
|
168
168
|
padding-left: 0;
|