create-sitecore-jss 22.2.0-canary.6 → 22.2.0-canary.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +17 -42
- package/dist/common/index.js +3 -1
- package/dist/common/processes/next.js +6 -3
- package/dist/common/processes/transform.js +13 -13
- package/dist/common/prompts/base.js +0 -25
- package/dist/common/prompts/proxy.js +35 -0
- package/dist/common/prompts/sxp.js +34 -0
- package/dist/common/utils/helpers.js +37 -2
- package/dist/init-runner.js +4 -3
- package/dist/initializers/angular/index.js +0 -3
- package/dist/initializers/angular/prompts.js +6 -6
- package/dist/initializers/angular-sxp/index.js +7 -1
- package/dist/initializers/angular-xmcloud/index.js +27 -3
- package/dist/initializers/nextjs/prompts.js +2 -0
- package/dist/initializers/node-xmcloud-proxy/index.js +2 -1
- package/dist/initializers/react/prompts.js +1 -1
- package/dist/initializers/react-native/prompts.js +1 -0
- package/dist/initializers/vue/prompts.js +1 -1
- package/dist/templates/angular/.env +4 -5
- package/dist/templates/angular/.eslintrc +1 -0
- package/dist/templates/angular/gitignore +5 -0
- package/dist/templates/angular/package.json +0 -2
- package/dist/templates/angular/scripts/config/plugins/fallback.ts +0 -1
- package/dist/templates/angular/scripts/generate-component-factory.ts +8 -0
- package/dist/templates/angular/scripts/generate-config.ts +25 -6
- package/dist/templates/angular/scripts/update-graphql-fragment-data.ts +21 -30
- package/dist/templates/angular/server.bundle.ts +3 -23
- package/dist/templates/angular/server.exports.ts +13 -0
- package/dist/templates/angular/src/app/JssState.ts +2 -9
- package/dist/templates/angular/src/app/app.module.ts +5 -4
- package/dist/templates/angular/src/app/app.server.module.ts +9 -6
- package/dist/templates/angular/src/app/i18n/jss-translation-client-loader.service.ts +15 -7
- package/dist/templates/angular/src/app/i18n/jss-translation-server-loader.service.ts +14 -2
- package/dist/templates/angular/src/app/jss-context.server-side.service.ts +4 -2
- package/dist/templates/angular/src/app/jss-context.service.ts +14 -11
- package/dist/templates/angular/src/app/jss-graphql.service.ts +7 -7
- package/dist/templates/angular/src/app/layout/jss-layout.service.ts +2 -2
- package/dist/templates/angular/src/app/lib/dictionary-service-factory.ts +4 -1
- package/dist/templates/angular/src/app/lib/graphql-client-factory/config.ts +21 -0
- package/dist/templates/angular/src/app/lib/graphql-client-factory/index.ts +16 -0
- package/dist/templates/angular/src/app/lib/layout-service-factory.ts +1 -1
- package/dist/templates/angular/src/app/routing/layout/layout.component.ts +10 -9
- package/dist/templates/angular/src/environments/gitignore +2 -1
- package/dist/templates/angular-sxp/.env +2 -0
- package/dist/templates/angular-sxp/scripts/config/plugins/disconnected.ts +4 -2
- package/dist/templates/angular-sxp/src/app/components/graph-ql-layout/graph-ql-layout.component.ts +1 -1
- package/dist/templates/angular-xmcloud/.env +8 -2
- package/dist/templates/angular-xmcloud/angular.json +0 -1
- package/dist/templates/angular-xmcloud/scripts/bootstrap.ts +28 -0
- package/dist/templates/angular-xmcloud/scripts/config/plugins/xmcloud.ts +16 -0
- package/dist/templates/angular-xmcloud/scripts/generate-metadata.ts +25 -0
- package/dist/templates/angular-xmcloud/server.exports.ts +24 -0
- package/dist/templates/angular-xmcloud/src/app/components/app-components.shared.module.ts +21 -0
- package/dist/templates/angular-xmcloud/src/app/components/column-splitter/column-splitter.component.html +5 -0
- package/dist/templates/angular-xmcloud/src/app/components/column-splitter/column-splitter.component.ts +40 -0
- package/dist/templates/angular-xmcloud/src/app/components/container/container.component.html +14 -0
- package/dist/templates/angular-xmcloud/src/app/components/container/container.component.ts +30 -0
- package/dist/templates/angular-xmcloud/src/app/components/image/image.component.html +36 -0
- package/dist/templates/angular-xmcloud/src/app/components/image/image.component.ts +67 -0
- package/dist/templates/angular-xmcloud/src/app/components/link-list/link-list.component.html +15 -0
- package/dist/templates/angular-xmcloud/src/app/components/link-list/link-list.component.ts +41 -0
- package/dist/templates/angular-xmcloud/src/app/components/navigation/navigation-item.component.html +23 -0
- package/dist/templates/angular-xmcloud/src/app/components/navigation/navigation-item.component.ts +65 -0
- package/dist/templates/angular-xmcloud/src/app/components/navigation/navigation.component.html +21 -0
- package/dist/templates/angular-xmcloud/src/app/components/navigation/navigation.component.ts +49 -0
- package/dist/templates/angular-xmcloud/src/app/components/page-content/page-content.component.html +5 -0
- package/dist/templates/angular-xmcloud/src/app/components/page-content/page-content.component.ts +39 -0
- package/dist/templates/angular-xmcloud/src/app/components/partial-design-dynamic-placeholder/partial-design-dynamic-placeholder.component.html +1 -0
- package/dist/templates/angular-xmcloud/src/app/components/partial-design-dynamic-placeholder/partial-design-dynamic-placeholder.component.ts +15 -0
- package/dist/templates/angular-xmcloud/src/app/components/promo/promo.component.html +21 -0
- package/dist/templates/angular-xmcloud/src/app/components/promo/promo.component.ts +13 -0
- package/dist/templates/angular-xmcloud/src/app/components/richtext/richtext.component.html +7 -12
- package/dist/templates/angular-xmcloud/src/app/components/richtext/richtext.component.ts +6 -1
- package/dist/templates/angular-xmcloud/src/app/components/row-splitter/row-splitter.component.html +11 -0
- package/dist/templates/angular-xmcloud/src/app/components/row-splitter/row-splitter.component.ts +35 -0
- package/dist/templates/angular-xmcloud/src/app/components/sxa.component.ts +4 -4
- package/dist/templates/angular-xmcloud/src/app/components/title/title.component.html +10 -0
- package/dist/templates/angular-xmcloud/src/app/components/title/title.component.ts +56 -0
- package/dist/templates/angular-xmcloud/src/app/jss-link.service.ts +55 -0
- package/dist/templates/angular-xmcloud/src/app/lib/config.ts +2 -0
- package/dist/templates/angular-xmcloud/src/app/lib/graphql-client-factory/config.ts +58 -0
- package/dist/templates/angular-xmcloud/src/app/routing/layout/layout.component.html +38 -0
- package/dist/templates/angular-xmcloud/src/app/routing/layout/layout.component.ts +104 -0
- package/dist/templates/angular-xmcloud/src/app/routing/scripts/scripts.component.html +3 -0
- package/dist/templates/angular-xmcloud/src/app/routing/scripts/scripts.module.ts +10 -0
- package/dist/templates/angular-xmcloud/src/assets/styles/basic/_header.scss +3 -1
- package/dist/templates/angular-xmcloud/src/assets/styles/main.scss +10 -0
- package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/_component-image.scss +1 -1
- package/dist/templates/nextjs/package.json +1 -1
- package/dist/templates/nextjs/scripts/config/plugins/fallback.ts +0 -1
- package/dist/templates/nextjs/scripts/generate-config.ts +8 -1
- package/dist/templates/nextjs/src/lib/page-props-factory/plugins/component-props.ts +2 -1
- package/dist/templates/nextjs-styleguide/scripts/config/plugins/disconnected.ts +1 -0
- package/dist/templates/nextjs-sxa/src/assets/sass/components/_component-image.scss +1 -1
- package/dist/templates/nextjs-sxa/src/components/Container.tsx +6 -14
- package/dist/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/component-themes.ts +2 -1
- package/dist/templates/nextjs-xmcloud/src/lib/page-props-factory/plugins/preview-mode.ts +2 -1
- package/dist/templates/node-headless-ssr-experience-edge/gitignore +19 -0
- package/dist/templates/node-headless-ssr-proxy/gitignore +19 -0
- package/dist/templates/node-headless-ssr-proxy/src/config.ts +3 -3
- package/dist/templates/node-headless-ssr-proxy/src/httpAgents.ts +2 -2
- package/dist/templates/node-headless-ssr-proxy/src/index.ts +9 -2
- package/dist/templates/node-xmcloud-proxy/.env +7 -1
- package/dist/templates/node-xmcloud-proxy/README.md +1 -1
- package/dist/templates/node-xmcloud-proxy/gitignore +33 -0
- package/dist/templates/node-xmcloud-proxy/package.json +3 -2
- package/dist/templates/node-xmcloud-proxy/src/config.ts +9 -3
- package/dist/templates/node-xmcloud-proxy/src/index.ts +54 -5
- package/dist/templates/node-xmcloud-proxy/src/types.ts +10 -42
- package/dist/templates/react/scripts/generate-config.js +10 -3
- package/dist/templates/vue/scripts/generate-config.js +5 -0
- package/package.json +2 -2
- package/dist/templates/angular/src/app/lib/graphql-client-factory.ts +0 -28
- package/dist/templates/angular-xmcloud/src/app/lib/graphql-client-factory.ts +0 -44
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Component, OnInit } from '@angular/core';
|
|
2
|
+
import { SxaComponent } from '../sxa.component';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'app-partial-design-dynamic-placeholder',
|
|
6
|
+
templateUrl: './partial-design-dynamic-placeholder.component.html',
|
|
7
|
+
})
|
|
8
|
+
export class PartialDesignDynamicPlaceholderComponent extends SxaComponent implements OnInit {
|
|
9
|
+
sig: string;
|
|
10
|
+
ngOnInit() {
|
|
11
|
+
super.ngOnInit();
|
|
12
|
+
|
|
13
|
+
this.sig = this.rendering.params?.sig || '';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<div class="component-content">
|
|
2
|
+
<ng-container *ngIf="rendering.fields; else empty">
|
|
3
|
+
<div class="field-promoicon">
|
|
4
|
+
<img *scImage="rendering.fields.PromoIcon" />
|
|
5
|
+
</div>
|
|
6
|
+
<div class="promo-text">
|
|
7
|
+
<div>
|
|
8
|
+
<div class="field-promotext">
|
|
9
|
+
<div *scRichText="rendering.fields.PromoText"></div>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="field-promolink">
|
|
13
|
+
<a *scLink="rendering.fields.PromoLink"></a>
|
|
14
|
+
</div>
|
|
15
|
+
</div>
|
|
16
|
+
</ng-container>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<ng-template #empty>
|
|
20
|
+
<span className="is-empty-hint">Promo</span>
|
|
21
|
+
</ng-template>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { SxaComponent } from '../sxa.component';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'app-promo',
|
|
6
|
+
templateUrl: './promo.component.html',
|
|
7
|
+
host: {
|
|
8
|
+
'class': 'component promo',
|
|
9
|
+
'[class]': "styles",
|
|
10
|
+
'[id]': "id",
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
export class PromoComponent extends SxaComponent {}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
>
|
|
5
|
-
<
|
|
6
|
-
<
|
|
7
|
-
|
|
8
|
-
</ng-container>
|
|
9
|
-
<ng-template #emptyHint>
|
|
10
|
-
<span class="is-empty-hint">Rich text</span>
|
|
11
|
-
</ng-template>
|
|
12
|
-
</div>
|
|
1
|
+
<div class="component-content">
|
|
2
|
+
<ng-container *ngIf="text; else emptyHint">
|
|
3
|
+
<div *scRichText="text"></div>
|
|
4
|
+
</ng-container>
|
|
5
|
+
<ng-template #emptyHint>
|
|
6
|
+
<span class="is-empty-hint">Rich text</span>
|
|
7
|
+
</ng-template>
|
|
13
8
|
</div>
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { Component, OnInit } from '@angular/core';
|
|
2
2
|
import { Field } from '@sitecore-jss/sitecore-jss-angular';
|
|
3
3
|
import { SxaComponent } from '../sxa.component';
|
|
4
4
|
|
|
5
5
|
@Component({
|
|
6
6
|
selector: 'app-richtext',
|
|
7
7
|
templateUrl: './richtext.component.html',
|
|
8
|
+
host: {
|
|
9
|
+
'class': 'component rich-text',
|
|
10
|
+
'[class]': "styles",
|
|
11
|
+
"[attr.id]": "id"
|
|
12
|
+
},
|
|
8
13
|
})
|
|
9
14
|
export class RichTextComponent extends SxaComponent implements OnInit {
|
|
10
15
|
text?: Field<string>;
|
package/dist/templates/angular-xmcloud/src/app/components/row-splitter/row-splitter.component.html
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<div
|
|
2
|
+
*ngFor="let ph of enabledPlaceholders"
|
|
3
|
+
class="container-fluid"
|
|
4
|
+
[ngClass]="getRowClass(+ph - 1)"
|
|
5
|
+
>
|
|
6
|
+
<div>
|
|
7
|
+
<div class="row">
|
|
8
|
+
<sc-placeholder [name]="getPlaceholderName(ph)" [rendering]="rendering"> </sc-placeholder>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
package/dist/templates/angular-xmcloud/src/app/components/row-splitter/row-splitter.component.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { SxaComponent } from '../sxa.component';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'app-row-splitter',
|
|
6
|
+
templateUrl: './row-splitter.component.html',
|
|
7
|
+
host: {
|
|
8
|
+
"class": "component row-splitter",
|
|
9
|
+
"[class]": "rowSplitterStyles",
|
|
10
|
+
"[id]": "id"
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
export class RowSplitterComponent extends SxaComponent {
|
|
14
|
+
get rowSplitterStyles(): string {
|
|
15
|
+
return `${this.rendering.params.GridParameters ?? ''} ${this.rendering.params.Styles ??
|
|
16
|
+
''}`.trimEnd();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get rowStyles(): string[] {
|
|
20
|
+
return Array.from({ length: 8 }, (_, i) => this.rendering.params[`Styles${i + 1}`]);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get enabledPlaceholders(): string[] {
|
|
24
|
+
return this.rendering.params.EnabledPlaceholders.split(',');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getRowClass(index: number): string {
|
|
28
|
+
const styleClass = this.rowStyles[index] || '';
|
|
29
|
+
return `${styleClass}`.trim();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getPlaceholderName(ph: string): string {
|
|
33
|
+
return `row-${ph}-{*}`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import { ComponentRendering } from '@sitecore-jss/sitecore-jss-angular';
|
|
1
|
+
import { OnInit, Input, Directive } from '@angular/core';
|
|
2
|
+
import { ComponentFields, ComponentRendering } from '@sitecore-jss/sitecore-jss-angular';
|
|
3
3
|
|
|
4
4
|
@Directive()
|
|
5
|
-
export abstract class SxaComponent implements OnInit {
|
|
6
|
-
@Input() rendering: ComponentRendering
|
|
5
|
+
export abstract class SxaComponent<FieldType = ComponentFields> implements OnInit {
|
|
6
|
+
@Input() rendering: ComponentRendering<FieldType>;
|
|
7
7
|
|
|
8
8
|
id?: string;
|
|
9
9
|
styles?: string;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Component, OnDestroy, OnInit } from '@angular/core';
|
|
2
|
+
import { LinkField, SxaTitleFields, TextField } from '@sitecore-jss/sitecore-jss-angular';
|
|
3
|
+
import { SxaComponent } from '../sxa.component';
|
|
4
|
+
import { Subscription } from 'rxjs';
|
|
5
|
+
import { JssContextService } from '../../jss-context.service';
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: 'app-title',
|
|
9
|
+
templateUrl: './title.component.html',
|
|
10
|
+
host: {
|
|
11
|
+
'class': 'component title',
|
|
12
|
+
'[class]': 'styles',
|
|
13
|
+
'[id]': 'id',
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
export class TitleComponent extends SxaComponent<SxaTitleFields> implements OnInit, OnDestroy {
|
|
17
|
+
text: TextField;
|
|
18
|
+
link: LinkField;
|
|
19
|
+
pageEditing?: boolean;
|
|
20
|
+
|
|
21
|
+
private contextSubscription: Subscription;
|
|
22
|
+
|
|
23
|
+
constructor(private jssContext: JssContextService) {
|
|
24
|
+
super();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
ngOnInit() {
|
|
28
|
+
super.ngOnInit();
|
|
29
|
+
const datasource =
|
|
30
|
+
this.rendering.fields?.data?.datasource || this.rendering.fields?.data?.contextItem;
|
|
31
|
+
this.text = datasource.field?.jsonValue;
|
|
32
|
+
this.link = {
|
|
33
|
+
value: {
|
|
34
|
+
href: datasource?.url?.path,
|
|
35
|
+
title: datasource?.field?.jsonValue?.value,
|
|
36
|
+
text: datasource?.field?.jsonValue?.value,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
this.contextSubscription = this.jssContext.state.subscribe(({ sitecore }) => {
|
|
40
|
+
this.pageEditing = sitecore.context.pageEditing;
|
|
41
|
+
if (sitecore.context.pageState !== 'normal') {
|
|
42
|
+
this.link.value.querystring = `sc_site=${datasource?.url?.siteName}`;
|
|
43
|
+
if (!this.text?.value) {
|
|
44
|
+
this.text.value = 'Title field';
|
|
45
|
+
this.link.value.href = '#';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
ngOnDestroy() {
|
|
52
|
+
if (this.contextSubscription) {
|
|
53
|
+
this.contextSubscription.unsubscribe();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Inject, Injectable } from '@angular/core';
|
|
2
|
+
import { DOCUMENT } from '@angular/common';
|
|
3
|
+
import { HTMLLink } from '@sitecore-jss/sitecore-jss-angular';
|
|
4
|
+
|
|
5
|
+
@Injectable({
|
|
6
|
+
providedIn: 'root',
|
|
7
|
+
})
|
|
8
|
+
export class JssLinkService {
|
|
9
|
+
constructor(@Inject(DOCUMENT) private document: Document) {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Adds link element in the document head.
|
|
13
|
+
* @param headLinks - An array of HTMLLink objects to add to the head.
|
|
14
|
+
*/
|
|
15
|
+
addHeadLinks(headLink: HTMLLink) {
|
|
16
|
+
if (!headLink) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Check if a link with the same rel and href already exists
|
|
21
|
+
if (this.isDuplicateLink(headLink)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
this.createLink(headLink);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new link element and appends it to the head.
|
|
30
|
+
* @param headLink - An HTMLLink object to be added.
|
|
31
|
+
*/
|
|
32
|
+
private createLink(headLink: HTMLLink) {
|
|
33
|
+
if (!headLink.rel || !headLink.href) {
|
|
34
|
+
console.log('Invalid link object:', headLink);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const link: HTMLLinkElement = this.document.createElement('link');
|
|
39
|
+
link.setAttribute('rel', headLink.rel);
|
|
40
|
+
link.setAttribute('href', headLink.href);
|
|
41
|
+
this.document.head.appendChild(link);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Checks for an existing link element with the same rel and href attributes.
|
|
46
|
+
* @param headLink - An HTMLLink object to be checked.
|
|
47
|
+
* @returns {boolean} - True if a matching link exists, false otherwise.
|
|
48
|
+
*/
|
|
49
|
+
private isDuplicateLink(headLink: HTMLLink): boolean {
|
|
50
|
+
const existingLink = this.document.head.querySelector(
|
|
51
|
+
`link[rel='${headLink.rel}'][href='${headLink.href}']`
|
|
52
|
+
);
|
|
53
|
+
return !!existingLink;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GraphQLRequestClientFactoryConfig,
|
|
3
|
+
getEdgeProxyContentUrl,
|
|
4
|
+
} from '@sitecore-jss/sitecore-jss-angular/cjs';
|
|
5
|
+
import { environment as env } from '../../../environments/environment';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Gets the configuration for the GraphQLRequestClientFactory
|
|
9
|
+
* @returns GraphQLRequestClientFactoryConfig
|
|
10
|
+
*/
|
|
11
|
+
export const getGraphQLClientFactoryConfig = () => {
|
|
12
|
+
let clientConfig: GraphQLRequestClientFactoryConfig;
|
|
13
|
+
|
|
14
|
+
// Server side requests should go directly to the Sitecore, browser requests should go through the proxy.
|
|
15
|
+
const isServer = typeof window === 'undefined';
|
|
16
|
+
// If we are in a production environment we are going to use Node XM Cloud proxy
|
|
17
|
+
const isProduction = env.production === 'true';
|
|
18
|
+
|
|
19
|
+
if (isProduction) {
|
|
20
|
+
if (!env.proxyHost) {
|
|
21
|
+
throw new Error('Please configure your proxyHost.');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (env.sitecoreEdgeContextId) {
|
|
25
|
+
clientConfig = {
|
|
26
|
+
endpoint: isServer
|
|
27
|
+
? getEdgeProxyContentUrl(env.sitecoreEdgeContextId, env.sitecoreEdgeUrl)
|
|
28
|
+
: getEdgeProxyContentUrl(env.sitecoreEdgeContextId, env.proxyHost),
|
|
29
|
+
};
|
|
30
|
+
} else if (env.graphQLEndpoint && env.sitecoreApiKey) {
|
|
31
|
+
const graphQLEndpointPath = new URL(env.graphQLEndpoint).pathname;
|
|
32
|
+
|
|
33
|
+
clientConfig = {
|
|
34
|
+
endpoint: isServer ? env.graphQLEndpoint : `${env.proxyHost}${graphQLEndpointPath}`,
|
|
35
|
+
apiKey: env.sitecoreApiKey,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
if (env.sitecoreEdgeContextId) {
|
|
40
|
+
clientConfig = {
|
|
41
|
+
endpoint: getEdgeProxyContentUrl(env.sitecoreEdgeContextId, env.sitecoreEdgeUrl),
|
|
42
|
+
};
|
|
43
|
+
} else if (env.graphQLEndpoint && env.sitecoreApiKey) {
|
|
44
|
+
clientConfig = {
|
|
45
|
+
endpoint: env.graphQLEndpoint,
|
|
46
|
+
apiKey: env.sitecoreApiKey,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!clientConfig?.endpoint) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
'Please configure either your sitecoreEdgeContextId, or your graphQLEndpoint and sitecoreApiKey.'
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return clientConfig;
|
|
58
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<div class="{{ mainClassPageEditing }}">
|
|
2
|
+
<ng-container *ngIf="state === LayoutState.Layout">
|
|
3
|
+
<app-scripts></app-scripts>
|
|
4
|
+
<header>
|
|
5
|
+
<div id="header">
|
|
6
|
+
<sc-placeholder
|
|
7
|
+
name="headless-header"
|
|
8
|
+
[rendering]="route"
|
|
9
|
+
(loaded)="onPlaceholderLoaded($event)"
|
|
10
|
+
></sc-placeholder>
|
|
11
|
+
</div>
|
|
12
|
+
</header>
|
|
13
|
+
<main>
|
|
14
|
+
<div id="content">
|
|
15
|
+
<sc-placeholder
|
|
16
|
+
name="headless-main"
|
|
17
|
+
[rendering]="route"
|
|
18
|
+
(loaded)="onPlaceholderLoaded($event)"
|
|
19
|
+
></sc-placeholder>
|
|
20
|
+
</div>
|
|
21
|
+
</main>
|
|
22
|
+
<footer>
|
|
23
|
+
<div id="footer">
|
|
24
|
+
<sc-placeholder
|
|
25
|
+
name="headless-footer"
|
|
26
|
+
[rendering]="route"
|
|
27
|
+
(loaded)="onPlaceholderLoaded($event)"
|
|
28
|
+
></sc-placeholder>
|
|
29
|
+
</div>
|
|
30
|
+
</footer>
|
|
31
|
+
</ng-container>
|
|
32
|
+
|
|
33
|
+
<app-not-found
|
|
34
|
+
*ngIf="state === LayoutState.NotFound"
|
|
35
|
+
[errorContextData]="errorContextData"
|
|
36
|
+
></app-not-found>
|
|
37
|
+
<app-server-error *ngIf="state === LayoutState.Error"></app-server-error>
|
|
38
|
+
</div>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* eslint-disable no-shadow, no-console */
|
|
2
|
+
import { Component, OnInit, OnDestroy } from '@angular/core';
|
|
3
|
+
import {
|
|
4
|
+
RouteData,
|
|
5
|
+
Field,
|
|
6
|
+
LayoutServiceContextData,
|
|
7
|
+
getContentStylesheetLink,
|
|
8
|
+
} from '@sitecore-jss/sitecore-jss-angular';
|
|
9
|
+
import { ActivatedRoute } from '@angular/router';
|
|
10
|
+
import { Subscription } from 'rxjs';
|
|
11
|
+
import { JssState } from '../../JssState';
|
|
12
|
+
import { JssMetaService } from '../../jss-meta.service';
|
|
13
|
+
import { JssLinkService } from '../../jss-link.service';
|
|
14
|
+
import { environment as env } from '../../../environments/environment';
|
|
15
|
+
|
|
16
|
+
enum LayoutState {
|
|
17
|
+
Layout,
|
|
18
|
+
NotFound,
|
|
19
|
+
Error,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface RouteFields {
|
|
23
|
+
[name: string]: unknown;
|
|
24
|
+
pageTitle?: Field<string>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@Component({
|
|
28
|
+
selector: 'app-layout',
|
|
29
|
+
templateUrl: './layout.component.html',
|
|
30
|
+
})
|
|
31
|
+
export class LayoutComponent implements OnInit, OnDestroy {
|
|
32
|
+
route: RouteData<RouteFields>;
|
|
33
|
+
state: LayoutState;
|
|
34
|
+
LayoutState = LayoutState;
|
|
35
|
+
subscription: Subscription;
|
|
36
|
+
errorContextData: LayoutServiceContextData;
|
|
37
|
+
mainClassPageEditing: string;
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
private activatedRoute: ActivatedRoute,
|
|
41
|
+
private readonly meta: JssMetaService,
|
|
42
|
+
private linkService: JssLinkService
|
|
43
|
+
) {}
|
|
44
|
+
|
|
45
|
+
ngOnInit() {
|
|
46
|
+
// route data is populated by the JssRouteResolver
|
|
47
|
+
this.subscription = this.activatedRoute.data.subscribe((data: { jssState: JssState }) => {
|
|
48
|
+
if (!data.jssState) {
|
|
49
|
+
this.state = LayoutState.NotFound;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (data.jssState.sitecore && data.jssState.sitecore.route) {
|
|
54
|
+
this.route = data.jssState.sitecore.route;
|
|
55
|
+
this.setMetadata(this.route.fields);
|
|
56
|
+
this.state = LayoutState.Layout;
|
|
57
|
+
this.mainClassPageEditing = data.jssState.sitecore.context.pageEditing
|
|
58
|
+
? 'editing-mode'
|
|
59
|
+
: 'prod-mode';
|
|
60
|
+
|
|
61
|
+
const contentStyles = getContentStylesheetLink(
|
|
62
|
+
{ sitecore: data.jssState.sitecore },
|
|
63
|
+
env.sitecoreEdgeContextId,
|
|
64
|
+
env.sitecoreEdgeUrl
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (contentStyles) {
|
|
68
|
+
this.linkService.addHeadLinks(contentStyles);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (data.jssState.routeFetchError) {
|
|
73
|
+
if (
|
|
74
|
+
data.jssState.routeFetchError.status >= 400 &&
|
|
75
|
+
data.jssState.routeFetchError.status < 500
|
|
76
|
+
) {
|
|
77
|
+
this.state = LayoutState.NotFound;
|
|
78
|
+
} else {
|
|
79
|
+
this.state = LayoutState.Error;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.errorContextData =
|
|
83
|
+
data.jssState.routeFetchError.data && data.jssState.routeFetchError.data.sitecore;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
ngOnDestroy() {
|
|
89
|
+
// important to unsubscribe when the component is destroyed
|
|
90
|
+
this.subscription.unsubscribe();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setMetadata(routeFields: RouteFields) {
|
|
94
|
+
// set page title, if it exists
|
|
95
|
+
if (routeFields && routeFields.pageTitle) {
|
|
96
|
+
this.meta.setTitle(routeFields.pageTitle.value || 'Page');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
onPlaceholderLoaded(_placeholderName: string) {
|
|
101
|
+
// you may optionally hook to the loaded event for a placeholder,
|
|
102
|
+
// which can be useful for analytics and other DOM-based things that need to know when a placeholder's content is available.
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { ScriptsComponent } from './scripts.component';
|
|
3
|
+
import { JssModule } from '@sitecore-jss/sitecore-jss-angular';
|
|
4
|
+
|
|
5
|
+
@NgModule({
|
|
6
|
+
exports: [ScriptsComponent],
|
|
7
|
+
imports: [JssModule],
|
|
8
|
+
declarations: [ScriptsComponent],
|
|
9
|
+
})
|
|
10
|
+
export class ScriptsModule {}
|
|
@@ -13,7 +13,6 @@ class FallbackPlugin implements ConfigPlugin {
|
|
|
13
13
|
async exec(config: JssConfig) {
|
|
14
14
|
return Object.assign({}, config, {
|
|
15
15
|
defaultLanguage: config.defaultLanguage || 'en',
|
|
16
|
-
sitecoreApiKey: config.sitecoreApiKey || 'no-api-key-set',
|
|
17
16
|
layoutServiceConfigurationName: config.layoutServiceConfigurationName || 'default',
|
|
18
17
|
publicUrl: config.publicUrl || getPublicUrl(),
|
|
19
18
|
});
|
|
@@ -29,6 +29,11 @@ generateConfig(defaultConfig);
|
|
|
29
29
|
* @param {JssConfig} defaultConfig Default configuration.
|
|
30
30
|
*/
|
|
31
31
|
function generateConfig(defaultConfig: JssConfig): void {
|
|
32
|
+
// Handle undefined values
|
|
33
|
+
Object.keys(defaultConfig).forEach(prop => {
|
|
34
|
+
defaultConfig[prop] = defaultConfig[prop] || '';
|
|
35
|
+
}, {});
|
|
36
|
+
|
|
32
37
|
jssConfigFactory
|
|
33
38
|
.create(defaultConfig)
|
|
34
39
|
.then(config => {
|
|
@@ -53,7 +58,9 @@ const config = {};\n`;
|
|
|
53
58
|
|
|
54
59
|
// Set configuration values, allowing override with environment variables
|
|
55
60
|
Object.keys(config).forEach(prop => {
|
|
56
|
-
|
|
61
|
+
// Handle undefined values
|
|
62
|
+
const value = config[prop] || '';
|
|
63
|
+
configText += `config.${prop} = process.env.${constantCase(prop)} || '${value.trim()}';\n`;
|
|
57
64
|
});
|
|
58
65
|
|
|
59
66
|
configText += `module.exports = config;`;
|
|
@@ -7,7 +7,8 @@ import { Plugin, isServerSidePropsContext } from '..';
|
|
|
7
7
|
class ComponentPropsPlugin implements Plugin {
|
|
8
8
|
private componentPropsService: ComponentPropsService;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// Make sure to run this plugin last to ensure that the updated layout data is used
|
|
11
|
+
order = 10;
|
|
11
12
|
|
|
12
13
|
constructor() {
|
|
13
14
|
this.componentPropsService = new ComponentPropsService();
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import {
|
|
3
2
|
ComponentParams,
|
|
4
3
|
ComponentRendering,
|
|
5
4
|
Placeholder,
|
|
6
|
-
useSitecoreContext,
|
|
7
5
|
} from '@sitecore-jss/sitecore-jss-nextjs';
|
|
8
|
-
|
|
9
|
-
const BACKGROUND_REG_EXP = new RegExp(
|
|
10
|
-
/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/gi
|
|
11
|
-
);
|
|
6
|
+
import React from 'react';
|
|
12
7
|
|
|
13
8
|
interface ComponentProps {
|
|
14
9
|
rendering: ComponentRendering & { params: ComponentParams };
|
|
@@ -16,22 +11,19 @@ interface ComponentProps {
|
|
|
16
11
|
}
|
|
17
12
|
|
|
18
13
|
const DefaultContainer = (props: ComponentProps): JSX.Element => {
|
|
19
|
-
const { sitecoreContext } = useSitecoreContext();
|
|
20
14
|
const containerStyles = props.params && props.params.Styles ? props.params.Styles : '';
|
|
21
15
|
const styles = `${props.params.GridParameters} ${containerStyles}`.trimEnd();
|
|
22
16
|
const phKey = `container-${props.params.DynamicPlaceholderId}`;
|
|
23
17
|
const id = props.params.RenderingIdentifier;
|
|
18
|
+
const mediaUrlPattern = new RegExp(/mediaurl=\"([^"]*)\"/, 'i');
|
|
24
19
|
let backgroundImage = props.params.BackgroundImage as string;
|
|
25
20
|
let backgroundStyle: { [key: string]: string } = {};
|
|
26
21
|
|
|
27
|
-
if (backgroundImage) {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
?.match(BACKGROUND_REG_EXP)
|
|
31
|
-
?.pop()
|
|
32
|
-
?.replace(/-/gi, '')}`;
|
|
22
|
+
if (backgroundImage && backgroundImage.match(mediaUrlPattern)) {
|
|
23
|
+
const mediaUrl = backgroundImage.match(mediaUrlPattern)?.[1] || '';
|
|
24
|
+
|
|
33
25
|
backgroundStyle = {
|
|
34
|
-
backgroundImage: `url('${
|
|
26
|
+
backgroundImage: `url('${mediaUrl}')`,
|
|
35
27
|
};
|
|
36
28
|
}
|
|
37
29
|
|