@digitalygo/create-diggocms-app 0.1.0
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/README.md +152 -0
- package/bin/cli.js +392 -0
- package/package.json +44 -0
- package/templates/full/.env.local.example +13 -0
- package/templates/full/README.md +101 -0
- package/templates/full/app/[...slug]/page.tsx +115 -0
- package/templates/full/app/globals.css +187 -0
- package/templates/full/app/layout.tsx +25 -0
- package/templates/full/app/page.tsx +6 -0
- package/templates/full/components/DiggoProvider.tsx +15 -0
- package/templates/full/components/ExtendedCard.tsx +15 -0
- package/templates/full/components/ExtendedImage.tsx +16 -0
- package/templates/full/components/ExtendedMenuContainer.tsx +10 -0
- package/templates/full/components/ExtendedMenuItem.tsx +22 -0
- package/templates/full/components/ExtendedRichtext.tsx +15 -0
- package/templates/full/components/ExtendedSubtitle.tsx +10 -0
- package/templates/full/components/ExtendedTitle.tsx +10 -0
- package/templates/full/components/server-components.ts +8 -0
- package/templates/full/lib/data-fetching.ts +205 -0
- package/templates/full/lib/diggo-config.ts +48 -0
- package/templates/full/next-env.d.ts +2 -0
- package/templates/full/next.config.ts +7 -0
- package/templates/full/package.json +25 -0
- package/templates/full/tsconfig.json +23 -0
- package/templates/minimal/.env.local.example +13 -0
- package/templates/minimal/README.md +67 -0
- package/templates/minimal/app/[...slug]/page.tsx +56 -0
- package/templates/minimal/app/globals.css +11 -0
- package/templates/minimal/app/layout.tsx +22 -0
- package/templates/minimal/app/page.tsx +6 -0
- package/templates/minimal/components/DiggoProvider.tsx +15 -0
- package/templates/minimal/lib/data-fetching.ts +59 -0
- package/templates/minimal/lib/diggo-config.ts +35 -0
- package/templates/minimal/next-env.d.ts +2 -0
- package/templates/minimal/next.config.ts +7 -0
- package/templates/minimal/package.json +25 -0
- package/templates/minimal/tsconfig.json +23 -0
- package/templates/with-mock/.env.local.example +13 -0
- package/templates/with-mock/README.md +128 -0
- package/templates/with-mock/app/[...slug]/page.tsx +115 -0
- package/templates/with-mock/app/globals.css +187 -0
- package/templates/with-mock/app/layout.tsx +25 -0
- package/templates/with-mock/app/page.tsx +6 -0
- package/templates/with-mock/components/DiggoProvider.tsx +15 -0
- package/templates/with-mock/components/ExtendedCard.tsx +15 -0
- package/templates/with-mock/components/ExtendedImage.tsx +16 -0
- package/templates/with-mock/components/ExtendedMenuContainer.tsx +10 -0
- package/templates/with-mock/components/ExtendedMenuItem.tsx +22 -0
- package/templates/with-mock/components/ExtendedRichtext.tsx +15 -0
- package/templates/with-mock/components/ExtendedSubtitle.tsx +10 -0
- package/templates/with-mock/components/ExtendedTitle.tsx +10 -0
- package/templates/with-mock/components/server-components.ts +8 -0
- package/templates/with-mock/fixtures/collection.json +28 -0
- package/templates/with-mock/fixtures/menu.json +29 -0
- package/templates/with-mock/fixtures/pages/chi-siamo.json +37 -0
- package/templates/with-mock/fixtures/pages/contatti.json +33 -0
- package/templates/with-mock/fixtures/pages/home.json +62 -0
- package/templates/with-mock/fixtures/pages/index.json +17 -0
- package/templates/with-mock/lib/data-fetching.ts +205 -0
- package/templates/with-mock/lib/diggo-config.ts +48 -0
- package/templates/with-mock/next-env.d.ts +2 -0
- package/templates/with-mock/next.config.ts +7 -0
- package/templates/with-mock/package.json +27 -0
- package/templates/with-mock/scripts/mock-server.ts +231 -0
- package/templates/with-mock/tsconfig.json +23 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { Metadata } from 'next';
|
|
3
|
+
import Link from 'next/link';
|
|
4
|
+
import { notFound } from 'next/navigation';
|
|
5
|
+
import { fetchPageData, fetchMenuData } from '@/lib/data-fetching';
|
|
6
|
+
import {
|
|
7
|
+
componentsRegistry,
|
|
8
|
+
navigationRegistry,
|
|
9
|
+
isMockMode,
|
|
10
|
+
hasBaseUrl,
|
|
11
|
+
} from '@/lib/diggo-config';
|
|
12
|
+
import { renderPage, renderMenu } from '@digitalygo/diggocms-sdk-core/server';
|
|
13
|
+
|
|
14
|
+
export const dynamic = 'force-dynamic';
|
|
15
|
+
|
|
16
|
+
interface CatchAllPageProps {
|
|
17
|
+
params: Promise<{ slug: string[] }>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function generateMetadata({
|
|
21
|
+
params,
|
|
22
|
+
}: CatchAllPageProps): Promise<Metadata> {
|
|
23
|
+
const { slug: slugParam } = await params;
|
|
24
|
+
const slug = (Array.isArray(slugParam) ? slugParam : []).join('/') || 'home';
|
|
25
|
+
const { page } = await fetchPageData(slug);
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
title: page?.title,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default async function CatchAllPage({
|
|
33
|
+
params,
|
|
34
|
+
}: CatchAllPageProps): Promise<ReactElement> {
|
|
35
|
+
const { slug: slugParam } = await params;
|
|
36
|
+
const slug = (Array.isArray(slugParam) ? slugParam : []).join('/') || 'home';
|
|
37
|
+
|
|
38
|
+
const [{ page, error, usingMock }, { menu }] = await Promise.all([
|
|
39
|
+
fetchPageData(slug),
|
|
40
|
+
fetchMenuData('main'),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const showMockIndicator = usingMock || isMockMode();
|
|
44
|
+
const showError = error && !page;
|
|
45
|
+
|
|
46
|
+
if (!page) {
|
|
47
|
+
if (!hasBaseUrl() && !isMockMode()) {
|
|
48
|
+
return (
|
|
49
|
+
<div className="container">
|
|
50
|
+
<header className="header">
|
|
51
|
+
<div className="header-content container">
|
|
52
|
+
<div className="logo">My DiggoCMS App</div>
|
|
53
|
+
</div>
|
|
54
|
+
</header>
|
|
55
|
+
<main className="main container">
|
|
56
|
+
<div className="error-banner">
|
|
57
|
+
<strong>Error:</strong> BASE_URL is not configured and MOCK mode
|
|
58
|
+
is disabled.
|
|
59
|
+
</div>
|
|
60
|
+
<p>
|
|
61
|
+
Please configure your environment variables. Copy{' '}
|
|
62
|
+
<code>.env.local.example</code> to <code>.env.local</code> and set
|
|
63
|
+
either:
|
|
64
|
+
</p>
|
|
65
|
+
<ul style={{ marginLeft: '1.5rem', marginTop: '0.5rem' }}>
|
|
66
|
+
<li>
|
|
67
|
+
<code>MOCK=1</code> to use local fixtures
|
|
68
|
+
</li>
|
|
69
|
+
<li>
|
|
70
|
+
<code>BASE_URL</code> to your CMS API endpoint
|
|
71
|
+
</li>
|
|
72
|
+
</ul>
|
|
73
|
+
</main>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
notFound();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div>
|
|
83
|
+
<header className="header">
|
|
84
|
+
<div className="header-content container">
|
|
85
|
+
<Link href="/" className="logo">
|
|
86
|
+
My DiggoCMS App
|
|
87
|
+
</Link>
|
|
88
|
+
{menu && renderMenu(menu, navigationRegistry)}
|
|
89
|
+
</div>
|
|
90
|
+
</header>
|
|
91
|
+
|
|
92
|
+
<main className="main container">
|
|
93
|
+
{showError && !showMockIndicator && (
|
|
94
|
+
<div className="error-banner">
|
|
95
|
+
<strong>Warning:</strong> {error}
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
{showMockIndicator && (
|
|
100
|
+
<div className="mock-badge">
|
|
101
|
+
Mock Mode
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
|
|
105
|
+
{renderPage(page, componentsRegistry)}
|
|
106
|
+
</main>
|
|
107
|
+
|
|
108
|
+
<footer className="footer">
|
|
109
|
+
<div className="container">
|
|
110
|
+
<p>My DiggoCMS App © {new Date().getFullYear()}</p>
|
|
111
|
+
</div>
|
|
112
|
+
</footer>
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
9
|
+
line-height: 1.6;
|
|
10
|
+
color: #333;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.container {
|
|
14
|
+
max-width: 1200px;
|
|
15
|
+
margin: 0 auto;
|
|
16
|
+
padding: 0 1rem;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Header Styles */
|
|
20
|
+
.header {
|
|
21
|
+
background: #fff;
|
|
22
|
+
border-bottom: 1px solid #e5e7eb;
|
|
23
|
+
padding: 1rem 0;
|
|
24
|
+
margin-bottom: 2rem;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header-content {
|
|
28
|
+
display: flex;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
align-items: center;
|
|
31
|
+
flex-wrap: wrap;
|
|
32
|
+
gap: 1rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.logo {
|
|
36
|
+
font-size: 1.5rem;
|
|
37
|
+
font-weight: 700;
|
|
38
|
+
color: #3b82f6;
|
|
39
|
+
text-decoration: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Main Content */
|
|
43
|
+
.main {
|
|
44
|
+
min-height: calc(100vh - 200px);
|
|
45
|
+
padding-bottom: 3rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Footer Styles */
|
|
49
|
+
.footer {
|
|
50
|
+
background: #f9fafb;
|
|
51
|
+
border-top: 1px solid #e5e7eb;
|
|
52
|
+
padding: 2rem 0;
|
|
53
|
+
text-align: center;
|
|
54
|
+
color: #6b7280;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Error Banner */
|
|
58
|
+
.error-banner {
|
|
59
|
+
background: #fef3c7;
|
|
60
|
+
border: 1px solid #fbbf24;
|
|
61
|
+
border-radius: 0.375rem;
|
|
62
|
+
padding: 1rem;
|
|
63
|
+
margin-bottom: 1.5rem;
|
|
64
|
+
color: #92400e;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Mock Badge */
|
|
68
|
+
.mock-badge {
|
|
69
|
+
display: inline-block;
|
|
70
|
+
background: #dbeafe;
|
|
71
|
+
color: #1e40af;
|
|
72
|
+
padding: 0.25rem 0.75rem;
|
|
73
|
+
border-radius: 9999px;
|
|
74
|
+
font-size: 0.75rem;
|
|
75
|
+
font-weight: 500;
|
|
76
|
+
margin-bottom: 1rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Component Styles */
|
|
80
|
+
.diggo-title {
|
|
81
|
+
font-size: 2.5rem;
|
|
82
|
+
font-weight: 700;
|
|
83
|
+
color: #111827;
|
|
84
|
+
margin-bottom: 1rem;
|
|
85
|
+
line-height: 1.2;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.diggo-subtitle {
|
|
89
|
+
font-size: 1.5rem;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
color: #374151;
|
|
92
|
+
margin-bottom: 1rem;
|
|
93
|
+
margin-top: 2rem;
|
|
94
|
+
line-height: 1.3;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.diggo-image {
|
|
98
|
+
max-width: 100%;
|
|
99
|
+
height: auto;
|
|
100
|
+
border-radius: 0.5rem;
|
|
101
|
+
margin: 1rem 0;
|
|
102
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.diggo-richtext {
|
|
106
|
+
margin: 1rem 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.diggo-richtext p {
|
|
110
|
+
margin-bottom: 1rem;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.diggo-card {
|
|
114
|
+
background: #fff;
|
|
115
|
+
border: 1px solid #e5e7eb;
|
|
116
|
+
border-radius: 0.5rem;
|
|
117
|
+
padding: 1.5rem;
|
|
118
|
+
margin: 1.5rem 0;
|
|
119
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.diggo-card .diggo-title {
|
|
123
|
+
font-size: 1.25rem;
|
|
124
|
+
margin-bottom: 0.5rem;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.diggo-card .diggo-subtitle {
|
|
128
|
+
font-size: 1rem;
|
|
129
|
+
color: #6b7280;
|
|
130
|
+
margin-top: 0;
|
|
131
|
+
margin-bottom: 1rem;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Navigation Styles */
|
|
135
|
+
.menu {
|
|
136
|
+
display: flex;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.menu-list {
|
|
140
|
+
display: flex;
|
|
141
|
+
list-style: none;
|
|
142
|
+
gap: 1.5rem;
|
|
143
|
+
flex-wrap: wrap;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.menu-item {
|
|
147
|
+
position: relative;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.menu-link {
|
|
151
|
+
color: #374151;
|
|
152
|
+
text-decoration: none;
|
|
153
|
+
font-weight: 500;
|
|
154
|
+
padding: 0.5rem 0;
|
|
155
|
+
transition: color 0.2s;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.menu-link:hover {
|
|
159
|
+
color: #3b82f6;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.menu-link[aria-current='page'] {
|
|
163
|
+
color: #3b82f6;
|
|
164
|
+
border-bottom: 2px solid #3b82f6;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.menu-item ul {
|
|
168
|
+
display: none;
|
|
169
|
+
position: absolute;
|
|
170
|
+
top: 100%;
|
|
171
|
+
left: 0;
|
|
172
|
+
background: #fff;
|
|
173
|
+
border: 1px solid #e5e7eb;
|
|
174
|
+
border-radius: 0.375rem;
|
|
175
|
+
padding: 0.5rem 0;
|
|
176
|
+
min-width: 150px;
|
|
177
|
+
list-style: none;
|
|
178
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.menu-item:hover > ul {
|
|
182
|
+
display: block;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.menu-item ul li {
|
|
186
|
+
padding: 0.25rem 1rem;
|
|
187
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import { DiggoProvider } from '@/components/DiggoProvider';
|
|
3
|
+
import './globals.css';
|
|
4
|
+
|
|
5
|
+
export const metadata = {
|
|
6
|
+
title: {
|
|
7
|
+
template: '%s | My DiggoCMS App',
|
|
8
|
+
default: 'My DiggoCMS App',
|
|
9
|
+
},
|
|
10
|
+
description: 'Built with DiggoCMS SDK',
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default function RootLayout({
|
|
14
|
+
children,
|
|
15
|
+
}: {
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
}): ReactElement {
|
|
18
|
+
return (
|
|
19
|
+
<html lang="en">
|
|
20
|
+
<body>
|
|
21
|
+
<DiggoProvider>{children}</DiggoProvider>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
4
|
+
import { DiggoProvider as SDKProvider } from '@digitalygo/diggocms-sdk-core';
|
|
5
|
+
import { sdkConfig } from '@/lib/diggo-config';
|
|
6
|
+
|
|
7
|
+
interface DiggoProviderWrapperProps {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function DiggoProvider({
|
|
12
|
+
children,
|
|
13
|
+
}: DiggoProviderWrapperProps): ReactElement {
|
|
14
|
+
return <SDKProvider config={sdkConfig}>{children}</SDKProvider>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CardProps } from '@digitalygo/diggocms-sdk-core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
import { ExtendedTitle } from './ExtendedTitle';
|
|
4
|
+
import { ExtendedSubtitle } from './ExtendedSubtitle';
|
|
5
|
+
import { ExtendedRichtext } from './ExtendedRichtext';
|
|
6
|
+
|
|
7
|
+
export function ExtendedCard({ title, subtitle, content }: CardProps): ReactElement | null {
|
|
8
|
+
return (
|
|
9
|
+
<div className="diggo-card">
|
|
10
|
+
{title && <ExtendedTitle content={title} />}
|
|
11
|
+
{subtitle && <ExtendedSubtitle content={subtitle} />}
|
|
12
|
+
{content && <ExtendedRichtext content={content} />}
|
|
13
|
+
</div>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ImageProps } from '@digitalygo/diggocms-sdk-core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
export function ExtendedImage({ src, alt }: ImageProps): ReactElement | null {
|
|
5
|
+
if (!src) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<img
|
|
11
|
+
src={src}
|
|
12
|
+
alt={alt || ''}
|
|
13
|
+
className="diggo-image"
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MenuContainerProps } from '@digitalygo/diggocms-sdk-core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
export function ExtendedMenuContainer({ children }: MenuContainerProps): ReactElement {
|
|
5
|
+
return (
|
|
6
|
+
<nav className="menu">
|
|
7
|
+
<ul className="menu-list">{children}</ul>
|
|
8
|
+
</nav>
|
|
9
|
+
);
|
|
10
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MenuItemProps } from '@digitalygo/diggocms-sdk-core';
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
interface ExtendedMenuItemProps extends MenuItemProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function ExtendedMenuItem({
|
|
9
|
+
label,
|
|
10
|
+
href,
|
|
11
|
+
current,
|
|
12
|
+
children,
|
|
13
|
+
}: ExtendedMenuItemProps): ReactElement {
|
|
14
|
+
return (
|
|
15
|
+
<li className="menu-item">
|
|
16
|
+
<a href={href} aria-current={current ? 'page' : undefined} className="menu-link">
|
|
17
|
+
{label}
|
|
18
|
+
</a>
|
|
19
|
+
{children}
|
|
20
|
+
</li>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RichtextProps } from '@digitalygo/diggocms-sdk-core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
export function ExtendedRichtext({ content }: RichtextProps): ReactElement | null {
|
|
5
|
+
if (!content) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<div
|
|
11
|
+
className="diggo-richtext"
|
|
12
|
+
dangerouslySetInnerHTML={{ __html: content }}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SubtitleProps } from '@digitalygo/diggocms-sdk-core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
export function ExtendedSubtitle({ content }: SubtitleProps): ReactElement | null {
|
|
5
|
+
if (!content) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return <h2 className="diggo-subtitle">{content}</h2>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TitleProps } from '@digitalygo/diggocms-sdk-core';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
|
|
4
|
+
export function ExtendedTitle({ content }: TitleProps): ReactElement | null {
|
|
5
|
+
if (!content) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return <h1 className="diggo-title">{content}</h1>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Re-export components for server-side usage (they're server-safe pure components)
|
|
2
|
+
export { ExtendedTitle } from './ExtendedTitle';
|
|
3
|
+
export { ExtendedSubtitle } from './ExtendedSubtitle';
|
|
4
|
+
export { ExtendedImage } from './ExtendedImage';
|
|
5
|
+
export { ExtendedRichtext } from './ExtendedRichtext';
|
|
6
|
+
export { ExtendedCard } from './ExtendedCard';
|
|
7
|
+
export { ExtendedMenuItem } from './ExtendedMenuItem';
|
|
8
|
+
export { ExtendedMenuContainer } from './ExtendedMenuContainer';
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
PagePayload,
|
|
3
|
+
CollectionPayload,
|
|
4
|
+
MenuPayload,
|
|
5
|
+
} from '@digitalygo/diggocms-sdk-core';
|
|
6
|
+
import { sdkConfig, isMockMode, hasBaseUrl } from './diggo-config';
|
|
7
|
+
|
|
8
|
+
interface PageIndexItem {
|
|
9
|
+
id: string;
|
|
10
|
+
slug: string;
|
|
11
|
+
title: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const DEFAULT_MOCK_API_URL = 'http://localhost:3001';
|
|
15
|
+
|
|
16
|
+
function getMockApiBaseUrl(): string {
|
|
17
|
+
return process.env.MOCK_API_URL ?? DEFAULT_MOCK_API_URL;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function fetchFromMockApi<T>(endpoint: string): Promise<T | null> {
|
|
21
|
+
try {
|
|
22
|
+
const baseUrl = getMockApiBaseUrl();
|
|
23
|
+
const response = await fetch(`${baseUrl}${endpoint}`);
|
|
24
|
+
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (await response.json()) as T;
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function loadPagesIndex(): Promise<PageIndexItem[]> {
|
|
36
|
+
const index = await fetchFromMockApi<PageIndexItem[]>('/pages');
|
|
37
|
+
return index ?? [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface FetchPageResult {
|
|
41
|
+
page: PagePayload | null;
|
|
42
|
+
error: string | null;
|
|
43
|
+
usingMock: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface FetchCollectionResult {
|
|
47
|
+
collection: CollectionPayload | null;
|
|
48
|
+
error: string | null;
|
|
49
|
+
usingMock: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface FetchMenuResult {
|
|
53
|
+
menu: MenuPayload | null;
|
|
54
|
+
error: string | null;
|
|
55
|
+
usingMock: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function normalizeSlug(slug: string): string {
|
|
59
|
+
if (slug === 'home' || slug === '') {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
return slug;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function loadPageFromMockApi(slug: string): Promise<PagePayload | null> {
|
|
66
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
67
|
+
const index = await loadPagesIndex();
|
|
68
|
+
|
|
69
|
+
const pageExists = index.some(
|
|
70
|
+
(item) => normalizeSlug(item.slug) === normalizedSlug
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (!pageExists) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const endpoint =
|
|
78
|
+
normalizedSlug === '' ? '/pages/home' : `/pages/${normalizedSlug}`;
|
|
79
|
+
|
|
80
|
+
return fetchFromMockApi<PagePayload>(endpoint);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function fetchPageData(slug: string): Promise<FetchPageResult> {
|
|
84
|
+
if (isMockMode()) {
|
|
85
|
+
const page = await loadPageFromMockApi(slug);
|
|
86
|
+
return {
|
|
87
|
+
page,
|
|
88
|
+
error: page ? null : 'Failed to load mock page from API',
|
|
89
|
+
usingMock: true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!hasBaseUrl()) {
|
|
94
|
+
return {
|
|
95
|
+
page: null,
|
|
96
|
+
error: 'BASE_URL is not configured and MOCK mode is not enabled.',
|
|
97
|
+
usingMock: false,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const response = await fetch(`${sdkConfig.baseUrl}/pages/${slug}`);
|
|
103
|
+
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
return {
|
|
106
|
+
page: null,
|
|
107
|
+
error: `Failed to fetch page: ${response.statusText}`,
|
|
108
|
+
usingMock: false,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const page = (await response.json()) as PagePayload;
|
|
113
|
+
return { page, error: null, usingMock: false };
|
|
114
|
+
} catch {
|
|
115
|
+
return {
|
|
116
|
+
page: null,
|
|
117
|
+
error: 'Error connecting to CMS',
|
|
118
|
+
usingMock: false,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function fetchCollectionData(
|
|
124
|
+
type: string
|
|
125
|
+
): Promise<FetchCollectionResult> {
|
|
126
|
+
if (isMockMode()) {
|
|
127
|
+
const collection = await fetchFromMockApi<CollectionPayload>(
|
|
128
|
+
`/collections/${type}`
|
|
129
|
+
);
|
|
130
|
+
return {
|
|
131
|
+
collection,
|
|
132
|
+
error: collection ? null : 'Failed to load mock collection from API',
|
|
133
|
+
usingMock: true,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!hasBaseUrl()) {
|
|
138
|
+
return {
|
|
139
|
+
collection: null,
|
|
140
|
+
error: 'BASE_URL is not configured and MOCK mode is not enabled.',
|
|
141
|
+
usingMock: false,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const response = await fetch(`${sdkConfig.baseUrl}/collections/${type}`);
|
|
147
|
+
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
return {
|
|
150
|
+
collection: null,
|
|
151
|
+
error: `Failed to fetch collection: ${response.statusText}`,
|
|
152
|
+
usingMock: false,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const collection = (await response.json()) as CollectionPayload;
|
|
157
|
+
return { collection, error: null, usingMock: false };
|
|
158
|
+
} catch {
|
|
159
|
+
return {
|
|
160
|
+
collection: null,
|
|
161
|
+
error: 'Error connecting to CMS',
|
|
162
|
+
usingMock: false,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export async function fetchMenuData(key: string): Promise<FetchMenuResult> {
|
|
168
|
+
if (isMockMode()) {
|
|
169
|
+
const menu = await fetchFromMockApi<MenuPayload>(`/menus/${key}`);
|
|
170
|
+
return {
|
|
171
|
+
menu,
|
|
172
|
+
error: menu ? null : 'Failed to load mock menu from API',
|
|
173
|
+
usingMock: true,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!hasBaseUrl()) {
|
|
178
|
+
return {
|
|
179
|
+
menu: null,
|
|
180
|
+
error: 'BASE_URL is not configured and MOCK mode is not enabled.',
|
|
181
|
+
usingMock: false,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
try {
|
|
186
|
+
const response = await fetch(`${sdkConfig.baseUrl}/menus/${key}`);
|
|
187
|
+
|
|
188
|
+
if (!response.ok) {
|
|
189
|
+
return {
|
|
190
|
+
menu: null,
|
|
191
|
+
error: `Failed to fetch menu: ${response.statusText}`,
|
|
192
|
+
usingMock: false,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const menu = (await response.json()) as MenuPayload;
|
|
197
|
+
return { menu, error: null, usingMock: false };
|
|
198
|
+
} catch {
|
|
199
|
+
return {
|
|
200
|
+
menu: null,
|
|
201
|
+
error: 'Error connecting to CMS',
|
|
202
|
+
usingMock: false,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|