@puckeditor/cli 0.24.0-canary.301a0304
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/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/bin.mjs +7304 -0
- package/dist/docs/api-reference/actions.md +63 -0
- package/dist/docs/api-reference/components/action-bar-action.md +35 -0
- package/dist/docs/api-reference/components/action-bar-group.md +24 -0
- package/dist/docs/api-reference/components/action-bar-label.md +25 -0
- package/dist/docs/api-reference/components/action-bar-separator.md +16 -0
- package/dist/docs/api-reference/components/action-bar.md +32 -0
- package/dist/docs/api-reference/components/auto-field.md +63 -0
- package/dist/docs/api-reference/components/drawer-item.md +75 -0
- package/dist/docs/api-reference/components/drawer.md +29 -0
- package/dist/docs/api-reference/components/drop-zone.md +232 -0
- package/dist/docs/api-reference/components/field-label.md +138 -0
- package/dist/docs/api-reference/components/inline-text-field.md +77 -0
- package/dist/docs/api-reference/components/puck-components.md +19 -0
- package/dist/docs/api-reference/components/puck-fields.md +39 -0
- package/dist/docs/api-reference/components/puck-layout.md +27 -0
- package/dist/docs/api-reference/components/puck-outline.md +19 -0
- package/dist/docs/api-reference/components/puck-preview.md +39 -0
- package/dist/docs/api-reference/components/puck.md +561 -0
- package/dist/docs/api-reference/components/render.md +94 -0
- package/dist/docs/api-reference/components/rich-text-menu-control.md +87 -0
- package/dist/docs/api-reference/components/rich-text-menu-group.md +27 -0
- package/dist/docs/api-reference/components/rich-text-menu.md +99 -0
- package/dist/docs/api-reference/components.md +32 -0
- package/dist/docs/api-reference/configuration/component-config.md +569 -0
- package/dist/docs/api-reference/configuration/config.md +108 -0
- package/dist/docs/api-reference/configuration.md +4 -0
- package/dist/docs/api-reference/data-model/app-state.md +168 -0
- package/dist/docs/api-reference/data-model/component-data.md +62 -0
- package/dist/docs/api-reference/data-model/data.md +95 -0
- package/dist/docs/api-reference/data-model/item-selector.md +34 -0
- package/dist/docs/api-reference/data-model/root-data.md +59 -0
- package/dist/docs/api-reference/data-model.md +8 -0
- package/dist/docs/api-reference/dictionary.md +172 -0
- package/dist/docs/api-reference/field-transforms.md +51 -0
- package/dist/docs/api-reference/fields/array.md +211 -0
- package/dist/docs/api-reference/fields/base.md +96 -0
- package/dist/docs/api-reference/fields/custom.md +193 -0
- package/dist/docs/api-reference/fields/external.md +413 -0
- package/dist/docs/api-reference/fields/number.md +132 -0
- package/dist/docs/api-reference/fields/object.md +78 -0
- package/dist/docs/api-reference/fields/radio.md +82 -0
- package/dist/docs/api-reference/fields/richtext.md +422 -0
- package/dist/docs/api-reference/fields/select.md +79 -0
- package/dist/docs/api-reference/fields/slot.md +302 -0
- package/dist/docs/api-reference/fields/text.md +93 -0
- package/dist/docs/api-reference/fields/textarea.md +93 -0
- package/dist/docs/api-reference/fields.md +16 -0
- package/dist/docs/api-reference/functions/migrate.md +204 -0
- package/dist/docs/api-reference/functions/register-overlay-portal.md +45 -0
- package/dist/docs/api-reference/functions/resolve-all-data.md +27 -0
- package/dist/docs/api-reference/functions/set-deep.md +55 -0
- package/dist/docs/api-reference/functions/transform-props.md +51 -0
- package/dist/docs/api-reference/functions/use-get-puck.md +24 -0
- package/dist/docs/api-reference/functions/use-puck.md +43 -0
- package/dist/docs/api-reference/functions/walk-tree.md +88 -0
- package/dist/docs/api-reference/functions.md +8 -0
- package/dist/docs/api-reference/overrides/action-bar.md +35 -0
- package/dist/docs/api-reference/overrides/component-overlay.md +41 -0
- package/dist/docs/api-reference/overrides/drawer-item.md +24 -0
- package/dist/docs/api-reference/overrides/drawer.md +19 -0
- package/dist/docs/api-reference/overrides/field-label.md +18 -0
- package/dist/docs/api-reference/overrides/field-types.md +51 -0
- package/dist/docs/api-reference/overrides/fields.md +19 -0
- package/dist/docs/api-reference/overrides/header-actions.md +24 -0
- package/dist/docs/api-reference/overrides/header.md +29 -0
- package/dist/docs/api-reference/overrides/iframe.md +32 -0
- package/dist/docs/api-reference/overrides/outline.md +19 -0
- package/dist/docs/api-reference/overrides/preview.md +19 -0
- package/dist/docs/api-reference/overrides/puck.md +19 -0
- package/dist/docs/api-reference/overrides.md +28 -0
- package/dist/docs/api-reference/permissions.md +55 -0
- package/dist/docs/api-reference/plugin.md +112 -0
- package/dist/docs/api-reference/plugins/blocks-plugin.md +57 -0
- package/dist/docs/api-reference/plugins/fields-plugin.md +68 -0
- package/dist/docs/api-reference/plugins/legacy-side-bar-plugin.md +54 -0
- package/dist/docs/api-reference/plugins/outline-plugin.md +57 -0
- package/dist/docs/api-reference/puck-api.md +278 -0
- package/dist/docs/api-reference/theming/action-bar.md +32 -0
- package/dist/docs/api-reference/theming/button.md +65 -0
- package/dist/docs/api-reference/theming/canvas.md +20 -0
- package/dist/docs/api-reference/theming/computed-values.md +194 -0
- package/dist/docs/api-reference/theming/drawer.md +34 -0
- package/dist/docs/api-reference/theming/fields.md +70 -0
- package/dist/docs/api-reference/theming/global.md +127 -0
- package/dist/docs/api-reference/theming/header.md +19 -0
- package/dist/docs/api-reference/theming/icon-button.md +28 -0
- package/dist/docs/api-reference/theming/outline.md +35 -0
- package/dist/docs/api-reference/theming/plugin-bar.md +24 -0
- package/dist/docs/api-reference/theming/sidebar.md +19 -0
- package/dist/docs/api-reference/theming/slot.md +27 -0
- package/dist/docs/cli.md +201 -0
- package/dist/docs/extending-puck/composition.md +54 -0
- package/dist/docs/extending-puck/custom-fields.md +133 -0
- package/dist/docs/extending-puck/field-transforms.md +89 -0
- package/dist/docs/extending-puck/internal-puck-api.md +96 -0
- package/dist/docs/extending-puck/plugins.md +159 -0
- package/dist/docs/extending-puck/theming.md +88 -0
- package/dist/docs/extending-puck/ui-overrides.md +134 -0
- package/dist/docs/getting-started.md +68 -0
- package/dist/docs/guides/migrations/dropzones-to-slots.md +138 -0
- package/dist/docs/index.json +466 -0
- package/dist/docs/index.md +37 -0
- package/dist/docs/integrating-puck/categories.md +92 -0
- package/dist/docs/integrating-puck/component-configuration.md +159 -0
- package/dist/docs/integrating-puck/data-migration.md +86 -0
- package/dist/docs/integrating-puck/dynamic-fields.md +86 -0
- package/dist/docs/integrating-puck/dynamic-props.md +137 -0
- package/dist/docs/integrating-puck/external-data-sources.md +149 -0
- package/dist/docs/integrating-puck/feature-toggling.md +121 -0
- package/dist/docs/integrating-puck/localization.md +228 -0
- package/dist/docs/integrating-puck/multi-column-layouts.md +226 -0
- package/dist/docs/integrating-puck/overlay-portals.md +25 -0
- package/dist/docs/integrating-puck/rich-text-editing.md +230 -0
- package/dist/docs/integrating-puck/root-configuration.md +171 -0
- package/dist/docs/integrating-puck/server-components.md +199 -0
- package/dist/docs/integrating-puck/styling.md +117 -0
- package/dist/docs/integrating-puck/viewports.md +75 -0
- package/dist/templates/astro/README.md +52 -0
- package/dist/templates/astro/_gitignore +24 -0
- package/dist/templates/astro/astro.config.mjs +14 -0
- package/dist/templates/astro/database.json +1 -0
- package/dist/templates/astro/package.json +25 -0
- package/dist/templates/astro/public/favicon.svg +9 -0
- package/dist/templates/astro/src/lib/pages.ts +21 -0
- package/dist/templates/astro/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/astro/src/pages/[...puckPath].astro +25 -0
- package/dist/templates/astro/src/pages/api/pages.ts +18 -0
- package/dist/templates/astro/src/puck/editor.tsx +32 -0
- package/dist/templates/astro/src/puck/pages.ts +15 -0
- package/dist/templates/astro/src/puck/render.tsx +9 -0
- package/dist/templates/astro/src/puck.config.tsx +23 -0
- package/dist/templates/astro/tsconfig.json +14 -0
- package/dist/templates/astro-ai/README.md +64 -0
- package/dist/templates/astro-ai/_gitignore +24 -0
- package/dist/templates/astro-ai/astro.config.mjs +21 -0
- package/dist/templates/astro-ai/database.json +1 -0
- package/dist/templates/astro-ai/package.json +27 -0
- package/dist/templates/astro-ai/public/favicon.svg +9 -0
- package/dist/templates/astro-ai/src/lib/pages.ts +21 -0
- package/dist/templates/astro-ai/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/astro-ai/src/pages/[...puckPath].astro +25 -0
- package/dist/templates/astro-ai/src/pages/api/pages.ts +18 -0
- package/dist/templates/astro-ai/src/pages/api/puck/[...all].ts +36 -0
- package/dist/templates/astro-ai/src/puck/editor.tsx +53 -0
- package/dist/templates/astro-ai/src/puck/pages.ts +15 -0
- package/dist/templates/astro-ai/src/puck/render.tsx +10 -0
- package/dist/templates/astro-ai/src/puck.config.tsx +23 -0
- package/dist/templates/astro-ai/tsconfig.json +14 -0
- package/dist/templates/express/README.md +66 -0
- package/dist/templates/express/_gitignore +16 -0
- package/dist/templates/express/database.json +1 -0
- package/dist/templates/express/package.json +20 -0
- package/dist/templates/express/src/index.ts +15 -0
- package/dist/templates/express/src/puck/pages.ts +39 -0
- package/dist/templates/express/tsconfig.json +12 -0
- package/dist/templates/express-ai/README.md +81 -0
- package/dist/templates/express-ai/_gitignore +16 -0
- package/dist/templates/express-ai/database.json +1 -0
- package/dist/templates/express-ai/package.json +22 -0
- package/dist/templates/express-ai/src/index.ts +17 -0
- package/dist/templates/express-ai/src/puck/cloud.ts +71 -0
- package/dist/templates/express-ai/src/puck/pages.ts +39 -0
- package/dist/templates/express-ai/tsconfig.json +12 -0
- package/dist/templates/hono/README.md +66 -0
- package/dist/templates/hono/_gitignore +32 -0
- package/dist/templates/hono/database.json +1 -0
- package/dist/templates/hono/package.json +20 -0
- package/dist/templates/hono/src/index.ts +21 -0
- package/dist/templates/hono/src/puck/pages.ts +32 -0
- package/dist/templates/hono/tsconfig.json +13 -0
- package/dist/templates/hono-ai/README.md +81 -0
- package/dist/templates/hono-ai/_gitignore +32 -0
- package/dist/templates/hono-ai/database.json +1 -0
- package/dist/templates/hono-ai/package.json +22 -0
- package/dist/templates/hono-ai/src/index.ts +23 -0
- package/dist/templates/hono-ai/src/puck/cloud.ts +30 -0
- package/dist/templates/hono-ai/src/puck/pages.ts +32 -0
- package/dist/templates/hono-ai/tsconfig.json +13 -0
- package/dist/templates/manifest.json +4 -0
- package/dist/templates/next/README.md +112 -0
- package/dist/templates/next/_gitignore +35 -0
- package/dist/templates/next/app/[...puckPath]/client.tsx +9 -0
- package/dist/templates/next/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/next/app/favicon.ico +0 -0
- package/dist/templates/next/app/layout.tsx +13 -0
- package/dist/templates/next/app/page.tsx +1 -0
- package/dist/templates/next/app/puck/[...puckPath]/client.tsx +20 -0
- package/dist/templates/next/app/puck/[...puckPath]/page.tsx +55 -0
- package/dist/templates/next/app/puck/api/route.ts +25 -0
- package/dist/templates/next/app/puck/page.tsx +3 -0
- package/dist/templates/next/app/styles.css +3 -0
- package/dist/templates/next/database.json +1 -0
- package/dist/templates/next/lib/get-page.ts +11 -0
- package/dist/templates/next/next.config.js +3 -0
- package/dist/templates/next/package.json +25 -0
- package/dist/templates/next/proxy.ts +27 -0
- package/dist/templates/next/puck.config.tsx +25 -0
- package/dist/templates/next/tsconfig/base.json +20 -0
- package/dist/templates/next/tsconfig/nextjs.json +21 -0
- package/dist/templates/next/tsconfig.json +8 -0
- package/dist/templates/next-ai/README.md +169 -0
- package/dist/templates/next-ai/_gitignore +35 -0
- package/dist/templates/next-ai/app/[...puckPath]/client.tsx +12 -0
- package/dist/templates/next-ai/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/next-ai/app/api/pages/route.ts +26 -0
- package/dist/templates/next-ai/app/api/puck/[...all]/route.ts +31 -0
- package/dist/templates/next-ai/app/layout.tsx +13 -0
- package/dist/templates/next-ai/app/page.tsx +1 -0
- package/dist/templates/next-ai/app/puck/[...puckPath]/client.tsx +38 -0
- package/dist/templates/next-ai/app/puck/[...puckPath]/page.tsx +57 -0
- package/dist/templates/next-ai/app/puck/page.tsx +3 -0
- package/dist/templates/next-ai/app/styles.css +3 -0
- package/dist/templates/next-ai/database.json +1 -0
- package/dist/templates/next-ai/lib/get-page.ts +11 -0
- package/dist/templates/next-ai/next.config.js +3 -0
- package/dist/templates/next-ai/package.json +27 -0
- package/dist/templates/next-ai/proxy.ts +27 -0
- package/dist/templates/next-ai/public/favicon.ico +0 -0
- package/dist/templates/next-ai/puck.config.tsx +25 -0
- package/dist/templates/next-ai/tsconfig/base.json +20 -0
- package/dist/templates/next-ai/tsconfig/nextjs.json +21 -0
- package/dist/templates/next-ai/tsconfig.json +8 -0
- package/dist/templates/react-router/README.md +113 -0
- package/dist/templates/react-router/_gitignore +6 -0
- package/dist/templates/react-router/app/components/puck-render.tsx +8 -0
- package/dist/templates/react-router/app/lib/pages.server.ts +29 -0
- package/dist/templates/react-router/app/lib/resolve-puck-path.server.ts +19 -0
- package/dist/templates/react-router/app/root.tsx +65 -0
- package/dist/templates/react-router/app/routes/_index.tsx +31 -0
- package/dist/templates/react-router/app/routes/puck-splat.tsx +95 -0
- package/dist/templates/react-router/app/routes.ts +7 -0
- package/dist/templates/react-router/database.json +1 -0
- package/dist/templates/react-router/package.json +33 -0
- package/dist/templates/react-router/public/favicon.ico +0 -0
- package/dist/templates/react-router/puck.config.tsx +23 -0
- package/dist/templates/react-router/react-router.config.ts +7 -0
- package/dist/templates/react-router/tsconfig.json +29 -0
- package/dist/templates/react-router/vite.config.ts +10 -0
- package/dist/templates/react-router-ai/README.md +172 -0
- package/dist/templates/react-router-ai/_gitignore +6 -0
- package/dist/templates/react-router-ai/app/components/puck-render.tsx +11 -0
- package/dist/templates/react-router-ai/app/lib/pages.server.ts +29 -0
- package/dist/templates/react-router-ai/app/lib/resolve-puck-path.server.ts +19 -0
- package/dist/templates/react-router-ai/app/root.tsx +65 -0
- package/dist/templates/react-router-ai/app/routes/_index.tsx +31 -0
- package/dist/templates/react-router-ai/app/routes/api.puck.ts +34 -0
- package/dist/templates/react-router-ai/app/routes/puck-splat.tsx +119 -0
- package/dist/templates/react-router-ai/app/routes.ts +8 -0
- package/dist/templates/react-router-ai/database.json +1 -0
- package/dist/templates/react-router-ai/package.json +35 -0
- package/dist/templates/react-router-ai/public/favicon.ico +0 -0
- package/dist/templates/react-router-ai/puck.config.tsx +25 -0
- package/dist/templates/react-router-ai/react-router.config.ts +7 -0
- package/dist/templates/react-router-ai/tsconfig.json +29 -0
- package/dist/templates/react-router-ai/vite.config.ts +10 -0
- package/dist/templates/tanstack-start/README.md +113 -0
- package/dist/templates/tanstack-start/_gitignore +12 -0
- package/dist/templates/tanstack-start/database.json +1 -0
- package/dist/templates/tanstack-start/package.json +26 -0
- package/dist/templates/tanstack-start/puck.config.tsx +23 -0
- package/dist/templates/tanstack-start/src/components/puck-render.tsx +8 -0
- package/dist/templates/tanstack-start/src/lib/pages.server.ts +26 -0
- package/dist/templates/tanstack-start/src/lib/pages.ts +39 -0
- package/dist/templates/tanstack-start/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/tanstack-start/src/routeTree.gen.ts +86 -0
- package/dist/templates/tanstack-start/src/router.tsx +19 -0
- package/dist/templates/tanstack-start/src/routes/$.tsx +41 -0
- package/dist/templates/tanstack-start/src/routes/__root.tsx +42 -0
- package/dist/templates/tanstack-start/src/routes/index.tsx +18 -0
- package/dist/templates/tanstack-start/src/styles.css +13 -0
- package/dist/templates/tanstack-start/tsconfig.json +24 -0
- package/dist/templates/tanstack-start/vite.config.ts +15 -0
- package/dist/templates/tanstack-start-ai/README.md +171 -0
- package/dist/templates/tanstack-start-ai/_gitignore +12 -0
- package/dist/templates/tanstack-start-ai/database.json +1 -0
- package/dist/templates/tanstack-start-ai/package.json +28 -0
- package/dist/templates/tanstack-start-ai/puck.config.tsx +23 -0
- package/dist/templates/tanstack-start-ai/src/components/puck-render.tsx +11 -0
- package/dist/templates/tanstack-start-ai/src/lib/pages.server.ts +26 -0
- package/dist/templates/tanstack-start-ai/src/lib/pages.ts +39 -0
- package/dist/templates/tanstack-start-ai/src/lib/resolve-puck-path.ts +19 -0
- package/dist/templates/tanstack-start-ai/src/routeTree.gen.ts +104 -0
- package/dist/templates/tanstack-start-ai/src/router.tsx +19 -0
- package/dist/templates/tanstack-start-ai/src/routes/$.tsx +73 -0
- package/dist/templates/tanstack-start-ai/src/routes/__root.tsx +42 -0
- package/dist/templates/tanstack-start-ai/src/routes/api/puck/$.ts +39 -0
- package/dist/templates/tanstack-start-ai/src/routes/index.tsx +18 -0
- package/dist/templates/tanstack-start-ai/src/styles.css +13 -0
- package/dist/templates/tanstack-start-ai/tsconfig.json +24 -0
- package/dist/templates/tanstack-start-ai/vite.config.ts +15 -0
- package/dist/templates/vinext/README.md +112 -0
- package/dist/templates/vinext/_gitignore +33 -0
- package/dist/templates/vinext/app/[...puckPath]/client.tsx +9 -0
- package/dist/templates/vinext/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/vinext/app/favicon.ico +0 -0
- package/dist/templates/vinext/app/layout.tsx +13 -0
- package/dist/templates/vinext/app/page.tsx +1 -0
- package/dist/templates/vinext/app/puck/[...puckPath]/client.tsx +20 -0
- package/dist/templates/vinext/app/puck/[...puckPath]/page.tsx +55 -0
- package/dist/templates/vinext/app/puck/api/route.ts +25 -0
- package/dist/templates/vinext/app/puck/page.tsx +3 -0
- package/dist/templates/vinext/app/styles.css +3 -0
- package/dist/templates/vinext/database.json +1 -0
- package/dist/templates/vinext/lib/get-page.ts +11 -0
- package/dist/templates/vinext/package.json +30 -0
- package/dist/templates/vinext/proxy.ts +27 -0
- package/dist/templates/vinext/puck.config.tsx +25 -0
- package/dist/templates/vinext/tsconfig.json +30 -0
- package/dist/templates/vinext/vite.config.ts +6 -0
- package/dist/templates/vinext-ai/README.md +169 -0
- package/dist/templates/vinext-ai/_gitignore +33 -0
- package/dist/templates/vinext-ai/app/[...puckPath]/client.tsx +12 -0
- package/dist/templates/vinext-ai/app/[...puckPath]/page.tsx +49 -0
- package/dist/templates/vinext-ai/app/api/pages/route.ts +26 -0
- package/dist/templates/vinext-ai/app/api/puck/[...all]/route.ts +31 -0
- package/dist/templates/vinext-ai/app/layout.tsx +13 -0
- package/dist/templates/vinext-ai/app/page.tsx +1 -0
- package/dist/templates/vinext-ai/app/puck/[...puckPath]/client.tsx +38 -0
- package/dist/templates/vinext-ai/app/puck/[...puckPath]/page.tsx +57 -0
- package/dist/templates/vinext-ai/app/puck/page.tsx +3 -0
- package/dist/templates/vinext-ai/app/styles.css +3 -0
- package/dist/templates/vinext-ai/database.json +1 -0
- package/dist/templates/vinext-ai/lib/get-page.ts +11 -0
- package/dist/templates/vinext-ai/package.json +32 -0
- package/dist/templates/vinext-ai/proxy.ts +27 -0
- package/dist/templates/vinext-ai/public/favicon.ico +0 -0
- package/dist/templates/vinext-ai/puck.config.tsx +25 -0
- package/dist/templates/vinext-ai/tsconfig.json +30 -0
- package/dist/templates/vinext-ai/vite.config.ts +9 -0
- package/dist/templates/vite/README.md +56 -0
- package/dist/templates/vite/_gitignore +24 -0
- package/dist/templates/vite/database.json +1 -0
- package/dist/templates/vite/index.html +12 -0
- package/dist/templates/vite/package.json +29 -0
- package/dist/templates/vite/server/index.ts +13 -0
- package/dist/templates/vite/server/prod.ts +18 -0
- package/dist/templates/vite/server/puck/pages.ts +32 -0
- package/dist/templates/vite/src/App.tsx +11 -0
- package/dist/templates/vite/src/main.tsx +12 -0
- package/dist/templates/vite/src/puck/editor.tsx +28 -0
- package/dist/templates/vite/src/puck/page.tsx +27 -0
- package/dist/templates/vite/src/puck/pages.ts +15 -0
- package/dist/templates/vite/src/puck/root.tsx +27 -0
- package/dist/templates/vite/src/puck.config.tsx +23 -0
- package/dist/templates/vite/tsconfig.app.json +26 -0
- package/dist/templates/vite/tsconfig.json +7 -0
- package/dist/templates/vite/tsconfig.node.json +23 -0
- package/dist/templates/vite/vite.config.ts +14 -0
- package/dist/templates/vite-ai/README.md +67 -0
- package/dist/templates/vite-ai/_gitignore +24 -0
- package/dist/templates/vite-ai/database.json +1 -0
- package/dist/templates/vite-ai/index.html +12 -0
- package/dist/templates/vite-ai/package.json +31 -0
- package/dist/templates/vite-ai/server/index.ts +15 -0
- package/dist/templates/vite-ai/server/prod.ts +18 -0
- package/dist/templates/vite-ai/server/puck/cloud.ts +30 -0
- package/dist/templates/vite-ai/server/puck/pages.ts +32 -0
- package/dist/templates/vite-ai/src/App.tsx +11 -0
- package/dist/templates/vite-ai/src/main.tsx +12 -0
- package/dist/templates/vite-ai/src/puck/editor.tsx +49 -0
- package/dist/templates/vite-ai/src/puck/page.tsx +28 -0
- package/dist/templates/vite-ai/src/puck/pages.ts +15 -0
- package/dist/templates/vite-ai/src/puck/root.tsx +27 -0
- package/dist/templates/vite-ai/src/puck.config.tsx +23 -0
- package/dist/templates/vite-ai/tsconfig.app.json +26 -0
- package/dist/templates/vite-ai/tsconfig.json +7 -0
- package/dist/templates/vite-ai/tsconfig.node.json +23 -0
- package/dist/templates/vite-ai/vite.config.ts +14 -0
- package/package.json +51 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": [
|
|
3
|
+
"**/*",
|
|
4
|
+
"**/.server/**/*",
|
|
5
|
+
"**/.client/**/*",
|
|
6
|
+
".react-router/types/**/*"
|
|
7
|
+
],
|
|
8
|
+
"compilerOptions": {
|
|
9
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
10
|
+
"types": ["node", "vite/client"],
|
|
11
|
+
"target": "ES2022",
|
|
12
|
+
"module": "ES2022",
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"rootDirs": [".", "./.react-router/types"],
|
|
16
|
+
"baseUrl": ".",
|
|
17
|
+
"paths": {
|
|
18
|
+
"~/*": ["./app/*"],
|
|
19
|
+
"@puckeditor/core": ["../../packages/core/index.ts"],
|
|
20
|
+
"@puckeditor/core/puck.css": ["../../packages/core/bundle/index.css"]
|
|
21
|
+
},
|
|
22
|
+
"esModuleInterop": true,
|
|
23
|
+
"verbatimModuleSyntax": true,
|
|
24
|
+
"noEmit": true,
|
|
25
|
+
"resolveJsonModule": true,
|
|
26
|
+
"skipLibCheck": true,
|
|
27
|
+
"strict": true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [reactRouter(), tsconfigPaths()],
|
|
7
|
+
optimizeDeps: {
|
|
8
|
+
include: ["@puckeditor/core"],
|
|
9
|
+
},
|
|
10
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Puck AI + React Router recipe
|
|
2
|
+
|
|
3
|
+
[Puck](https://puckeditor.com) is the open-source visual editor for React. It lets you create page builders that use your own components.
|
|
4
|
+
|
|
5
|
+
[Puck AI](https://puckeditor.com/docs/ai/overview) builds on the same principles to let you generate pages by assembling your existing components or creating new ones on the fly, either as a copilot in the editor or headlessly.
|
|
6
|
+
|
|
7
|
+
This recipe connects Puck and Puck AI to [React Router](https://reactrouter.com) in framework mode, so you can create and edit pages for any route in this app.
|
|
8
|
+
|
|
9
|
+
## Core concepts
|
|
10
|
+
|
|
11
|
+
If you're new to Puck, this section introduces the core concepts you need to know.
|
|
12
|
+
|
|
13
|
+
### Puck
|
|
14
|
+
|
|
15
|
+
The Puck visual editor has three main parts: a config, the editor, and the renderer.
|
|
16
|
+
|
|
17
|
+
#### Config
|
|
18
|
+
|
|
19
|
+
The [config](https://puckeditor.com/docs/integrating-puck/component-configuration) registers the components users can use to build pages in the editor and the fields they can edit.
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
const config = {
|
|
23
|
+
components: {
|
|
24
|
+
HeadingBlock: {
|
|
25
|
+
fields: {
|
|
26
|
+
title: { type: "text" },
|
|
27
|
+
},
|
|
28
|
+
render: ({ title }) => <h1>{title}</h1>,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### The editor
|
|
35
|
+
|
|
36
|
+
The [`<Puck>`](https://puckeditor.com/docs/api-reference/components/puck) component renders the editor. It uses a config, exports [pages as JSON](https://puckeditor.com/docs/api-reference/data-model/data), and accepts initial page data for editing existing pages.
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
<Puck
|
|
40
|
+
config={config} // The components available to the editor
|
|
41
|
+
data={data} // The page JSON to edit
|
|
42
|
+
onPublish={(data) => {
|
|
43
|
+
// Save data to your database
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### The renderer
|
|
49
|
+
|
|
50
|
+
The [`<Render>`](https://puckeditor.com/docs/api-reference/components/render) component renders pages. It expects the page JSON and the config used to create that page.
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<Render
|
|
54
|
+
config={config} // The components used to create the page
|
|
55
|
+
data={data} // The page JSON to render
|
|
56
|
+
/>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Puck AI
|
|
60
|
+
|
|
61
|
+
This recipe adds Puck AI as a copilot. It has two parts: the AI plugin (browser) and the Cloud Client (server).
|
|
62
|
+
|
|
63
|
+
#### The AI plugin
|
|
64
|
+
|
|
65
|
+
The [AI plugin](https://puckeditor.com/docs/api-reference/ai/ai-plugin/installation) renders the chat in the editor and sends each message to the Cloud Client on your server.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
const aiPlugin = createAiPlugin();
|
|
69
|
+
|
|
70
|
+
function Editor() {
|
|
71
|
+
return <Puck plugins={[aiPlugin]} config={config} data={data} />;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### The Cloud Client
|
|
76
|
+
|
|
77
|
+
The [Cloud Client](https://puckeditor.com/docs/api-reference/ai/cloud-client/installation) provides APIs for connecting your server to the Puck cloud. This recipe uses its [`puckHandler`](https://puckeditor.com/docs/api-reference/ai/cloud-client/puck-handler) API, which receives each chat message, forwards it to the Puck cloud, and streams the response back to the plugin in the browser.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
const options = {
|
|
81
|
+
ai: {
|
|
82
|
+
context: "We are Google. You create Google landing pages.",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export function loader(args: LoaderFunctionArgs) {
|
|
87
|
+
return puckHandler(args.request, options);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function action(args: ActionFunctionArgs) {
|
|
91
|
+
return puckHandler(args.request, options);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Puck AI modes
|
|
96
|
+
|
|
97
|
+
Puck AI can build pages in two ways:
|
|
98
|
+
|
|
99
|
+
- **Assembly mode** only builds pages using components from your config.
|
|
100
|
+
- **Design mode** can generate new components when needed.
|
|
101
|
+
|
|
102
|
+
This recipe comes with [Design mode](https://puckeditor.com/docs/api-reference/ai/cloud-client/puck-handler#aidesignmode) enabled out of the box.
|
|
103
|
+
|
|
104
|
+
## Run the recipe
|
|
105
|
+
|
|
106
|
+
### 1. Add a Puck API key
|
|
107
|
+
|
|
108
|
+
Start by creating an account, [generating an API key](https://cloud.puckeditor.com/api-keys), and adding it to an `.env.local` file:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
PUCK_API_KEY=your-api-key
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 2. Start the development server
|
|
115
|
+
|
|
116
|
+
Run:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
npm run dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Once the server is running, navigate to [http://localhost:5173](http://localhost:5173) to view the home page, or [http://localhost:5173/edit](http://localhost:5173/edit) to edit it with Puck.
|
|
123
|
+
|
|
124
|
+
### 3. Create a page with Puck AI
|
|
125
|
+
|
|
126
|
+
Navigate to [http://localhost:5173/edit](http://localhost:5173/edit), click the **AI** button in the left sidebar, enter a prompt, and press Enter.
|
|
127
|
+
|
|
128
|
+
### 4. Publish the page
|
|
129
|
+
|
|
130
|
+
Once your page is ready, select **Publish** in the header to save the result, then navigate to [http://localhost:5173](http://localhost:5173) to view the published page.
|
|
131
|
+
|
|
132
|
+
You can also create a page at any path by navigating to `/your/path/edit` and publishing it. The route `/your/path` will render the page.
|
|
133
|
+
|
|
134
|
+
## How it works
|
|
135
|
+
|
|
136
|
+
When a URL ends in `/edit`, `resolvePuckPath` (`app/lib/resolve-puck-path.server.ts`) returns the path of the page being edited. The loader in `app/routes/puck-splat.tsx` loads the saved page, or starts with an empty page if the path is new.
|
|
137
|
+
|
|
138
|
+
Selecting **Publish** sends the page data to the action in `app/routes/puck-splat.tsx`. The action writes the JSON to `database.json`. The route then loads the same data and renders it with [`<Render>`](https://puckeditor.com/docs/api-reference/components/render).
|
|
139
|
+
|
|
140
|
+
The table below shows the files that implement this flow.
|
|
141
|
+
|
|
142
|
+
| File | Purpose |
|
|
143
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
144
|
+
| `puck.config.tsx` | Defines the components, fields, and default props available to Puck and Assembly mode. Add your own components here. |
|
|
145
|
+
| `app/routes.ts` | Registers the home page, Puck AI API, and catch-all page route. |
|
|
146
|
+
| `app/routes/puck-splat.tsx` | Loads and saves page data, then renders the editor or published page. |
|
|
147
|
+
| `app/routes/api.puck.ts` | Handles requests from the AI plugin and configures AI generation. |
|
|
148
|
+
| `app/routes/_index.tsx` | Loads and renders the home page. |
|
|
149
|
+
| `app/lib/resolve-puck-path.server.ts` | Maps an `/edit` URL to the path of the page being edited. |
|
|
150
|
+
| `app/lib/pages.server.ts` | Reads and writes page data in `database.json`. Replace this with your own data fetching and saving logic. |
|
|
151
|
+
| `app/components/puck-render.tsx` | Renders saved page data with `<Render>`. |
|
|
152
|
+
| `database.json` | Acts as a local database. Replace this with your own database solution. |
|
|
153
|
+
|
|
154
|
+
## Before deploying to production
|
|
155
|
+
|
|
156
|
+
Before deploying this recipe, make sure to:
|
|
157
|
+
|
|
158
|
+
- **Protect the editor and APIs.** The `/edit` routes, publish action, and `/api/puck` route are public by default. Add authentication, authorization, and rate limits to protect page data and AI usage.
|
|
159
|
+
- **Add your component library.** Replace the example `HeadingBlock` in `puck.config.tsx` with the components and fields your users need.
|
|
160
|
+
- **Set your business context.** Replace the example Google context in `app/routes/api.puck.ts` with clear information about your product, audience, and content rules.
|
|
161
|
+
- **Use a real database.** Replace `database.json` and the functions in `app/lib/pages.server.ts`. Local files are not reliable across server instances or serverless deployments.
|
|
162
|
+
- **Choose a deployment strategy.** This recipe uses server-side rendering, loaders, and actions. Deploy it to a React Router-compatible server runtime.
|
|
163
|
+
|
|
164
|
+
## Learn more
|
|
165
|
+
|
|
166
|
+
- [Puck documentation](https://puckeditor.com/docs)
|
|
167
|
+
- [Getting started with Puck](https://puckeditor.com/docs/getting-started)
|
|
168
|
+
- [Integrating Puck](https://puckeditor.com/docs/integrating-puck/component-configuration)
|
|
169
|
+
- [Puck AI documentation](https://puckeditor.com/docs/ai/overview)
|
|
170
|
+
- [Getting started with Puck AI](https://puckeditor.com/docs/ai/getting-started)
|
|
171
|
+
- [React Router framework mode](https://reactrouter.com/start/framework/installation)
|
|
172
|
+
- [Puck Discord](https://discord.gg/D9e4E3MQVZ)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Data } from "@puckeditor/core";
|
|
2
|
+
import { Render } from "@puckeditor/core";
|
|
3
|
+
import { withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
4
|
+
|
|
5
|
+
import { config } from "../../puck.config";
|
|
6
|
+
|
|
7
|
+
export function PuckRender({ data }: { data: Data }) {
|
|
8
|
+
const configWithDesignedComponents = withDynamicConfig(config, data);
|
|
9
|
+
|
|
10
|
+
return <Render config={configWithDesignedComponents} data={data} />;
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { fileURLToPath } from "url";
|
|
3
|
+
import fs from "fs/promises";
|
|
4
|
+
import type { Data } from "@puckeditor/core";
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
const databasePath = path.join(__dirname, "..", "..", "database.json");
|
|
9
|
+
|
|
10
|
+
export async function getPage(path: string) {
|
|
11
|
+
const pages = await readDatabase();
|
|
12
|
+
return pages[path];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function savePage(path: string, data: Data) {
|
|
16
|
+
const pages = await readDatabase();
|
|
17
|
+
pages[path] = data;
|
|
18
|
+
await fs.writeFile(databasePath, JSON.stringify(pages), { encoding: "utf8" });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function readDatabase() {
|
|
22
|
+
try {
|
|
23
|
+
const file = await fs.readFile(databasePath, "utf8");
|
|
24
|
+
return JSON.parse(file) as Record<string, Data>;
|
|
25
|
+
} catch (error: unknown) {
|
|
26
|
+
console.error(error);
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function resolvePuckPath(
|
|
2
|
+
path = "",
|
|
3
|
+
// `base` can be any valid origin, it is required for the URL constructor so
|
|
4
|
+
// we can return a pathname - you can change this if you want, but it isn't
|
|
5
|
+
// important
|
|
6
|
+
base = "https://placeholder.com/"
|
|
7
|
+
) {
|
|
8
|
+
const url = new URL(path, base);
|
|
9
|
+
const segments = url.pathname.split("/");
|
|
10
|
+
const isEditorRoute = segments.at(-1) === "edit";
|
|
11
|
+
const pathname = isEditorRoute
|
|
12
|
+
? segments.slice(0, -1).join("/")
|
|
13
|
+
: url.pathname;
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
isEditorRoute,
|
|
17
|
+
path: new URL(pathname, base).pathname,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRouteErrorResponse,
|
|
3
|
+
Links,
|
|
4
|
+
Meta,
|
|
5
|
+
Outlet,
|
|
6
|
+
Scripts,
|
|
7
|
+
ScrollRestoration,
|
|
8
|
+
} from "react-router";
|
|
9
|
+
|
|
10
|
+
import type { Route } from "./+types/root";
|
|
11
|
+
|
|
12
|
+
export function Layout({ children }: { children: React.ReactNode }) {
|
|
13
|
+
return (
|
|
14
|
+
<html lang="en">
|
|
15
|
+
<head>
|
|
16
|
+
<meta charSet="utf-8" />
|
|
17
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
18
|
+
<Meta />
|
|
19
|
+
<Links />
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
{children}
|
|
23
|
+
<ScrollRestoration />
|
|
24
|
+
<Scripts />
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default function App() {
|
|
31
|
+
return <Outlet />;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
|
35
|
+
let message = "Oops!";
|
|
36
|
+
let details = "An unexpected error occurred.";
|
|
37
|
+
let stack: string | undefined;
|
|
38
|
+
|
|
39
|
+
if (isRouteErrorResponse(error)) {
|
|
40
|
+
message = error.status === 404 ? "404" : "Error";
|
|
41
|
+
details =
|
|
42
|
+
error.status === 404
|
|
43
|
+
? "The requested page could not be found."
|
|
44
|
+
: error.statusText || details;
|
|
45
|
+
} else if (
|
|
46
|
+
import.meta.env.NODE_ENV !== "production" &&
|
|
47
|
+
error &&
|
|
48
|
+
error instanceof Error
|
|
49
|
+
) {
|
|
50
|
+
details = error.message;
|
|
51
|
+
stack = error.stack;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<main>
|
|
56
|
+
<h1>{message}</h1>
|
|
57
|
+
<p>{details}</p>
|
|
58
|
+
{stack && (
|
|
59
|
+
<pre>
|
|
60
|
+
<code>{stack}</code>
|
|
61
|
+
</pre>
|
|
62
|
+
)}
|
|
63
|
+
</main>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Route } from "./+types/_index";
|
|
2
|
+
import { PuckRender } from "~/components/puck-render";
|
|
3
|
+
import { resolvePuckPath } from "~/lib/resolve-puck-path.server";
|
|
4
|
+
import { getPage } from "~/lib/pages.server";
|
|
5
|
+
|
|
6
|
+
export async function loader() {
|
|
7
|
+
const { isEditorRoute, path } = resolvePuckPath("/");
|
|
8
|
+
let page = await getPage(path);
|
|
9
|
+
|
|
10
|
+
if (!page) {
|
|
11
|
+
throw new Response("Not Found", { status: 404 });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
isEditorRoute,
|
|
16
|
+
path,
|
|
17
|
+
data: page,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function meta({ loaderData }: Route.MetaArgs) {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
title: loaderData.data.root.props?.title ?? "",
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default function PuckSplatRoute({ loaderData }: Route.ComponentProps) {
|
|
30
|
+
return <PuckRender data={loaderData.data} />;
|
|
31
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Handles all requests for Puck AI
|
|
2
|
+
// Learn more: https://puckeditor.com/docs/ai/getting-started
|
|
3
|
+
import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router";
|
|
4
|
+
import type { PuckCloudOptions } from "@puckeditor/cloud-client";
|
|
5
|
+
import { puckHandler } from "@puckeditor/cloud-client";
|
|
6
|
+
|
|
7
|
+
const options: PuckCloudOptions = {
|
|
8
|
+
ai: {
|
|
9
|
+
// Replace with your business context
|
|
10
|
+
context: "We are Google. You create Google landing pages.",
|
|
11
|
+
designMode: {
|
|
12
|
+
// Allow AI to generate new components using "design mode"
|
|
13
|
+
// Learn more: https://puckeditor.com/docs/ai/design-mode
|
|
14
|
+
allowed: true,
|
|
15
|
+
// Constrain component generation, replace with your own instructions
|
|
16
|
+
instructions: `
|
|
17
|
+
#### Color Palette
|
|
18
|
+
|
|
19
|
+
Always use the following colors:
|
|
20
|
+
|
|
21
|
+
* Primary: \`#1976d2\`
|
|
22
|
+
* Secondary: \`#9c27b0\`
|
|
23
|
+
`,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export async function loader(args: LoaderFunctionArgs) {
|
|
29
|
+
return puckHandler(args.request, options);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function action(args: ActionFunctionArgs) {
|
|
33
|
+
return puckHandler(args.request, options);
|
|
34
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useFetcher, useLoaderData } from "react-router";
|
|
3
|
+
import type { Data } from "@puckeditor/core";
|
|
4
|
+
import { Puck, blocksPlugin, outlinePlugin } from "@puckeditor/core";
|
|
5
|
+
import { createAiPlugin, withDynamicConfig } from "@puckeditor/plugin-ai";
|
|
6
|
+
|
|
7
|
+
import type { Route } from "./+types/puck-splat";
|
|
8
|
+
import { config } from "../../puck.config";
|
|
9
|
+
import type { UserData } from "../../puck.config";
|
|
10
|
+
import { resolvePuckPath } from "~/lib/resolve-puck-path.server";
|
|
11
|
+
import { getPage, savePage } from "~/lib/pages.server";
|
|
12
|
+
import { PuckRender } from "~/components/puck-render";
|
|
13
|
+
|
|
14
|
+
import editorStyles from "@puckeditor/core/puck.css?url";
|
|
15
|
+
import pluginStyles from "@puckeditor/plugin-ai/styles.css?url";
|
|
16
|
+
|
|
17
|
+
export async function loader({ params }: Route.LoaderArgs) {
|
|
18
|
+
const pathname = params["*"] ?? "/";
|
|
19
|
+
const { isEditorRoute, path } = resolvePuckPath(pathname);
|
|
20
|
+
let page = await getPage(path);
|
|
21
|
+
|
|
22
|
+
// Throw a 404 if we're not rendering the editor and data for the page does not exist
|
|
23
|
+
if (!isEditorRoute && !page) {
|
|
24
|
+
throw new Response("Not Found", { status: 404 });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Empty shell for new pages
|
|
28
|
+
if (isEditorRoute && !page) {
|
|
29
|
+
page = {
|
|
30
|
+
content: [],
|
|
31
|
+
root: {
|
|
32
|
+
props: {
|
|
33
|
+
title: "",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
isEditorRoute,
|
|
41
|
+
path,
|
|
42
|
+
data: page,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function meta({ loaderData }: Route.MetaArgs) {
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
title: loaderData.isEditorRoute
|
|
50
|
+
? `Edit: ${loaderData.path}`
|
|
51
|
+
: loaderData.data.root.props?.title ?? "",
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function action({ params, request }: Route.ActionArgs) {
|
|
57
|
+
const pathname = params["*"] ?? "/";
|
|
58
|
+
const { path } = resolvePuckPath(pathname);
|
|
59
|
+
const body = (await request.json()) as { data: Data };
|
|
60
|
+
|
|
61
|
+
await savePage(path, body.data);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const aiPlugin = createAiPlugin({
|
|
65
|
+
// Allow users to switch between design and assembly mode.
|
|
66
|
+
// Read more: https://puckeditor.com/docs/ai/design-mode
|
|
67
|
+
designMode: {
|
|
68
|
+
visible: true,
|
|
69
|
+
},
|
|
70
|
+
// Select design mode by default.
|
|
71
|
+
defaultMode: "design",
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Place the ai plugin in the first position in the side nav.
|
|
75
|
+
const plugins = [aiPlugin, blocksPlugin(), outlinePlugin()];
|
|
76
|
+
|
|
77
|
+
function Editor() {
|
|
78
|
+
const loaderData = useLoaderData<typeof loader>();
|
|
79
|
+
const fetcher = useFetcher<typeof action>();
|
|
80
|
+
|
|
81
|
+
const configWithDesignedComponents = useMemo(
|
|
82
|
+
() => withDynamicConfig(config, loaderData.data),
|
|
83
|
+
[config, loaderData.data]
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<>
|
|
88
|
+
<link rel="stylesheet" href={editorStyles} id="puck-css" />
|
|
89
|
+
<link rel="stylesheet" href={pluginStyles} id="puck-plugin-ai-css" />
|
|
90
|
+
<Puck
|
|
91
|
+
plugins={plugins}
|
|
92
|
+
config={configWithDesignedComponents}
|
|
93
|
+
data={loaderData.data}
|
|
94
|
+
onPublish={async (data) => {
|
|
95
|
+
await fetcher.submit(
|
|
96
|
+
{ data: data as UserData },
|
|
97
|
+
{
|
|
98
|
+
action: "",
|
|
99
|
+
method: "post",
|
|
100
|
+
encType: "application/json",
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}}
|
|
104
|
+
/>
|
|
105
|
+
</>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default function PuckSplatRoute({ loaderData }: Route.ComponentProps) {
|
|
110
|
+
return (
|
|
111
|
+
<div>
|
|
112
|
+
{loaderData.isEditorRoute ? (
|
|
113
|
+
<Editor />
|
|
114
|
+
) : (
|
|
115
|
+
<PuckRender data={loaderData.data} />
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RouteConfig } from "@react-router/dev/routes";
|
|
2
|
+
import { route, index } from "@react-router/dev/routes";
|
|
3
|
+
|
|
4
|
+
export default [
|
|
5
|
+
index("routes/_index.tsx"),
|
|
6
|
+
route("api/puck/*", "routes/api.puck.ts"),
|
|
7
|
+
route("*", "routes/puck-splat.tsx"),
|
|
8
|
+
] satisfies RouteConfig;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"/":{"content":[{"type":"HeadingBlock","props":{"title":"Edit this page by adding /edit to the end of the URL","id":"HeadingBlock-1694032984497"}}],"root":{"props":{"title":"Puck + React Router 7 demo"}},"zones":{}}}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-router-ai-recipe",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "react-router build",
|
|
8
|
+
"dev": "react-router dev",
|
|
9
|
+
"start": "react-router-serve ./build/server/index.js",
|
|
10
|
+
"typecheck": "react-router typegen && tsc"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@puckeditor/cloud-client": "^0",
|
|
14
|
+
"@puckeditor/core": "workspace:*",
|
|
15
|
+
"@puckeditor/plugin-ai": "^0",
|
|
16
|
+
"@react-router/node": "^7.18.0",
|
|
17
|
+
"@react-router/serve": "^7.18.0",
|
|
18
|
+
"isbot": "^5",
|
|
19
|
+
"react": "^19.0.0",
|
|
20
|
+
"react-dom": "^19.0.0",
|
|
21
|
+
"react-router": "^7.18.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@react-router/dev": "^7.18.0",
|
|
25
|
+
"@types/node": "^20",
|
|
26
|
+
"@types/react": "^19.0.1",
|
|
27
|
+
"@types/react-dom": "^19.0.2",
|
|
28
|
+
"typescript": "^5.8.3",
|
|
29
|
+
"vite": "^7.3.2",
|
|
30
|
+
"vite-tsconfig-paths": "^5.1.4"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Config, Data } from "@puckeditor/core";
|
|
2
|
+
|
|
3
|
+
export type Props = {
|
|
4
|
+
HeadingBlock: { title: string };
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export type UserData = Data<Props>;
|
|
8
|
+
|
|
9
|
+
export const config: Config<Props> = {
|
|
10
|
+
components: {
|
|
11
|
+
HeadingBlock: {
|
|
12
|
+
fields: {
|
|
13
|
+
title: { type: "text" },
|
|
14
|
+
},
|
|
15
|
+
defaultProps: {
|
|
16
|
+
title: "Heading",
|
|
17
|
+
},
|
|
18
|
+
render: ({ title }) => (
|
|
19
|
+
<div style={{ padding: 64 }}>
|
|
20
|
+
<h1>{title}</h1>
|
|
21
|
+
</div>
|
|
22
|
+
),
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": [
|
|
3
|
+
"**/*",
|
|
4
|
+
"**/.server/**/*",
|
|
5
|
+
"**/.client/**/*",
|
|
6
|
+
".react-router/types/**/*"
|
|
7
|
+
],
|
|
8
|
+
"compilerOptions": {
|
|
9
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
10
|
+
"types": ["node", "vite/client"],
|
|
11
|
+
"target": "ES2022",
|
|
12
|
+
"module": "ES2022",
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"rootDirs": [".", "./.react-router/types"],
|
|
16
|
+
"baseUrl": ".",
|
|
17
|
+
"paths": {
|
|
18
|
+
"~/*": ["./app/*"],
|
|
19
|
+
"@puckeditor/core": ["../../packages/core/index.ts"],
|
|
20
|
+
"@puckeditor/core/puck.css": ["../../packages/core/bundle/index.css"]
|
|
21
|
+
},
|
|
22
|
+
"esModuleInterop": true,
|
|
23
|
+
"verbatimModuleSyntax": true,
|
|
24
|
+
"noEmit": true,
|
|
25
|
+
"resolveJsonModule": true,
|
|
26
|
+
"skipLibCheck": true,
|
|
27
|
+
"strict": true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
import tsconfigPaths from "vite-tsconfig-paths";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [reactRouter(), tsconfigPaths()],
|
|
7
|
+
optimizeDeps: {
|
|
8
|
+
include: ["@puckeditor/core", "@puckeditor/plugin-ai"],
|
|
9
|
+
},
|
|
10
|
+
});
|