@salesforcedevs/docs-components 1.17.5-edit → 1.17.5-search-alpha1

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/lwc.config.json CHANGED
@@ -18,7 +18,6 @@
18
18
  "doc/header",
19
19
  "doc/heading",
20
20
  "doc/headingAnchor",
21
- "doc/markdownEditor",
22
21
  "doc/overview",
23
22
  "doc/phase",
24
23
  "doc/specificationContent",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "1.17.5-edit",
3
+ "version": "1.17.5-search-alpha1",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -1,13 +1,7 @@
1
1
  <template>
2
2
  <doc-content-layout
3
3
  lwc:if={isVersionFetched}
4
- use-old-sidebar={useOldSidebar}
5
4
  class="content-type content-type-reference"
6
- coveo-organization-id={coveoOrganizationId}
7
- coveo-public-access-token={coveoPublicAccessToken}
8
- coveo-analytics-token={coveoAnalyticsToken}
9
- coveo-search-hub={coveoSearchHub}
10
- coveo-advanced-query-config={coveoAdvancedQueryConfig}
11
5
  breadcrumbs={breadcrumbs}
12
6
  sidebar-header={sidebarHeader}
13
7
  sidebar-value={selectedSidebarValue}
@@ -3,7 +3,7 @@ import { noCase } from "no-case";
3
3
  import { sentenceCase } from "sentence-case";
4
4
  import qs from "query-string";
5
5
  import { AmfModelParser } from "doc/amfModelParser";
6
- import { normalizeBoolean, toJson } from "dxUtils/normalizers";
6
+ import { normalizeBoolean } from "dxUtils/normalizers";
7
7
  import type { OptionWithLink } from "typings/custom";
8
8
  import type {
9
9
  AmfConfig,
@@ -28,7 +28,7 @@ import {
28
28
  } from "./constants";
29
29
  import { restoreScroll } from "dx/scrollManager";
30
30
  import { DocPhaseInfo } from "typings/custom";
31
- import { logCoveoPageView, oldVersionDocInfo } from "docUtils/utils";
31
+ import { oldVersionDocInfo } from "docUtils/utils";
32
32
 
33
33
  type NavigationItem = {
34
34
  label: string;
@@ -41,11 +41,6 @@ type NavigationItem = {
41
41
  export default class AmfReference extends LightningElement {
42
42
  @api breadcrumbs: string | null = null;
43
43
  @api sidebarHeader!: string;
44
- @api coveoOrganizationId!: string;
45
- @api coveoPublicAccessToken!: string;
46
- @api coveoAnalyticsToken!: string;
47
- @api coveoSearchHub!: string;
48
- @api useOldSidebar: boolean = false;
49
44
  @api tocTitle?: string;
50
45
  @api tocOptions?: string;
51
46
  @api languages!: OptionWithLink[];
@@ -54,7 +49,6 @@ export default class AmfReference extends LightningElement {
54
49
  @track navigation = [] as NavigationItem[];
55
50
  @track versions: Array<ReferenceVersion> = [];
56
51
  @track showVersionBanner = false;
57
- @track _coveoAdvancedQueryConfig!: { [key: string]: any };
58
52
 
59
53
  // Update this to update what component gets rendered in the content block
60
54
  @track
@@ -160,31 +154,6 @@ export default class AmfReference extends LightningElement {
160
154
  this._expandChildren = normalizeBoolean(value);
161
155
  }
162
156
 
163
- /*
164
- * The get coveoAdvancedQueryConfig() method returns this._coveoAdvancedQueryConfig,
165
- * but before returning it, it checks if there are multiple versions (this.versions.length > 1)
166
- * and if a version is selected (this.selectedVersion). If both conditions are met,
167
- * it updates the version property of this._coveoAdvancedQueryConfig with the selected version.
168
- */
169
- @api
170
- get coveoAdvancedQueryConfig(): { [key: string]: any } {
171
- const coveoConfig = this._coveoAdvancedQueryConfig;
172
- if (this.versions.length > 1 && this.selectedVersion) {
173
- const currentGAVersionRef = this.versions[0];
174
- if (this.selectedVersion.id !== currentGAVersionRef.id) {
175
- // Currently Coveo only supports query without "v"
176
- const version = this.selectedVersion.id.replace("v", "");
177
- coveoConfig.version = version;
178
- this._coveoAdvancedQueryConfig = coveoConfig;
179
- }
180
- }
181
- return this._coveoAdvancedQueryConfig;
182
- }
183
-
184
- set coveoAdvancedQueryConfig(config) {
185
- this._coveoAdvancedQueryConfig = toJson(config);
186
- }
187
-
188
157
  private get enableFooter(): boolean {
189
158
  return !this.hideFooter;
190
159
  }
@@ -1436,10 +1405,6 @@ export default class AmfReference extends LightningElement {
1436
1405
  metaVal
1437
1406
  );
1438
1407
 
1439
- logCoveoPageView(
1440
- this.coveoOrganizationId,
1441
- this.coveoAnalyticsToken
1442
- );
1443
1408
  this.updateUrlWithSelected(parentReferencePath, metaVal);
1444
1409
  this.updateTags(metadata.navTitle);
1445
1410
  } else {
@@ -17,6 +17,6 @@ iframe {
17
17
  border: 1px solid var(--dx-g-gray-90);
18
18
  }
19
19
 
20
- .container {
20
+ .playground-container {
21
21
  position: relative;
22
22
  }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="container" lwc:if={playgroundAvailable}>
2
+ <div class="playground-container" lwc:if={playgroundAvailable}>
3
3
  <dx-spinner
4
4
  size="large"
5
5
  variant="brand"
@@ -8,7 +8,7 @@
8
8
  <iframe
9
9
  src={playgroundSrc}
10
10
  onload={handleIframeLoad}
11
- title="Component Playground"
11
+ title={playgroundTitle}
12
12
  allow="clipboard-write"
13
13
  ></iframe>
14
14
  </div>
@@ -8,6 +8,19 @@ export default class ComponentPlayground extends LightningElement {
8
8
 
9
9
  isLoading = true;
10
10
 
11
+ /**
12
+ * Returns a formatted title for the component playground
13
+ * Maps 'aura' model to 'Aura' and 'lwc' model to 'Lightning'
14
+ * Capitalizes the first letter of the component name
15
+ * @returns {string} Formatted playground title
16
+ */
17
+ get playgroundTitle() {
18
+ const modelName = this.model === "aura" ? "Aura" : "Lightning";
19
+ const componentName =
20
+ this.component.charAt(0).toUpperCase() + this.component.slice(1);
21
+ return `Example previews and code for ${modelName} ${componentName} component`;
22
+ }
23
+
11
24
  get playgroundAvailable() {
12
25
  return (
13
26
  this.playgroundAppUrl &&
@@ -1,43 +1,20 @@
1
1
  <template>
2
2
  <div class="content">
3
- <template lwc:if={useOldSidebar}>
4
- <dx-sidebar-old
5
- class="is-sticky left-nav-bar"
6
- trees={sidebarContent}
7
- value={sidebarValue}
8
- header={sidebarHeader}
9
- ontogglesidebar={onToggleSidebar}
10
- languages={languages}
11
- language={language}
12
- bail-href={bailHref}
13
- bail-label={bailLabel}
14
- dev-center={devCenter}
15
- brand={brand}
16
- >
17
- <slot name="sidebar-header" slot="version-picker"></slot>
18
- </dx-sidebar-old>
19
- </template>
20
- <template lwc:else>
21
- <dx-sidebar
22
- class="is-sticky left-nav-bar"
23
- trees={sidebarContent}
24
- value={sidebarValue}
25
- header={sidebarHeader}
26
- coveo-organization-id={coveoOrganizationId}
27
- coveo-public-access-token={coveoPublicAccessToken}
28
- coveo-search-hub={coveoSearchHub}
29
- coveo-advanced-query-config={coveoAdvancedQueryConfig}
30
- ontogglesidebar={onToggleSidebar}
31
- languages={languages}
32
- language={language}
33
- bail-href={bailHref}
34
- bail-label={bailLabel}
35
- dev-center={devCenter}
36
- brand={brand}
37
- >
38
- <slot name="sidebar-header" slot="version-picker"></slot>
39
- </dx-sidebar>
40
- </template>
3
+ <dx-sidebar-old
4
+ class="is-sticky left-nav-bar"
5
+ trees={sidebarContent}
6
+ value={sidebarValue}
7
+ header={sidebarHeader}
8
+ ontogglesidebar={onToggleSidebar}
9
+ languages={languages}
10
+ language={language}
11
+ bail-href={bailHref}
12
+ bail-label={bailLabel}
13
+ dev-center={devCenter}
14
+ brand={brand}
15
+ >
16
+ <slot name="sidebar-header" slot="version-picker"></slot>
17
+ </dx-sidebar-old>
41
18
  <div class="content-body-doc-phase-container">
42
19
  <slot name="doc-phase"></slot>
43
20
  <slot name="version-banner"></slot>
@@ -32,11 +32,6 @@ export default class ContentLayout extends LightningElement {
32
32
  @api sidebarHeader!: string;
33
33
  @api tocTitle!: string;
34
34
  @api enableSlotChange = false;
35
- @api coveoOrganizationId!: string;
36
- @api coveoPublicAccessToken!: string;
37
- @api coveoAnalyticsToken!: string;
38
- @api coveoSearchHub!: string;
39
- @api coveoAdvancedQueryConfig!: string;
40
35
  @api useOldSidebar?: boolean = false;
41
36
  @api languages!: OptionWithLink[];
42
37
  @api language!: string;
@@ -210,10 +205,7 @@ export default class ContentLayout extends LightningElement {
210
205
  We have to account for the global nav changing height due to animations.
211
206
  */
212
207
  adjustNavPosition = () => {
213
- const sidebarType = this.useOldSidebar
214
- ? "dx-sidebar-old"
215
- : "dx-sidebar";
216
- const sidebarEl = this.template.querySelector(sidebarType);
208
+ const sidebarEl = this.template.querySelector("dx-sidebar-old");
217
209
  const globalNavEl = document.querySelector(
218
210
  "hgf-c360nav"
219
211
  ) as HTMLElement;
@@ -1,43 +1,20 @@
1
1
  <template>
2
2
  <div class="content">
3
- <template lwc:if={useOldSidebar}>
4
- <dx-sidebar-old
5
- class="is-sticky left-nav-bar"
6
- trees={sidebarContent}
7
- value={sidebarValue}
8
- header={sidebarHeader}
9
- ontogglesidebar={onToggleSidebar}
10
- languages={languages}
11
- language={language}
12
- bail-href={bailHref}
13
- bail-label={bailLabel}
14
- dev-center={devCenter}
15
- brand={brand}
16
- >
17
- <slot name="sidebar-header" slot="version-picker"></slot>
18
- </dx-sidebar-old>
19
- </template>
20
- <template lwc:else>
21
- <dx-sidebar
22
- class="is-sticky left-nav-bar"
23
- trees={sidebarContent}
24
- value={sidebarValue}
25
- header={sidebarHeader}
26
- coveo-organization-id={coveoOrganizationId}
27
- coveo-public-access-token={coveoPublicAccessToken}
28
- coveo-search-hub={coveoSearchHub}
29
- coveo-advanced-query-config={coveoAdvancedQueryConfig}
30
- ontogglesidebar={onToggleSidebar}
31
- languages={languages}
32
- language={language}
33
- bail-href={bailHref}
34
- bail-label={bailLabel}
35
- dev-center={devCenter}
36
- brand={brand}
37
- >
38
- <slot name="sidebar-header" slot="version-picker"></slot>
39
- </dx-sidebar>
40
- </template>
3
+ <dx-sidebar-old
4
+ class="is-sticky left-nav-bar"
5
+ trees={sidebarContent}
6
+ value={sidebarValue}
7
+ header={sidebarHeader}
8
+ ontogglesidebar={onToggleSidebar}
9
+ languages={languages}
10
+ language={language}
11
+ bail-href={bailHref}
12
+ bail-label={bailLabel}
13
+ dev-center={devCenter}
14
+ brand={brand}
15
+ >
16
+ <slot name="sidebar-header" slot="version-picker"></slot>
17
+ </dx-sidebar-old>
41
18
  <div class="content-body-doc-phase-container">
42
19
  <slot name="doc-phase"></slot>
43
20
  <slot name="version-banner"></slot>
@@ -1,17 +1,11 @@
1
1
  <template>
2
2
  <doc-content-layout
3
- lwc:if={loaded}
3
+ lwc:if={displayContent}
4
4
  lwc:ref="docContentLayout"
5
- coveo-organization-id={coveoOrganizationId}
6
- coveo-public-access-token={coveoPublicAccessToken}
7
- coveo-analytics-token={coveoAnalyticsToken}
8
- coveo-search-hub={coveoSearchHub}
9
- coveo-advanced-query-config={coveoAdvancedQueryConfig}
10
5
  sidebar-header={docTitle}
11
6
  sidebar-content={sidebarContent}
12
7
  sidebar-value={sidebarValue}
13
8
  onselect={handleSelect}
14
- use-old-sidebar={useOldSidebar}
15
9
  onlangchange={handleLanguageChange}
16
10
  languages={sidebarFooterContent.languages}
17
11
  language={sidebarFooterContent.language}
@@ -49,4 +43,12 @@
49
43
  onnavclick={handleNavClick}
50
44
  ></doc-content>
51
45
  </doc-content-layout>
46
+ <div lwc:if={display404}>
47
+ <dx-error
48
+ image="https://a.sfdcstatic.com/developer-website/images/404.svg"
49
+ code="404"
50
+ header="Beep boop. That did not compute."
51
+ subtitle="The document you're looking for doesn't seem to exist."
52
+ ></dx-error>
53
+ </div>
52
54
  </template>
@@ -1,9 +1,7 @@
1
1
  /* eslint-disable @lwc/lwc/no-document-query */
2
2
  import { api, track } from "lwc";
3
- import { normalizeBoolean } from "dxUtils/normalizers";
4
3
  import { FetchContent } from "./utils";
5
4
  import {
6
- CoveoAdvancedQueryXMLConfig,
7
5
  DocLanguage,
8
6
  DocVersion,
9
7
  TreeNode,
@@ -11,11 +9,12 @@ import {
11
9
  SiderbarFooter,
12
10
  HistoryState,
13
11
  PageReference,
14
- TocMap
12
+ TocMap,
13
+ ContentData
15
14
  } from "./types";
16
15
  import { SearchSyncer } from "docUtils/searchSyncer";
17
16
  import { LightningElementWithState } from "dxBaseElements/lightningElementWithState";
18
- import { logCoveoPageView, oldVersionDocInfo } from "docUtils/utils";
17
+ import { oldVersionDocInfo } from "docUtils/utils";
19
18
  import { Breadcrumb, DocPhaseInfo, Language } from "typings/custom";
20
19
  import { track as trackGTM } from "dxUtils/analytics";
21
20
  import DOMPurify from "dompurify";
@@ -41,10 +40,6 @@ export default class DocXmlContent extends LightningElementWithState<{
41
40
  internalLinkClicked: boolean;
42
41
  }> {
43
42
  @api apiDomain = "https://developer.salesforce.com";
44
- @api coveoOrganizationId!: string;
45
- @api coveoPublicAccessToken!: string;
46
- @api coveoAnalyticsToken!: string;
47
- @api coveoSearchHub!: string;
48
43
  @api hideFooter = false;
49
44
 
50
45
  @api
@@ -58,21 +53,13 @@ export default class DocXmlContent extends LightningElementWithState<{
58
53
  }
59
54
  }
60
55
 
61
- @api
62
- get enableCoveo() {
63
- return this._enableCoveo;
64
- }
65
-
66
- set enableCoveo(value) {
67
- this._enableCoveo = normalizeBoolean(value);
68
- }
69
-
70
56
  private availableLanguages: Array<DocLanguage> = [];
71
57
  @track private availableVersions: Array<DocVersion> = [];
72
58
  private contentProvider?: FetchContent;
73
59
  private docContent = "";
74
60
  private language?: DocLanguage | null = null;
75
- private loaded = false;
61
+ private displayContent = false;
62
+ private display404 = false;
76
63
  private _pageHeader?: Header;
77
64
  private pdfUrl = "";
78
65
  private tocMap: TocMap = {};
@@ -81,7 +68,6 @@ export default class DocXmlContent extends LightningElementWithState<{
81
68
  private docTitle = "";
82
69
  private _pathName = "";
83
70
  private listenerAttached = false;
84
- private _enableCoveo?: boolean = false;
85
71
  private sidebarFooterContent: SiderbarFooter = { ...defaultSidebarFooter };
86
72
  private latestVersion = false;
87
73
  private previewVersion = false;
@@ -185,7 +171,13 @@ export default class DocXmlContent extends LightningElementWithState<{
185
171
  this.apiDomain,
186
172
  this.allLanguages
187
173
  );
188
- this.fetchDocument().then(() => (this.loaded = true));
174
+ this.fetchDocument().then((content: any) => {
175
+ if (content) {
176
+ this.displayContent = true;
177
+ } else {
178
+ this.display404 = true;
179
+ }
180
+ });
189
181
  window.addEventListener("popstate", this.handlePopState);
190
182
 
191
183
  this.searchSyncer.init();
@@ -252,35 +244,13 @@ export default class DocXmlContent extends LightningElementWithState<{
252
244
  // Coveo is enabled and the version is greater than 51 (within the latest 3 versions)
253
245
  // TODO: we need a better fix for version number check
254
246
  return !(
255
- this.enableCoveo &&
256
- this.coveoOrganizationId &&
257
- this.coveoPublicAccessToken &&
258
- (!this.version?.releaseVersion ||
259
- (this.version?.releaseVersion &&
260
- parseInt(
261
- this.version.releaseVersion.replace("v", ""),
262
- 10
263
- ) >= 53))
247
+ !this.version?.releaseVersion ||
248
+ (this.version?.releaseVersion &&
249
+ parseInt(this.version.releaseVersion.replace("v", ""), 10) >=
250
+ 53)
264
251
  );
265
252
  }
266
253
 
267
- private get coveoAdvancedQueryConfig(): CoveoAdvancedQueryXMLConfig {
268
- const config: {
269
- locale?: string;
270
- topicid?: string;
271
- version?: string;
272
- } = {
273
- locale: this.languageId,
274
- topicid: this.deliverable
275
- };
276
-
277
- if (this.releaseVersionId && this.releaseVersionId !== "noversion") {
278
- config.version = this.releaseVersionId;
279
- }
280
-
281
- return config;
282
- }
283
-
284
254
  private get pageHeader(): Header {
285
255
  if (!this._pageHeader) {
286
256
  this._pageHeader = document.querySelector("doc-header")!;
@@ -463,7 +433,7 @@ export default class DocXmlContent extends LightningElementWithState<{
463
433
  );
464
434
  }
465
435
 
466
- async fetchDocument(): Promise<void> {
436
+ async fetchDocument(): Promise<string> {
467
437
  this.setState({
468
438
  isFetchingDocument: true
469
439
  });
@@ -477,7 +447,7 @@ export default class DocXmlContent extends LightningElementWithState<{
477
447
  this.setState({
478
448
  isFetchingDocument: false
479
449
  });
480
- return;
450
+ return "";
481
451
  }
482
452
 
483
453
  this.docTitle = data.docTitle;
@@ -509,11 +479,11 @@ export default class DocXmlContent extends LightningElementWithState<{
509
479
  data.id
510
480
  ) {
511
481
  try {
512
- await this.fetchContent();
482
+ const moreData = await this.fetchContent();
513
483
  this.setState({
514
484
  isFetchingDocument: false
515
485
  });
516
- return;
486
+ return moreData.content;
517
487
  } catch (error) {
518
488
  this.pageReference.contentDocumentId = `${data.id}.htm`;
519
489
  this.pageReference.hash = "";
@@ -527,9 +497,10 @@ export default class DocXmlContent extends LightningElementWithState<{
527
497
  this.setState({
528
498
  isFetchingDocument: false
529
499
  });
500
+ return data.content;
530
501
  }
531
502
 
532
- async fetchContent(): Promise<void> {
503
+ async fetchContent(): Promise<ContentData> {
533
504
  this.setState({
534
505
  isFetchingContent: true
535
506
  });
@@ -553,6 +524,7 @@ export default class DocXmlContent extends LightningElementWithState<{
553
524
  this.setState({
554
525
  isFetchingContent: false
555
526
  });
527
+ return data;
556
528
  }
557
529
 
558
530
  updateHeaderAndSidebarFooter(): void {
@@ -579,7 +551,6 @@ export default class DocXmlContent extends LightningElementWithState<{
579
551
  }
580
552
 
581
553
  updateUrl(method = HistoryState.PUSH_STATE): void {
582
- logCoveoPageView(this.coveoOrganizationId, this.coveoAnalyticsToken);
583
554
  window.history[method](
584
555
  {},
585
556
  "docs",
@@ -1,225 +0,0 @@
1
- .markdown-editor {
2
- border: 1px solid #e1e5e9;
3
- border-radius: 4px;
4
- overflow: hidden;
5
- background: #fff;
6
- }
7
-
8
- /* Editor Toolbar */
9
- .editor-toolbar {
10
- display: flex;
11
- align-items: center;
12
- justify-content: flex-end;
13
- gap: 0.5rem;
14
- padding: 0.75rem 1rem;
15
- background: #f8f9fa;
16
- border-bottom: 1px solid #e1e5e9;
17
- flex-wrap: wrap;
18
- }
19
-
20
- .edit-button,
21
- .cancel-button,
22
- .save-button {
23
- min-width: 80px;
24
- }
25
-
26
- .status-indicator {
27
- margin-left: 0.5rem;
28
- font-size: 0.875rem;
29
- }
30
-
31
- .status-saving {
32
- color: #0176d3;
33
- }
34
-
35
- .status-success {
36
- color: #04844b;
37
- }
38
-
39
- .status-error {
40
- color: #ea001e;
41
- }
42
-
43
- /* Content Viewer */
44
- .content-viewer {
45
- padding: 1rem;
46
- }
47
-
48
- .content-display {
49
- line-height: 1.6;
50
- color: #3e3e3c;
51
- }
52
-
53
- .content-display h1,
54
- .content-display h2,
55
- .content-display h3,
56
- .content-display h4,
57
- .content-display h5,
58
- .content-display h6 {
59
- margin-top: 1.5rem;
60
- margin-bottom: 0.5rem;
61
- color: #181818;
62
- }
63
-
64
- .content-display p {
65
- margin-bottom: 1rem;
66
- }
67
-
68
- .content-display ul,
69
- .content-display ol {
70
- margin-bottom: 1rem;
71
- padding-left: 2rem;
72
- }
73
-
74
- .content-display code {
75
- background-color: #f3f2f2;
76
- padding: 0.125rem 0.25rem;
77
- border-radius: 0.25rem;
78
- font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
79
- font-size: 0.875rem;
80
- }
81
-
82
- .content-display pre {
83
- background-color: #f3f2f2;
84
- padding: 1rem;
85
- border-radius: 0.25rem;
86
- overflow-x: auto;
87
- margin-bottom: 1rem;
88
- }
89
-
90
- .content-display pre code {
91
- background-color: transparent;
92
- padding: 0;
93
- }
94
-
95
- /* HTML Content Styling */
96
- .html-content {
97
- line-height: 1.6;
98
- color: #3e3e3c;
99
- }
100
-
101
- .html-content h1,
102
- .html-content h2,
103
- .html-content h3,
104
- .html-content h4,
105
- .html-content h5,
106
- .html-content h6 {
107
- margin-top: 1.5rem;
108
- margin-bottom: 0.5rem;
109
- color: #181818;
110
- }
111
-
112
- .html-content p {
113
- margin-bottom: 1rem;
114
- }
115
-
116
- .html-content ul,
117
- .html-content ol {
118
- margin-bottom: 1rem;
119
- padding-left: 2rem;
120
- }
121
-
122
- .html-content code {
123
- background-color: #f3f2f2;
124
- padding: 0.125rem 0.25rem;
125
- border-radius: 0.25rem;
126
- font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
127
- font-size: 0.875rem;
128
- }
129
-
130
- .html-content pre {
131
- background-color: #f3f2f2;
132
- padding: 1rem;
133
- border-radius: 0.25rem;
134
- overflow-x: auto;
135
- margin-bottom: 1rem;
136
- }
137
-
138
- .html-content pre code {
139
- background-color: transparent;
140
- padding: 0;
141
- }
142
-
143
- /* No Content Message */
144
- .no-content {
145
- color: #706e6b;
146
- font-style: italic;
147
- text-align: center;
148
- padding: 2rem;
149
- background-color: #f8f9fa;
150
- border: 1px dashed #e1e5e9;
151
- border-radius: 4px;
152
- }
153
-
154
- /* Editor Wrapper */
155
- .editor-wrapper {
156
- position: relative;
157
- min-height: 300px;
158
- }
159
-
160
- .simple-editor {
161
- width: 100%;
162
- min-height: 300px;
163
- padding: 1rem;
164
- border: none;
165
- outline: none;
166
- font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
167
- font-size: 0.875rem;
168
- line-height: 1.5;
169
- resize: vertical;
170
- background: #fff;
171
- color: #3e3e3c;
172
- }
173
-
174
- .simple-editor:focus {
175
- outline: none;
176
- }
177
-
178
- .simple-editor::placeholder {
179
- color: #706e6b;
180
- }
181
-
182
- /* Loading Overlay */
183
- .loading-overlay {
184
- position: absolute;
185
- top: 0;
186
- left: 0;
187
- right: 0;
188
- bottom: 0;
189
- background: rgb(255 255 255 / 80%);
190
- display: flex;
191
- align-items: center;
192
- justify-content: center;
193
- z-index: 1000;
194
- }
195
-
196
- /* Responsive Design */
197
- @media (max-width: 768px) {
198
- .editor-toolbar {
199
- flex-wrap: wrap;
200
- gap: 0.25rem;
201
- justify-content: flex-end;
202
- }
203
-
204
- .status-indicator {
205
- margin-left: 0.25rem;
206
- width: auto;
207
- text-align: right;
208
- margin-top: 0;
209
- }
210
-
211
- .simple-editor {
212
- min-height: 250px;
213
- }
214
-
215
- .content-viewer {
216
- padding: 0.75rem;
217
- }
218
- }
219
-
220
- /* Empty state */
221
- .content-display:empty::before {
222
- content: "No content to display";
223
- color: #706e6b;
224
- font-style: italic;
225
- }
@@ -1,80 +0,0 @@
1
- <template>
2
- <div class="markdown-editor">
3
- <!-- Editor Toolbar -->
4
- <div class="editor-toolbar">
5
- <template if:true={showViewer}>
6
- <dx-button
7
- onclick={handleEdit}
8
- variant="tertiary"
9
- class="edit-button"
10
- >
11
- Edit Content
12
- </dx-button>
13
- </template>
14
-
15
- <template if:true={showEditor}>
16
- <dx-button
17
- onclick={handleCancel}
18
- variant="secondary"
19
- class="cancel-button"
20
- >
21
- Cancel
22
- </dx-button>
23
-
24
- <dx-button
25
- onclick={handleSave}
26
- variant="primary"
27
- disabled={saveButtonDisabled}
28
- class="save-button"
29
- >
30
- Save
31
- </dx-button>
32
-
33
- <div class="status-indicator">
34
- <span class={statusClass}>{statusMessage}</span>
35
- </div>
36
- </template>
37
- </div>
38
-
39
- <!-- Content Viewer (Read-only) -->
40
- <template if:true={showViewer}>
41
- <div class="content-viewer">
42
- <div class="content-display">
43
- <!-- Show HTML content if provided -->
44
- <template if:true={hasHtmlContent}>
45
- <div class="html-content" innerhtml={htmlContent}></div>
46
- </template>
47
-
48
- <!-- Show message if no HTML content -->
49
- <template if:false={hasHtmlContent}>
50
- <div class="no-content">
51
- No content to display. Click 'Edit Content' to fetch from the backend.
52
- </div>
53
- </template>
54
- </div>
55
- </div>
56
- </template>
57
-
58
- <!-- Simple Editor -->
59
- <template if:true={showEditor}>
60
- <div class="editor-wrapper">
61
- <textarea
62
- class="simple-editor"
63
- value={editorContent}
64
- onchange={handleContentChange}
65
- placeholder="Content will be loaded from the fetch URL..."
66
- ></textarea>
67
- </div>
68
- </template>
69
-
70
- <!-- Loading Overlay -->
71
- <template if:true={isLoading}>
72
- <div class="loading-overlay">
73
- <dx-spinner
74
- size="medium"
75
- alternative-text="Loading"
76
- ></dx-spinner>
77
- </div>
78
- </template>
79
- </div>
80
- </template>
@@ -1,148 +0,0 @@
1
- import { LightningElement, api, track } from "lwc";
2
-
3
- export default class MarkdownEditor extends LightningElement {
4
- @api fetchUrl: string = "";
5
- @api saveUrl: string = "";
6
- @api filePath: string = "";
7
- @api htmlContent: string = "";
8
-
9
- @track isEditing: boolean = false;
10
- @track editorContent: string = "";
11
- @track isLoading: boolean = false;
12
- @track saveStatus: "idle" | "saving" | "success" | "error" = "idle";
13
-
14
- // Event Handlers
15
- async handleEdit() {
16
- if (!this.fetchUrl) {
17
- console.error("Fetch URL not configured");
18
- return;
19
- }
20
-
21
- this.isLoading = true;
22
- this.saveStatus = "idle";
23
-
24
- try {
25
- const response = await fetch(this.fetchUrl, {
26
- method: "GET",
27
- headers: {
28
- "Content-Type": "application/json"
29
- }
30
- });
31
-
32
- if (response.ok) {
33
- const data = await response.json();
34
- this.editorContent = data.content || data.text || data.body || "";
35
- this.isEditing = true;
36
- } else {
37
- throw new Error(`Failed to fetch content: ${response.status}`);
38
- }
39
- } catch (error) {
40
- console.error("Failed to fetch content:", error);
41
- this.saveStatus = "error";
42
- } finally {
43
- this.isLoading = false;
44
- }
45
- }
46
-
47
- handleCancel() {
48
- this.isEditing = false;
49
- this.saveStatus = "idle";
50
- this.editorContent = "";
51
- }
52
-
53
- handleContentChange(event: Event) {
54
- const target = event.target as HTMLTextAreaElement;
55
- this.editorContent = target.value;
56
- }
57
-
58
- async handleSave() {
59
- if (!this.saveUrl) {
60
- console.error("Save URL not configured");
61
- this.saveStatus = "error";
62
- return;
63
- }
64
-
65
- this.saveStatus = "saving";
66
- this.isLoading = true;
67
-
68
- try {
69
- const response = await fetch(this.saveUrl, {
70
- method: "POST",
71
- headers: {
72
- "Content-Type": "application/json"
73
- },
74
- body: JSON.stringify({
75
- content: this.editorContent,
76
- filePath: this.filePath
77
- })
78
- });
79
-
80
- if (response.ok) {
81
- this.saveStatus = "success";
82
- this.isEditing = false;
83
- this.editorContent = "";
84
-
85
- // Dispatch save success event
86
- this.dispatchEvent(
87
- new CustomEvent("saved", {
88
- detail: {
89
- success: true,
90
- content: this.editorContent,
91
- filePath: this.filePath
92
- }
93
- })
94
- );
95
- } else {
96
- throw new Error(`Save failed: ${response.status}`);
97
- }
98
- } catch (error) {
99
- console.error("Save failed:", error);
100
- this.saveStatus = "error";
101
- } finally {
102
- this.isLoading = false;
103
- }
104
- }
105
-
106
- // Getters for UI state
107
- get showEditor() {
108
- return this.isEditing;
109
- }
110
-
111
- get showViewer() {
112
- return !this.isEditing;
113
- }
114
-
115
- get saveButtonDisabled() {
116
- return this.saveStatus === "saving" || this.isLoading || !this.editorContent.trim();
117
- }
118
-
119
- get statusMessage() {
120
- switch (this.saveStatus) {
121
- case "saving":
122
- return "Saving...";
123
- case "success":
124
- return "Saved successfully!";
125
- case "error":
126
- return "Save failed. Please try again.";
127
- default:
128
- return "";
129
- }
130
- }
131
-
132
- get statusClass() {
133
- switch (this.saveStatus) {
134
- case "saving":
135
- return "status-saving";
136
- case "success":
137
- return "status-success";
138
- case "error":
139
- return "status-error";
140
- default:
141
- return "";
142
- }
143
- }
144
-
145
- get hasHtmlContent() {
146
- return this.htmlContent && this.htmlContent.trim().length > 0;
147
- }
148
- }