react-layout-sdk 1.1.0 ā 1.1.2
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/bin/init.js +94 -66
- package/package.json +2 -2
package/bin/init.js
CHANGED
|
@@ -3,24 +3,29 @@ const fs = require('fs');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
|
|
5
5
|
const projectRoot = process.cwd();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
6
|
+
|
|
7
|
+
// Detect project structure
|
|
8
|
+
const hasSrc = fs.existsSync(path.join(projectRoot, 'src'));
|
|
9
|
+
const basePath = hasSrc ? path.join(projectRoot, 'src') : projectRoot;
|
|
10
|
+
|
|
11
|
+
const componentsDir = path.join(basePath, 'components');
|
|
12
|
+
const hasAppRouter = fs.existsSync(path.join(basePath, 'app'));
|
|
13
|
+
const hasPagesRouter = fs.existsSync(path.join(basePath, 'pages'));
|
|
14
|
+
|
|
15
|
+
if (!hasAppRouter && !hasPagesRouter) {
|
|
16
|
+
console.error("ā Could not find an 'app' or 'pages' directory. Make sure you are running this in the root of a Next.js project.");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
10
19
|
|
|
11
20
|
// Helper to ensure directory exists
|
|
12
21
|
function ensureDirSync(dirPath) {
|
|
13
22
|
if (!fs.existsSync(dirPath)) {
|
|
14
23
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
15
|
-
console.log(
|
|
24
|
+
console.log(`š Created directory: ${dirPath}`);
|
|
16
25
|
}
|
|
17
26
|
}
|
|
18
27
|
|
|
19
|
-
// Ensure base directories exist
|
|
20
|
-
ensureDirSync(srcDir);
|
|
21
28
|
ensureDirSync(componentsDir);
|
|
22
|
-
ensureDirSync(appDir);
|
|
23
|
-
ensureDirSync(pageDir);
|
|
24
29
|
|
|
25
30
|
// 1. Create factory.ts
|
|
26
31
|
const factoryPath = path.join(componentsDir, 'factory.ts');
|
|
@@ -34,9 +39,7 @@ export const componentMap = {
|
|
|
34
39
|
`;
|
|
35
40
|
if (!fs.existsSync(factoryPath)) {
|
|
36
41
|
fs.writeFileSync(factoryPath, factoryContent);
|
|
37
|
-
console.log('ā
Created
|
|
38
|
-
} else {
|
|
39
|
-
console.log('ā ļø src/components/factory.ts already exists, skipping.');
|
|
42
|
+
console.log('ā
Created components/factory.ts');
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
// 2. Create Header.tsx
|
|
@@ -54,9 +57,6 @@ export default function Header(props: any) {
|
|
|
54
57
|
{logoUrl && <img src={logoUrl} alt="Logo" width="40" />}
|
|
55
58
|
<h1 style={{ margin: 0, fontSize: '1.5rem' }}>{title}</h1>
|
|
56
59
|
</div>
|
|
57
|
-
<nav>
|
|
58
|
-
{/* Navigation links will go here */}
|
|
59
|
-
</nav>
|
|
60
60
|
</div>
|
|
61
61
|
</header>
|
|
62
62
|
);
|
|
@@ -64,9 +64,7 @@ export default function Header(props: any) {
|
|
|
64
64
|
`;
|
|
65
65
|
if (!fs.existsSync(headerPath)) {
|
|
66
66
|
fs.writeFileSync(headerPath, headerContent);
|
|
67
|
-
console.log('ā
Created
|
|
68
|
-
} else {
|
|
69
|
-
console.log('ā ļø src/components/Header.tsx already exists, skipping.');
|
|
67
|
+
console.log('ā
Created components/Header.tsx');
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
// 3. Create Footer.tsx
|
|
@@ -75,7 +73,6 @@ const footerContent = `import React from 'react';
|
|
|
75
73
|
|
|
76
74
|
export default function Footer(props: any) {
|
|
77
75
|
const text = props?.text || 'Ā© 2026 Velox Layout';
|
|
78
|
-
|
|
79
76
|
return (
|
|
80
77
|
<footer style={{ padding: '20px', background: '#333', color: '#fff', textAlign: 'center', marginTop: '40px' }}>
|
|
81
78
|
<p style={{ margin: 0 }}>{text}</p>
|
|
@@ -85,77 +82,108 @@ export default function Footer(props: any) {
|
|
|
85
82
|
`;
|
|
86
83
|
if (!fs.existsSync(footerPath)) {
|
|
87
84
|
fs.writeFileSync(footerPath, footerContent);
|
|
88
|
-
console.log('ā
Created
|
|
89
|
-
} else {
|
|
90
|
-
console.log('ā ļø src/components/Footer.tsx already exists, skipping.');
|
|
85
|
+
console.log('ā
Created components/Footer.tsx');
|
|
91
86
|
}
|
|
92
87
|
|
|
93
|
-
// 4.
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
// 4. Generate Page routing
|
|
89
|
+
if (hasAppRouter) {
|
|
90
|
+
console.log('š Detected Next.js App Router');
|
|
91
|
+
|
|
92
|
+
// Prevent Next.js route conflict by renaming existing app/page.tsx
|
|
93
|
+
const existingAppPage = path.join(basePath, 'app', 'page.tsx');
|
|
94
|
+
if (fs.existsSync(existingAppPage)) {
|
|
95
|
+
const backupPath = path.join(basePath, 'app', 'page.tsx.bak');
|
|
96
|
+
fs.renameSync(existingAppPage, backupPath);
|
|
97
|
+
console.log('ā ļø Renamed existing app/page.tsx to app/page.tsx.bak to avoid catch-all route conflict.');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const pageDir = path.join(basePath, 'app', '[[...slug]]');
|
|
101
|
+
ensureDirSync(pageDir);
|
|
102
|
+
|
|
103
|
+
const appPagePath = path.join(pageDir, 'page.tsx');
|
|
104
|
+
const appPageContent = `import React from 'react';
|
|
96
105
|
import { fetchVeloxLayout, Placeholder } from 'react-layout-sdk';
|
|
97
106
|
import { componentMap } from '@/components/factory';
|
|
98
107
|
|
|
99
108
|
export default async function Page({ params }: { params: { slug?: string[] } }) {
|
|
100
109
|
const slugArray = params.slug || [];
|
|
101
110
|
const path = slugArray.join('/') || '/';
|
|
102
|
-
|
|
103
|
-
// Make sure to replace this URL with your actual Strapi URL
|
|
104
111
|
const STRAPI_URL = process.env.NEXT_PUBLIC_STRAPI_URL || 'http://localhost:1337';
|
|
105
112
|
|
|
106
113
|
try {
|
|
107
114
|
const layoutData = await fetchVeloxLayout(STRAPI_URL, path, 'en');
|
|
108
|
-
|
|
109
|
-
if (!layoutData || !layoutData.strapi) {
|
|
110
|
-
return (
|
|
111
|
-
<div style={{ textAlign: 'center', padding: '50px' }}>
|
|
112
|
-
<h1>404 - Page/Layout Not Found</h1>
|
|
113
|
-
<p>Could not fetch layout for path: {path}</p>
|
|
114
|
-
</div>
|
|
115
|
-
);
|
|
116
|
-
}
|
|
115
|
+
if (!layoutData || !layoutData.strapi) return <h1>404 - Not Found</h1>;
|
|
117
116
|
|
|
118
117
|
const { route } = layoutData.strapi;
|
|
119
118
|
|
|
120
119
|
return (
|
|
121
120
|
<div className="layout-wrapper">
|
|
122
|
-
<Placeholder
|
|
123
|
-
name="header"
|
|
124
|
-
rendering={route.placeholders.header || []}
|
|
125
|
-
componentMap={componentMap}
|
|
126
|
-
/>
|
|
127
|
-
|
|
121
|
+
<Placeholder name="header" rendering={route.placeholders.header || []} componentMap={componentMap} />
|
|
128
122
|
<main style={{ minHeight: '60vh', padding: '20px' }}>
|
|
129
|
-
<Placeholder
|
|
130
|
-
name="main"
|
|
131
|
-
rendering={route.placeholders.main || []}
|
|
132
|
-
componentMap={componentMap}
|
|
133
|
-
/>
|
|
123
|
+
<Placeholder name="main" rendering={route.placeholders.main || []} componentMap={componentMap} />
|
|
134
124
|
</main>
|
|
135
|
-
|
|
136
|
-
<Placeholder
|
|
137
|
-
name="footer"
|
|
138
|
-
rendering={route.placeholders.footer || []}
|
|
139
|
-
componentMap={componentMap}
|
|
140
|
-
/>
|
|
125
|
+
<Placeholder name="footer" rendering={route.placeholders.footer || []} componentMap={componentMap} />
|
|
141
126
|
</div>
|
|
142
127
|
);
|
|
143
128
|
} catch (error) {
|
|
144
|
-
|
|
145
|
-
return (
|
|
146
|
-
<div style={{ textAlign: 'center', padding: '50px', color: 'red' }}>
|
|
147
|
-
<h1>Error Loading Layout</h1>
|
|
148
|
-
<p>Please check your Strapi server connection.</p>
|
|
149
|
-
</div>
|
|
150
|
-
);
|
|
129
|
+
return <h1>Error Loading Layout</h1>;
|
|
151
130
|
}
|
|
152
131
|
}
|
|
153
132
|
`;
|
|
154
|
-
if (!fs.existsSync(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
133
|
+
if (!fs.existsSync(appPagePath)) {
|
|
134
|
+
fs.writeFileSync(appPagePath, appPageContent);
|
|
135
|
+
console.log('ā
Created app/[[...slug]]/page.tsx');
|
|
136
|
+
}
|
|
137
|
+
} else if (hasPagesRouter) {
|
|
138
|
+
console.log('š Detected Next.js Pages Router');
|
|
139
|
+
|
|
140
|
+
// Prevent Next.js route conflict by renaming existing pages/index.tsx
|
|
141
|
+
const existingPagesIndex = path.join(basePath, 'pages', 'index.tsx');
|
|
142
|
+
if (fs.existsSync(existingPagesIndex)) {
|
|
143
|
+
const backupPath = path.join(basePath, 'pages', 'index.tsx.bak');
|
|
144
|
+
fs.renameSync(existingPagesIndex, backupPath);
|
|
145
|
+
console.log('ā ļø Renamed existing pages/index.tsx to pages/index.tsx.bak to avoid catch-all route conflict.');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const pagePath = path.join(basePath, 'pages', '[[...slug]].tsx');
|
|
149
|
+
const pagesContent = `import React from 'react';
|
|
150
|
+
import { fetchVeloxLayout, Placeholder } from 'react-layout-sdk';
|
|
151
|
+
import { componentMap } from '@/components/factory';
|
|
152
|
+
|
|
153
|
+
export default function LayoutPage({ layoutData, error }: any) {
|
|
154
|
+
if (error || !layoutData?.strapi) return <h1>404 - Layout Not Found</h1>;
|
|
155
|
+
|
|
156
|
+
const { route } = layoutData.strapi;
|
|
157
|
+
return (
|
|
158
|
+
<div className="layout-wrapper">
|
|
159
|
+
<Placeholder name="header" rendering={route.placeholders.header || []} componentMap={componentMap} />
|
|
160
|
+
<main style={{ minHeight: '60vh', padding: '20px' }}>
|
|
161
|
+
<Placeholder name="main" rendering={route.placeholders.main || []} componentMap={componentMap} />
|
|
162
|
+
</main>
|
|
163
|
+
<Placeholder name="footer" rendering={route.placeholders.footer || []} componentMap={componentMap} />
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export async function getServerSideProps(context: any) {
|
|
169
|
+
const slugArray = context.params?.slug || [];
|
|
170
|
+
const path = slugArray.join('/') || '/';
|
|
171
|
+
const STRAPI_URL = process.env.NEXT_PUBLIC_STRAPI_URL || 'http://localhost:1337';
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
const layoutData = await fetchVeloxLayout(STRAPI_URL, path, 'en');
|
|
175
|
+
if (!layoutData) return { notFound: true };
|
|
176
|
+
|
|
177
|
+
return { props: { layoutData } };
|
|
178
|
+
} catch (error) {
|
|
179
|
+
return { props: { error: true } };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
`;
|
|
183
|
+
if (!fs.existsSync(pagePath)) {
|
|
184
|
+
fs.writeFileSync(pagePath, pagesContent);
|
|
185
|
+
console.log('ā
Created pages/[[...slug]].tsx');
|
|
186
|
+
}
|
|
159
187
|
}
|
|
160
188
|
|
|
161
|
-
console.log('
|
|
189
|
+
console.log('\nš Layout setup complete! Please verify your Strapi URL in your routing page.');
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-layout-sdk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "React components for Velox SDK (Sitecore-like routing)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"react-layout-sdk": "
|
|
9
|
+
"react-layout-sdk": "bin/init.js"
|
|
10
10
|
},
|
|
11
11
|
"peerDependencies": {
|
|
12
12
|
"react": ">=18.0.0",
|