diff --git a/apps/web/package.json b/apps/web/package.json index 55e475563..0229b2a69 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -33,6 +33,7 @@ "dependencies": { "@edge-csrf/nextjs": "2.0.0", "@hookform/resolvers": "^3.3.4", + "@keystatic/next": "^5.0.0", "@kit/accounts": "workspace:^", "@kit/admin": "workspace:^", "@kit/auth": "workspace:^", @@ -42,6 +43,7 @@ "@kit/database-webhooks": "workspace:^", "@kit/email-templates": "workspace:^", "@kit/i18n": "workspace:^", + "@kit/keystatic": "workspace:^", "@kit/mailers": "workspace:^", "@kit/monitoring": "workspace:^", "@kit/next": "workspace:^", @@ -107,4 +109,4 @@ "> 0.2%", "not dead" ] -} +} \ No newline at end of file diff --git a/packages/cms/keystatic/package.json b/packages/cms/keystatic/package.json index 2ab8dc6c4..eac1a71f1 100644 --- a/packages/cms/keystatic/package.json +++ b/packages/cms/keystatic/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@keystatic/core": "0.5.14", - "@keystatic/next": "5.0.0", + "@keystatic/next": "^5.0.0", "@markdoc/markdoc": "^0.4.0" }, "devDependencies": { diff --git a/packages/cms/keystatic/src/create-reader.ts b/packages/cms/keystatic/src/create-reader.ts index 5461be15b..1f4cffa6f 100644 --- a/packages/cms/keystatic/src/create-reader.ts +++ b/packages/cms/keystatic/src/create-reader.ts @@ -9,14 +9,10 @@ export async function createKeystaticReader() { switch (STORAGE_KIND) { case 'local': { if (process.env.NEXT_RUNTIME === 'nodejs') { - const path = await import('node:path'); const { default: config } = await import('./keystatic.config'); const { createReader } = await import('@keystatic/core/reader'); - const contentPath = process.env.NEXT_PUBLIC_KEYSTATIC_CONTENT_PATH; - const repositoryPath = path.join(process.cwd(), contentPath as string); - - return createReader(repositoryPath, config); + return createReader(process.cwd(), config); } else { // we should never get here but the compiler requires the check // to ensure we don't parse the package at build time diff --git a/packages/cms/keystatic/src/index.ts b/packages/cms/keystatic/src/index.ts index a88c01a47..a08c2867d 100644 --- a/packages/cms/keystatic/src/index.ts +++ b/packages/cms/keystatic/src/index.ts @@ -1,2 +1,3 @@ export * from './keystatic-client'; export * from './content-renderer'; +export * from './keystatic.config'; diff --git a/packages/cms/keystatic/src/keystatic-route-handler.tsx b/packages/cms/keystatic/src/keystatic-route-handler.ts similarity index 68% rename from packages/cms/keystatic/src/keystatic-route-handler.tsx rename to packages/cms/keystatic/src/keystatic-route-handler.ts index 1950942f9..41ed54602 100644 --- a/packages/cms/keystatic/src/keystatic-route-handler.tsx +++ b/packages/cms/keystatic/src/keystatic-route-handler.ts @@ -2,6 +2,6 @@ import { makeRouteHandler } from '@keystatic/next/route-handler'; import config from './keystatic.config'; -export const { POST, GET } = makeRouteHandler({ +export const keystaticRouteHandlers = makeRouteHandler({ config, }); diff --git a/packages/cms/keystatic/src/keystatic.config.ts b/packages/cms/keystatic/src/keystatic.config.ts index c3141bfdb..2b5cb1354 100644 --- a/packages/cms/keystatic/src/keystatic.config.ts +++ b/packages/cms/keystatic/src/keystatic.config.ts @@ -39,7 +39,9 @@ const storage = z.union([local, cloud, github]).parse({ pathPrefix: process.env.KEYSTATIC_PATH_PREFIX, }); -const keyStaticConfig = createKeyStaticConfig(); +const keyStaticConfig = createKeyStaticConfig( + process.env.NEXT_PUBLIC_KEYSTATIC_CONTENT_PATH ?? 'content', +); export default keyStaticConfig; @@ -75,14 +77,14 @@ export type PostEntryProps = Entry< (typeof keyStaticConfig)['collections']['posts'] >; -function createKeyStaticConfig() { +function createKeyStaticConfig(path: string) { return config({ storage, collections: { posts: collection({ label: 'Posts', slugField: 'title', - path: `posts/*`, + path: `${path}/posts/*`, format: { contentField: 'content' }, schema: { title: fields.slug({ name: { label: 'Title' } }), @@ -107,7 +109,7 @@ function createKeyStaticConfig() { documentation: collection({ label: 'Documentation', slugField: 'title', - path: `documentation/**`, + path: `${path}/documentation/**`, format: { contentField: 'content' }, schema: { title: fields.slug({ name: { label: 'Title' } }), diff --git a/turbo/generators/config.ts b/turbo/generators/config.ts index eb864d0da..777d83b1b 100644 --- a/turbo/generators/config.ts +++ b/turbo/generators/config.ts @@ -1,83 +1,11 @@ -import { execSync } from "node:child_process"; -import type { PlopTypes } from "@turbo/gen"; +import type { PlopTypes } from '@turbo/gen'; + +import { createKeystaticAdminGenerator } from './templates/keystatic/generator'; +import { createPackageGenerator } from './templates/package/generator'; + +// List of generators to be registered +const generators = [createPackageGenerator, createKeystaticAdminGenerator]; export default function generator(plop: PlopTypes.NodePlopAPI): void { - plop.setGenerator("init", { - description: "Generate a new package for the Monorepo", - prompts: [ - { - type: "input", - name: "name", - message: - "What is the name of the package? (You can skip the `@kit/` prefix)", - }, - { - type: "input", - name: "deps", - message: - "Enter a space separated list of dependencies you would like to install", - }, - ], - actions: [ - (answers) => { - if ("name" in answers && typeof answers.name === "string") { - if (answers.name.startsWith("@kit/")) { - answers.name = answers.name.replace("@kit/", ""); - } - } - return "Config sanitized"; - }, - { - type: "add", - path: "packages/{{ name }}/package.json", - templateFile: "templates/package.json.hbs", - }, - { - type: "add", - path: "packages/{{ name }}/tsconfig.json", - templateFile: "templates/tsconfig.json.hbs", - }, - { - type: "add", - path: "packages/{{ name }}/index.ts", - template: "export * from './src';", - }, - { - type: "add", - path: "packages/{{ name }}/src/index.ts", - template: "export const name = '{{ name }}';", - }, - { - type: "modify", - path: "packages/{{ name }}/package.json", - async transform(content, answers) { - const pkg = JSON.parse(content); - - for (const dep of answers.deps.split(" ").filter(Boolean)) { - const version = await fetch( - `https://registry.npmjs.org/-/package/${dep}/dist-tags`, - ) - .then((res) => res.json()) - .then((json) => json.latest); - pkg.dependencies![dep] = `^${version}`; - } - return JSON.stringify(pkg, null, 2); - }, - }, - async (answers) => { - /** - * Install deps and format everything - */ - execSync("pnpm manypkg fix", { - stdio: "inherit", - }); - execSync( - `pnpm prettier --write packages/${ - (answers as { name: string }).name - }/** --list-different`, - ); - return "Package scaffolded"; - }, - ], - }); + generators.forEach((gen) => gen(plop)); } diff --git a/turbo/generators/templates/keystatic/generator.ts b/turbo/generators/templates/keystatic/generator.ts new file mode 100644 index 000000000..7e4dda742 --- /dev/null +++ b/turbo/generators/templates/keystatic/generator.ts @@ -0,0 +1,65 @@ +import type { PlopTypes } from '@turbo/gen'; +import { execSync } from 'node:child_process'; + +export function createKeystaticAdminGenerator(plop: PlopTypes.NodePlopAPI) { + return plop.setGenerator('init', { + description: 'Generate a the admin for Keystatic', + prompts: [], + actions: [ + { + type: 'add', + path: 'apps/web/app/keystatic/layout.tsx', + templateFile: 'templates/keystatic/layout.tsx.hbs', + }, + { + type: 'add', + path: 'apps/web/app/keystatic/[[...params]]/page.tsx', + templateFile: 'templates/keystatic/page.tsx.hbs', + }, + { + type: 'add', + path: 'apps/web/app/api/keystatic/[...params]/route.ts', + templateFile: 'templates/keystatic/route.ts.hbs', + }, + { + type: 'modify', + path: 'apps/web/package.json', + async transform(content, answers) { + const pkg = JSON.parse(content); + const dep = `@keystatic/next`; + + const version = await fetch( + `https://registry.npmjs.org/-/package/${dep}/dist-tags`, + ) + .then((res) => res.json()) + .then((json) => json.latest); + + pkg.dependencies![dep] = `^${version}`; + pkg.dependencies!['@kit/keystatic'] = `workspace:*`; + + return JSON.stringify(pkg, null, 2); + }, + }, + async (answers) => { + /** + * Install deps and format everything + */ + execSync('pnpm manypkg fix', { + stdio: 'inherit', + }); + + execSync('pnpm i', { + stdio: 'inherit', + }); + + execSync( + `pnpm prettier --write packages/${ + (answers as { name: string }).name + }/** --list-different`, + ); + + return `Keystatic admin generated!`; + }, + ], + }); +} diff --git a/turbo/generators/templates/keystatic/layout.tsx.hbs b/turbo/generators/templates/keystatic/layout.tsx.hbs new file mode 100644 index 000000000..d78a4226a --- /dev/null +++ b/turbo/generators/templates/keystatic/layout.tsx.hbs @@ -0,0 +1,7 @@ +import KeystaticAdmin from '@kit/keystatic/admin'; + +export default function Layout() { + return ( + + ); +} \ No newline at end of file diff --git a/turbo/generators/templates/keystatic/page.tsx.hbs b/turbo/generators/templates/keystatic/page.tsx.hbs new file mode 100644 index 000000000..84a86be32 --- /dev/null +++ b/turbo/generators/templates/keystatic/page.tsx.hbs @@ -0,0 +1,5 @@ +// src/app/keystatic/[[...params]]/page.tsx + +export default function Page() { + return null; +} \ No newline at end of file diff --git a/turbo/generators/templates/keystatic/route.ts.hbs b/turbo/generators/templates/keystatic/route.ts.hbs new file mode 100644 index 000000000..b46ae50bb --- /dev/null +++ b/turbo/generators/templates/keystatic/route.ts.hbs @@ -0,0 +1,3 @@ +import { keystaticRouteHandlers } from '@kit/keystatic/route-handler'; + +export const { POST, GET } = keystaticRouteHandlers; \ No newline at end of file diff --git a/turbo/generators/templates/package/generator.ts b/turbo/generators/templates/package/generator.ts new file mode 100644 index 000000000..7d9957de0 --- /dev/null +++ b/turbo/generators/templates/package/generator.ts @@ -0,0 +1,84 @@ +import type { PlopTypes } from '@turbo/gen'; +import { execSync } from 'node:child_process'; + +export function createPackageGenerator(plop: PlopTypes.NodePlopAPI) { + plop.setGenerator('init', { + description: 'Generate a new package for the Monorepo', + prompts: [ + { + type: 'input', + name: 'name', + message: + 'What is the name of the package? (You can skip the `@kit/` prefix)', + }, + { + type: 'input', + name: 'deps', + message: + 'Enter a space separated list of dependencies you would like to install', + }, + ], + actions: [ + (answers) => { + if ('name' in answers && typeof answers.name === 'string') { + if (answers.name.startsWith('@kit/')) { + answers.name = answers.name.replace('@kit/', ''); + } + } + return 'Config sanitized'; + }, + { + type: 'add', + path: 'packages/{{ name }}/package.json', + templateFile: 'templates/package/package.json.hbs', + }, + { + type: 'add', + path: 'packages/{{ name }}/tsconfig.json', + templateFile: 'templates/package/tsconfig.json.hbs', + }, + { + type: 'add', + path: 'packages/{{ name }}/index.ts', + template: "export * from './src';", + }, + { + type: 'add', + path: 'packages/{{ name }}/src/index.ts', + template: "export const name = '{{ name }}';", + }, + { + type: 'modify', + path: 'packages/{{ name }}/package.json', + async transform(content, answers) { + const pkg = JSON.parse(content); + + for (const dep of answers.deps.split(' ').filter(Boolean)) { + const version = await fetch( + `https://registry.npmjs.org/-/package/${dep}/dist-tags`, + ) + .then((res) => res.json()) + .then((json) => json.latest); + + pkg.dependencies![dep] = `^${version}`; + } + return JSON.stringify(pkg, null, 2); + }, + }, + async (answers) => { + /** + * Install deps and format everything + */ + execSync('pnpm manypkg fix', { + stdio: 'inherit', + }); + execSync( + `pnpm prettier --write packages/${ + (answers as { name: string }).name + }/** --list-different`, + ); + return 'Package scaffolded'; + }, + ], + }); +} diff --git a/turbo/generators/templates/package.json.hbs b/turbo/generators/templates/package/package.json.hbs similarity index 100% rename from turbo/generators/templates/package.json.hbs rename to turbo/generators/templates/package/package.json.hbs diff --git a/turbo/generators/templates/tsconfig.json.hbs b/turbo/generators/templates/package/tsconfig.json.hbs similarity index 100% rename from turbo/generators/templates/tsconfig.json.hbs rename to turbo/generators/templates/package/tsconfig.json.hbs