create-sitecore-jss 22.2.0-canary.3 → 22.2.0-canary.31

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.
Files changed (158) hide show
  1. package/dist/bin.js +17 -42
  2. package/dist/common/index.js +5 -3
  3. package/dist/common/processes/install.js +1 -1
  4. package/dist/common/processes/next.js +6 -3
  5. package/dist/common/processes/transform.js +19 -19
  6. package/dist/common/prompts/base.js +0 -25
  7. package/dist/common/prompts/proxy.js +35 -0
  8. package/dist/common/prompts/sxp.js +34 -0
  9. package/dist/common/utils/helpers.js +29 -19
  10. package/dist/init-runner.js +6 -3
  11. package/dist/initializers/angular/index.js +0 -3
  12. package/dist/initializers/angular/prompts.js +6 -6
  13. package/dist/initializers/angular-sxp/index.js +8 -2
  14. package/dist/initializers/angular-xmcloud/index.js +28 -4
  15. package/dist/initializers/nextjs/index.js +2 -2
  16. package/dist/initializers/nextjs/prompts.js +2 -0
  17. package/dist/initializers/nextjs/remove-dev-dependencies.js +2 -2
  18. package/dist/initializers/nextjs-multisite/index.js +1 -1
  19. package/dist/initializers/nextjs-styleguide/index.js +1 -1
  20. package/dist/initializers/nextjs-styleguide-tracking/index.js +1 -1
  21. package/dist/initializers/nextjs-sxa/index.js +1 -1
  22. package/dist/initializers/nextjs-xmcloud/index.js +1 -1
  23. package/dist/initializers/node-xmcloud-proxy/index.js +2 -1
  24. package/dist/initializers/react/index.js +3 -3
  25. package/dist/initializers/react/prompts.js +1 -1
  26. package/dist/initializers/react-native/prompts.js +1 -0
  27. package/dist/initializers/vue/prompts.js +1 -1
  28. package/dist/templates/angular/.env +4 -5
  29. package/dist/templates/angular/package.json +0 -2
  30. package/dist/templates/angular/scripts/config/plugins/fallback.ts +0 -1
  31. package/dist/templates/angular/scripts/generate-config.ts +25 -6
  32. package/dist/templates/angular/scripts/update-graphql-fragment-data.ts +21 -30
  33. package/dist/templates/angular/server.bundle.ts +4 -5
  34. package/dist/templates/angular/src/app/JssState.ts +3 -6
  35. package/dist/templates/angular/src/app/lib/dictionary-service-factory.ts +4 -1
  36. package/dist/templates/angular/src/app/lib/graphql-client-factory/config.ts +21 -0
  37. package/dist/templates/angular/src/app/lib/graphql-client-factory/index.ts +16 -0
  38. package/dist/templates/angular/src/app/lib/layout-service-factory.ts +1 -1
  39. package/dist/templates/angular/src/app/routing/layout/layout.component.ts +10 -9
  40. package/dist/templates/angular-sxp/.env +2 -0
  41. package/dist/templates/angular-sxp/scripts/config/plugins/disconnected.ts +4 -2
  42. package/dist/templates/angular-xmcloud/.env +7 -1
  43. package/dist/templates/angular-xmcloud/angular.json +34 -0
  44. package/dist/templates/angular-xmcloud/package.json +15 -10
  45. package/dist/templates/angular-xmcloud/scripts/config/plugins/xmcloud.ts +16 -0
  46. package/dist/templates/angular-xmcloud/src/app/components/column-splitter/column-splitter.component.html +10 -0
  47. package/dist/templates/angular-xmcloud/src/app/components/column-splitter/column-splitter.component.ts +35 -0
  48. package/dist/templates/angular-xmcloud/src/app/components/container/container.component.html +15 -0
  49. package/dist/templates/angular-xmcloud/src/app/components/container/container.component.ts +30 -0
  50. package/dist/templates/angular-xmcloud/src/app/components/image/image.component.html +36 -0
  51. package/dist/templates/angular-xmcloud/src/app/components/image/image.component.ts +67 -0
  52. package/dist/templates/angular-xmcloud/src/app/components/link-list/link-list.component.html +17 -0
  53. package/dist/templates/angular-xmcloud/src/app/components/link-list/link-list.component.ts +36 -0
  54. package/dist/templates/angular-xmcloud/src/app/components/richtext/richtext.component.html +13 -0
  55. package/dist/templates/angular-xmcloud/src/app/components/richtext/richtext.component.ts +16 -0
  56. package/dist/templates/angular-xmcloud/src/app/components/sxa.component.ts +15 -0
  57. package/dist/templates/angular-xmcloud/src/app/jss-link.service.ts +55 -0
  58. package/dist/templates/angular-xmcloud/src/app/lib/config.ts +2 -0
  59. package/dist/templates/angular-xmcloud/src/app/lib/graphql-client-factory/config.ts +58 -0
  60. package/dist/templates/angular-xmcloud/src/app/routing/layout/layout.component.html +39 -0
  61. package/dist/templates/angular-xmcloud/src/app/routing/layout/layout.component.ts +104 -0
  62. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_component.scss +48 -0
  63. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_container.scss +64 -0
  64. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_fonts.scss +3 -0
  65. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_footer.scss +31 -0
  66. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_header.scss +49 -0
  67. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_navigation.scss +150 -0
  68. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_promo.scss +58 -0
  69. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_rich-text.scss +11 -0
  70. package/dist/templates/angular-xmcloud/src/assets/styles/basic/_variables.scss +10 -0
  71. package/dist/templates/angular-xmcloud/src/assets/styles/basic/main.scss +8 -0
  72. package/dist/templates/angular-xmcloud/src/assets/styles/main.scss +4 -0
  73. package/dist/templates/angular-xmcloud/src/assets/styles/sass/_app.scss +103 -0
  74. package/dist/templates/angular-xmcloud/src/assets/styles/sass/abstracts/_functions.scss +8 -0
  75. package/dist/templates/angular-xmcloud/src/assets/styles/sass/abstracts/_mixins.scss +121 -0
  76. package/dist/templates/angular-xmcloud/src/assets/styles/sass/abstracts/_vars.scss +3 -0
  77. package/dist/templates/angular-xmcloud/src/assets/styles/sass/abstracts/vars/_colors.scss +283 -0
  78. package/dist/templates/angular-xmcloud/src/assets/styles/sass/abstracts/vars/_fontSizes.scss +16 -0
  79. package/dist/templates/angular-xmcloud/src/assets/styles/sass/abstracts/vars/_margins.scss +11 -0
  80. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/fonts/_fonts.scss +1 -0
  81. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/fonts/index.scss +1 -0
  82. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/index.scss +3 -0
  83. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/links/_link-button.scss +26 -0
  84. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/links/index.scss +1 -0
  85. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/reset/_inputs.scss +58 -0
  86. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/reset/_links.scss +14 -0
  87. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/reset/_ui-datepicker.scss +7 -0
  88. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/richtext/_richtext-files-icons.scss +86 -0
  89. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/richtext/_richtext.scss +101 -0
  90. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/richtext/index.scss +2 -0
  91. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/typehead/_typehead.scss +95 -0
  92. package/dist/templates/angular-xmcloud/src/assets/styles/sass/base/typehead/index.scss +1 -0
  93. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/_component-column-splitter.scss +14 -0
  94. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/_component-container.scss +27 -0
  95. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/_component-image.scss +18 -0
  96. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/_component-navigation.scss +51 -0
  97. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/_component-promo.scss +42 -0
  98. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/_component-richtext-content.scss +19 -0
  99. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/common/_alignment.scss +26 -0
  100. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/common/_boxed.scss +16 -0
  101. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/common/_clearfix.scss +11 -0
  102. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/common/_highlighted.scss +63 -0
  103. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/common/_link-button.scss +16 -0
  104. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/common/_promoted-box.scss +3 -0
  105. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/common/index.scss +6 -0
  106. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/container/_bordered.scss +24 -0
  107. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/container/_title-row-box.scss +66 -0
  108. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/container/index.scss +1 -0
  109. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/image/_image-default-size.scss +6 -0
  110. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/image/index.scss +1 -0
  111. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/image-alignment/_image-left.scss +3 -0
  112. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/image-alignment/_image-right.scss +3 -0
  113. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/index.scss +17 -0
  114. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/layout/_acaindent.scss +5 -0
  115. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/layout/_background.scss +27 -0
  116. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/layout/index.scss +1 -0
  117. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/link-list/_component-link-list.scss +45 -0
  118. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/link-list/_list-vertical.scss +20 -0
  119. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/link-list/index.scss +2 -0
  120. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/navigation/_navigation-fat.scss +58 -0
  121. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/navigation/_navigation-main-horizontal-vertical.scss +176 -0
  122. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/navigation/_navigation-mobile.scss +85 -0
  123. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/navigation/_navigation-sidebar.scss +29 -0
  124. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/navigation/_sitemap-navigation.scss +20 -0
  125. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/navigation/index.scss +5 -0
  126. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/promo/_absolute-bottom-link.scss +8 -0
  127. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/promo/_promo-hero.scss +40 -0
  128. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/promo/_promo-shadow.scss +42 -0
  129. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/promo/index.scss +3 -0
  130. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/rich-text/_rich-text-lists.scss +63 -0
  131. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/rich-text/index.scss +1 -0
  132. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/spacing/_background-colors.scss +14 -0
  133. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/spacing/_indent.scss +13 -0
  134. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/spacing/index.scss +2 -0
  135. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/title/_component-title.scss +30 -0
  136. package/dist/templates/angular-xmcloud/src/assets/styles/sass/components/title/index.scss +1 -0
  137. package/dist/templates/angular-xmcloud/src/assets/styles/sass/main.scss +4 -0
  138. package/dist/templates/angular-xmcloud/src/assets/styles/sass/variants/index.scss +6 -0
  139. package/dist/templates/angular-xmcloud/src/assets/styles/sass/variants/link-list/index.scss +0 -0
  140. package/dist/templates/angular-xmcloud/src/assets/styles/sass/variants/navigation/index.scss +0 -0
  141. package/dist/templates/angular-xmcloud/src/assets/styles/sass/variants/page-content/index.scss +0 -0
  142. package/dist/templates/angular-xmcloud/src/assets/styles/sass/variants/promo/index.scss +0 -0
  143. package/dist/templates/angular-xmcloud/src/assets/styles/sass/variants/rich-text/index.scss +0 -0
  144. package/dist/templates/angular-xmcloud/src/assets/styles/sass/variants/title/index.scss +0 -0
  145. package/dist/templates/nextjs/scripts/config/plugins/fallback.ts +0 -1
  146. package/dist/templates/nextjs/scripts/generate-config.ts +8 -1
  147. package/dist/templates/nextjs-styleguide/scripts/config/plugins/disconnected.ts +1 -0
  148. package/dist/templates/nextjs-sxa/src/assets/sass/components/_component-image.scss +1 -1
  149. package/dist/templates/nextjs-sxa/src/components/Container.tsx +6 -14
  150. package/dist/templates/node-xmcloud-proxy/package.json +2 -2
  151. package/dist/templates/node-xmcloud-proxy/src/config.ts +8 -2
  152. package/dist/templates/node-xmcloud-proxy/src/index.ts +28 -4
  153. package/dist/templates/node-xmcloud-proxy/src/types.ts +5 -3
  154. package/dist/templates/react/scripts/generate-config.js +10 -3
  155. package/dist/templates/vue/scripts/generate-config.js +5 -0
  156. package/package.json +2 -2
  157. package/dist/templates/angular/src/app/lib/graphql-client-factory.ts +0 -28
  158. package/dist/templates/angular-xmcloud/src/app/lib/graphql-client-factory.ts +0 -44
@@ -0,0 +1,30 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { SxaComponent } from '../sxa.component';
3
+
4
+ @Component({
5
+ selector: 'app-container',
6
+ templateUrl: './container.component.html',
7
+ })
8
+ export class ContainerComponent extends SxaComponent implements OnInit {
9
+ placeholderName: string;
10
+ wrapped: boolean;
11
+
12
+ override ngOnInit() {
13
+ super.ngOnInit();
14
+
15
+ this.placeholderName = `container-${this.rendering.params?.DynamicPlaceholderId}`;
16
+ this.wrapped = this.rendering.params?.Styles?.split(' ').includes('container');
17
+ }
18
+
19
+ get backgroundStyle() {
20
+ const backgroundImage = this.rendering.params?.BackgroundImage;
21
+ const mediaUrlPattern = new RegExp(/mediaurl=\"([^"]*)\"/, 'i');
22
+ if (!backgroundImage || !backgroundImage.match(mediaUrlPattern)) {
23
+ return {};
24
+ }
25
+ const mediaUrl = backgroundImage.match(mediaUrlPattern)[1];
26
+ return {
27
+ backgroundImage: `url('${mediaUrl}')`,
28
+ };
29
+ }
30
+ }
@@ -0,0 +1,36 @@
1
+ <ng-container [ngTemplateOutlet]="variant"></ng-container>
2
+
3
+ <ng-template #default>
4
+ <div class="component image {{ styles }}" [attr.id]="id" *ngIf="rendering.fields; else empty">
5
+ <div className="component-content">
6
+ <ng-container *ngIf="isEditing || !rendering.fields.TargetUrl?.value?.href; else withLink">
7
+ <img *scImage="rendering.fields.Image" />
8
+ </ng-container>
9
+ <span class="image-caption field-imagecaption" *scText="rendering.fields.ImageCaption"></span>
10
+ </div>
11
+ </div>
12
+ </ng-template>
13
+
14
+ <ng-template #banner>
15
+ <div class="component hero-banner {{ styles }} {{ classHeroBannerEmpty }}" [attr.id]="id">
16
+ <div class="component-content sc-sxa-image-hero-banner" [ngStyle]="backgroundStyle">
17
+ <ng-container *ngIf="isEditing">
18
+ <img *scImage="modifyImageProps" />
19
+ </ng-container>
20
+ </div>
21
+ </div>
22
+ </ng-template>
23
+
24
+ <ng-template #withLink>
25
+ <a *scLink="rendering.fields.TargetUrl">
26
+ <img *scImage="rendering.fields.Image" />
27
+ </a>
28
+ </ng-template>
29
+
30
+ <ng-template #empty>
31
+ <div className="component image {{ styles }}">
32
+ <div class="component-content">
33
+ <span class="is-empty-hint">Image</span>
34
+ </div>
35
+ </div>
36
+ </ng-template>
@@ -0,0 +1,67 @@
1
+ import { Component, OnInit, OnDestroy, ViewChild, TemplateRef } from '@angular/core';
2
+ import { Subscription } from 'rxjs';
3
+ import { EditMode, ImageField } from '@sitecore-jss/sitecore-jss-angular';
4
+ import { SxaComponent } from '../sxa.component';
5
+ import { JssContextService } from '../../jss-context.service';
6
+
7
+ @Component({
8
+ selector: 'app-image',
9
+ templateUrl: './image.component.html',
10
+ })
11
+ export class ImageComponent extends SxaComponent implements OnInit, OnDestroy {
12
+ @ViewChild('default', { static: true }) defaultVariant: TemplateRef<any>;
13
+ @ViewChild('banner', { static: true }) bannerVariant: TemplateRef<any>;
14
+ classHeroBannerEmpty = '';
15
+ backgroundStyle = {};
16
+ modifyImageProps = {};
17
+ isEditing = false;
18
+ private contextSubscription: Subscription;
19
+
20
+ constructor(private jssContext: JssContextService) {
21
+ super();
22
+ }
23
+
24
+ ngOnInit() {
25
+ super.ngOnInit();
26
+
27
+ const imageField = this.rendering.fields?.Image as ImageField;
28
+ this.backgroundStyle = imageField?.value?.src && {
29
+ 'background-image': `url('${imageField.value.src}')`,
30
+ };
31
+
32
+ this.contextSubscription = this.jssContext.state.subscribe((newState) => {
33
+ this.isEditing = newState.sitecore && newState.sitecore.context.pageEditing;
34
+
35
+ this.classHeroBannerEmpty =
36
+ this.isEditing && imageField?.value?.class === 'scEmptyImage' ? 'hero-banner-empty' : '';
37
+
38
+ const isMetadataMode = newState.sitecore?.context?.editMode === EditMode.Metadata;
39
+ this.modifyImageProps = !isMetadataMode
40
+ ? {
41
+ ...imageField,
42
+ editable: imageField?.editable
43
+ ?.replace(`width="${imageField?.value?.width}"`, 'width="100%"')
44
+ .replace(`height="${imageField?.value?.height}"`, 'height="100%"'),
45
+ }
46
+ : {
47
+ ...imageField,
48
+ value: {
49
+ ...imageField?.value,
50
+ style: { width: '100%', height: '100%' },
51
+ },
52
+ };
53
+ });
54
+ }
55
+
56
+ ngOnDestroy() {
57
+ if (this.contextSubscription) {
58
+ this.contextSubscription.unsubscribe();
59
+ }
60
+ }
61
+
62
+ public get variant(): TemplateRef<any> {
63
+ return this.rendering.params?.FieldNames === 'Banner'
64
+ ? this.bannerVariant
65
+ : this.defaultVariant;
66
+ }
67
+ }
@@ -0,0 +1,17 @@
1
+ <div class="component link-list {{ styles }}" [attr.id]="id">
2
+ <div class="component-content">
3
+ <ng-container *ngIf="title; else defaultTitle">
4
+ <h3 *scText="title"></h3>
5
+ </ng-container>
6
+ <ul>
7
+ <li *ngFor="let fieldLink of fieldLinks;index as i" [ngClass]="getFieldLinkClass(i)" >
8
+ <div class="field-link">
9
+ <a *scLink="fieldLink"></a>
10
+ </div>
11
+ </li>
12
+ </ul>
13
+ </div>
14
+ <ng-template #defaultTitle>
15
+ <span class="is-empty-hint">Link list</span>
16
+ </ng-template>
17
+ </div>
@@ -0,0 +1,36 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { SxaComponent } from '../sxa.component';
3
+ import { Field, LinkField, SxaLinkListFields } from '@sitecore-jss/sitecore-jss-angular';
4
+
5
+ @Component({
6
+ selector: 'app-link-list',
7
+ templateUrl: './link-list.component.html',
8
+ })
9
+ export class LinkListComponent extends SxaComponent<SxaLinkListFields> implements OnInit {
10
+ title?: Field<string>;
11
+ fieldLinks: LinkField[] = [];
12
+
13
+ getFieldLinkClass(index: number): string {
14
+ let className = `item${index}`;
15
+ className += (index + 1) % 2 == 0 ? ' even' : ' odd';
16
+ if (index === 0) {
17
+ className += ' first';
18
+ }
19
+ if (index + 1 === this.fieldLinks.length) {
20
+ className += ' last';
21
+ }
22
+ return className;
23
+ }
24
+
25
+ ngOnInit() {
26
+ super.ngOnInit();
27
+ const datasource = this.rendering.fields?.data?.datasource;
28
+ if (datasource) {
29
+ this.title = datasource.field?.title as Field<string>;
30
+ datasource.children.results.forEach(item => {
31
+ if (item.field?.link)
32
+ this.fieldLinks.push(item.field.link as LinkField);
33
+ });
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,13 @@
1
+ <div
2
+ class="component rich-text {{ styles }}"
3
+ [attr.id]="id"
4
+ >
5
+ <div class="component-content">
6
+ <ng-container *ngIf="text; else emptyHint">
7
+ <div *scRichText="text"></div>
8
+ </ng-container>
9
+ <ng-template #emptyHint>
10
+ <span class="is-empty-hint">Rich text</span>
11
+ </ng-template>
12
+ </div>
13
+ </div>
@@ -0,0 +1,16 @@
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { Field } from '@sitecore-jss/sitecore-jss-angular';
3
+ import { SxaComponent } from '../sxa.component';
4
+
5
+ @Component({
6
+ selector: 'app-richtext',
7
+ templateUrl: './richtext.component.html',
8
+ })
9
+ export class RichTextComponent extends SxaComponent implements OnInit {
10
+ text?: Field<string>;
11
+
12
+ ngOnInit() {
13
+ super.ngOnInit();
14
+ this.text = this.rendering.fields?.Text as Field<string>;
15
+ }
16
+ }
@@ -0,0 +1,15 @@
1
+ import { OnInit, Input, Directive } from '@angular/core';
2
+ import { ComponentFields, ComponentRendering } from '@sitecore-jss/sitecore-jss-angular';
3
+
4
+ @Directive()
5
+ export abstract class SxaComponent<FieldType = ComponentFields> implements OnInit {
6
+ @Input() rendering: ComponentRendering<FieldType>;
7
+
8
+ id?: string;
9
+ styles?: string;
10
+
11
+ ngOnInit() {
12
+ this.id = this.rendering.params?.RenderingIdentifier;
13
+ this.styles = this.rendering.params?.styles;
14
+ }
15
+ }
@@ -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
+ }
@@ -12,4 +12,6 @@ export interface JssConfig extends Record<string, string | boolean | undefined>
12
12
  defaultServerRoute?: string;
13
13
  proxyBuildPath?: string;
14
14
  proxyHost?: string;
15
+ sitecoreEdgeUrl?: string;
16
+ sitecoreEdgeContextId?: string;
15
17
  }
@@ -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,39 @@
1
+ <app-navigation></app-navigation>
2
+ <div class="{{ mainClassPageEditing }}">
3
+ <ng-container *ngIf="state === LayoutState.Layout">
4
+ <app-scripts></app-scripts>
5
+ <header>
6
+ <div id="header">
7
+ <sc-placeholder
8
+ name="headless-header"
9
+ [rendering]="route"
10
+ (loaded)="onPlaceholderLoaded($event)"
11
+ ></sc-placeholder>
12
+ </div>
13
+ </header>
14
+ <main>
15
+ <div id="content">
16
+ <sc-placeholder
17
+ name="headless-main"
18
+ [rendering]="route"
19
+ (loaded)="onPlaceholderLoaded($event)"
20
+ ></sc-placeholder>
21
+ </div>
22
+ </main>
23
+ <footer>
24
+ <div id="footer">
25
+ <sc-placeholder
26
+ name="headless-footer"
27
+ [rendering]="route"
28
+ (loaded)="onPlaceholderLoaded($event)"
29
+ ></sc-placeholder>
30
+ </div>
31
+ </footer>
32
+ </ng-container>
33
+
34
+ <app-not-found
35
+ *ngIf="state === LayoutState.NotFound"
36
+ [errorContextData]="errorContextData"
37
+ ></app-not-found>
38
+ <app-server-error *ngIf="state === LayoutState.Error"></app-server-error>
39
+ </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,48 @@
1
+ .component-content {
2
+ @include respond-to(mobile-large) {
3
+ .row {
4
+ padding: 0;
5
+ margin: 0;
6
+ }
7
+ }
8
+ }
9
+ @include respond-to(mobile-large) {
10
+ .row {
11
+ margin: 0;
12
+ padding: 0;
13
+ > * {
14
+ padding: 0;
15
+ margin: 0;
16
+ }
17
+ }
18
+ }
19
+
20
+ .hero-banner {
21
+ .component-content {
22
+ background-position: center;
23
+ background-repeat: no-repeat;
24
+ background-size: cover;
25
+ height: 800px;
26
+
27
+ @include respond-to(mobile-large) {
28
+ height: 300px;
29
+ }
30
+ }
31
+ .sc-image-wrapper {
32
+ opacity: 0;
33
+ }
34
+ &.scEnabledChrome {
35
+ &.hero-banner-empty {
36
+ .sc-image-wrapper {
37
+ display: block;
38
+ width: 100%;
39
+
40
+ .scEmptyImage {
41
+ max-height: 800px;
42
+ max-width: 100%;
43
+ width: 100%;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,64 @@
1
+ @import "sass/abstracts/mixins";
2
+ @import "variables";
3
+
4
+ body {
5
+ font-family: Roboto;
6
+ color: $main-color;
7
+ }
8
+
9
+
10
+ @media (min-width: 1400px) {
11
+ .container {
12
+ max-width: 1250px;
13
+ }
14
+ }
15
+
16
+ main {
17
+ .main-header {
18
+ margin-top: 55px;
19
+ margin-bottom: 30px;
20
+
21
+ @include respond-to(mobile-large) {
22
+ margin-bottom: 0;
23
+ }
24
+
25
+ h4 {
26
+ font-size: $text-size-50;
27
+ font-weight: 500;
28
+ line-height: 70px;
29
+ }
30
+ }
31
+
32
+ .main-news-header {
33
+ margin-top: 60px;
34
+
35
+ h2 {
36
+ font-size: $text-size-36;
37
+ line-height: 43px;
38
+ }
39
+ }
40
+
41
+ @include respond-to(mobile-large) {
42
+ padding-top: 0;
43
+ margin-bottom: 0;
44
+
45
+ .main-header {
46
+ margin-top: 10px;
47
+
48
+ h4 {
49
+ font-size: $text-size-24;
50
+ line-height: 32px;
51
+ }
52
+ }
53
+
54
+ .main-news-header {
55
+ padding-bottom: 35px;
56
+
57
+ h2 {
58
+ margin-top: 0;
59
+ font-size: $text-size-18;
60
+ line-height: 22px;
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,3 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');
2
+ /* FontAwesome */
3
+ @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css');
@@ -0,0 +1,31 @@
1
+ @import "sass/abstracts/mixins";
2
+ @import "variables";
3
+
4
+ footer {
5
+ @include respond-to(mobile-large) {
6
+ padding-top: 0;
7
+ }
8
+ .container-dark-background {
9
+ background-color: #262626;
10
+ }
11
+
12
+ .contacts {
13
+ font-size: $text-size-14;
14
+
15
+ a {
16
+ color: $text-white;
17
+ }
18
+
19
+ p, span {
20
+ color: $text-white;
21
+ }
22
+ }
23
+
24
+ .indent-inner {
25
+ padding: 65px;
26
+
27
+ @include respond-to(mobile-large) {
28
+ padding: 40px 0;
29
+ }
30
+ }
31
+ }