create-nextly-app 0.0.1 → 0.0.2-alpha.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.
Files changed (53) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +131 -0
  3. package/bin/create-nextly-app.js +3 -0
  4. package/dist/chunk-AYJ2RKVJ.mjs +28752 -0
  5. package/dist/chunk-AYJ2RKVJ.mjs.map +1 -0
  6. package/dist/cli.cjs +32410 -0
  7. package/dist/cli.cjs.map +1 -0
  8. package/dist/cli.d.cts +1 -0
  9. package/dist/cli.d.ts +1 -0
  10. package/dist/cli.mjs +3633 -0
  11. package/dist/cli.mjs.map +1 -0
  12. package/dist/index.cjs +24776 -0
  13. package/dist/index.cjs.map +1 -0
  14. package/dist/index.d.cts +69 -0
  15. package/dist/index.d.ts +69 -0
  16. package/dist/index.mjs +6 -0
  17. package/dist/index.mjs.map +1 -0
  18. package/package.json +83 -10
  19. package/templates/base/.env.example +16 -0
  20. package/templates/base/README.md +30 -0
  21. package/templates/base/eslint.config.mjs +18 -0
  22. package/templates/base/next.config.ts +21 -0
  23. package/templates/base/postcss.config.mjs +7 -0
  24. package/templates/base/public/file.svg +1 -0
  25. package/templates/base/public/globe.svg +1 -0
  26. package/templates/base/public/next.svg +1 -0
  27. package/templates/base/public/vercel.svg +1 -0
  28. package/templates/base/public/window.svg +1 -0
  29. package/templates/base/src/app/admin/[[...params]]/layout.tsx +20 -0
  30. package/templates/base/src/app/admin/[[...params]]/page.tsx +27 -0
  31. package/templates/base/src/app/admin/api/[[...params]]/route.ts +12 -0
  32. package/templates/base/src/app/api/health/route.ts +7 -0
  33. package/templates/base/src/app/api/media/[[...path]]/route.ts +34 -0
  34. package/templates/base/src/app/favicon.ico +0 -0
  35. package/templates/base/src/app/globals.css +55 -0
  36. package/templates/base/src/app/layout.tsx +43 -0
  37. package/templates/base/src/app/page.tsx +65 -0
  38. package/templates/base/src/types/generated/.gitkeep +0 -0
  39. package/templates/base/src/types/generated/nextly-types.ts +12 -0
  40. package/templates/base/tsconfig.json +35 -0
  41. package/templates/blank/.env.example +8 -0
  42. package/templates/blank/README.md +63 -0
  43. package/templates/blank/nextly.config.ts +14 -0
  44. package/templates/blank/src/access/README.md +22 -0
  45. package/templates/blank/src/app/(frontend)/page.tsx +176 -0
  46. package/templates/blank/src/app/globals.css +79 -0
  47. package/templates/blank/src/app/layout.tsx +46 -0
  48. package/templates/blank/src/collections/README.md +22 -0
  49. package/templates/blank/src/components/README.md +10 -0
  50. package/templates/blank/src/components/ThemeToggle.tsx +113 -0
  51. package/templates/blank/src/lib/README.md +15 -0
  52. package/templates/blank/src/singles/README.md +19 -0
  53. package/templates/blank/template.json +14 -0
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Project type / template selection.
3
+ * "blog" is the first content template added for alpha.
4
+ */
5
+ type ProjectType = "blank" | "blog";
6
+ /**
7
+ * Schema approach selection for content templates.
8
+ * - code-first: Full schema definitions in nextly.config.ts (like Payload CMS)
9
+ * - visual: Empty config, schemas created via Admin Panel UI (like Strapi/WordPress)
10
+ * - both: Core schemas in code, additional schemas creatable via Admin Panel
11
+ */
12
+ type ProjectApproach = "code-first" | "visual";
13
+ /**
14
+ * Supported database types
15
+ */
16
+ type DatabaseType = "postgresql" | "mysql" | "sqlite";
17
+ /**
18
+ * Options for createNextly function
19
+ */
20
+ interface CreateNextlyOptions {
21
+ /** Working directory (defaults to process.cwd()) */
22
+ cwd?: string;
23
+ /** Skip interactive prompts and use defaults */
24
+ defaults?: boolean;
25
+ /** Pre-selected project type / template name */
26
+ projectType?: ProjectType;
27
+ /** Pre-selected database type */
28
+ database?: DatabaseType;
29
+ /** Skip dependency installation (useful for local testing before packages are published) */
30
+ skipInstall?: boolean;
31
+ /** Use yalc for local package installation (for testing before npm publish) */
32
+ useYalc?: boolean;
33
+ /**
34
+ * Project name derived from the CLI's positional `[directory]` argument.
35
+ * Must be a bare directory name (no slashes). Callers pass the basename
36
+ * of the user-provided argument.
37
+ */
38
+ projectNameFromArg?: string;
39
+ /**
40
+ * When true, the CLI was invoked with "." meaning "install in current directory".
41
+ * Different from projectNameFromArg which creates a subdirectory.
42
+ */
43
+ installInCwd?: boolean;
44
+ /** Schema approach for content templates (code-first, visual) */
45
+ approach?: ProjectApproach;
46
+ /** Path to local templates directory (for development, bypasses GitHub download) */
47
+ localTemplatePath?: string;
48
+ /** Git branch for template download from GitHub (defaults to "main") */
49
+ branch?: string;
50
+ }
51
+
52
+ /**
53
+ * Main entry point for scaffolding Nextly in a Next.js project.
54
+ *
55
+ * Two flows:
56
+ * 1. Empty directory -> scaffold Next.js + install Nextly
57
+ * 2. Existing Next.js project -> install Nextly into it
58
+ *
59
+ * Interactive prompt order:
60
+ * 1. Project name (or detect existing project)
61
+ * 2. Template selection (blank, blog, etc.)
62
+ * 3. Schema approach (code-first, visual) — only for content templates
63
+ * 4. Demo content (yes/no) - only for content templates
64
+ * 5. Database selection (sqlite, postgresql, mysql)
65
+ * 6. Database connection string (only for postgresql/mysql)
66
+ */
67
+ declare function createNextly(options?: CreateNextlyOptions): Promise<void>;
68
+
69
+ export { type CreateNextlyOptions, createNextly };
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Project type / template selection.
3
+ * "blog" is the first content template added for alpha.
4
+ */
5
+ type ProjectType = "blank" | "blog";
6
+ /**
7
+ * Schema approach selection for content templates.
8
+ * - code-first: Full schema definitions in nextly.config.ts (like Payload CMS)
9
+ * - visual: Empty config, schemas created via Admin Panel UI (like Strapi/WordPress)
10
+ * - both: Core schemas in code, additional schemas creatable via Admin Panel
11
+ */
12
+ type ProjectApproach = "code-first" | "visual";
13
+ /**
14
+ * Supported database types
15
+ */
16
+ type DatabaseType = "postgresql" | "mysql" | "sqlite";
17
+ /**
18
+ * Options for createNextly function
19
+ */
20
+ interface CreateNextlyOptions {
21
+ /** Working directory (defaults to process.cwd()) */
22
+ cwd?: string;
23
+ /** Skip interactive prompts and use defaults */
24
+ defaults?: boolean;
25
+ /** Pre-selected project type / template name */
26
+ projectType?: ProjectType;
27
+ /** Pre-selected database type */
28
+ database?: DatabaseType;
29
+ /** Skip dependency installation (useful for local testing before packages are published) */
30
+ skipInstall?: boolean;
31
+ /** Use yalc for local package installation (for testing before npm publish) */
32
+ useYalc?: boolean;
33
+ /**
34
+ * Project name derived from the CLI's positional `[directory]` argument.
35
+ * Must be a bare directory name (no slashes). Callers pass the basename
36
+ * of the user-provided argument.
37
+ */
38
+ projectNameFromArg?: string;
39
+ /**
40
+ * When true, the CLI was invoked with "." meaning "install in current directory".
41
+ * Different from projectNameFromArg which creates a subdirectory.
42
+ */
43
+ installInCwd?: boolean;
44
+ /** Schema approach for content templates (code-first, visual) */
45
+ approach?: ProjectApproach;
46
+ /** Path to local templates directory (for development, bypasses GitHub download) */
47
+ localTemplatePath?: string;
48
+ /** Git branch for template download from GitHub (defaults to "main") */
49
+ branch?: string;
50
+ }
51
+
52
+ /**
53
+ * Main entry point for scaffolding Nextly in a Next.js project.
54
+ *
55
+ * Two flows:
56
+ * 1. Empty directory -> scaffold Next.js + install Nextly
57
+ * 2. Existing Next.js project -> install Nextly into it
58
+ *
59
+ * Interactive prompt order:
60
+ * 1. Project name (or detect existing project)
61
+ * 2. Template selection (blank, blog, etc.)
62
+ * 3. Schema approach (code-first, visual) — only for content templates
63
+ * 4. Demo content (yes/no) - only for content templates
64
+ * 5. Database selection (sqlite, postgresql, mysql)
65
+ * 6. Database connection string (only for postgresql/mysql)
66
+ */
67
+ declare function createNextly(options?: CreateNextlyOptions): Promise<void>;
68
+
69
+ export { type CreateNextlyOptions, createNextly };
package/dist/index.mjs ADDED
@@ -0,0 +1,6 @@
1
+ import { createRequire } from 'module';
2
+ export { createNextly } from './chunk-AYJ2RKVJ.mjs';
3
+
4
+ createRequire(import.meta.url);
5
+ //# sourceMappingURL=index.mjs.map
6
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
package/package.json CHANGED
@@ -1,13 +1,86 @@
1
1
  {
2
2
  "name": "create-nextly-app",
3
- "version": "0.0.1",
4
- "description": "",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
3
+ "version": "0.0.2-alpha.0",
4
+ "description": "CLI to scaffold Nextly in your Next.js project",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "dist/index.mjs",
8
+ "module": "dist/index.mjs",
9
+ "types": "dist/index.d.ts",
10
+ "bin": {
11
+ "create-nextly-app": "./bin/create-nextly-app.js"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.mjs",
17
+ "require": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "bin",
23
+ "templates"
24
+ ],
25
+ "dependencies": {
26
+ "@clack/prompts": "^1.1.0",
27
+ "commander": "^14.0.2",
28
+ "execa": "^9.6.0",
29
+ "fs-extra": "^11.3.0",
30
+ "ora": "^9.0.0",
31
+ "picocolors": "^1.1.1",
32
+ "tar": "^7.4.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/fs-extra": "^11.0.4",
36
+ "@types/tar": "^6.1.13",
37
+ "@types/node": "^20.19.17",
38
+ "@vitest/coverage-v8": "^4.0.8",
39
+ "@vitest/ui": "^4.0.8",
40
+ "eslint": "^9.34.0",
41
+ "tsup": "^8.5.0",
42
+ "typescript": "^5.9.3",
43
+ "vite-tsconfig-paths": "^5.1.4",
44
+ "vitest": "^4.0.8",
45
+ "@nextlyhq/eslint-config": "0.0.1",
46
+ "@nextlyhq/telemetry": "0.0.1",
47
+ "@nextlyhq/tsconfig": "0.0.1"
48
+ },
49
+ "engines": {
50
+ "node": ">=20.0.0"
8
51
  },
9
- "keywords": [],
10
- "author": "mobeenabdullah",
11
- "license": "ISC",
12
- "type": "commonjs"
13
- }
52
+ "keywords": [
53
+ "nextly",
54
+ "cms",
55
+ "nextjs",
56
+ "cli",
57
+ "scaffold",
58
+ "create-nextly-app",
59
+ "create-app"
60
+ ],
61
+ "repository": {
62
+ "type": "git",
63
+ "url": "git+https://github.com/nextlyhq/nextly.git",
64
+ "directory": "packages/create-nextly-app"
65
+ },
66
+ "publishConfig": {
67
+ "access": "public",
68
+ "registry": "https://registry.npmjs.org/",
69
+ "provenance": true
70
+ },
71
+ "homepage": "https://nextlyhq.com",
72
+ "bugs": {
73
+ "url": "https://github.com/nextlyhq/nextly/issues"
74
+ },
75
+ "author": "Nextly <contact@nextlyhq.com> (https://nextlyhq.com)",
76
+ "scripts": {
77
+ "build": "tsup",
78
+ "dev": "tsup --watch",
79
+ "check-types": "tsc --noEmit",
80
+ "lint": "eslint . --max-warnings 0",
81
+ "lint:fix": "eslint . --fix",
82
+ "test": "vitest run --passWithNoTests",
83
+ "test:watch": "vitest",
84
+ "clean": "rimraf dist"
85
+ }
86
+ }
@@ -0,0 +1,16 @@
1
+ # Nextly Configuration
2
+ # Generated by create-nextly-app
3
+
4
+ # Database Configuration
5
+ DB_DIALECT={{databaseDialect}}
6
+ DATABASE_URL={{databaseUrl}}
7
+
8
+ # Authentication (REQUIRED)
9
+ # Generate with: openssl rand -base64 32
10
+ NEXTLY_SECRET=change-me-generate-a-secure-secret
11
+
12
+ # Application URL
13
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
14
+
15
+ # Storage Configuration
16
+ {{storageEnvVars}}
@@ -0,0 +1,30 @@
1
+ # Base template
2
+
3
+ Shared scaffolding for all `create-nextly-app` templates. The CLI applies this template first, then overlays the user-selected template (`blank`, `blog`, or future) on top.
4
+
5
+ > Not user-selectable. You will not see "base" in the CLI menu. It is always applied beneath your chosen template.
6
+
7
+ ## What's in here
8
+
9
+ - Admin route handler stub (`app/admin/[[...params]]/page.tsx`)
10
+ - Default API handler stubs
11
+ - Shared styles and Tailwind preset wiring
12
+ - Default `tsconfig.json`, `next.config.ts`, `eslint.config.mjs`, `postcss.config.mjs`
13
+
14
+ ## Maintainer notes
15
+
16
+ When editing files in `base/`, run the CLI against `--template blank` and `--template blog` locally to confirm both still scaffold cleanly:
17
+
18
+ ```bash
19
+ pnpm --filter create-nextly-app dev -- my-test \
20
+ --template blank \
21
+ --local-template ./templates \
22
+ --skip-install
23
+
24
+ pnpm --filter create-nextly-app dev -- my-test \
25
+ --template blog \
26
+ --local-template ./templates \
27
+ --skip-install
28
+ ```
29
+
30
+ See [CONTRIBUTING.md](../../CONTRIBUTING.md).
@@ -0,0 +1,18 @@
1
+ import { defineConfig, globalIgnores } from "eslint/config";
2
+ import nextVitals from "eslint-config-next/core-web-vitals";
3
+ import nextTs from "eslint-config-next/typescript";
4
+
5
+ const eslintConfig = defineConfig([
6
+ ...nextVitals,
7
+ ...nextTs,
8
+ // Override default ignores of eslint-config-next.
9
+ globalIgnores([
10
+ // Default ignores of eslint-config-next:
11
+ ".next/**",
12
+ "out/**",
13
+ "build/**",
14
+ "next-env.d.ts",
15
+ ]),
16
+ ]);
17
+
18
+ export default eslintConfig;
@@ -0,0 +1,21 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ serverExternalPackages: [
5
+ "nextly",
6
+ "@nextlyhq/adapter-drizzle",
7
+ "@nextlyhq/adapter-postgres",
8
+ "@nextlyhq/adapter-mysql",
9
+ "@nextlyhq/adapter-sqlite",
10
+ "drizzle-orm",
11
+ "drizzle-kit",
12
+ "pg",
13
+ "mysql2",
14
+ "better-sqlite3",
15
+ "bcryptjs",
16
+ "sharp",
17
+ "esbuild",
18
+ ],
19
+ };
20
+
21
+ export default nextConfig;
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
@@ -0,0 +1,20 @@
1
+ import { getBrandingCss } from "nextly/config";
2
+
3
+ import config from "../../../../nextly.config";
4
+
5
+ const brandingCss = getBrandingCss(config.admin?.branding);
6
+
7
+ export default function AdminLayout({
8
+ children,
9
+ }: {
10
+ children: React.ReactNode;
11
+ }) {
12
+ return (
13
+ <>
14
+ {brandingCss && (
15
+ <style dangerouslySetInnerHTML={{ __html: brandingCss }} />
16
+ )}
17
+ {children}
18
+ </>
19
+ );
20
+ }
@@ -0,0 +1,27 @@
1
+ "use client";
2
+
3
+ // Plugin-side admin imports. Every scaffold ships @nextlyhq/plugin-form-builder
4
+ // as a dependency (see packages/create-nextly-app utils/template.ts). These
5
+ // three lines register the plugin's custom admin field components and load its
6
+ // CSS so the Forms collection's drag-and-drop field builder and Submissions
7
+ // filter UI render correctly. Without them, Forms still appears in the sidebar
8
+ // but the builder falls back to plain JSON/text inputs.
9
+ import "@nextlyhq/admin/style.css";
10
+ import "@nextlyhq/plugin-form-builder/admin";
11
+ import "@nextlyhq/plugin-form-builder/styles/builder.css";
12
+ import "@nextlyhq/plugin-form-builder/styles/submissions-filter.css";
13
+ import { RootLayout, QueryProvider, ErrorBoundary } from "@nextlyhq/admin";
14
+
15
+ export default function AdminPage() {
16
+ return (
17
+ <ErrorBoundary
18
+ onError={(error, errorInfo) => {
19
+ console.error("Admin error:", error, errorInfo);
20
+ }}
21
+ >
22
+ <QueryProvider>
23
+ <RootLayout />
24
+ </QueryProvider>
25
+ </ErrorBoundary>
26
+ );
27
+ }
@@ -0,0 +1,12 @@
1
+ import { createDynamicHandlers } from "nextly/runtime";
2
+
3
+ import nextlyConfig from "../../../../../nextly.config";
4
+
5
+ const handlers = createDynamicHandlers({ config: nextlyConfig });
6
+
7
+ export const GET = handlers.GET;
8
+ export const POST = handlers.POST;
9
+ export const PUT = handlers.PUT;
10
+ export const PATCH = handlers.PATCH;
11
+ export const DELETE = handlers.DELETE;
12
+ export const OPTIONS = handlers.OPTIONS;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Health Check Endpoint
3
+ *
4
+ * GET /api/health - Check if the API is running
5
+ */
6
+
7
+ export { GET, HEAD } from "nextly/api/health";
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Media API Routes (Catch-All Handler)
3
+ *
4
+ * This single route handles all media operations:
5
+ *
6
+ * Media Files:
7
+ * - GET /api/media - List media with pagination
8
+ * - POST /api/media - Upload new media file
9
+ * - GET /api/media/:id - Get media by ID
10
+ * - PATCH /api/media/:id - Update media metadata
11
+ * - DELETE /api/media/:id - Delete media file
12
+ * - PATCH /api/media/:id/move - Move media to folder
13
+ *
14
+ * Folders:
15
+ * - GET /api/media/folders - List folders
16
+ * - POST /api/media/folders - Create folder
17
+ * - GET /api/media/folders/:id - Get folder by ID
18
+ * - PATCH /api/media/folders/:id - Update folder
19
+ * - DELETE /api/media/folders/:id - Delete folder
20
+ * - GET /api/media/folders/:id/contents - Get folder contents
21
+ * - GET /api/media/folders/root/contents - Get root folder contents
22
+ */
23
+
24
+ import { createMediaHandlers } from "nextly/api/media-handlers";
25
+
26
+ import nextlyConfig from "../../../../../nextly.config";
27
+
28
+ // Pass config to ensure storage plugins work across all worker processes
29
+ const handlers = createMediaHandlers({ config: nextlyConfig });
30
+
31
+ export const GET = handlers.GET;
32
+ export const POST = handlers.POST;
33
+ export const PATCH = handlers.PATCH;
34
+ export const DELETE = handlers.DELETE;
@@ -0,0 +1,55 @@
1
+ @import "tailwindcss";
2
+
3
+ :root {
4
+ --background: #ffffff;
5
+ --foreground: #171717;
6
+ }
7
+
8
+ @theme inline {
9
+ --color-background: var(--background);
10
+ --color-foreground: var(--foreground);
11
+ --font-sans: var(--font-geist-sans);
12
+ --font-mono: var(--font-geist-mono);
13
+ }
14
+
15
+ @media (prefers-color-scheme: dark) {
16
+ :root {
17
+ --background: #0a0a0a;
18
+ --foreground: #ededed;
19
+ }
20
+ }
21
+
22
+ body {
23
+ background: var(--background);
24
+ color: var(--foreground);
25
+ font-family: Arial, Helvetica, sans-serif;
26
+ }
27
+
28
+ /* ===============================================================
29
+ Accessibility baseline
30
+ ---------------------------------------------------------------
31
+ Applied globally so the template passes a WCAG AA keyboard audit
32
+ out of the box. Adjust to match your brand.
33
+ =============================================================== */
34
+
35
+ /* Visible focus ring for keyboard users. `:focus-visible` only fires
36
+ on keyboard / programmatic focus, so clicking a button doesn't
37
+ show the ring but tabbing to it does. */
38
+ *:focus-visible {
39
+ outline: 2px solid currentColor;
40
+ outline-offset: 2px;
41
+ border-radius: 2px;
42
+ }
43
+
44
+ /* Honor OS-level reduced-motion preference — disables hover scale,
45
+ transitions, and animations for users who've opted out. */
46
+ @media (prefers-reduced-motion: reduce) {
47
+ *,
48
+ *::before,
49
+ *::after {
50
+ animation-duration: 0.01ms !important;
51
+ animation-iteration-count: 1 !important;
52
+ transition-duration: 0.01ms !important;
53
+ scroll-behavior: auto !important;
54
+ }
55
+ }
@@ -0,0 +1,43 @@
1
+ import type { Metadata } from "next";
2
+ import { Geist, Geist_Mono } from "next/font/google";
3
+ import "./globals.css";
4
+
5
+ const geistSans = Geist({
6
+ variable: "--font-geist-sans",
7
+ subsets: ["latin"],
8
+ });
9
+
10
+ const geistMono = Geist_Mono({
11
+ variable: "--font-geist-mono",
12
+ subsets: ["latin"],
13
+ });
14
+
15
+ /**
16
+ * `metadataBase` tells Next.js how to resolve relative URLs in OpenGraph
17
+ * images, Twitter images, and canonical URLs. Set `NEXT_PUBLIC_SITE_URL`
18
+ * in your environment to your production domain (e.g.
19
+ * `https://yourblog.com`). The localhost fallback keeps dev working.
20
+ */
21
+ export const metadata: Metadata = {
22
+ metadataBase: new URL(
23
+ process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000"
24
+ ),
25
+ title: { default: "Nextly", template: "%s — Nextly" },
26
+ description: "A site built with Nextly.",
27
+ };
28
+
29
+ export default function RootLayout({
30
+ children,
31
+ }: Readonly<{
32
+ children: React.ReactNode;
33
+ }>) {
34
+ return (
35
+ <html lang="en" suppressHydrationWarning>
36
+ <body
37
+ className={`${geistSans.variable} ${geistMono.variable} antialiased`}
38
+ >
39
+ {children}
40
+ </body>
41
+ </html>
42
+ );
43
+ }
@@ -0,0 +1,65 @@
1
+ import Image from "next/image";
2
+
3
+ export default function Home() {
4
+ return (
5
+ <div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
6
+ <main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
7
+ <Image
8
+ className="dark:invert"
9
+ src="/next.svg"
10
+ alt="Next.js logo"
11
+ width={100}
12
+ height={20}
13
+ priority
14
+ />
15
+ <div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
16
+ <h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
17
+ To get started, edit the page.tsx file.
18
+ </h1>
19
+ <p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
20
+ Looking for a starting point or more instructions? Head over to{" "}
21
+ <a
22
+ href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
23
+ className="font-medium text-zinc-950 dark:text-zinc-50"
24
+ >
25
+ Templates
26
+ </a>{" "}
27
+ or the{" "}
28
+ <a
29
+ href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
30
+ className="font-medium text-zinc-950 dark:text-zinc-50"
31
+ >
32
+ Learning
33
+ </a>{" "}
34
+ center.
35
+ </p>
36
+ </div>
37
+ <div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
38
+ <a
39
+ className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
40
+ href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
41
+ target="_blank"
42
+ rel="noopener noreferrer"
43
+ >
44
+ <Image
45
+ className="dark:invert"
46
+ src="/vercel.svg"
47
+ alt="Vercel logomark"
48
+ width={16}
49
+ height={16}
50
+ />
51
+ Deploy Now
52
+ </a>
53
+ <a
54
+ className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
55
+ href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
56
+ target="_blank"
57
+ rel="noopener noreferrer"
58
+ >
59
+ Documentation
60
+ </a>
61
+ </div>
62
+ </main>
63
+ </div>
64
+ );
65
+ }
File without changes
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Nextly Generated Types
3
+ *
4
+ * This file will be auto-generated when you run:
5
+ * npx nextly dev
6
+ * npx nextly generate:types
7
+ *
8
+ * Do not edit this file manually - it will be overwritten.
9
+ */
10
+
11
+ // Types will be generated here after running nextly dev
12
+ export {};