create-puck-app 0.11.1-canary.1a8f6b8 → 0.11.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/package.json CHANGED
@@ -1,15 +1,21 @@
1
1
  {
2
2
  "name": "create-puck-app",
3
- "version": "0.11.1-canary.1a8f6b8",
3
+ "version": "0.11.1",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "create-puck-app": "./index.js"
9
9
  },
10
+ "files": [
11
+ "templates",
12
+ "index.js"
13
+ ],
10
14
  "scripts": {
11
15
  "generate": "node scripts/generate.js",
12
- "prepublishOnly": "yarn generate"
16
+ "prepublishOnly": "yarn generate",
17
+ "removeGitignore": "mv templates/.gitignore templates/gitignore",
18
+ "restoreGitignore": "mv templates/gitignore templates/.gitignore"
13
19
  },
14
20
  "dependencies": {
15
21
  "commander": "^10.0.1",
@@ -0,0 +1,8 @@
1
+ # Ignore everything
2
+ *.*
3
+
4
+ # Explicitly ignore gitignore without extension
5
+ gitignore
6
+
7
+ # Except for handlebars files
8
+ !*.hbs
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ root: true,
3
+ extends: ["custom"],
4
+ };
@@ -0,0 +1,9 @@
1
+ "use client";
2
+
3
+ import type { Data } from "@measured/puck";
4
+ import { Render } from "@measured/puck";
5
+ import config from "../../puck.config";
6
+
7
+ export function Client({ data }: { data: Data }) {
8
+ return <Render config={config} data={data} />;
9
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * This file implements a catch-all route that renders the user-facing pages
3
+ * generated by Puck. For any route visited (with exception of other hardcoded
4
+ * pages in /app), it will check your database (via `getPage`) for a Puck page
5
+ * and render it using <Render>.
6
+ *
7
+ * All routes produced by this page are statically rendered using incremental
8
+ * static site generation. After the first visit, the page will be cached as
9
+ * a static file. Subsequent visits will receive the cache. Publishing a page
10
+ * will invalidate the cache as the page is written in /api/puck/route.ts
11
+ */
12
+
13
+ import { Client } from "./client";
14
+ import { notFound } from "next/navigation";
15
+ import { Metadata } from "next";
16
+ import { getPage } from "../../lib/get-page";
17
+
18
+ export async function generateMetadata({
19
+ params: { puckPath = [] },
20
+ }: {
21
+ params: { puckPath: string[] };
22
+ }): Promise<Metadata> {
23
+ const path = `/${puckPath.join("/")}`;
24
+
25
+ return {
26
+ title: getPage(path)?.root.title,
27
+ };
28
+ }
29
+
30
+ export default async function Page({
31
+ params: { puckPath = [] },
32
+ }: {
33
+ params: { puckPath: string[] };
34
+ }) {
35
+ const path = `/${puckPath.join("/")}`;
36
+ const data = getPage(path);
37
+
38
+ if (!data) {
39
+ return notFound();
40
+ }
41
+
42
+ return <Client data={data} />;
43
+ }
44
+
45
+ // Force Next.js to produce static pages: https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic
46
+ // Delete this if you need dynamic rendering, such as access to headers or cookies
47
+ export const dynamic = "force-static";
@@ -0,0 +1,14 @@
1
+ import "@measured/puck/dist/index.css";
2
+ import "./styles.css";
3
+
4
+ export default function RootLayout({
5
+ children,
6
+ }: {
7
+ children: React.ReactNode;
8
+ }) {
9
+ return (
10
+ <html lang="en">
11
+ <body>{children}</body>
12
+ </html>
13
+ );
14
+ }
@@ -0,0 +1 @@
1
+ export { default, generateMetadata } from "./[...puckPath]/page";
@@ -0,0 +1,20 @@
1
+ "use client";
2
+
3
+ import type { Data } from "@measured/puck";
4
+ import { Puck } from "@measured/puck";
5
+ import config from "../../../puck.config";
6
+
7
+ export function Client({ path, data }: { path: string; data: Data }) {
8
+ return (
9
+ <Puck
10
+ config={config}
11
+ data={data}
12
+ onPublish={async (data: Data) => {
13
+ await fetch("/puck/api", {
14
+ method: "post",
15
+ body: JSON.stringify({ data, path }),
16
+ });
17
+ }}
18
+ />
19
+ );
20
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * This file implements a *magic* catch-all route that renders the Puck editor.
3
+ *
4
+ * This route exposes /puck/[...puckPath], but is disabled by middleware.ts. The middleware
5
+ * then rewrites all URL requests ending in `/edit` to this route, allowing you to visit any
6
+ * page in your application and add /edit to the end to spin up a Puck editor.
7
+ *
8
+ * This approach enables public pages to be statically rendered whilst the /puck route can
9
+ * remain dynamic.
10
+ *
11
+ * NB this route is public, and you will need to add authentication
12
+ */
13
+
14
+ import { Client } from "./client";
15
+ import { Metadata } from "next";
16
+ import { getPage } from "../../../lib/get-page";
17
+
18
+ export async function generateMetadata({
19
+ params: { puckPath = [] },
20
+ }: {
21
+ params: { puckPath: string[] };
22
+ }): Promise<Metadata> {
23
+ const path = `/${puckPath.join("/")}`;
24
+
25
+ return {
26
+ title: "Puck: " + path,
27
+ };
28
+ }
29
+
30
+ export default async function Page({
31
+ params: { puckPath = [] },
32
+ }: {
33
+ params: { puckPath: string[] };
34
+ }) {
35
+ const path = `/${puckPath.join("/")}`;
36
+ const data = getPage(path);
37
+
38
+ return <Client path={path} data={data} />;
39
+ }
@@ -0,0 +1,25 @@
1
+ import { revalidatePath } from "next/cache";
2
+ import { NextResponse } from "next/server";
3
+ import fs from "fs";
4
+
5
+ export async function POST(request: Request) {
6
+ const payload = await request.json();
7
+
8
+ const existingData = JSON.parse(
9
+ fs.existsSync("database.json")
10
+ ? fs.readFileSync("database.json", "utf-8")
11
+ : "{}"
12
+ );
13
+
14
+ const updatedData = {
15
+ ...existingData,
16
+ [payload.path]: payload.data,
17
+ };
18
+
19
+ fs.writeFileSync("database.json", JSON.stringify(updatedData));
20
+
21
+ // Purge Next.js cache
22
+ revalidatePath(payload.path);
23
+
24
+ return NextResponse.json({ status: "ok" });
25
+ }
@@ -0,0 +1 @@
1
+ export { default, generateMetadata } from "./[...puckPath]/page";
@@ -0,0 +1,5 @@
1
+ html,
2
+ body {
3
+ margin: 0;
4
+ padding: 0;
5
+ }
@@ -0,0 +1,36 @@
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # dependencies
4
+ /node_modules
5
+ /.pnp
6
+ .pnp.js
7
+
8
+ # testing
9
+ /coverage
10
+
11
+ # next.js
12
+ /.next/
13
+ /out/
14
+
15
+ # production
16
+ /build
17
+
18
+ # misc
19
+ .DS_Store
20
+ *.pem
21
+
22
+ # debug
23
+ npm-debug.log*
24
+ yarn-debug.log*
25
+ yarn-error.log*
26
+
27
+ # local env files
28
+ .env.local
29
+ .env.development.local
30
+ .env.test.local
31
+ .env.production.local
32
+
33
+ # vercel
34
+ .vercel
35
+
36
+ database.json
@@ -0,0 +1,11 @@
1
+ import { Data } from "@measured/puck";
2
+ import fs from "fs";
3
+
4
+ // Replace with call to your database
5
+ export const getPage = (path: string) => {
6
+ const allData: Record<string, Data> | null = fs.existsSync("database.json")
7
+ ? JSON.parse(fs.readFileSync("database.json", "utf-8"))
8
+ : null;
9
+
10
+ return allData ? allData[path] : null;
11
+ };
@@ -0,0 +1,27 @@
1
+ import { NextResponse } from "next/server";
2
+
3
+ import type { NextRequest } from "next/server";
4
+
5
+ export async function middleware(req: NextRequest) {
6
+ const res = NextResponse.next();
7
+
8
+ if (req.method === "GET") {
9
+ // Rewrite routes that match "/[...puckPath]/edit" to "/puck/[...puckPath]"
10
+ if (req.nextUrl.pathname.endsWith("/edit")) {
11
+ const pathWithoutEdit = req.nextUrl.pathname.slice(
12
+ 0,
13
+ req.nextUrl.pathname.length - 5
14
+ );
15
+ const pathWithEditPrefix = `/puck${pathWithoutEdit}`;
16
+
17
+ return NextResponse.rewrite(new URL(pathWithEditPrefix, req.url));
18
+ }
19
+
20
+ // Disable "/puck/[...puckPath]"
21
+ if (req.nextUrl.pathname.startsWith("/puck")) {
22
+ return NextResponse.redirect(new URL("/", req.url));
23
+ }
24
+ }
25
+
26
+ return res;
27
+ }
@@ -0,0 +1,5 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+
4
+ // NOTE: This file should not be edited
5
+ // see https://nextjs.org/docs/basic-features/typescript for more information.
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ reactStrictMode: true,
3
+ transpilePackages: ["ui"],
4
+ };
@@ -0,0 +1,25 @@
1
+ import type { Config } from "@measured/puck";
2
+
3
+ type Props = {
4
+ HeadingBlock: { title: string };
5
+ };
6
+
7
+ export const config: Config<Props> = {
8
+ components: {
9
+ HeadingBlock: {
10
+ fields: {
11
+ title: { type: "text" },
12
+ },
13
+ defaultProps: {
14
+ title: "Heading",
15
+ },
16
+ render: ({ title }) => (
17
+ <div style={{ padding: 64 }}>
18
+ <h1>{title}</h1>
19
+ </div>
20
+ ),
21
+ },
22
+ },
23
+ };
24
+
25
+ export default config;
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "display": "Default",
4
+ "compilerOptions": {
5
+ "composite": false,
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "esModuleInterop": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "inlineSources": false,
11
+ "isolatedModules": true,
12
+ "moduleResolution": "node",
13
+ "noUnusedLocals": false,
14
+ "noUnusedParameters": false,
15
+ "preserveWatchOutput": true,
16
+ "skipLibCheck": true,
17
+ "strict": true
18
+ },
19
+ "exclude": ["node_modules"]
20
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "display": "Next.js",
4
+ "extends": "./base.json",
5
+ "compilerOptions": {
6
+ "plugins": [{ "name": "next" }],
7
+ "allowJs": true,
8
+ "declaration": false,
9
+ "declarationMap": false,
10
+ "incremental": true,
11
+ "jsx": "preserve",
12
+ "lib": ["dom", "dom.iterable", "esnext"],
13
+ "module": "esnext",
14
+ "noEmit": true,
15
+ "resolveJsonModule": true,
16
+ "strict": false,
17
+ "target": "es5"
18
+ },
19
+ "include": ["src", "next-env.d.ts"],
20
+ "exclude": ["node_modules"]
21
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig/nextjs.json",
3
+ "compilerOptions": {
4
+ "plugins": [{ "name": "next" }]
5
+ },
6
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
7
+ "exclude": ["node_modules"]
8
+ }
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from "fs";
4
- import path from "path";
5
- import { glob } from "glob";
6
- import { dirname } from "path";
7
- import { fileURLToPath } from "url";
8
-
9
- const verbose = false;
10
-
11
- const run = async () => {
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = dirname(__filename);
14
-
15
- // Copy template files to the new directory
16
- const recipePath = path.join(__dirname, "../../../recipes");
17
- const templatePath = path.join(__dirname, "../templates");
18
-
19
- if (!fs.existsSync(recipePath)) {
20
- console.error(`No recipe directory could be found at ${recipePath}.`);
21
- return;
22
- }
23
-
24
- if (!fs.existsSync(templatePath)) {
25
- console.error(`No template directory could be found at ${templatePath}.`);
26
- return;
27
- }
28
-
29
- // Copy recipe files
30
- const recipeFiles = glob.sync(`**/*`, {
31
- cwd: recipePath,
32
- nodir: true,
33
- dot: true,
34
- });
35
-
36
- console.warn(
37
- `⚠️ The following files use handlebars templates. Please manually update them:`
38
- );
39
-
40
- let counter = 0;
41
-
42
- for (const recipeFile of recipeFiles) {
43
- const filePath = path.join(recipePath, recipeFile);
44
-
45
- const targetPath = filePath
46
- .replace(recipePath, templatePath)
47
- .replace(".gitignore", "gitignore"); // rename .gitignore to gitignore so NPM publish doesn't ignore it
48
-
49
- // Don't copy file if it's templated by handlebars
50
- if (fs.existsSync(`${targetPath}.hbs`)) {
51
- console.warn(`- ${recipeFile}`);
52
- } else {
53
- if (verbose) {
54
- console.log(`Copying ${filePath} -> ${targetPath}`);
55
- }
56
-
57
- const data = await fs.readFileSync(filePath, "utf-8");
58
-
59
- const dir = path.dirname(targetPath);
60
-
61
- await fs.mkdirSync(dir, { recursive: true });
62
-
63
- await fs.writeFileSync(targetPath, data);
64
-
65
- counter += 1;
66
- }
67
- }
68
-
69
- console.log(`Copied ${counter} files into generator!`);
70
- };
71
-
72
- await run();