react-layout-sdk 1.0.0 → 1.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.
Files changed (2) hide show
  1. package/bin/init.js +171 -0
  2. package/package.json +4 -1
package/bin/init.js ADDED
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const projectRoot = process.cwd();
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
+ }
19
+
20
+ // Helper to ensure directory exists
21
+ function ensureDirSync(dirPath) {
22
+ if (!fs.existsSync(dirPath)) {
23
+ fs.mkdirSync(dirPath, { recursive: true });
24
+ console.log(`šŸ“ Created directory: ${dirPath}`);
25
+ }
26
+ }
27
+
28
+ ensureDirSync(componentsDir);
29
+
30
+ // 1. Create factory.ts
31
+ const factoryPath = path.join(componentsDir, 'factory.ts');
32
+ const factoryContent = `import Header from './Header';
33
+ import Footer from './Footer';
34
+
35
+ export const componentMap = {
36
+ 'velox.header': Header,
37
+ 'velox.footer': Footer,
38
+ };
39
+ `;
40
+ if (!fs.existsSync(factoryPath)) {
41
+ fs.writeFileSync(factoryPath, factoryContent);
42
+ console.log('āœ… Created components/factory.ts');
43
+ }
44
+
45
+ // 2. Create Header.tsx
46
+ const headerPath = path.join(componentsDir, 'Header.tsx');
47
+ const headerContent = `import React from 'react';
48
+
49
+ export default function Header(props: any) {
50
+ const title = props?.title || 'Velox Header';
51
+ const logoUrl = props?.logoUrl;
52
+
53
+ return (
54
+ <header style={{ padding: '20px', background: '#f5f5f5', borderBottom: '1px solid #ddd' }}>
55
+ <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
56
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
57
+ {logoUrl && <img src={logoUrl} alt="Logo" width="40" />}
58
+ <h1 style={{ margin: 0, fontSize: '1.5rem' }}>{title}</h1>
59
+ </div>
60
+ </div>
61
+ </header>
62
+ );
63
+ }
64
+ `;
65
+ if (!fs.existsSync(headerPath)) {
66
+ fs.writeFileSync(headerPath, headerContent);
67
+ console.log('āœ… Created components/Header.tsx');
68
+ }
69
+
70
+ // 3. Create Footer.tsx
71
+ const footerPath = path.join(componentsDir, 'Footer.tsx');
72
+ const footerContent = `import React from 'react';
73
+
74
+ export default function Footer(props: any) {
75
+ const text = props?.text || 'Ā© 2026 Velox Layout';
76
+ return (
77
+ <footer style={{ padding: '20px', background: '#333', color: '#fff', textAlign: 'center', marginTop: '40px' }}>
78
+ <p style={{ margin: 0 }}>{text}</p>
79
+ </footer>
80
+ );
81
+ }
82
+ `;
83
+ if (!fs.existsSync(footerPath)) {
84
+ fs.writeFileSync(footerPath, footerContent);
85
+ console.log('āœ… Created components/Footer.tsx');
86
+ }
87
+
88
+ // 4. Generate Page routing
89
+ if (hasAppRouter) {
90
+ console.log('šŸ” Detected Next.js App Router');
91
+ const pageDir = path.join(basePath, 'app', '[[...slug]]');
92
+ ensureDirSync(pageDir);
93
+
94
+ const appPagePath = path.join(pageDir, 'page.tsx');
95
+ const appPageContent = `import React from 'react';
96
+ import { fetchVeloxLayout, Placeholder } from 'react-layout-sdk';
97
+ import { componentMap } from '@/components/factory';
98
+
99
+ export default async function Page({ params }: { params: { slug?: string[] } }) {
100
+ const slugArray = params.slug || [];
101
+ const path = slugArray.join('/') || '/';
102
+ const STRAPI_URL = process.env.NEXT_PUBLIC_STRAPI_URL || 'http://localhost:1337';
103
+
104
+ try {
105
+ const layoutData = await fetchVeloxLayout(STRAPI_URL, path, 'en');
106
+ if (!layoutData || !layoutData.strapi) return <h1>404 - Not Found</h1>;
107
+
108
+ const { route } = layoutData.strapi;
109
+
110
+ return (
111
+ <div className="layout-wrapper">
112
+ <Placeholder name="header" rendering={route.placeholders.header || []} componentMap={componentMap} />
113
+ <main style={{ minHeight: '60vh', padding: '20px' }}>
114
+ <Placeholder name="main" rendering={route.placeholders.main || []} componentMap={componentMap} />
115
+ </main>
116
+ <Placeholder name="footer" rendering={route.placeholders.footer || []} componentMap={componentMap} />
117
+ </div>
118
+ );
119
+ } catch (error) {
120
+ return <h1>Error Loading Layout</h1>;
121
+ }
122
+ }
123
+ `;
124
+ if (!fs.existsSync(appPagePath)) {
125
+ fs.writeFileSync(appPagePath, appPageContent);
126
+ console.log('āœ… Created app/[[...slug]]/page.tsx');
127
+ }
128
+ } else if (hasPagesRouter) {
129
+ console.log('šŸ” Detected Next.js Pages Router');
130
+ const pagePath = path.join(basePath, 'pages', '[[...slug]].tsx');
131
+ const pagesContent = `import React from 'react';
132
+ import { fetchVeloxLayout, Placeholder } from 'react-layout-sdk';
133
+ import { componentMap } from '@/components/factory';
134
+
135
+ export default function LayoutPage({ layoutData, error }: any) {
136
+ if (error || !layoutData?.strapi) return <h1>404 - Layout Not Found</h1>;
137
+
138
+ const { route } = layoutData.strapi;
139
+ return (
140
+ <div className="layout-wrapper">
141
+ <Placeholder name="header" rendering={route.placeholders.header || []} componentMap={componentMap} />
142
+ <main style={{ minHeight: '60vh', padding: '20px' }}>
143
+ <Placeholder name="main" rendering={route.placeholders.main || []} componentMap={componentMap} />
144
+ </main>
145
+ <Placeholder name="footer" rendering={route.placeholders.footer || []} componentMap={componentMap} />
146
+ </div>
147
+ );
148
+ }
149
+
150
+ export async function getServerSideProps(context: any) {
151
+ const slugArray = context.params?.slug || [];
152
+ const path = slugArray.join('/') || '/';
153
+ const STRAPI_URL = process.env.NEXT_PUBLIC_STRAPI_URL || 'http://localhost:1337';
154
+
155
+ try {
156
+ const layoutData = await fetchVeloxLayout(STRAPI_URL, path, 'en');
157
+ if (!layoutData) return { notFound: true };
158
+
159
+ return { props: { layoutData } };
160
+ } catch (error) {
161
+ return { props: { error: true } };
162
+ }
163
+ }
164
+ `;
165
+ if (!fs.existsSync(pagePath)) {
166
+ fs.writeFileSync(pagePath, pagesContent);
167
+ console.log('āœ… Created pages/[[...slug]].tsx');
168
+ }
169
+ }
170
+
171
+ console.log('\nšŸš€ Layout setup complete! Please verify your Strapi URL in your routing page.');
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "react-layout-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
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
+ "bin": {
9
+ "react-layout-sdk": "./bin/init.js"
10
+ },
8
11
  "peerDependencies": {
9
12
  "react": ">=18.0.0",
10
13
  "react-dom": ">=18.0.0"