@fydemy/cms 1.0.2 → 1.0.3
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/dist/admin.template.tsx +661 -0
- package/dist/bin.js +89 -12
- package/dist/bin.js.map +1 -1
- package/dist/bin.mjs +89 -12
- package/dist/bin.mjs.map +1 -1
- package/dist/components/ui/badge.tsx +36 -0
- package/dist/components/ui/button.tsx +56 -0
- package/dist/components/ui/card.tsx +86 -0
- package/dist/components/ui/input.tsx +25 -0
- package/dist/components/ui/label.tsx +24 -0
- package/dist/components/ui/textarea.tsx +24 -0
- package/dist/components.json +16 -0
- package/dist/index.js +89 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +89 -12
- package/dist/index.mjs.map +1 -1
- package/dist/lib/utils.ts +6 -0
- package/dist/login.template.tsx +126 -0
- package/package.json +4 -1
package/dist/bin.js
CHANGED
|
@@ -26,6 +26,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
// src/init/setup.ts
|
|
27
27
|
var import_promises = __toESM(require("fs/promises"));
|
|
28
28
|
var import_path = __toESM(require("path"));
|
|
29
|
+
var import_child_process = require("child_process");
|
|
30
|
+
var import_util = require("util");
|
|
31
|
+
var execAsync = (0, import_util.promisify)(import_child_process.exec);
|
|
29
32
|
async function initCMS(config = {}) {
|
|
30
33
|
const contentDir = config.contentDir || "public/content";
|
|
31
34
|
const fullPath = import_path.default.join(process.cwd(), contentDir);
|
|
@@ -39,6 +42,48 @@ async function initCMS(config = {}) {
|
|
|
39
42
|
return;
|
|
40
43
|
}
|
|
41
44
|
console.log("\u{1F680} Initializing @fydemy/cms...");
|
|
45
|
+
console.log("\u{1F4E6} Checking dependencies...");
|
|
46
|
+
try {
|
|
47
|
+
const packageJsonPath = import_path.default.join(process.cwd(), "package.json");
|
|
48
|
+
const packageJson = JSON.parse(await import_promises.default.readFile(packageJsonPath, "utf-8"));
|
|
49
|
+
const dependencies = {
|
|
50
|
+
...packageJson.dependencies,
|
|
51
|
+
...packageJson.devDependencies
|
|
52
|
+
};
|
|
53
|
+
const missingDeps = [];
|
|
54
|
+
if (!dependencies["@fydemy/cms"]) missingDeps.push("@fydemy/cms");
|
|
55
|
+
if (!dependencies["tailwindcss"]) missingDeps.push("tailwindcss");
|
|
56
|
+
if (!dependencies["class-variance-authority"])
|
|
57
|
+
missingDeps.push("class-variance-authority");
|
|
58
|
+
if (!dependencies["clsx"]) missingDeps.push("clsx");
|
|
59
|
+
if (!dependencies["tailwind-merge"]) missingDeps.push("tailwind-merge");
|
|
60
|
+
if (!dependencies["@radix-ui/react-slot"])
|
|
61
|
+
missingDeps.push("@radix-ui/react-slot");
|
|
62
|
+
if (!dependencies["@radix-ui/react-label"])
|
|
63
|
+
missingDeps.push("@radix-ui/react-label");
|
|
64
|
+
if (missingDeps.length > 0) {
|
|
65
|
+
console.log(
|
|
66
|
+
`\u{1F527} Installing missing dependencies: ${missingDeps.join(", ")}...`
|
|
67
|
+
);
|
|
68
|
+
let installCmd = "npm install";
|
|
69
|
+
try {
|
|
70
|
+
await import_promises.default.access("pnpm-lock.yaml");
|
|
71
|
+
installCmd = "pnpm add";
|
|
72
|
+
} catch {
|
|
73
|
+
try {
|
|
74
|
+
await import_promises.default.access("yarn.lock");
|
|
75
|
+
installCmd = "yarn add";
|
|
76
|
+
} catch {
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
await execAsync(`${installCmd} ${missingDeps.join(" ")}`);
|
|
80
|
+
console.log("\u2705 Dependencies installed");
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.warn(
|
|
84
|
+
"\u26A0\uFE0F Could not check/install dependencies automatically. Please ensure all dependencies are installed."
|
|
85
|
+
);
|
|
86
|
+
}
|
|
42
87
|
await import_promises.default.mkdir(fullPath, { recursive: true });
|
|
43
88
|
const exampleContent = `---
|
|
44
89
|
title: Example Post
|
|
@@ -64,23 +109,55 @@ This is an example markdown file. You can edit or delete it from the admin dashb
|
|
|
64
109
|
const adminDir = import_path.default.join(appDir, "admin");
|
|
65
110
|
const loginDir = import_path.default.join(adminDir, "login");
|
|
66
111
|
await import_promises.default.mkdir(loginDir, { recursive: true });
|
|
67
|
-
await import_promises.default.
|
|
68
|
-
import_path.default.join(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
112
|
+
const loginTemplate = await import_promises.default.readFile(
|
|
113
|
+
import_path.default.join(__dirname, "login.template.tsx"),
|
|
114
|
+
"utf-8"
|
|
115
|
+
);
|
|
116
|
+
const adminTemplate = await import_promises.default.readFile(
|
|
117
|
+
import_path.default.join(__dirname, "admin.template.tsx"),
|
|
118
|
+
"utf-8"
|
|
119
|
+
);
|
|
120
|
+
await import_promises.default.writeFile(import_path.default.join(adminDir, "page.tsx"), adminTemplate, "utf-8");
|
|
121
|
+
await import_promises.default.writeFile(import_path.default.join(loginDir, "page.tsx"), loginTemplate, "utf-8");
|
|
122
|
+
console.log("\u2705 Scaffolded Admin UI (shadcn/ui components)");
|
|
123
|
+
const componentsDir = import_path.default.join(process.cwd(), "components", "ui");
|
|
124
|
+
const libDir = import_path.default.join(process.cwd(), "lib");
|
|
125
|
+
await import_promises.default.mkdir(componentsDir, { recursive: true });
|
|
126
|
+
await import_promises.default.mkdir(libDir, { recursive: true });
|
|
127
|
+
const utilsTemplate = await import_promises.default.readFile(
|
|
128
|
+
import_path.default.join(__dirname, "lib", "utils.ts"),
|
|
129
|
+
"utf-8"
|
|
130
|
+
);
|
|
131
|
+
await import_promises.default.writeFile(import_path.default.join(libDir, "utils.ts"), utilsTemplate, "utf-8");
|
|
132
|
+
const componentFiles = [
|
|
133
|
+
"button.tsx",
|
|
134
|
+
"input.tsx",
|
|
135
|
+
"card.tsx",
|
|
136
|
+
"label.tsx",
|
|
137
|
+
"textarea.tsx",
|
|
138
|
+
"badge.tsx"
|
|
139
|
+
];
|
|
140
|
+
for (const componentFile of componentFiles) {
|
|
141
|
+
const componentTemplate = await import_promises.default.readFile(
|
|
142
|
+
import_path.default.join(__dirname, "components", "ui", componentFile),
|
|
143
|
+
"utf-8"
|
|
144
|
+
);
|
|
145
|
+
await import_promises.default.writeFile(
|
|
146
|
+
import_path.default.join(componentsDir, componentFile),
|
|
147
|
+
componentTemplate,
|
|
148
|
+
"utf-8"
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const componentsJsonTemplate = await import_promises.default.readFile(
|
|
152
|
+
import_path.default.join(__dirname, "components.json"),
|
|
73
153
|
"utf-8"
|
|
74
154
|
);
|
|
75
155
|
await import_promises.default.writeFile(
|
|
76
|
-
import_path.default.join(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
export default Login;
|
|
80
|
-
`,
|
|
156
|
+
import_path.default.join(process.cwd(), "components.json"),
|
|
157
|
+
componentsJsonTemplate,
|
|
81
158
|
"utf-8"
|
|
82
159
|
);
|
|
83
|
-
console.log("\u2705
|
|
160
|
+
console.log("\u2705 Scaffolded shadcn/ui components");
|
|
84
161
|
const apiCmsDir = import_path.default.join(appDir, "api", "cms");
|
|
85
162
|
await import_promises.default.mkdir(import_path.default.join(apiCmsDir, "login"), { recursive: true });
|
|
86
163
|
await import_promises.default.writeFile(
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n '❌ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"🚀 Initializing @fydemy/cms...\");\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"✅ Created content directory and example file\");\n\n // 2. Scaffold Admin Pages\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n await fs.writeFile(\n path.join(adminDir, \"page.tsx\"),\n `import { AdminDashboard } from '@fydemy/cms';\\n\\nexport default AdminDashboard;\\n`,\n \"utf-8\"\n );\n\n await fs.writeFile(\n path.join(loginDir, \"page.tsx\"),\n `import { Login } from '@fydemy/cms';\\n\\nexport default Login;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created Admin UI pages\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"⚠️ middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"🎉 CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":["path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n '❌ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"🚀 Initializing @fydemy/cms...\");\n\n // 0. Install Dependencies\n console.log(\"📦 Checking dependencies...\");\n try {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const missingDeps = [];\n if (!dependencies[\"@fydemy/cms\"]) missingDeps.push(\"@fydemy/cms\");\n if (!dependencies[\"tailwindcss\"]) missingDeps.push(\"tailwindcss\");\n\n // shadcn dependencies\n if (!dependencies[\"class-variance-authority\"])\n missingDeps.push(\"class-variance-authority\");\n if (!dependencies[\"clsx\"]) missingDeps.push(\"clsx\");\n if (!dependencies[\"tailwind-merge\"]) missingDeps.push(\"tailwind-merge\");\n if (!dependencies[\"@radix-ui/react-slot\"])\n missingDeps.push(\"@radix-ui/react-slot\");\n if (!dependencies[\"@radix-ui/react-label\"])\n missingDeps.push(\"@radix-ui/react-label\");\n\n if (missingDeps.length > 0) {\n console.log(\n `🔧 Installing missing dependencies: ${missingDeps.join(\", \")}...`\n );\n // Detect package manager (default to npm if locking file not found)\n let installCmd = \"npm install\";\n try {\n await fs.access(\"pnpm-lock.yaml\");\n installCmd = \"pnpm add\";\n } catch {\n try {\n await fs.access(\"yarn.lock\");\n installCmd = \"yarn add\";\n } catch {\n // npm\n }\n }\n\n await execAsync(`${installCmd} ${missingDeps.join(\" \")}`);\n console.log(\"✅ Dependencies installed\");\n }\n } catch (error) {\n console.warn(\n \"⚠️ Could not check/install dependencies automatically. Please ensure all dependencies are installed.\"\n );\n }\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"✅ Created content directory and example file\");\n\n // 2. Scaffold Admin Pages (Ejected Code)\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n // Read template files from the dist directory (publicDir copied them there)\n const loginTemplate = await fs.readFile(\n path.join(__dirname, \"login.template.tsx\"),\n \"utf-8\"\n );\n const adminTemplate = await fs.readFile(\n path.join(__dirname, \"admin.template.tsx\"),\n \"utf-8\"\n );\n\n await fs.writeFile(path.join(adminDir, \"page.tsx\"), adminTemplate, \"utf-8\");\n\n await fs.writeFile(path.join(loginDir, \"page.tsx\"), loginTemplate, \"utf-8\");\n console.log(\"✅ Scaffolded Admin UI (shadcn/ui components)\");\n\n // 2.5. Scaffold shadcn/ui Components and Utilities\n const componentsDir = path.join(process.cwd(), \"components\", \"ui\");\n const libDir = path.join(process.cwd(), \"lib\");\n\n await fs.mkdir(componentsDir, { recursive: true });\n await fs.mkdir(libDir, { recursive: true });\n\n // Copy utils.ts\n const utilsTemplate = await fs.readFile(\n path.join(__dirname, \"lib\", \"utils.ts\"),\n \"utf-8\"\n );\n await fs.writeFile(path.join(libDir, \"utils.ts\"), utilsTemplate, \"utf-8\");\n\n // Copy shadcn components\n const componentFiles = [\n \"button.tsx\",\n \"input.tsx\",\n \"card.tsx\",\n \"label.tsx\",\n \"textarea.tsx\",\n \"badge.tsx\",\n ];\n\n for (const componentFile of componentFiles) {\n const componentTemplate = await fs.readFile(\n path.join(__dirname, \"components\", \"ui\", componentFile),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(componentsDir, componentFile),\n componentTemplate,\n \"utf-8\"\n );\n }\n\n // Copy components.json\n const componentsJsonTemplate = await fs.readFile(\n path.join(__dirname, \"components.json\"),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(process.cwd(), \"components.json\"),\n componentsJsonTemplate,\n \"utf-8\"\n );\n\n console.log(\"✅ Scaffolded shadcn/ui components\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"⚠️ middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"🎉 CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,sBAAe;AACf,kBAAiB;AACjB,2BAAqB;AACrB,kBAA0B;AAE1B,IAAM,gBAAY,uBAAU,yBAAI;AAYhC,eAAsB,QAAQ,SAAwB,CAAC,GAAG;AACxD,QAAM,aAAa,OAAO,cAAc;AACxC,QAAM,WAAW,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,UAAU;AACpD,QAAM,SAAS,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,KAAK;AAG7C,MAAI;AACF,UAAM,gBAAAC,QAAG,OAAO,MAAM;AAAA,EACxB,QAAQ;AACN,YAAQ;AAAA,MACN;AAAA,IACF;AACA;AAAA,EACF;AAEA,UAAQ,IAAI,uCAAgC;AAG5C,UAAQ,IAAI,oCAA6B;AACzC,MAAI;AACF,UAAM,kBAAkB,YAAAD,QAAK,KAAK,QAAQ,IAAI,GAAG,cAAc;AAC/D,UAAM,cAAc,KAAK,MAAM,MAAM,gBAAAC,QAAG,SAAS,iBAAiB,OAAO,CAAC;AAC1E,UAAM,eAAe;AAAA,MACnB,GAAG,YAAY;AAAA,MACf,GAAG,YAAY;AAAA,IACjB;AAEA,UAAM,cAAc,CAAC;AACrB,QAAI,CAAC,aAAa,aAAa,EAAG,aAAY,KAAK,aAAa;AAChE,QAAI,CAAC,aAAa,aAAa,EAAG,aAAY,KAAK,aAAa;AAGhE,QAAI,CAAC,aAAa,0BAA0B;AAC1C,kBAAY,KAAK,0BAA0B;AAC7C,QAAI,CAAC,aAAa,MAAM,EAAG,aAAY,KAAK,MAAM;AAClD,QAAI,CAAC,aAAa,gBAAgB,EAAG,aAAY,KAAK,gBAAgB;AACtE,QAAI,CAAC,aAAa,sBAAsB;AACtC,kBAAY,KAAK,sBAAsB;AACzC,QAAI,CAAC,aAAa,uBAAuB;AACvC,kBAAY,KAAK,uBAAuB;AAE1C,QAAI,YAAY,SAAS,GAAG;AAC1B,cAAQ;AAAA,QACN,8CAAuC,YAAY,KAAK,IAAI,CAAC;AAAA,MAC/D;AAEA,UAAI,aAAa;AACjB,UAAI;AACF,cAAM,gBAAAA,QAAG,OAAO,gBAAgB;AAChC,qBAAa;AAAA,MACf,QAAQ;AACN,YAAI;AACF,gBAAM,gBAAAA,QAAG,OAAO,WAAW;AAC3B,uBAAa;AAAA,QACf,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,YAAM,UAAU,GAAG,UAAU,IAAI,YAAY,KAAK,GAAG,CAAC,EAAE;AACxD,cAAQ,IAAI,+BAA0B;AAAA,IACxC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAGA,QAAM,gBAAAA,QAAG,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAE5C,QAAM,iBAAiB;AAAA;AAAA;AAAA,SAGjB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgB9B,QAAM,cAAc,YAAAD,QAAK,KAAK,UAAU,YAAY;AACpD,QAAM,gBAAAC,QAAG,UAAU,aAAa,gBAAgB,OAAO;AACvD,UAAQ,IAAI,mDAA8C;AAG1D,QAAM,WAAW,YAAAD,QAAK,KAAK,QAAQ,OAAO;AAC1C,QAAM,WAAW,YAAAA,QAAK,KAAK,UAAU,OAAO;AAE5C,QAAM,gBAAAC,QAAG,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAG5C,QAAM,gBAAgB,MAAM,gBAAAA,QAAG;AAAA,IAC7B,YAAAD,QAAK,KAAK,WAAW,oBAAoB;AAAA,IACzC;AAAA,EACF;AACA,QAAM,gBAAgB,MAAM,gBAAAC,QAAG;AAAA,IAC7B,YAAAD,QAAK,KAAK,WAAW,oBAAoB;AAAA,IACzC;AAAA,EACF;AAEA,QAAM,gBAAAC,QAAG,UAAU,YAAAD,QAAK,KAAK,UAAU,UAAU,GAAG,eAAe,OAAO;AAE1E,QAAM,gBAAAC,QAAG,UAAU,YAAAD,QAAK,KAAK,UAAU,UAAU,GAAG,eAAe,OAAO;AAC1E,UAAQ,IAAI,mDAA8C;AAG1D,QAAM,gBAAgB,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,cAAc,IAAI;AACjE,QAAM,SAAS,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,KAAK;AAE7C,QAAM,gBAAAC,QAAG,MAAM,eAAe,EAAE,WAAW,KAAK,CAAC;AACjD,QAAM,gBAAAA,QAAG,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AAG1C,QAAM,gBAAgB,MAAM,gBAAAA,QAAG;AAAA,IAC7B,YAAAD,QAAK,KAAK,WAAW,OAAO,UAAU;AAAA,IACtC;AAAA,EACF;AACA,QAAM,gBAAAC,QAAG,UAAU,YAAAD,QAAK,KAAK,QAAQ,UAAU,GAAG,eAAe,OAAO;AAGxE,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,aAAW,iBAAiB,gBAAgB;AAC1C,UAAM,oBAAoB,MAAM,gBAAAC,QAAG;AAAA,MACjC,YAAAD,QAAK,KAAK,WAAW,cAAc,MAAM,aAAa;AAAA,MACtD;AAAA,IACF;AACA,UAAM,gBAAAC,QAAG;AAAA,MACP,YAAAD,QAAK,KAAK,eAAe,aAAa;AAAA,MACtC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,yBAAyB,MAAM,gBAAAC,QAAG;AAAA,IACtC,YAAAD,QAAK,KAAK,WAAW,iBAAiB;AAAA,IACtC;AAAA,EACF;AACA,QAAM,gBAAAC,QAAG;AAAA,IACP,YAAAD,QAAK,KAAK,QAAQ,IAAI,GAAG,iBAAiB;AAAA,IAC1C;AAAA,IACA;AAAA,EACF;AAEA,UAAQ,IAAI,wCAAmC;AAG/C,QAAM,YAAY,YAAAA,QAAK,KAAK,QAAQ,OAAO,KAAK;AAGhD,QAAM,gBAAAC,QAAG,MAAM,YAAAD,QAAK,KAAK,WAAW,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACjE,QAAM,gBAAAC,QAAG;AAAA,IACP,YAAAD,QAAK,KAAK,WAAW,SAAS,UAAU;AAAA,IACxC;AAAA;AAAA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,gBAAAC,QAAG,MAAM,YAAAD,QAAK,KAAK,WAAW,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAClE,QAAM,gBAAAC,QAAG;AAAA,IACP,YAAAD,QAAK,KAAK,WAAW,UAAU,UAAU;AAAA,IACzC;AAAA;AAAA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,gBAAAC,QAAG,MAAM,YAAAD,QAAK,KAAK,WAAW,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAClE,QAAM,gBAAAC,QAAG;AAAA,IACP,YAAAD,QAAK,KAAK,WAAW,UAAU,UAAU;AAAA,IACzC;AAAA;AAAA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,gBAAAC,QAAG,MAAM,YAAAD,QAAK,KAAK,WAAW,QAAQ,aAAa,GAAG;AAAA,IAC1D,WAAW;AAAA,EACb,CAAC;AACD,QAAM,gBAAAC,QAAG;AAAA,IACP,YAAAD,QAAK,KAAK,WAAW,QAAQ,eAAe,UAAU;AAAA,IACtD;AAAA;AAAA;AAAA;AAAA;AAAA,IACA;AAAA,EACF;AAGA,QAAM,gBAAAC,QAAG,MAAM,YAAAD,QAAK,KAAK,WAAW,WAAW,WAAW,GAAG;AAAA,IAC3D,WAAW;AAAA,EACb,CAAC;AACD,QAAM,gBAAAC,QAAG;AAAA,IACP,YAAAD,QAAK,KAAK,WAAW,WAAW,aAAa,UAAU;AAAA,IACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IACA;AAAA,EACF;AACA,UAAQ,IAAI,2BAAsB;AAGlC,QAAM,iBAAiB,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,eAAe;AAC/D,MAAI;AACF,UAAM,gBAAAC,QAAG,OAAO,cAAc;AAC9B,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAWf;AAAA,EACC,QAAQ;AACN,UAAM,gBAAAA,QAAG;AAAA,MACP;AAAA,MACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MACA;AAAA,IACF;AACA,YAAQ,IAAI,8BAAyB;AAAA,EACvC;AAGA,QAAM,iBAAiB,YAAAD,QAAK,KAAK,QAAQ,IAAI,GAAG,oBAAoB;AACpE,QAAM,gBAAAC,QAAG;AAAA,IACP;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IACA;AAAA,EACF;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,yCAAkC;AAC9C,UAAQ;AAAA,IACN;AAAA,EACF;AACA,UAAQ,IAAI,yCAAyC;AACvD;;;AC3QA,QAAQ,EAAE,MAAM,CAAC,QAAiB;AAChC,UAAQ,MAAM,2BAA2B,GAAG;AAC5C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["path","fs"]}
|
package/dist/bin.mjs
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// src/init/setup.ts
|
|
4
4
|
import fs from "fs/promises";
|
|
5
5
|
import path from "path";
|
|
6
|
+
import { exec } from "child_process";
|
|
7
|
+
import { promisify } from "util";
|
|
8
|
+
var execAsync = promisify(exec);
|
|
6
9
|
async function initCMS(config = {}) {
|
|
7
10
|
const contentDir = config.contentDir || "public/content";
|
|
8
11
|
const fullPath = path.join(process.cwd(), contentDir);
|
|
@@ -16,6 +19,48 @@ async function initCMS(config = {}) {
|
|
|
16
19
|
return;
|
|
17
20
|
}
|
|
18
21
|
console.log("\u{1F680} Initializing @fydemy/cms...");
|
|
22
|
+
console.log("\u{1F4E6} Checking dependencies...");
|
|
23
|
+
try {
|
|
24
|
+
const packageJsonPath = path.join(process.cwd(), "package.json");
|
|
25
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
|
|
26
|
+
const dependencies = {
|
|
27
|
+
...packageJson.dependencies,
|
|
28
|
+
...packageJson.devDependencies
|
|
29
|
+
};
|
|
30
|
+
const missingDeps = [];
|
|
31
|
+
if (!dependencies["@fydemy/cms"]) missingDeps.push("@fydemy/cms");
|
|
32
|
+
if (!dependencies["tailwindcss"]) missingDeps.push("tailwindcss");
|
|
33
|
+
if (!dependencies["class-variance-authority"])
|
|
34
|
+
missingDeps.push("class-variance-authority");
|
|
35
|
+
if (!dependencies["clsx"]) missingDeps.push("clsx");
|
|
36
|
+
if (!dependencies["tailwind-merge"]) missingDeps.push("tailwind-merge");
|
|
37
|
+
if (!dependencies["@radix-ui/react-slot"])
|
|
38
|
+
missingDeps.push("@radix-ui/react-slot");
|
|
39
|
+
if (!dependencies["@radix-ui/react-label"])
|
|
40
|
+
missingDeps.push("@radix-ui/react-label");
|
|
41
|
+
if (missingDeps.length > 0) {
|
|
42
|
+
console.log(
|
|
43
|
+
`\u{1F527} Installing missing dependencies: ${missingDeps.join(", ")}...`
|
|
44
|
+
);
|
|
45
|
+
let installCmd = "npm install";
|
|
46
|
+
try {
|
|
47
|
+
await fs.access("pnpm-lock.yaml");
|
|
48
|
+
installCmd = "pnpm add";
|
|
49
|
+
} catch {
|
|
50
|
+
try {
|
|
51
|
+
await fs.access("yarn.lock");
|
|
52
|
+
installCmd = "yarn add";
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
await execAsync(`${installCmd} ${missingDeps.join(" ")}`);
|
|
57
|
+
console.log("\u2705 Dependencies installed");
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.warn(
|
|
61
|
+
"\u26A0\uFE0F Could not check/install dependencies automatically. Please ensure all dependencies are installed."
|
|
62
|
+
);
|
|
63
|
+
}
|
|
19
64
|
await fs.mkdir(fullPath, { recursive: true });
|
|
20
65
|
const exampleContent = `---
|
|
21
66
|
title: Example Post
|
|
@@ -41,23 +86,55 @@ This is an example markdown file. You can edit or delete it from the admin dashb
|
|
|
41
86
|
const adminDir = path.join(appDir, "admin");
|
|
42
87
|
const loginDir = path.join(adminDir, "login");
|
|
43
88
|
await fs.mkdir(loginDir, { recursive: true });
|
|
44
|
-
await fs.
|
|
45
|
-
path.join(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
89
|
+
const loginTemplate = await fs.readFile(
|
|
90
|
+
path.join(__dirname, "login.template.tsx"),
|
|
91
|
+
"utf-8"
|
|
92
|
+
);
|
|
93
|
+
const adminTemplate = await fs.readFile(
|
|
94
|
+
path.join(__dirname, "admin.template.tsx"),
|
|
95
|
+
"utf-8"
|
|
96
|
+
);
|
|
97
|
+
await fs.writeFile(path.join(adminDir, "page.tsx"), adminTemplate, "utf-8");
|
|
98
|
+
await fs.writeFile(path.join(loginDir, "page.tsx"), loginTemplate, "utf-8");
|
|
99
|
+
console.log("\u2705 Scaffolded Admin UI (shadcn/ui components)");
|
|
100
|
+
const componentsDir = path.join(process.cwd(), "components", "ui");
|
|
101
|
+
const libDir = path.join(process.cwd(), "lib");
|
|
102
|
+
await fs.mkdir(componentsDir, { recursive: true });
|
|
103
|
+
await fs.mkdir(libDir, { recursive: true });
|
|
104
|
+
const utilsTemplate = await fs.readFile(
|
|
105
|
+
path.join(__dirname, "lib", "utils.ts"),
|
|
106
|
+
"utf-8"
|
|
107
|
+
);
|
|
108
|
+
await fs.writeFile(path.join(libDir, "utils.ts"), utilsTemplate, "utf-8");
|
|
109
|
+
const componentFiles = [
|
|
110
|
+
"button.tsx",
|
|
111
|
+
"input.tsx",
|
|
112
|
+
"card.tsx",
|
|
113
|
+
"label.tsx",
|
|
114
|
+
"textarea.tsx",
|
|
115
|
+
"badge.tsx"
|
|
116
|
+
];
|
|
117
|
+
for (const componentFile of componentFiles) {
|
|
118
|
+
const componentTemplate = await fs.readFile(
|
|
119
|
+
path.join(__dirname, "components", "ui", componentFile),
|
|
120
|
+
"utf-8"
|
|
121
|
+
);
|
|
122
|
+
await fs.writeFile(
|
|
123
|
+
path.join(componentsDir, componentFile),
|
|
124
|
+
componentTemplate,
|
|
125
|
+
"utf-8"
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const componentsJsonTemplate = await fs.readFile(
|
|
129
|
+
path.join(__dirname, "components.json"),
|
|
50
130
|
"utf-8"
|
|
51
131
|
);
|
|
52
132
|
await fs.writeFile(
|
|
53
|
-
path.join(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
export default Login;
|
|
57
|
-
`,
|
|
133
|
+
path.join(process.cwd(), "components.json"),
|
|
134
|
+
componentsJsonTemplate,
|
|
58
135
|
"utf-8"
|
|
59
136
|
);
|
|
60
|
-
console.log("\u2705
|
|
137
|
+
console.log("\u2705 Scaffolded shadcn/ui components");
|
|
61
138
|
const apiCmsDir = path.join(appDir, "api", "cms");
|
|
62
139
|
await fs.mkdir(path.join(apiCmsDir, "login"), { recursive: true });
|
|
63
140
|
await fs.writeFile(
|
package/dist/bin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n '❌ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"🚀 Initializing @fydemy/cms...\");\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"✅ Created content directory and example file\");\n\n // 2. Scaffold Admin Pages\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n await fs.writeFile(\n path.join(adminDir, \"page.tsx\"),\n `import { AdminDashboard } from '@fydemy/cms';\\n\\nexport default AdminDashboard;\\n`,\n \"utf-8\"\n );\n\n await fs.writeFile(\n path.join(loginDir, \"page.tsx\"),\n `import { Login } from '@fydemy/cms';\\n\\nexport default Login;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created Admin UI pages\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"⚠️ middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"🎉 CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/init/setup.ts","../src/bin.ts"],"sourcesContent":["import fs from \"fs/promises\";\nimport path from \"path\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n '❌ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"🚀 Initializing @fydemy/cms...\");\n\n // 0. Install Dependencies\n console.log(\"📦 Checking dependencies...\");\n try {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const missingDeps = [];\n if (!dependencies[\"@fydemy/cms\"]) missingDeps.push(\"@fydemy/cms\");\n if (!dependencies[\"tailwindcss\"]) missingDeps.push(\"tailwindcss\");\n\n // shadcn dependencies\n if (!dependencies[\"class-variance-authority\"])\n missingDeps.push(\"class-variance-authority\");\n if (!dependencies[\"clsx\"]) missingDeps.push(\"clsx\");\n if (!dependencies[\"tailwind-merge\"]) missingDeps.push(\"tailwind-merge\");\n if (!dependencies[\"@radix-ui/react-slot\"])\n missingDeps.push(\"@radix-ui/react-slot\");\n if (!dependencies[\"@radix-ui/react-label\"])\n missingDeps.push(\"@radix-ui/react-label\");\n\n if (missingDeps.length > 0) {\n console.log(\n `🔧 Installing missing dependencies: ${missingDeps.join(\", \")}...`\n );\n // Detect package manager (default to npm if locking file not found)\n let installCmd = \"npm install\";\n try {\n await fs.access(\"pnpm-lock.yaml\");\n installCmd = \"pnpm add\";\n } catch {\n try {\n await fs.access(\"yarn.lock\");\n installCmd = \"yarn add\";\n } catch {\n // npm\n }\n }\n\n await execAsync(`${installCmd} ${missingDeps.join(\" \")}`);\n console.log(\"✅ Dependencies installed\");\n }\n } catch (error) {\n console.warn(\n \"⚠️ Could not check/install dependencies automatically. Please ensure all dependencies are installed.\"\n );\n }\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"✅ Created content directory and example file\");\n\n // 2. Scaffold Admin Pages (Ejected Code)\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n // Read template files from the dist directory (publicDir copied them there)\n const loginTemplate = await fs.readFile(\n path.join(__dirname, \"login.template.tsx\"),\n \"utf-8\"\n );\n const adminTemplate = await fs.readFile(\n path.join(__dirname, \"admin.template.tsx\"),\n \"utf-8\"\n );\n\n await fs.writeFile(path.join(adminDir, \"page.tsx\"), adminTemplate, \"utf-8\");\n\n await fs.writeFile(path.join(loginDir, \"page.tsx\"), loginTemplate, \"utf-8\");\n console.log(\"✅ Scaffolded Admin UI (shadcn/ui components)\");\n\n // 2.5. Scaffold shadcn/ui Components and Utilities\n const componentsDir = path.join(process.cwd(), \"components\", \"ui\");\n const libDir = path.join(process.cwd(), \"lib\");\n\n await fs.mkdir(componentsDir, { recursive: true });\n await fs.mkdir(libDir, { recursive: true });\n\n // Copy utils.ts\n const utilsTemplate = await fs.readFile(\n path.join(__dirname, \"lib\", \"utils.ts\"),\n \"utf-8\"\n );\n await fs.writeFile(path.join(libDir, \"utils.ts\"), utilsTemplate, \"utf-8\");\n\n // Copy shadcn components\n const componentFiles = [\n \"button.tsx\",\n \"input.tsx\",\n \"card.tsx\",\n \"label.tsx\",\n \"textarea.tsx\",\n \"badge.tsx\",\n ];\n\n for (const componentFile of componentFiles) {\n const componentTemplate = await fs.readFile(\n path.join(__dirname, \"components\", \"ui\", componentFile),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(componentsDir, componentFile),\n componentTemplate,\n \"utf-8\"\n );\n }\n\n // Copy components.json\n const componentsJsonTemplate = await fs.readFile(\n path.join(__dirname, \"components.json\"),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(process.cwd(), \"components.json\"),\n componentsJsonTemplate,\n \"utf-8\"\n );\n\n console.log(\"✅ Scaffolded shadcn/ui components\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"⚠️ middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"🎉 CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n","#!/usr/bin/env node\n\nimport { initCMS } from \"./init/setup\";\n\ninitCMS().catch((err: unknown) => {\n console.error(\"Error initializing CMS:\", err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default:
|
|
12
|
+
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
13
|
+
secondary:
|
|
14
|
+
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
15
|
+
destructive:
|
|
16
|
+
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
17
|
+
outline: "text-foreground",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: {
|
|
21
|
+
variant: "default",
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
export interface BadgeProps
|
|
27
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
28
|
+
VariantProps<typeof badgeVariants> {}
|
|
29
|
+
|
|
30
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
31
|
+
return (
|
|
32
|
+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { Badge, badgeVariants };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
13
|
+
destructive:
|
|
14
|
+
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
15
|
+
outline:
|
|
16
|
+
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
17
|
+
secondary:
|
|
18
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
19
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
20
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
default: "h-10 px-4 py-2",
|
|
24
|
+
sm: "h-9 rounded-md px-3",
|
|
25
|
+
lg: "h-11 rounded-md px-8",
|
|
26
|
+
icon: "h-10 w-10",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: "default",
|
|
31
|
+
size: "default",
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
export interface ButtonProps
|
|
37
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
38
|
+
VariantProps<typeof buttonVariants> {
|
|
39
|
+
asChild?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
43
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
44
|
+
const Comp = asChild ? Slot : "button";
|
|
45
|
+
return (
|
|
46
|
+
<Comp
|
|
47
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
48
|
+
ref={ref}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
Button.displayName = "Button";
|
|
55
|
+
|
|
56
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
const Card = React.forwardRef<
|
|
6
|
+
HTMLDivElement,
|
|
7
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
8
|
+
>(({ className, ...props }, ref) => (
|
|
9
|
+
<div
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={cn(
|
|
12
|
+
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
));
|
|
18
|
+
Card.displayName = "Card";
|
|
19
|
+
|
|
20
|
+
const CardHeader = React.forwardRef<
|
|
21
|
+
HTMLDivElement,
|
|
22
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<div
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
));
|
|
30
|
+
CardHeader.displayName = "CardHeader";
|
|
31
|
+
|
|
32
|
+
const CardTitle = React.forwardRef<
|
|
33
|
+
HTMLParagraphElement,
|
|
34
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
35
|
+
>(({ className, ...props }, ref) => (
|
|
36
|
+
<h3
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"text-2xl font-semibold leading-none tracking-tight",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
));
|
|
45
|
+
CardTitle.displayName = "CardTitle";
|
|
46
|
+
|
|
47
|
+
const CardDescription = React.forwardRef<
|
|
48
|
+
HTMLParagraphElement,
|
|
49
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
50
|
+
>(({ className, ...props }, ref) => (
|
|
51
|
+
<p
|
|
52
|
+
ref={ref}
|
|
53
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
));
|
|
57
|
+
CardDescription.displayName = "CardDescription";
|
|
58
|
+
|
|
59
|
+
const CardContent = React.forwardRef<
|
|
60
|
+
HTMLDivElement,
|
|
61
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
62
|
+
>(({ className, ...props }, ref) => (
|
|
63
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
64
|
+
));
|
|
65
|
+
CardContent.displayName = "CardContent";
|
|
66
|
+
|
|
67
|
+
const CardFooter = React.forwardRef<
|
|
68
|
+
HTMLDivElement,
|
|
69
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
70
|
+
>(({ className, ...props }, ref) => (
|
|
71
|
+
<div
|
|
72
|
+
ref={ref}
|
|
73
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
));
|
|
77
|
+
CardFooter.displayName = "CardFooter";
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
Card,
|
|
81
|
+
CardHeader,
|
|
82
|
+
CardFooter,
|
|
83
|
+
CardTitle,
|
|
84
|
+
CardDescription,
|
|
85
|
+
CardContent,
|
|
86
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
export interface InputProps
|
|
6
|
+
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
|
7
|
+
|
|
8
|
+
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|
9
|
+
({ className, type, ...props }, ref) => {
|
|
10
|
+
return (
|
|
11
|
+
<input
|
|
12
|
+
type={type}
|
|
13
|
+
className={cn(
|
|
14
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
ref={ref}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
Input.displayName = "Input";
|
|
24
|
+
|
|
25
|
+
export { Input };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const labelVariants = cva(
|
|
8
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const Label = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof LabelPrimitive.Root>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
|
|
14
|
+
VariantProps<typeof labelVariants>
|
|
15
|
+
>(({ className, ...props }, ref) => (
|
|
16
|
+
<LabelPrimitive.Root
|
|
17
|
+
ref={ref}
|
|
18
|
+
className={cn(labelVariants(), className)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
));
|
|
22
|
+
Label.displayName = LabelPrimitive.Root.displayName;
|
|
23
|
+
|
|
24
|
+
export { Label };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
export interface TextareaProps
|
|
6
|
+
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
|
7
|
+
|
|
8
|
+
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|
9
|
+
({ className, ...props }, ref) => {
|
|
10
|
+
return (
|
|
11
|
+
<textarea
|
|
12
|
+
className={cn(
|
|
13
|
+
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
14
|
+
className
|
|
15
|
+
)}
|
|
16
|
+
ref={ref}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
Textarea.displayName = "Textarea";
|
|
23
|
+
|
|
24
|
+
export { Textarea };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
+
"style": "default",
|
|
4
|
+
"rsc": true,
|
|
5
|
+
"tsx": true,
|
|
6
|
+
"tailwind": {
|
|
7
|
+
"config": "tailwind.config.ts",
|
|
8
|
+
"css": "app/globals.css",
|
|
9
|
+
"baseColor": "slate",
|
|
10
|
+
"cssVariables": true
|
|
11
|
+
},
|
|
12
|
+
"aliases": {
|
|
13
|
+
"components": "@/components",
|
|
14
|
+
"utils": "@/lib/utils"
|
|
15
|
+
}
|
|
16
|
+
}
|