create-content-sdk-app 2.0.0 → 2.0.1
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/templates/nextjs/.agents/skills/content-sdk-component-data-strategy/SKILL.md +37 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-component-registration/SKILL.md +36 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-component-scaffold/SKILL.md +34 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-component-variants/SKILL.md +36 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-dictionary-and-i18n/SKILL.md +35 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-editing-safe-rendering/SKILL.md +37 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-field-usage-image-link-text/SKILL.md +36 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-graphql-data-fetching/SKILL.md +38 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-multisite-management/SKILL.md +37 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-route-configuration/SKILL.md +38 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-site-setup-and-env/SKILL.md +36 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-sitemap-robots/SKILL.md +37 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-troubleshoot-editing/SKILL.md +39 -0
- package/dist/templates/nextjs/.agents/skills/content-sdk-upgrade-assistant/SKILL.md +36 -0
- package/dist/templates/nextjs/AGENTS.md +1 -0
- package/dist/templates/nextjs/CLAUDE.md +6 -170
- package/dist/templates/nextjs/Skills.md +79 -0
- package/dist/templates/nextjs/package.json +2 -2
- package/dist/templates/nextjs/src/Bootstrap.tsx +20 -13
- package/dist/templates/nextjs/src/byoc/index.tsx +1 -1
- package/dist/templates/nextjs/src/components/content-sdk/CdpPageView.tsx +1 -1
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-component-data-strategy/SKILL.md +37 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-component-registration/SKILL.md +38 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-component-scaffold/SKILL.md +38 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-component-variants/SKILL.md +36 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-dictionary-and-i18n/SKILL.md +37 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-editing-safe-rendering/SKILL.md +37 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-field-usage-image-link-text/SKILL.md +36 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-graphql-data-fetching/SKILL.md +37 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-multisite-management/SKILL.md +37 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-route-configuration/SKILL.md +38 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-site-setup-and-env/SKILL.md +36 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-sitemap-robots/SKILL.md +37 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-troubleshoot-editing/SKILL.md +39 -0
- package/dist/templates/nextjs-app-router/.agents/skills/content-sdk-upgrade-assistant/SKILL.md +36 -0
- package/dist/templates/nextjs-app-router/.sitecore/import-map.server.ts +2 -2
- package/dist/templates/nextjs-app-router/AGENTS.md +6 -6
- package/dist/templates/nextjs-app-router/CLAUDE.md +6 -271
- package/dist/templates/nextjs-app-router/README.md +0 -36
- package/dist/templates/nextjs-app-router/Skills.md +79 -0
- package/dist/templates/nextjs-app-router/package.json +3 -2
- package/dist/templates/nextjs-app-router/src/Bootstrap.tsx +20 -12
- package/dist/templates/nextjs-app-router/src/app/[site]/[locale]/[[...path]]/layout.tsx +19 -0
- package/dist/templates/nextjs-app-router/src/app/[site]/[locale]/[[...path]]/not-found.tsx +3 -28
- package/dist/templates/nextjs-app-router/src/app/[site]/[locale]/[[...path]]/page.tsx +6 -21
- package/dist/templates/nextjs-app-router/src/app/[site]/layout.tsx +5 -21
- package/dist/templates/nextjs-app-router/src/app/not-found.tsx +1 -23
- package/dist/templates/nextjs-app-router/src/byoc/index.tsx +1 -1
- package/dist/templates/nextjs-app-router/src/components/content-sdk/CdpPageView.tsx +1 -1
- package/package.json +2 -2
- package/dist/initializers/angular/args.js +0 -2
- package/dist/initializers/angular/index.js +0 -30
- package/dist/initializers/angular/prompts.js +0 -20
- package/dist/templates/angular/.postcssrc.json +0 -5
- package/dist/templates/angular/.vscode/extensions.json +0 -4
- package/dist/templates/angular/README.md +0 -3
- package/dist/templates/angular/angular.json +0 -79
- package/dist/templates/angular/package.json +0 -58
- package/dist/templates/angular/public/favicon.ico +0 -0
- package/dist/templates/angular/src/app/app.config.server.ts +0 -12
- package/dist/templates/angular/src/app/app.config.ts +0 -31
- package/dist/templates/angular/src/app/app.css +0 -0
- package/dist/templates/angular/src/app/app.html +0 -1
- package/dist/templates/angular/src/app/app.routes.server.ts +0 -15
- package/dist/templates/angular/src/app/app.routes.ts +0 -28
- package/dist/templates/angular/src/app/app.ts +0 -12
- package/dist/templates/angular/src/app/loaders/error.loader.ts +0 -12
- package/dist/templates/angular/src/app/loaders/index.ts +0 -14
- package/dist/templates/angular/src/app/loaders/not-found.loader.ts +0 -12
- package/dist/templates/angular/src/app/loaders/page.loader.ts +0 -15
- package/dist/templates/angular/src/app/loaders/stub-utils.ts +0 -83
- package/dist/templates/angular/src/app/pages/error.component.ts +0 -124
- package/dist/templates/angular/src/app/pages/not-found.component.ts +0 -85
- package/dist/templates/angular/src/app/pages/page.component.ts +0 -58
- package/dist/templates/angular/src/app/shared/layout.component.ts +0 -106
- package/dist/templates/angular/src/index.html +0 -13
- package/dist/templates/angular/src/main.server.ts +0 -8
- package/dist/templates/angular/src/main.ts +0 -6
- package/dist/templates/angular/src/server.ts +0 -65
- package/dist/templates/angular/src/styles.css +0 -3
- package/dist/templates/angular/tsconfig.json +0 -38
- package/dist/templates/angular/tsconfig.spec.json +0 -10
- package/dist/templates/nextjs/LLMs.txt +0 -179
- package/dist/templates/nextjs-app-router/LLMs.txt +0 -236
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Routes } from '@angular/router';
|
|
2
|
-
import { loaderResolver } from '@sitecore-content-sdk/angular';
|
|
3
|
-
import { PageComponent } from './pages/page.component';
|
|
4
|
-
import { NotFoundComponent } from './pages/not-found.component';
|
|
5
|
-
import { ErrorComponent } from './pages/error.component';
|
|
6
|
-
|
|
7
|
-
export const routes: Routes = [
|
|
8
|
-
{
|
|
9
|
-
path: '',
|
|
10
|
-
children: [
|
|
11
|
-
{
|
|
12
|
-
path: '500',
|
|
13
|
-
component: ErrorComponent,
|
|
14
|
-
resolve: { page: loaderResolver('500') },
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
path: '404',
|
|
18
|
-
component: NotFoundComponent,
|
|
19
|
-
resolve: { page: loaderResolver('404') },
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
path: '**',
|
|
23
|
-
component: PageComponent,
|
|
24
|
-
resolve: { page: loaderResolver('page') },
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
},
|
|
28
|
-
];
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Component, signal } from '@angular/core';
|
|
2
|
-
import { RouterOutlet } from '@angular/router';
|
|
3
|
-
|
|
4
|
-
@Component({
|
|
5
|
-
selector: 'app-root',
|
|
6
|
-
imports: [RouterOutlet],
|
|
7
|
-
templateUrl: './app.html',
|
|
8
|
-
styleUrl: './app.css'
|
|
9
|
-
})
|
|
10
|
-
export class App {
|
|
11
|
-
protected readonly title = signal('angular-sample');
|
|
12
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { LoaderFn, Page } from '@sitecore-content-sdk/angular';
|
|
2
|
-
import { errorPageResult } from './stub-utils';
|
|
3
|
-
|
|
4
|
-
const DEFAULT_MESSAGE = 'Internal Server Error';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 500 loader. Returns a page with route.fields.error set to the message.
|
|
8
|
-
* The Error component should read layout.sitecore.route.fields?.error?.value for custom text.
|
|
9
|
-
*/
|
|
10
|
-
export const errorLoader: LoaderFn<Page> = async (context) => {
|
|
11
|
-
return errorPageResult(context.url, DEFAULT_MESSAGE);
|
|
12
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export { pageLoader } from './page.loader';
|
|
2
|
-
export { notFoundLoader } from './not-found.loader';
|
|
3
|
-
export { errorLoader } from './error.loader';
|
|
4
|
-
|
|
5
|
-
import { pageLoader } from './page.loader';
|
|
6
|
-
import { notFoundLoader } from './not-found.loader';
|
|
7
|
-
import { errorLoader } from './error.loader';
|
|
8
|
-
|
|
9
|
-
/** Loaders object for use in provideLoaderRegistry() and createLoaderDataServiceMiddleware(). */
|
|
10
|
-
export const LOADERS = {
|
|
11
|
-
page: pageLoader,
|
|
12
|
-
'404': notFoundLoader,
|
|
13
|
-
'500': errorLoader,
|
|
14
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { LoaderFn, Page } from '@sitecore-content-sdk/angular';
|
|
2
|
-
import { errorPageResult } from './stub-utils';
|
|
3
|
-
|
|
4
|
-
const DEFAULT_MESSAGE = 'Page Not Found';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 404 loader. Returns a page with route.fields.error set to the message.
|
|
8
|
-
* The NotFound component should read layout.sitecore.route.fields?.error?.value for custom text.
|
|
9
|
-
*/
|
|
10
|
-
export const notFoundLoader: LoaderFn<Page> = async (context) => {
|
|
11
|
-
return errorPageResult(context.url, DEFAULT_MESSAGE);
|
|
12
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { LoaderFn, Page } from '@sitecore-content-sdk/angular';
|
|
2
|
-
import { NotFoundNavigationError } from '@sitecore-content-sdk/angular';
|
|
3
|
-
import { stubPageResult } from './stub-utils';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Page loader: fetches layout data from Sitecore for the current URL.
|
|
7
|
-
* Used by the route resolver to enable dynamic route rendering.
|
|
8
|
-
*/
|
|
9
|
-
export const pageLoader: LoaderFn<Page> = async (context) => {
|
|
10
|
-
const page = stubPageResult(context.url);
|
|
11
|
-
if (!page) {
|
|
12
|
-
throw new NotFoundNavigationError();
|
|
13
|
-
}
|
|
14
|
-
return page;
|
|
15
|
-
};
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import type { Page } from '@sitecore-content-sdk/angular';
|
|
2
|
-
import { LayoutServicePageState } from '@sitecore-content-sdk/angular';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Stub helpers until proper implementation (e.g. Sitecore layout service integration).
|
|
6
|
-
* Used by app loaders to return minimal valid Page shapes.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Returns a stubbed Page for the page loader: route data, mode data, 'en' locale and basic text fields.
|
|
11
|
-
* Replace with real layout/route data from Sitecore when implemented.
|
|
12
|
-
*/
|
|
13
|
-
export function stubPageResult(url: string): Page {
|
|
14
|
-
return {
|
|
15
|
-
layout: {
|
|
16
|
-
sitecore: {
|
|
17
|
-
context: {
|
|
18
|
-
url,
|
|
19
|
-
},
|
|
20
|
-
route: {
|
|
21
|
-
name: url,
|
|
22
|
-
placeholders: {},
|
|
23
|
-
fields: {},
|
|
24
|
-
databaseName: 'web',
|
|
25
|
-
deviceId: 'web',
|
|
26
|
-
itemLanguage: 'en',
|
|
27
|
-
itemVersion: 1,
|
|
28
|
-
layoutId: '123',
|
|
29
|
-
templateId: '123',
|
|
30
|
-
templateName: '123',
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
locale: 'en',
|
|
35
|
-
mode: {
|
|
36
|
-
name: LayoutServicePageState.Normal,
|
|
37
|
-
isNormal: true,
|
|
38
|
-
isPreview: false,
|
|
39
|
-
isEditing: false,
|
|
40
|
-
isDesignLibrary: false,
|
|
41
|
-
designLibrary: {
|
|
42
|
-
isVariantGeneration: false,
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Returns a stubbed Page for not-found (404) or error (500) loaders with an error message in route.fields.error.
|
|
50
|
-
* Replace with proper error page handling when implemented.
|
|
51
|
-
*/
|
|
52
|
-
export function errorPageResult(url: string, errorMessage: string): Page {
|
|
53
|
-
return {
|
|
54
|
-
layout: {
|
|
55
|
-
sitecore: {
|
|
56
|
-
context: { url },
|
|
57
|
-
route: {
|
|
58
|
-
name: url,
|
|
59
|
-
placeholders: {},
|
|
60
|
-
fields: {
|
|
61
|
-
error: { value: errorMessage },
|
|
62
|
-
},
|
|
63
|
-
databaseName: 'web',
|
|
64
|
-
deviceId: 'web',
|
|
65
|
-
itemLanguage: 'en',
|
|
66
|
-
itemVersion: 1,
|
|
67
|
-
layoutId: '123',
|
|
68
|
-
templateId: '123',
|
|
69
|
-
templateName: '123',
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
locale: 'en',
|
|
74
|
-
mode: {
|
|
75
|
-
name: LayoutServicePageState.Normal,
|
|
76
|
-
isNormal: true,
|
|
77
|
-
isPreview: false,
|
|
78
|
-
isEditing: false,
|
|
79
|
-
isDesignLibrary: false,
|
|
80
|
-
designLibrary: { isVariantGeneration: false },
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { Component, computed, inject } from '@angular/core';
|
|
2
|
-
import { ActivatedRoute } from '@angular/router';
|
|
3
|
-
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
|
-
|
|
5
|
-
const DEFAULT_TITLE = 'Internal Server Error';
|
|
6
|
-
const DEFAULT_MESSAGE = 'Something went wrong on our end. Please try again later.';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 500 error page component.
|
|
10
|
-
* Reads page from the '500' loader; displays route.fields.error.value or default text.
|
|
11
|
-
*/
|
|
12
|
-
@Component({
|
|
13
|
-
selector: 'app-error',
|
|
14
|
-
template: `
|
|
15
|
-
<div class="error-container">
|
|
16
|
-
<div class="error-content">
|
|
17
|
-
<h1 class="error-code">{{ errorCode }}</h1>
|
|
18
|
-
<h2 class="error-title">{{ errorTitle() }}</h2>
|
|
19
|
-
<p class="error-message">{{ errorMessage() }}</p>
|
|
20
|
-
<div class="error-actions">
|
|
21
|
-
<button class="btn btn-primary" (click)="goHome()">Go Home</button>
|
|
22
|
-
<button class="btn btn-secondary" (click)="retry()">Retry</button>
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
`,
|
|
27
|
-
styles: [
|
|
28
|
-
`
|
|
29
|
-
.error-container {
|
|
30
|
-
display: flex;
|
|
31
|
-
align-items: center;
|
|
32
|
-
justify-content: center;
|
|
33
|
-
min-height: 100vh;
|
|
34
|
-
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
.error-content {
|
|
38
|
-
text-align: center;
|
|
39
|
-
background: white;
|
|
40
|
-
padding: 3rem;
|
|
41
|
-
border-radius: 8px;
|
|
42
|
-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
43
|
-
max-width: 500px;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
.error-code {
|
|
47
|
-
font-size: 4rem;
|
|
48
|
-
font-weight: bold;
|
|
49
|
-
color: #e74c3c;
|
|
50
|
-
margin: 0;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.error-title {
|
|
54
|
-
font-size: 1.5rem;
|
|
55
|
-
color: #2c3e50;
|
|
56
|
-
margin: 1rem 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.error-message {
|
|
60
|
-
color: #7f8c8d;
|
|
61
|
-
margin: 1.5rem 0 2rem;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.error-actions {
|
|
65
|
-
display: flex;
|
|
66
|
-
gap: 1rem;
|
|
67
|
-
justify-content: center;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.btn {
|
|
71
|
-
padding: 0.75rem 1.5rem;
|
|
72
|
-
border: none;
|
|
73
|
-
border-radius: 4px;
|
|
74
|
-
font-size: 1rem;
|
|
75
|
-
cursor: pointer;
|
|
76
|
-
transition: background-color 0.3s;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.btn-primary {
|
|
80
|
-
background-color: #3498db;
|
|
81
|
-
color: white;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.btn-primary:hover {
|
|
85
|
-
background-color: #2980b9;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.btn-secondary {
|
|
89
|
-
background-color: #95a5a6;
|
|
90
|
-
color: white;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.btn-secondary:hover {
|
|
94
|
-
background-color: #7f8c8d;
|
|
95
|
-
}
|
|
96
|
-
`,
|
|
97
|
-
],
|
|
98
|
-
})
|
|
99
|
-
export class ErrorComponent {
|
|
100
|
-
readonly errorCode = 500;
|
|
101
|
-
|
|
102
|
-
private readonly route = inject(ActivatedRoute);
|
|
103
|
-
private readonly routeData = toSignal(this.route.data);
|
|
104
|
-
|
|
105
|
-
private readonly errorFromPage = computed(() => {
|
|
106
|
-
const page = this.routeData()?.['page'] as
|
|
107
|
-
| { layout?: { sitecore?: { route?: { fields?: { error?: { value?: string } } } } } }
|
|
108
|
-
| undefined;
|
|
109
|
-
return page?.layout?.sitecore?.route?.fields?.error?.value;
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
readonly errorTitle = computed(() => DEFAULT_TITLE);
|
|
113
|
-
readonly errorMessage = computed(() =>
|
|
114
|
-
typeof this.errorFromPage() === 'string' ? this.errorFromPage()! : DEFAULT_MESSAGE
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
goHome(): void {
|
|
118
|
-
window.location.href = '/';
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
retry(): void {
|
|
122
|
-
window.location.reload();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { Component, computed, inject } from '@angular/core';
|
|
2
|
-
import { ActivatedRoute } from '@angular/router';
|
|
3
|
-
import { RouterLink } from '@angular/router';
|
|
4
|
-
import { toSignal } from '@angular/core/rxjs-interop';
|
|
5
|
-
|
|
6
|
-
const DEFAULT_TITLE = 'Page Not Found';
|
|
7
|
-
const DEFAULT_MESSAGE = 'Sorry, the page you\'re looking for doesn\'t exist or has been moved.';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 404 Not Found error page component.
|
|
11
|
-
* Reads page from the '404' loader; displays route.fields.error.value or default text.
|
|
12
|
-
*/
|
|
13
|
-
@Component({
|
|
14
|
-
selector: 'app-404',
|
|
15
|
-
standalone: true,
|
|
16
|
-
imports: [RouterLink],
|
|
17
|
-
template: `
|
|
18
|
-
<div class="not-found-container">
|
|
19
|
-
<div class="not-found-content">
|
|
20
|
-
<h1>404</h1>
|
|
21
|
-
<h2>{{ title() }}</h2>
|
|
22
|
-
<p>{{ message() }}</p>
|
|
23
|
-
<a routerLink="/" class="back-link">Return to Home</a>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
`,
|
|
27
|
-
styles: [`
|
|
28
|
-
.not-found-container {
|
|
29
|
-
display: flex;
|
|
30
|
-
justify-content: center;
|
|
31
|
-
align-items: center;
|
|
32
|
-
min-height: 100vh;
|
|
33
|
-
background-color: #f5f5f5;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.not-found-content {
|
|
37
|
-
text-align: center;
|
|
38
|
-
padding: 2rem;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
h1 {
|
|
42
|
-
font-size: 6rem;
|
|
43
|
-
margin: 0;
|
|
44
|
-
color: #333;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
h2 {
|
|
48
|
-
font-size: 2rem;
|
|
49
|
-
margin: 1rem 0;
|
|
50
|
-
color: #666;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
p {
|
|
54
|
-
font-size: 1.1rem;
|
|
55
|
-
color: #999;
|
|
56
|
-
margin-bottom: 2rem;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.back-link {
|
|
60
|
-
display: inline-block;
|
|
61
|
-
padding: 0.75rem 1.5rem;
|
|
62
|
-
background-color: #0061cc;
|
|
63
|
-
color: white;
|
|
64
|
-
text-decoration: none;
|
|
65
|
-
border-radius: 4px;
|
|
66
|
-
transition: background-color 0.3s ease;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.back-link:hover {
|
|
70
|
-
background-color: #0052a3;
|
|
71
|
-
}
|
|
72
|
-
`],
|
|
73
|
-
})
|
|
74
|
-
export class NotFoundComponent {
|
|
75
|
-
private readonly route = inject(ActivatedRoute);
|
|
76
|
-
private readonly routeData = toSignal(this.route.data);
|
|
77
|
-
|
|
78
|
-
private readonly errorFromPage = computed(() => {
|
|
79
|
-
const page = this.routeData()?.['page'] as { layout?: { sitecore?: { route?: { fields?: { error?: { value?: string } } } } } } | undefined;
|
|
80
|
-
return page?.layout?.sitecore?.route?.fields?.error?.value;
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
readonly title = computed(() => DEFAULT_TITLE);
|
|
84
|
-
readonly message = computed(() => (typeof this.errorFromPage() === 'string' ? this.errorFromPage()! : DEFAULT_MESSAGE));
|
|
85
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Component, computed, inject } from '@angular/core';
|
|
2
|
-
import { ActivatedRoute, Router } from '@angular/router';
|
|
3
|
-
import { Page } from '@sitecore-content-sdk/angular';
|
|
4
|
-
import { toSignal } from '@angular/core/rxjs-interop';
|
|
5
|
-
import { LayoutComponent } from '../shared/layout.component';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Page component that sets the Sitecore context and dictionary phrases, then renders the layout.
|
|
9
|
-
* Gets page and dictionary data from route resolvers.
|
|
10
|
-
* Displays current route and fields returned by pageLoader.
|
|
11
|
-
*/
|
|
12
|
-
@Component({
|
|
13
|
-
selector: 'app-page',
|
|
14
|
-
standalone: true,
|
|
15
|
-
imports: [LayoutComponent],
|
|
16
|
-
template: `
|
|
17
|
-
@let pageValue = page();
|
|
18
|
-
<section class="page-loader-info" style="margin: 1rem; padding: 1rem; border: 1px solid #ccc; border-radius: 4px;">
|
|
19
|
-
<h2 style="margin-top: 0;">Current route</h2>
|
|
20
|
-
<p><strong>URL:</strong> {{ router.url }}</p>
|
|
21
|
-
|
|
22
|
-
@if (pageValue) {
|
|
23
|
-
<h2>Page loader data</h2>
|
|
24
|
-
<dl style="display: grid; grid-template-columns: auto 1fr; gap: 0.25rem 1rem;">
|
|
25
|
-
<dt>Route name</dt>
|
|
26
|
-
<dd>{{ routeName(pageValue) }}</dd>
|
|
27
|
-
<dt>Locale</dt>
|
|
28
|
-
<dd>{{ pageValue.locale }}</dd>
|
|
29
|
-
<dt>Site name</dt>
|
|
30
|
-
<dd>{{ pageValue.siteName ?? '—' }}</dd>
|
|
31
|
-
<dt>Mode</dt>
|
|
32
|
-
<dd>{{ pageValue.mode?.name ?? '—' }}</dd>
|
|
33
|
-
<dt>Route fields</dt>
|
|
34
|
-
<dd><pre style="margin: 0; font-size: 0.875rem;">{{ routeFieldsJson(pageValue) }}</pre></dd>
|
|
35
|
-
</dl>
|
|
36
|
-
}
|
|
37
|
-
</section>
|
|
38
|
-
@if (pageValue) {
|
|
39
|
-
<app-layout [page]="pageValue"></app-layout>
|
|
40
|
-
}
|
|
41
|
-
`,
|
|
42
|
-
})
|
|
43
|
-
export class PageComponent {
|
|
44
|
-
private readonly activatedRoute = inject(ActivatedRoute);
|
|
45
|
-
readonly router = inject(Router);
|
|
46
|
-
private data = toSignal(this.activatedRoute.data);
|
|
47
|
-
page = computed(() => this.data()?.page as Page | null);
|
|
48
|
-
|
|
49
|
-
routeName(p: Page): string {
|
|
50
|
-
return p?.layout?.sitecore?.route?.name ?? '—';
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
routeFieldsJson(p: Page): string {
|
|
54
|
-
const fields = p?.layout?.sitecore?.route?.fields;
|
|
55
|
-
if (fields == null || Object.keys(fields).length === 0) return '{}';
|
|
56
|
-
return JSON.stringify(fields, null, 2);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { Component, input, computed, effect, inject } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
// import { RouterLink } from '@angular/router';
|
|
4
|
-
import { Title } from '@angular/platform-browser';
|
|
5
|
-
import { Page, Field } from '@sitecore-content-sdk/angular';
|
|
6
|
-
import { RouterLink } from '@angular/router';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Route fields interface for page title
|
|
10
|
-
*/
|
|
11
|
-
interface RouteFields {
|
|
12
|
-
[key: string]: unknown;
|
|
13
|
-
Title?: Field<string>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Layout component that provides the main structure for Sitecore pages.
|
|
18
|
-
* Renders header, main content, and footer placeholders.
|
|
19
|
-
* @public
|
|
20
|
-
*/
|
|
21
|
-
@Component({
|
|
22
|
-
selector: 'app-layout',
|
|
23
|
-
standalone: true,
|
|
24
|
-
imports: [CommonModule, RouterLink],
|
|
25
|
-
template: `
|
|
26
|
-
<div [class]="mainClass()">
|
|
27
|
-
<!-- <sc-editing-scripts></sc-editing-scripts> -->
|
|
28
|
-
<header>
|
|
29
|
-
<div id="header">
|
|
30
|
-
<a [routerLink]="'/'">Home</a>
|
|
31
|
-
<a [routerLink]="'/about'">About</a>
|
|
32
|
-
</div>
|
|
33
|
-
</header>
|
|
34
|
-
<main>
|
|
35
|
-
<div id="content">Main content</div>
|
|
36
|
-
</main>
|
|
37
|
-
<footer>
|
|
38
|
-
<div id="footer">footer</div>
|
|
39
|
-
</footer>
|
|
40
|
-
</div>
|
|
41
|
-
`,
|
|
42
|
-
styles: `
|
|
43
|
-
:host {
|
|
44
|
-
display: block;
|
|
45
|
-
min-height: 100vh;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.editing-mode {
|
|
49
|
-
/* Styles for editing mode */
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.prod-mode {
|
|
53
|
-
/* Styles for production mode */
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.loading {
|
|
57
|
-
display: flex;
|
|
58
|
-
justify-content: center;
|
|
59
|
-
align-items: center;
|
|
60
|
-
min-height: 100vh;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
header {
|
|
64
|
-
width: 100%;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
main {
|
|
68
|
-
flex: 1;
|
|
69
|
-
width: 100%;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
footer {
|
|
73
|
-
width: 100%;
|
|
74
|
-
}
|
|
75
|
-
`,
|
|
76
|
-
})
|
|
77
|
-
export class LayoutComponent {
|
|
78
|
-
/**
|
|
79
|
-
* Page data from Sitecore
|
|
80
|
-
*/
|
|
81
|
-
readonly page = input.required<Page>();
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Current route data derived from page
|
|
85
|
-
*/
|
|
86
|
-
readonly route = computed(() => this.page().layout?.sitecore?.route ?? null);
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Main container CSS class based on editing mode
|
|
90
|
-
*/
|
|
91
|
-
readonly mainClass = computed(() => (this.page().mode?.isEditing ? 'editing-mode' : 'prod-mode'));
|
|
92
|
-
|
|
93
|
-
private readonly titleService = inject(Title);
|
|
94
|
-
|
|
95
|
-
constructor() {
|
|
96
|
-
// Effect to update the page title when the page changes
|
|
97
|
-
effect(() => {
|
|
98
|
-
const route = this.route();
|
|
99
|
-
if (route) {
|
|
100
|
-
const fields = route.fields as RouteFields | undefined;
|
|
101
|
-
const title = fields?.Title?.value ?? 'Page';
|
|
102
|
-
this.titleService.setTitle(title);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<title>Angular Content SDK Sample</title>
|
|
6
|
-
<base href="/">
|
|
7
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
-
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
|
9
|
-
</head>
|
|
10
|
-
<body>
|
|
11
|
-
<app-root></app-root>
|
|
12
|
-
</body>
|
|
13
|
-
</html>
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { BootstrapContext, bootstrapApplication } from '@angular/platform-browser';
|
|
2
|
-
import { App } from './app/app';
|
|
3
|
-
import { config } from './app/app.config.server';
|
|
4
|
-
|
|
5
|
-
const bootstrap = (context: BootstrapContext) =>
|
|
6
|
-
bootstrapApplication(App, config, context);
|
|
7
|
-
|
|
8
|
-
export default bootstrap;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AngularNodeAppEngine,
|
|
3
|
-
createNodeRequestHandler,
|
|
4
|
-
isMainModule,
|
|
5
|
-
writeResponseToNodeResponse,
|
|
6
|
-
} from '@angular/ssr/node';
|
|
7
|
-
import express from 'express';
|
|
8
|
-
import { join } from 'node:path';
|
|
9
|
-
import { createLoaderDataServiceMiddleware } from '@sitecore-content-sdk/angular';
|
|
10
|
-
import { LOADERS } from './app/loaders';
|
|
11
|
-
|
|
12
|
-
const browserDistFolder = join(import.meta.dirname, '../browser');
|
|
13
|
-
|
|
14
|
-
const app = express();
|
|
15
|
-
const angularApp = new AngularNodeAppEngine();
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Loader data endpoint (/_data). Must use the same loaders as the client registry
|
|
19
|
-
* so client-side navigation can fetch route data via POST /_data.
|
|
20
|
-
*/
|
|
21
|
-
app.use(express.json());
|
|
22
|
-
app.use(createLoaderDataServiceMiddleware({ loaders: LOADERS }));
|
|
23
|
-
/**
|
|
24
|
-
* Serve static files from /browser
|
|
25
|
-
*/
|
|
26
|
-
app.use(
|
|
27
|
-
express.static(browserDistFolder, {
|
|
28
|
-
maxAge: '1y',
|
|
29
|
-
index: false,
|
|
30
|
-
redirect: false,
|
|
31
|
-
})
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Handle all other requests by rendering the Angular application.
|
|
36
|
-
* Catches ExternalRedirectError from loaders so server-side external redirects send HTTP 302.
|
|
37
|
-
*/
|
|
38
|
-
app.use((req, res, next) => {
|
|
39
|
-
angularApp
|
|
40
|
-
.handle(req)
|
|
41
|
-
.then((response) => (response ? writeResponseToNodeResponse(response, res) : next()))
|
|
42
|
-
.catch((err) => {
|
|
43
|
-
next(err);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Start the server if this module is the main entry point
|
|
49
|
-
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
|
|
50
|
-
*/
|
|
51
|
-
if (isMainModule(import.meta.url)) {
|
|
52
|
-
const port = process.env.PORT || 4000;
|
|
53
|
-
app.listen(port, (error) => {
|
|
54
|
-
if (error) {
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
console.log(`Node Express server listening on http://localhost:${port}`);
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions.
|
|
64
|
-
*/
|
|
65
|
-
export const reqHandler = createNodeRequestHandler(app);
|