rankrunners-cms 0.0.18 → 0.0.19
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 +39 -18
- package/package.json +8 -9
- package/src/api/client/pages.ts +57 -0
- package/src/editor/render/PageRendererContent.tsx +2 -51
- package/src/editor/render/PageRendererSSR.tsx +15 -0
- package/src/editor/render/Preview.tsx +1 -4
- package/src/tanstack/editor/Editor.tsx +3 -5
- package/src/tanstack/editor/PageRenderer.tsx +4 -0
package/README.md
CHANGED
|
@@ -571,25 +571,46 @@ Update the `server.ts` script, or add a Tanstack Start middleware to handle `[si
|
|
|
571
571
|
// Build static routes with intelligent preloading
|
|
572
572
|
const { routes } = await initializeStaticRoutes(CLIENT_DIRECTORY)
|
|
573
573
|
|
|
574
|
-
//
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
574
|
+
// Import sitemap handler dynamically to help Bun bundle it
|
|
575
|
+
const downloadSitemapAsResponse = (
|
|
576
|
+
await import('rankrunners-cms/src/api/client/sitemap')
|
|
577
|
+
).downloadSitemapAsResponse
|
|
578
|
+
|
|
579
|
+
// Create Bun server
|
|
580
|
+
const server = Bun.serve({
|
|
581
|
+
port: SERVER_PORT,
|
|
582
|
+
|
|
583
|
+
routes: {
|
|
584
|
+
// Serve static assets, robots.txt, sitemaps (*.xml), and all other routes
|
|
585
|
+
...routes,
|
|
586
|
+
'/*': (req: Request) => {
|
|
587
|
+
const url = new URL(req.url)
|
|
588
|
+
const pathname = url.pathname
|
|
589
|
+
|
|
590
|
+
// Check if it's a sitemap file (ends with .xml)
|
|
591
|
+
if (pathname === 'robots.txt' || pathname.endsWith('.xml')) {
|
|
592
|
+
const sitemapFile = pathname.substring(1) // Remove leading slash
|
|
593
|
+
return downloadSitemapAsResponse(sitemapFile)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Otherwise, pass to TanStack Start handler
|
|
597
|
+
try {
|
|
598
|
+
return handler.fetch(req)
|
|
599
|
+
} catch (error) {
|
|
600
|
+
log.error(`Server handler error: ${String(error)}`)
|
|
601
|
+
return new Response('Internal Server Error', { status: 500 })
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
|
|
606
|
+
// Global error handler
|
|
607
|
+
error(error) {
|
|
608
|
+
log.error(
|
|
609
|
+
`Uncaught server error: ${error instanceof Error ? error.message : String(error)}`,
|
|
610
|
+
)
|
|
590
611
|
return new Response('Internal Server Error', { status: 500 })
|
|
591
|
-
}
|
|
592
|
-
}
|
|
612
|
+
},
|
|
613
|
+
})
|
|
593
614
|
```
|
|
594
615
|
|
|
595
616
|
---
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rankrunners-cms",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.19",
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@puckeditor/core": "^0.21.
|
|
6
|
+
"@puckeditor/core": "^0.21.1",
|
|
7
7
|
"next": "^16.1.2",
|
|
8
8
|
"@tanstack/router-core": "^1.150.0",
|
|
9
9
|
"@tanstack/react-router": "^1.150.0",
|
|
@@ -29,15 +29,14 @@
|
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@types/react": "^19.2.
|
|
33
|
-
"bun-types": "^1.3.
|
|
32
|
+
"@types/react": "^19.2.11",
|
|
33
|
+
"bun-types": "^1.3.8",
|
|
34
34
|
"typescript": "^5.9.3",
|
|
35
|
-
"@tanstack/router-core": "^1.
|
|
36
|
-
"@tanstack/react-router": "^1.
|
|
37
|
-
"next": "^16.1.
|
|
35
|
+
"@tanstack/router-core": "^1.158.0",
|
|
36
|
+
"@tanstack/react-router": "^1.158.0",
|
|
37
|
+
"next": "^16.1.6",
|
|
38
38
|
"valibot": "^1.2.0",
|
|
39
|
-
"lucide-react": "^0.
|
|
40
|
-
"react": "^19.2.3"
|
|
39
|
+
"lucide-react": "^0.563.0"
|
|
41
40
|
},
|
|
42
41
|
"dependencies": {
|
|
43
42
|
"classnames": "^2.5.1",
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { CMSUserData } from "../../editor";
|
|
2
|
+
import { fetchWithCache } from "../../libs";
|
|
3
|
+
import { CMS_BASE_URL, SITE_ID } from "../constants";
|
|
4
|
+
|
|
5
|
+
export const getPageContents = async (
|
|
6
|
+
pathname: string,
|
|
7
|
+
allPageData: Record<string, CMSUserData<any>>,
|
|
8
|
+
previewToken?: string,
|
|
9
|
+
) => {
|
|
10
|
+
// remove trailing (left and right) slashes
|
|
11
|
+
pathname = pathname.replace(/^\/+|\/+$/g, "");
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
const res = await fetchWithCache(
|
|
15
|
+
`${CMS_BASE_URL}/public/seo/${SITE_ID}/pages/${pathname}`,
|
|
16
|
+
{
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (res.ok) {
|
|
24
|
+
const json = (await res.json()) as { content?: string };
|
|
25
|
+
|
|
26
|
+
if (json.content) {
|
|
27
|
+
const content = JSON.parse(json.content) as CMSUserData<any>;
|
|
28
|
+
|
|
29
|
+
if (content.root && content.content) {
|
|
30
|
+
return content;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const actualData = allPageData[pathname as keyof typeof allPageData];
|
|
36
|
+
|
|
37
|
+
if (actualData) {
|
|
38
|
+
// Starting new page from existing published data
|
|
39
|
+
return actualData as CMSUserData<any>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Starting new blank page
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error("Error fetching page data:", error);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (previewToken) {
|
|
48
|
+
// New blank page in preview mode
|
|
49
|
+
return {
|
|
50
|
+
content: [],
|
|
51
|
+
root: { props: { title: "New Page" } },
|
|
52
|
+
zones: {},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return null;
|
|
57
|
+
};
|
|
@@ -1,56 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import type { CMSUserData } from "../types";
|
|
3
3
|
import { Render, type Config } from "@puckeditor/core";
|
|
4
|
-
import {
|
|
5
|
-
import { fetchWithCache } from "../../libs";
|
|
6
|
-
|
|
7
|
-
const getPageContents = async (
|
|
8
|
-
pathname: string,
|
|
9
|
-
allPageData: Record<string, CMSUserData<any>>,
|
|
10
|
-
) => {
|
|
11
|
-
// remove trailing (left and right) slashes
|
|
12
|
-
pathname = pathname.replace(/^\/+|\/+$/g, "");
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const res = await fetchWithCache(
|
|
16
|
-
`${CMS_BASE_URL}/public/seo/${SITE_ID}/pages/${pathname}`,
|
|
17
|
-
{
|
|
18
|
-
headers: {
|
|
19
|
-
"Content-Type": "application/json",
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
if (res.ok) {
|
|
25
|
-
const json = (await res.json()) as { content?: string };
|
|
26
|
-
|
|
27
|
-
if (json.content) {
|
|
28
|
-
const content = JSON.parse(json.content) as CMSUserData<any>;
|
|
29
|
-
|
|
30
|
-
if (content.root && content.content) {
|
|
31
|
-
return content;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const actualData = allPageData[pathname as keyof typeof allPageData];
|
|
37
|
-
|
|
38
|
-
if (actualData) {
|
|
39
|
-
// Starting new page from existing published data
|
|
40
|
-
return actualData as CMSUserData<any>;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Starting new blank page
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error("Error fetching page data:", error);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
content: [],
|
|
50
|
-
root: { props: { title: "New Page" } },
|
|
51
|
-
zones: {},
|
|
52
|
-
};
|
|
53
|
-
};
|
|
4
|
+
import { getPageContents } from "../../api/client/pages";
|
|
54
5
|
|
|
55
6
|
export type PageRendererContentProps = {
|
|
56
7
|
pathname: string;
|
|
@@ -82,4 +33,4 @@ export const PageRendererContent = ({
|
|
|
82
33
|
}
|
|
83
34
|
|
|
84
35
|
return <Render config={config} data={data} />;
|
|
85
|
-
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Render, type Config } from "@puckeditor/core";
|
|
2
|
+
import type { CMSUserData } from "../types";
|
|
3
|
+
|
|
4
|
+
export type PageRendererSSRProps = {
|
|
5
|
+
config: Config;
|
|
6
|
+
data: CMSUserData<any>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SSR-compatible PageRenderer that receives pre-fetched data from the loader.
|
|
11
|
+
* Use this component with TanStack Router's loader for server-side rendering.
|
|
12
|
+
*/
|
|
13
|
+
export const PageRendererSSR = ({ config, data }: PageRendererSSRProps) => {
|
|
14
|
+
return <Render config={config} data={data} />;
|
|
15
|
+
};
|
|
@@ -126,7 +126,7 @@ export const BaseEditor =
|
|
|
126
126
|
alert("Failed to upload changes to CMS");
|
|
127
127
|
} else {
|
|
128
128
|
alert(
|
|
129
|
-
"Changes uploaded successfully to CMS! The page will now reflect the changes."
|
|
129
|
+
"Changes uploaded successfully to CMS! The page will now reflect the changes.",
|
|
130
130
|
);
|
|
131
131
|
}
|
|
132
132
|
} catch (error) {
|
|
@@ -141,9 +141,6 @@ export const BaseEditor =
|
|
|
141
141
|
iframe={{
|
|
142
142
|
enabled: true,
|
|
143
143
|
}}
|
|
144
|
-
fieldTransforms={{
|
|
145
|
-
userField: ({ value }) => value, // Included to check types
|
|
146
|
-
}}
|
|
147
144
|
overrides={{
|
|
148
145
|
fieldTypes: {
|
|
149
146
|
// Example of user field provided via overrides
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { BaseEditor } from "../../editor/render/Preview";
|
|
4
|
-
import { usePathnameTanstack, useSearchParamsTanstack } from "../hooks";
|
|
1
|
+
import { BaseEditor } from '../../editor/render/Preview'
|
|
2
|
+
import { usePathnameTanstack, useSearchParamsTanstack } from '../hooks'
|
|
5
3
|
|
|
6
4
|
export const EditorTanstack = BaseEditor({
|
|
7
5
|
usePathname: usePathnameTanstack,
|
|
8
6
|
useSearchParams: useSearchParamsTanstack,
|
|
9
|
-
})
|
|
7
|
+
})
|
|
@@ -9,6 +9,10 @@ export type PageRendererTanstackInitializerProps = {
|
|
|
9
9
|
allPageData: Record<string, CMSUserData<any>>;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Use PageRendererTanstackSSR for SSR support instead.
|
|
14
|
+
* This component fetches data on the client side.
|
|
15
|
+
*/
|
|
12
16
|
export const PageRendererTanstack =
|
|
13
17
|
({ config, allPageData }: PageRendererTanstackInitializerProps) =>
|
|
14
18
|
() => {
|