cms-renderer 0.0.0 → 0.1.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/chunk-HVKFEZBT.js +116 -0
- package/dist/chunk-HVKFEZBT.js.map +1 -0
- package/dist/chunk-JHKDRASN.js +39 -0
- package/dist/chunk-JHKDRASN.js.map +1 -0
- package/dist/chunk-RPM73PQZ.js +17 -0
- package/dist/chunk-RPM73PQZ.js.map +1 -0
- package/dist/lib/block-renderer.d.ts +32 -0
- package/dist/lib/block-renderer.js +7 -0
- package/dist/lib/block-renderer.js.map +1 -0
- package/dist/lib/cms-api.d.ts +25 -0
- package/dist/lib/cms-api.js +7 -0
- package/dist/lib/cms-api.js.map +1 -0
- package/dist/lib/data-utils.d.ts +218 -0
- package/dist/lib/data-utils.js +247 -0
- package/dist/lib/data-utils.js.map +1 -0
- package/dist/lib/image/lazy-load.d.ts +75 -0
- package/dist/lib/image/lazy-load.js +83 -0
- package/dist/lib/image/lazy-load.js.map +1 -0
- package/dist/lib/markdown-utils.d.ts +172 -0
- package/dist/lib/markdown-utils.js +137 -0
- package/dist/lib/markdown-utils.js.map +1 -0
- package/dist/lib/renderer.d.ts +40 -0
- package/dist/lib/renderer.js +371 -0
- package/dist/lib/renderer.js.map +1 -0
- package/{lib/result.ts → dist/lib/result.d.ts} +32 -146
- package/dist/lib/result.js +37 -0
- package/dist/lib/result.js.map +1 -0
- package/dist/lib/schema.d.ts +15 -0
- package/dist/lib/schema.js +35 -0
- package/dist/lib/schema.js.map +1 -0
- package/{lib/trpc.ts → dist/lib/trpc.d.ts} +6 -4
- package/dist/lib/trpc.js +7 -0
- package/dist/lib/trpc.js.map +1 -0
- package/dist/lib/types.d.ts +163 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/types.js.map +1 -0
- package/package.json +50 -11
- package/.turbo/turbo-check-types.log +0 -2
- package/lib/__tests__/enrich-block-images.test.ts +0 -394
- package/lib/block-renderer.tsx +0 -60
- package/lib/cms-api.ts +0 -86
- package/lib/data-utils.ts +0 -572
- package/lib/image/lazy-load.ts +0 -209
- package/lib/markdown-utils.ts +0 -368
- package/lib/renderer.tsx +0 -189
- package/lib/schema.ts +0 -74
- package/lib/types.ts +0 -201
- package/next.config.ts +0 -39
- package/postcss.config.mjs +0 -5
- package/tsconfig.json +0 -12
- package/tsconfig.tsbuildinfo +0 -1
package/lib/renderer.tsx
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Catch-all Route Handler for Parametric Routes
|
|
3
|
-
*
|
|
4
|
-
* Handles routes with multiple segments like /us/en/products.
|
|
5
|
-
* Uses the CMS API to fetch and render blocks.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
isArticlePublished,
|
|
10
|
-
isValidBlockSchemaName,
|
|
11
|
-
normalizeArticleContent,
|
|
12
|
-
} from '@repo/cms-schema/blocks';
|
|
13
|
-
import type { Metadata } from 'next';
|
|
14
|
-
import { unstable_noStore } from 'next/cache';
|
|
15
|
-
import { notFound } from 'next/navigation';
|
|
16
|
-
import { BlockRenderer } from './block-renderer';
|
|
17
|
-
import { getCmsClient } from './cms-api';
|
|
18
|
-
import type { BlockComponentRegistry, BlockData } from './types';
|
|
19
|
-
|
|
20
|
-
type PageProps = {
|
|
21
|
-
params: Promise<{ slug: string[] }>;
|
|
22
|
-
registry?: Partial<BlockComponentRegistry>;
|
|
23
|
-
/** API key for CMS API authentication */
|
|
24
|
-
apiKey?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Force dynamic rendering to ensure routes are always fresh.
|
|
29
|
-
* This prevents Next.js from caching pages when routes are published.
|
|
30
|
-
*/
|
|
31
|
-
export const dynamic = 'force-dynamic';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Catch-all route handler for parametric routes.
|
|
35
|
-
*
|
|
36
|
-
* Handles paths like:
|
|
37
|
-
* - /us/en/products -> slug = ['us', 'en', 'products']
|
|
38
|
-
* - /about -> slug = ['about']
|
|
39
|
-
*
|
|
40
|
-
* Reconstructs the full path and fetches route via tRPC.
|
|
41
|
-
*/
|
|
42
|
-
export default async function ParametricRoutePage({ params, registry, apiKey }: PageProps) {
|
|
43
|
-
// Prevent any caching - ensure we always fetch fresh route data
|
|
44
|
-
unstable_noStore();
|
|
45
|
-
|
|
46
|
-
const { slug } = await params;
|
|
47
|
-
|
|
48
|
-
// Reconstruct full path from slug segments and normalize it
|
|
49
|
-
const rawPath = `/${slug.join('/')}`;
|
|
50
|
-
const path = normalizePath(rawPath);
|
|
51
|
-
|
|
52
|
-
// Get CMS API client with optional API key
|
|
53
|
-
const client = getCmsClient({ apiKey });
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
// Fetch route by path via CMS API
|
|
57
|
-
const { route } = await client.route.getByPath.query({ path });
|
|
58
|
-
|
|
59
|
-
// Only show Live routes on public website
|
|
60
|
-
if (route.state !== 'Live') {
|
|
61
|
-
console.error(`Route found but not Live. Path: ${path}, State: ${route.state}`);
|
|
62
|
-
notFound();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Fetch all blocks by ID via CMS API (skip any that fail)
|
|
66
|
-
const blockPromises = route.block_ids.map(async (blockId) => {
|
|
67
|
-
try {
|
|
68
|
-
const result = await client.block.getById.query({ id: blockId });
|
|
69
|
-
return result.block;
|
|
70
|
-
} catch (error) {
|
|
71
|
-
// Log error but don't fail the entire page
|
|
72
|
-
console.error(`Failed to fetch block ${blockId}:`, error);
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
const blockResults = await Promise.all(blockPromises);
|
|
77
|
-
|
|
78
|
-
// Transform blocks to BlockData format for BlockRenderer
|
|
79
|
-
// Filter out any blocks that failed to load
|
|
80
|
-
const blocks: BlockData[] = [];
|
|
81
|
-
|
|
82
|
-
for (const block of blockResults) {
|
|
83
|
-
if (!block || block.published_content === null) continue;
|
|
84
|
-
|
|
85
|
-
const content = block.published_content as Record<string, unknown> | null;
|
|
86
|
-
if (!content) continue;
|
|
87
|
-
|
|
88
|
-
// Handle 'article' blocks separately before checking schema type
|
|
89
|
-
if (block.schema_name === 'article') {
|
|
90
|
-
const article = normalizeArticleContent(content);
|
|
91
|
-
const isPublished = article ? isArticlePublished(article) : null;
|
|
92
|
-
if (article && isPublished) {
|
|
93
|
-
blocks.push({ id: block.id, type: 'article', content: article });
|
|
94
|
-
}
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Skip blocks with invalid schema names (after handling 'article')
|
|
99
|
-
if (!isValidBlockSchemaName(block.schema_name)) {
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// For all block types, map schema_name to type and include content
|
|
104
|
-
// Image references are automatically resolved by block.getById
|
|
105
|
-
blocks.push({
|
|
106
|
-
id: block.id,
|
|
107
|
-
type: block.schema_name,
|
|
108
|
-
content,
|
|
109
|
-
} as BlockData);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<main>
|
|
114
|
-
{blocks.map((block) => (
|
|
115
|
-
<BlockRenderer registry={registry ?? {}} key={block.id} block={block} />
|
|
116
|
-
))}
|
|
117
|
-
</main>
|
|
118
|
-
);
|
|
119
|
-
} catch (error) {
|
|
120
|
-
// Log error for debugging
|
|
121
|
-
console.error(`Route fetch error for path: ${path}`, error);
|
|
122
|
-
|
|
123
|
-
// If route not found or param validation fails, show 404
|
|
124
|
-
// TRPCClientError has data.code for the error code
|
|
125
|
-
const errorCode =
|
|
126
|
-
error instanceof Error && 'data' in error
|
|
127
|
-
? (error as { data?: { code?: string } }).data?.code
|
|
128
|
-
: error instanceof Error && 'code' in error
|
|
129
|
-
? (error as { code: string }).code
|
|
130
|
-
: undefined;
|
|
131
|
-
|
|
132
|
-
if (errorCode === 'NOT_FOUND' || errorCode === 'P0002') {
|
|
133
|
-
notFound();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Re-throw other errors
|
|
137
|
-
throw error;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// -----------------------------------------------------------------------------
|
|
142
|
-
// Metadata
|
|
143
|
-
// -----------------------------------------------------------------------------
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Generate metadata for the page.
|
|
147
|
-
* Uses Next.js 15+ async params pattern.
|
|
148
|
-
*/
|
|
149
|
-
export async function generateMetadata({ params, apiKey }: PageProps): Promise<Metadata> {
|
|
150
|
-
const { slug } = await params;
|
|
151
|
-
const rawPath = `/${slug.join('/')}`;
|
|
152
|
-
const path = normalizePath(rawPath);
|
|
153
|
-
const client = getCmsClient({ apiKey });
|
|
154
|
-
|
|
155
|
-
try {
|
|
156
|
-
const { route } = await client.route.getByPath.query({ path });
|
|
157
|
-
return {
|
|
158
|
-
title: `${route.path} | Website`,
|
|
159
|
-
description: `Content page: ${route.path}`,
|
|
160
|
-
};
|
|
161
|
-
} catch {
|
|
162
|
-
return {
|
|
163
|
-
title: 'Page Not Found | Website',
|
|
164
|
-
description: 'The requested page could not be found.',
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function normalizePath(path: string): string {
|
|
170
|
-
if (!path || path === '/') {
|
|
171
|
-
return '/';
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Remove trailing slashes, ensure leading slash
|
|
175
|
-
let normalized = path.trim();
|
|
176
|
-
|
|
177
|
-
// Remove trailing slashes (but keep root "/")
|
|
178
|
-
normalized = normalized.replace(/\/+$/, '');
|
|
179
|
-
|
|
180
|
-
// Ensure leading slash
|
|
181
|
-
if (!normalized.startsWith('/')) {
|
|
182
|
-
normalized = `/${normalized}`;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Collapse multiple consecutive slashes to single slash
|
|
186
|
-
normalized = normalized.replace(/\/+/g, '/');
|
|
187
|
-
|
|
188
|
-
return normalized;
|
|
189
|
-
}
|
package/lib/schema.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// Fetch schema from the CMS for a headless setup
|
|
2
|
-
// This should look like this
|
|
3
|
-
//
|
|
4
|
-
// import { schema, configureSchema } from "@profound/cms";
|
|
5
|
-
//
|
|
6
|
-
// // Option 1: Use default config (reads from CMS_API_URL env var)
|
|
7
|
-
// const footerData = schema.name("footer").fetchAll();
|
|
8
|
-
//
|
|
9
|
-
// // Option 2: Configure with custom API base and fetch options
|
|
10
|
-
// const customSchema = configureSchema({
|
|
11
|
-
// apiBase: "https://my-cms.example.com/api",
|
|
12
|
-
// fetchOptions: { headers: { Authorization: "Bearer token" } },
|
|
13
|
-
// });
|
|
14
|
-
// const footerData = customSchema.name("footer").fetchAll();
|
|
15
|
-
//
|
|
16
|
-
// console.log(footerData); # [{ logo: "<cloudflare_signed_img_url>", "Footer_text": "Profound" }]
|
|
17
|
-
|
|
18
|
-
const DEFAULT_API_BASE = process.env.NEXT_PUBLIC_CMS_API_URL ?? 'http://localhost:4000/api';
|
|
19
|
-
|
|
20
|
-
interface SchemaConfig {
|
|
21
|
-
apiBase?: string;
|
|
22
|
-
fetchOptions?: RequestInit;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface SchemaQuery {
|
|
26
|
-
fetchAll: <T = Record<string, unknown>>() => Promise<T[]>;
|
|
27
|
-
fetchSingle: <T = Record<string, unknown>>() => Promise<T | null>;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface SchemaClient {
|
|
31
|
-
name: (schemaName: string) => SchemaQuery;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function createSchemaQuery(
|
|
35
|
-
apiBase: string,
|
|
36
|
-
schemaName: string,
|
|
37
|
-
fetchOptions: RequestInit = {}
|
|
38
|
-
): SchemaQuery {
|
|
39
|
-
const baseUrl = `${apiBase}/schemas/${schemaName}`;
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
async fetchAll<T = Record<string, unknown>>(): Promise<T[]> {
|
|
43
|
-
const response = await fetch(baseUrl, fetchOptions);
|
|
44
|
-
|
|
45
|
-
if (!response.ok) {
|
|
46
|
-
throw new Error(`Failed to fetch schema "${schemaName}": ${response.statusText}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return response.json();
|
|
50
|
-
},
|
|
51
|
-
|
|
52
|
-
async fetchSingle<T = Record<string, unknown>>(): Promise<T | null> {
|
|
53
|
-
const response = await fetch(`${baseUrl}?limit=1`, fetchOptions);
|
|
54
|
-
|
|
55
|
-
if (!response.ok) {
|
|
56
|
-
throw new Error(`Failed to fetch schema "${schemaName}": ${response.statusText}`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const data = await response.json();
|
|
60
|
-
return Array.isArray(data) ? (data[0] ?? null) : data;
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function configureSchema(config: SchemaConfig = {}): SchemaClient {
|
|
66
|
-
const apiBase = config.apiBase || DEFAULT_API_BASE;
|
|
67
|
-
const fetchOptions = config.fetchOptions || {};
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
name: (schemaName: string): SchemaQuery => createSchemaQuery(apiBase, schemaName, fetchOptions),
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export const schema: SchemaClient = configureSchema();
|
package/lib/types.ts
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Block Rendering Types
|
|
3
|
-
*
|
|
4
|
-
* Type definitions for the ComponentMap pattern.
|
|
5
|
-
* Block types map to React components via the blockComponents registry.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { ComponentType } from 'react';
|
|
9
|
-
|
|
10
|
-
// -----------------------------------------------------------------------------
|
|
11
|
-
// Block Type Discriminant
|
|
12
|
-
// -----------------------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Valid block type strings.
|
|
16
|
-
* Must match the schema_name field in block data from the tRPC API.
|
|
17
|
-
*/
|
|
18
|
-
export type BlockType =
|
|
19
|
-
| 'navigation'
|
|
20
|
-
| 'header'
|
|
21
|
-
| 'article'
|
|
22
|
-
| 'hero-block'
|
|
23
|
-
| 'features-block'
|
|
24
|
-
| 'cta-block'
|
|
25
|
-
| 'logo-trust-block';
|
|
26
|
-
|
|
27
|
-
// -----------------------------------------------------------------------------
|
|
28
|
-
// Content Types (inferred from seed data)
|
|
29
|
-
// -----------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Navigation link button structure.
|
|
33
|
-
*/
|
|
34
|
-
export interface NavigationButton {
|
|
35
|
-
label: string;
|
|
36
|
-
href: string;
|
|
37
|
-
ariaLabel: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Navigation link with type and button.
|
|
42
|
-
*/
|
|
43
|
-
export interface NavigationLink {
|
|
44
|
-
button: NavigationButton;
|
|
45
|
-
type: 'Default' | 'Flyout';
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Level 3 navigation item (leaf node).
|
|
50
|
-
*/
|
|
51
|
-
export interface Level3Link {
|
|
52
|
-
link: NavigationLink;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Level 2 navigation item with optional Level 3 children.
|
|
57
|
-
*/
|
|
58
|
-
export interface Level2Link {
|
|
59
|
-
link: NavigationLink;
|
|
60
|
-
children?: Level3Link[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Level 1 navigation item with optional Level 2 children.
|
|
65
|
-
*/
|
|
66
|
-
export interface Level1Link {
|
|
67
|
-
link: NavigationLink;
|
|
68
|
-
children?: Level2Link[];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Navigation block content.
|
|
73
|
-
*/
|
|
74
|
-
export interface NavigationContent {
|
|
75
|
-
logo?: {
|
|
76
|
-
url: string;
|
|
77
|
-
alt: string;
|
|
78
|
-
};
|
|
79
|
-
ariaLabel: string;
|
|
80
|
-
links: Level1Link[];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Header block content.
|
|
85
|
-
*/
|
|
86
|
-
export interface HeaderContent {
|
|
87
|
-
headline: string;
|
|
88
|
-
subheadline?: string;
|
|
89
|
-
backgroundImage?: {
|
|
90
|
-
url: string;
|
|
91
|
-
alt: string;
|
|
92
|
-
};
|
|
93
|
-
ctaButton?: {
|
|
94
|
-
label: string;
|
|
95
|
-
href: string;
|
|
96
|
-
};
|
|
97
|
-
alignment: 'left' | 'center' | 'right';
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Article block content.
|
|
102
|
-
*/
|
|
103
|
-
export interface ArticleContent {
|
|
104
|
-
headline: string;
|
|
105
|
-
author?: string;
|
|
106
|
-
publishedAt?: string;
|
|
107
|
-
body: string;
|
|
108
|
-
tags?: readonly string[] | string[];
|
|
109
|
-
status?: string;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Hero block content (from CMS schema).
|
|
114
|
-
*/
|
|
115
|
-
export type HeroBlockContent = import('@repo/cms-schema/blocks').HeroBlockContent;
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Features block content (from CMS schema).
|
|
119
|
-
*/
|
|
120
|
-
export type FeaturesBlockContent = import('@repo/cms-schema/blocks').FeaturesBlockContent;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* CTA block content (from CMS schema).
|
|
124
|
-
*/
|
|
125
|
-
export type CTABlockContent = import('@repo/cms-schema/blocks').CTABlockContent;
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Logo Trust block content (from CMS schema).
|
|
129
|
-
*/
|
|
130
|
-
export type LogoTrustBlockContent = import('@repo/cms-schema/blocks').LogoTrustBlockContent;
|
|
131
|
-
|
|
132
|
-
// -----------------------------------------------------------------------------
|
|
133
|
-
// Block Data Union
|
|
134
|
-
// -----------------------------------------------------------------------------
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Discriminated union of all block types.
|
|
138
|
-
* Use the `type` field to narrow to specific content types.
|
|
139
|
-
*
|
|
140
|
-
* Each block also carries its stable CMS `id`, which should be used as the
|
|
141
|
-
* React `key` when rendering lists of blocks.
|
|
142
|
-
*
|
|
143
|
-
* @example
|
|
144
|
-
* ```tsx
|
|
145
|
-
* function renderBlock(block: BlockData) {
|
|
146
|
-
* if (block.type === 'header') {
|
|
147
|
-
* // TypeScript knows block.content is HeaderContent
|
|
148
|
-
* return <h1>{block.content.headline}</h1>;
|
|
149
|
-
* }
|
|
150
|
-
* }
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
export type BlockData =
|
|
154
|
-
| { id: string; type: 'navigation'; content: NavigationContent }
|
|
155
|
-
| { id: string; type: 'header'; content: HeaderContent }
|
|
156
|
-
| { id: string; type: 'article'; content: ArticleContent }
|
|
157
|
-
| { id: string; type: 'hero-block'; content: HeroBlockContent }
|
|
158
|
-
| { id: string; type: 'features-block'; content: FeaturesBlockContent }
|
|
159
|
-
| { id: string; type: 'cta-block'; content: CTABlockContent }
|
|
160
|
-
| { id: string; type: 'logo-trust-block'; content: LogoTrustBlockContent };
|
|
161
|
-
|
|
162
|
-
// -----------------------------------------------------------------------------
|
|
163
|
-
// Component Types
|
|
164
|
-
// -----------------------------------------------------------------------------
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Props for a block component.
|
|
168
|
-
* Each block component receives its typed content.
|
|
169
|
-
*/
|
|
170
|
-
export interface BlockComponentProps<T> {
|
|
171
|
-
content: T;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* A React component that renders a specific block type.
|
|
176
|
-
*/
|
|
177
|
-
export type BlockComponent<T> = ComponentType<BlockComponentProps<T>>;
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Registry of block type to component mappings.
|
|
181
|
-
* This is the core of the ComponentMap pattern.
|
|
182
|
-
*/
|
|
183
|
-
export type BlockComponentRegistry = {
|
|
184
|
-
[K in BlockType]: BlockComponent<
|
|
185
|
-
K extends 'navigation'
|
|
186
|
-
? NavigationContent
|
|
187
|
-
: K extends 'header'
|
|
188
|
-
? HeaderContent
|
|
189
|
-
: K extends 'article'
|
|
190
|
-
? ArticleContent
|
|
191
|
-
: K extends 'hero-block'
|
|
192
|
-
? HeroBlockContent
|
|
193
|
-
: K extends 'features-block'
|
|
194
|
-
? FeaturesBlockContent
|
|
195
|
-
: K extends 'cta-block'
|
|
196
|
-
? CTABlockContent
|
|
197
|
-
: K extends 'logo-trust-block'
|
|
198
|
-
? LogoTrustBlockContent
|
|
199
|
-
: never
|
|
200
|
-
>;
|
|
201
|
-
};
|
package/next.config.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import type { NextConfig } from 'next';
|
|
3
|
-
|
|
4
|
-
const nextConfig: NextConfig = {
|
|
5
|
-
turbopack: {
|
|
6
|
-
root: resolve(import.meta.dirname, '../..'),
|
|
7
|
-
},
|
|
8
|
-
transpilePackages: ['@repo/cms-schema', '@repo/markdown-wasm'],
|
|
9
|
-
serverExternalPackages: ['md4w'],
|
|
10
|
-
images: {
|
|
11
|
-
remotePatterns: [
|
|
12
|
-
{
|
|
13
|
-
protocol: 'https',
|
|
14
|
-
hostname: '**',
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
protocol: 'http',
|
|
18
|
-
hostname: 'localhost',
|
|
19
|
-
},
|
|
20
|
-
],
|
|
21
|
-
},
|
|
22
|
-
// Prevent browser caching of dynamic pages
|
|
23
|
-
async headers() {
|
|
24
|
-
return [
|
|
25
|
-
{
|
|
26
|
-
// Apply to all pages
|
|
27
|
-
source: '/:path*',
|
|
28
|
-
headers: [
|
|
29
|
-
{
|
|
30
|
-
key: 'Cache-Control',
|
|
31
|
-
value: 'no-store, must-revalidate',
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
},
|
|
35
|
-
];
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default nextConfig;
|
package/postcss.config.mjs
DELETED
package/tsconfig.json
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "@repo/typescript-config/nextjs.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"strict": true,
|
|
5
|
-
"baseUrl": ".",
|
|
6
|
-
"paths": {
|
|
7
|
-
"@/*": ["./*"]
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
|
-
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
|
11
|
-
"exclude": ["node_modules", "tests", "**/__tests__/**", "**/*.test.ts", "**/*.test.tsx", "e2e"]
|
|
12
|
-
}
|