portfolify 2.0.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 (66) hide show
  1. package/dist/commands/generate.d.ts +7 -0
  2. package/dist/commands/generate.d.ts.map +1 -0
  3. package/dist/commands/generate.js +129 -0
  4. package/dist/commands/generate.js.map +1 -0
  5. package/dist/commands/portfolio.d.ts +12 -0
  6. package/dist/commands/portfolio.d.ts.map +1 -0
  7. package/dist/commands/portfolio.js +292 -0
  8. package/dist/commands/portfolio.js.map +1 -0
  9. package/dist/generator/index.d.ts +3 -0
  10. package/dist/generator/index.d.ts.map +1 -0
  11. package/dist/generator/index.js +572 -0
  12. package/dist/generator/index.js.map +1 -0
  13. package/dist/generator/portfolio-generator.d.ts +4 -0
  14. package/dist/generator/portfolio-generator.d.ts.map +1 -0
  15. package/dist/generator/portfolio-generator.js +1577 -0
  16. package/dist/generator/portfolio-generator.js.map +1 -0
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +40 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/prompts/index.d.ts +81 -0
  22. package/dist/prompts/index.d.ts.map +1 -0
  23. package/dist/prompts/index.js +330 -0
  24. package/dist/prompts/index.js.map +1 -0
  25. package/dist/prompts/portfolio-prompts.d.ts +60 -0
  26. package/dist/prompts/portfolio-prompts.d.ts.map +1 -0
  27. package/dist/prompts/portfolio-prompts.js +635 -0
  28. package/dist/prompts/portfolio-prompts.js.map +1 -0
  29. package/dist/themes/index.d.ts +15 -0
  30. package/dist/themes/index.d.ts.map +1 -0
  31. package/dist/themes/index.js +64 -0
  32. package/dist/themes/index.js.map +1 -0
  33. package/dist/utils/file.d.ts +5 -0
  34. package/dist/utils/file.d.ts.map +1 -0
  35. package/dist/utils/file.js +33 -0
  36. package/dist/utils/file.js.map +1 -0
  37. package/dist/utils/logger.d.ts +9 -0
  38. package/dist/utils/logger.d.ts.map +1 -0
  39. package/dist/utils/logger.js +22 -0
  40. package/dist/utils/logger.js.map +1 -0
  41. package/dist/utils/validator.d.ts +27 -0
  42. package/dist/utils/validator.d.ts.map +1 -0
  43. package/dist/utils/validator.js +322 -0
  44. package/dist/utils/validator.js.map +1 -0
  45. package/package.json +66 -0
  46. package/templates/index.html +16 -0
  47. package/templates/package.json +37 -0
  48. package/templates/postcss.config.js +6 -0
  49. package/templates/src/App.tsx +56 -0
  50. package/templates/src/components/Blog.tsx +119 -0
  51. package/templates/src/components/Footer.tsx +206 -0
  52. package/templates/src/components/Hero.tsx +182 -0
  53. package/templates/src/components/Projects.tsx +130 -0
  54. package/templates/src/components/SEO.tsx +38 -0
  55. package/templates/src/components/Skills.tsx +107 -0
  56. package/templates/src/components/ThemeToggle.tsx +39 -0
  57. package/templates/src/config/portfolio.json +61 -0
  58. package/templates/src/content/blog/welcome.mdx +29 -0
  59. package/templates/src/lib/blog.ts +63 -0
  60. package/templates/src/lib/utils.ts +6 -0
  61. package/templates/src/main.tsx +13 -0
  62. package/templates/src/styles/globals.css +123 -0
  63. package/templates/tailwind.config.js +65 -0
  64. package/templates/tsconfig.json +37 -0
  65. package/templates/tsconfig.node.json +12 -0
  66. package/templates/vite.config.ts +24 -0
@@ -0,0 +1,572 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+ import ora from 'ora';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname } from 'path';
6
+ import { copyDirectory, writeFile } from '../utils/file.js';
7
+ import { logger } from '../utils/logger.js';
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ export async function generatePortfolio(projectName, data, targetDir) {
11
+ const spinner = ora('Generating your portfolio...').start();
12
+ try {
13
+ // Determine template path
14
+ let templatePath = path.resolve(__dirname, '../../templates');
15
+ const isDebug = process.env.DEBUG === 'true';
16
+ if (isDebug) {
17
+ logger.info(`Template source path: ${templatePath}`);
18
+ logger.info(`Target destination: ${targetDir}`);
19
+ }
20
+ // Check if template path exists
21
+ if (!await fs.pathExists(templatePath)) {
22
+ const fallbacks = [
23
+ path.resolve(__dirname, '../../../template'),
24
+ path.resolve(__dirname, '../../../../packages/template'),
25
+ path.resolve(__dirname, '../templates'),
26
+ ];
27
+ let found = false;
28
+ for (const fallback of fallbacks) {
29
+ if (await fs.pathExists(fallback)) {
30
+ templatePath = fallback;
31
+ found = true;
32
+ if (isDebug)
33
+ logger.info(`Found template at: ${templatePath}`);
34
+ break;
35
+ }
36
+ }
37
+ if (!found) {
38
+ throw new Error(`Template directory not found.`);
39
+ }
40
+ }
41
+ const templateFiles = await fs.readdir(templatePath);
42
+ if (templateFiles.length === 0) {
43
+ throw new Error(`Template directory is empty: ${templatePath}`);
44
+ }
45
+ await fs.ensureDir(targetDir);
46
+ spinner.text = 'Copying template files...';
47
+ await copyDirectory(templatePath, targetDir);
48
+ const packageCheckPath = path.join(targetDir, 'package.json');
49
+ if (!await fs.pathExists(packageCheckPath)) {
50
+ throw new Error(`Failed to copy template files.`);
51
+ }
52
+ spinner.text = 'Creating configuration...';
53
+ const config = {
54
+ name: data.name,
55
+ role: data.role,
56
+ bio: data.bio,
57
+ skills: data.skills,
58
+ projects: data.projects,
59
+ enableBlog: data.enableBlog,
60
+ enableDarkMode: data.enableDarkMode,
61
+ defaultDarkMode: data.defaultDarkMode,
62
+ social: data.social,
63
+ theme: data.theme,
64
+ themeConfig: data.themeConfig,
65
+ siteUrl: data.siteUrl,
66
+ portfolioType: data.portfolioType || 'developer'
67
+ };
68
+ await writeFile(path.join(targetDir, 'src', 'config', 'portfolio.json'), JSON.stringify(config, null, 2));
69
+ spinner.text = 'Applying theme styles...';
70
+ await generateThemeCSS(targetDir, data);
71
+ await generateIndexHtml(targetDir, data);
72
+ const targetPackageJsonPath = path.join(targetDir, 'package.json');
73
+ const packageJson = await fs.readJson(targetPackageJsonPath);
74
+ packageJson.name = projectName;
75
+ if (data.enableBlog) {
76
+ packageJson.dependencies = packageJson.dependencies || {};
77
+ packageJson.dependencies['@mdx-js/react'] = '^3.0.0';
78
+ packageJson.dependencies['@mdx-js/rollup'] = '^3.0.0';
79
+ packageJson.dependencies['gray-matter'] = '^4.0.3';
80
+ packageJson.dependencies['reading-time'] = '^1.5.0';
81
+ packageJson.devDependencies = packageJson.devDependencies || {};
82
+ packageJson.devDependencies['@types/mdx'] = '^2.0.10';
83
+ }
84
+ await fs.writeJson(targetPackageJsonPath, packageJson, { spaces: 2 });
85
+ spinner.text = 'Creating README...';
86
+ await writeFile(path.join(targetDir, 'README.md'), generateReadme(projectName, data));
87
+ spinner.text = 'Adding MIT License...';
88
+ await writeFile(path.join(targetDir, 'LICENSE'), generateLicense(data.name));
89
+ spinner.text = 'Adding contributing guide...';
90
+ await writeFile(path.join(targetDir, 'CONTRIBUTING.md'), generateContributing(projectName));
91
+ if (data.siteUrl) {
92
+ spinner.text = 'Generating sitemap...';
93
+ await writeFile(path.join(targetDir, 'public', 'sitemap.xml'), generateSitemap(data));
94
+ await writeFile(path.join(targetDir, 'public', 'robots.txt'), generateRobotsTxt(data.siteUrl));
95
+ }
96
+ if (data.enableBlog) {
97
+ spinner.text = 'Setting up blog structure...';
98
+ await setupBlogStructure(targetDir);
99
+ }
100
+ spinner.succeed('Portfolio generated successfully!');
101
+ }
102
+ catch (error) {
103
+ spinner.fail('Failed to generate portfolio');
104
+ throw error;
105
+ }
106
+ }
107
+ async function generateThemeCSS(targetDir, data) {
108
+ const { themeConfig, enableDarkMode, defaultDarkMode } = data;
109
+ const colors = themeConfig.colors;
110
+ const typography = themeConfig.typography;
111
+ const layout = themeConfig.layout;
112
+ const cssContent = `@tailwind base;
113
+ @tailwind components;
114
+ @tailwind utilities;
115
+
116
+ @layer base {
117
+ * {
118
+ @apply border-border;
119
+ }
120
+
121
+ body {
122
+ @apply bg-background text-foreground;
123
+ font-family: ${typography.bodyFont};
124
+ -webkit-font-smoothing: antialiased;
125
+ -moz-osx-font-smoothing: grayscale;
126
+ }
127
+
128
+ h1, h2, h3, h4, h5, h6 {
129
+ font-family: ${typography.headingFont};
130
+ font-weight: ${typography.headingWeight};
131
+ }
132
+
133
+ :root {
134
+ --background: ${enableDarkMode && !defaultDarkMode ? colors.backgroundLight : colors.background};
135
+ --foreground: ${enableDarkMode && !defaultDarkMode ? colors.foregroundLight : colors.foreground};
136
+ --muted: ${enableDarkMode && !defaultDarkMode ? colors.mutedLight : colors.muted};
137
+ --muted-foreground: 215.4 16.3% 56.9%;
138
+ --primary: ${colors.primary};
139
+ --primary-foreground: 222.2 47.4% 11.2%;
140
+ --secondary: ${colors.secondary};
141
+ --secondary-foreground: 210 40% 98%;
142
+ --accent: ${colors.accent};
143
+ --accent-foreground: 222.2 47.4% 11.2%;
144
+ --card: ${enableDarkMode && !defaultDarkMode ? colors.cardLight : colors.card};
145
+ --card-foreground: ${enableDarkMode && !defaultDarkMode ? colors.foregroundLight : colors.cardForeground};
146
+ --border: ${enableDarkMode && !defaultDarkMode ? colors.borderLight : colors.border};
147
+ --input: 217.2 32.6% 17.5%;
148
+ --ring: 224.3 76.3% 48%;
149
+ --radius: ${layout.borderRadius};
150
+ }
151
+
152
+ .dark {
153
+ --background: ${colors.background};
154
+ --foreground: ${colors.foreground};
155
+ --muted: ${colors.muted};
156
+ --muted-foreground: 215.4 16.3% 56.9%;
157
+ --card: ${colors.card};
158
+ --card-foreground: ${colors.cardForeground};
159
+ --border: ${colors.border};
160
+ --input: 217.2 32.6% 17.5%;
161
+ }
162
+
163
+ .light {
164
+ --background: ${colors.backgroundLight};
165
+ --foreground: ${colors.foregroundLight};
166
+ --muted: ${colors.mutedLight};
167
+ --muted-foreground: 215.4 16.3% 46.9%;
168
+ --card: ${colors.cardLight};
169
+ --card-foreground: ${colors.foregroundLight};
170
+ --border: ${colors.borderLight};
171
+ --input: 220 13% 91%;
172
+ }
173
+ }
174
+
175
+ @layer utilities {
176
+ .glass {
177
+ background: rgba(255, 255, 255, 0.05);
178
+ -webkit-backdrop-filter: blur(12px);
179
+ backdrop-filter: blur(12px);
180
+ border: 1px solid rgba(255, 255, 255, 0.1);
181
+ }
182
+
183
+ .light .glass {
184
+ background: rgba(255, 255, 255, 0.7);
185
+ border: 1px solid rgba(0, 0, 0, 0.08);
186
+ }
187
+
188
+ .gradient-text {
189
+ @apply bg-clip-text text-transparent bg-gradient-to-r from-primary via-secondary to-accent;
190
+ }
191
+
192
+ .glow-effect {
193
+ box-shadow: 0 0 25px hsla(var(--primary), 0.4);
194
+ }
195
+
196
+ .animate-float {
197
+ animation: float 6s ease-in-out infinite;
198
+ }
199
+
200
+ .animate-glow {
201
+ animation: glow 2s ease-in-out infinite alternate;
202
+ }
203
+
204
+ .card-hover {
205
+ @apply transition-all duration-300 hover:scale-105 hover:-translate-y-2;
206
+ }
207
+
208
+ .btn-primary {
209
+ @apply px-6 py-3 rounded-lg bg-gradient-to-r from-primary to-secondary font-semibold transition-all duration-300 hover:scale-105 hover:shadow-lg;
210
+ }
211
+
212
+ .btn-secondary {
213
+ @apply px-6 py-3 rounded-lg bg-muted hover:bg-muted/80 font-medium transition-all duration-300;
214
+ }
215
+ }
216
+
217
+ @keyframes float {
218
+ 0%, 100% { transform: translateY(0); }
219
+ 50% { transform: translateY(-20px); }
220
+ }
221
+
222
+ @keyframes glow {
223
+ from { filter: brightness(1); }
224
+ to { filter: brightness(1.2); }
225
+ }
226
+
227
+ html {
228
+ scroll-behavior: smooth;
229
+ }
230
+
231
+ ::-webkit-scrollbar {
232
+ width: 10px;
233
+ }
234
+
235
+ ::-webkit-scrollbar-track {
236
+ background: hsl(var(--muted));
237
+ }
238
+
239
+ ::-webkit-scrollbar-thumb {
240
+ background: hsl(var(--primary));
241
+ border-radius: 5px;
242
+ }
243
+
244
+ ::-webkit-scrollbar-thumb:hover {
245
+ background: hsl(var(--secondary));
246
+ }
247
+
248
+ body {
249
+ transition: background-color 0.3s ease, color 0.3s ease;
250
+ }
251
+
252
+ *:focus-visible {
253
+ outline: 2px solid hsl(var(--primary));
254
+ outline-offset: 2px;
255
+ }
256
+ `;
257
+ await writeFile(path.join(targetDir, 'src', 'styles', 'globals.css'), cssContent);
258
+ }
259
+ async function generateIndexHtml(targetDir, data) {
260
+ const typography = data.themeConfig.typography;
261
+ const fontMap = {
262
+ 'JetBrains Mono, monospace': 'JetBrains+Mono:wght@400;500;600;700',
263
+ 'Inter, system-ui, sans-serif': 'Inter:wght@300;400;500;600;700;800',
264
+ 'Inter, sans-serif': 'Inter:wght@300;400;500;600;700;800',
265
+ 'Playfair Display, serif': 'Playfair+Display:wght@400;500;600;700',
266
+ 'Poppins, sans-serif': 'Poppins:wght@300;400;500;600;700',
267
+ 'Cormorant Garamond, serif': 'Cormorant+Garamond:wght@400;500;600;700',
268
+ 'Lato, sans-serif': 'Lato:wght@300;400;700',
269
+ 'Montserrat, sans-serif': 'Montserrat:wght@300;400;500;600;700',
270
+ 'Source Sans Pro, sans-serif': 'Source+Sans+3:wght@300;400;600',
271
+ 'Space Grotesk, sans-serif': 'Space+Grotesk:wght@400;500;600;700',
272
+ };
273
+ const headingFontUrl = fontMap[typography.headingFont] || 'Inter:wght@400;500;600;700';
274
+ const bodyFontUrl = fontMap[typography.bodyFont] || 'Inter:wght@300;400;500;600;700';
275
+ const fonts = new Set([headingFontUrl, bodyFontUrl]);
276
+ const fontsUrl = `https://fonts.googleapis.com/css2?${Array.from(fonts).map(f => `family=${f}`).join('&')}&display=swap`;
277
+ const indexHtml = `<!doctype html>
278
+ <html lang="en">
279
+ <head>
280
+ <meta charset="UTF-8" />
281
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
282
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
283
+ <meta name="theme-color" content="#000000" />
284
+ <link rel="preconnect" href="https://fonts.googleapis.com">
285
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
286
+ <link href="${fontsUrl}" rel="stylesheet">
287
+ <title>${data.name} | ${data.role}</title>
288
+ <meta name="description" content="${data.bio}" />
289
+ <meta name="keywords" content="${data.seoKeywords?.join(', ') || data.skills.slice(0, 5).join(', ')}" />
290
+
291
+ <!-- Open Graph / Facebook -->
292
+ <meta property="og:type" content="website" />
293
+ <meta property="og:url" content="${data.siteUrl || 'https://example.com'}" />
294
+ <meta property="og:title" content="${data.name} | ${data.role}" />
295
+ <meta property="og:description" content="${data.bio}" />
296
+
297
+ <!-- Twitter -->
298
+ <meta name="twitter:card" content="summary_large_image" />
299
+ <meta name="twitter:title" content="${data.name} | ${data.role}" />
300
+ <meta name="twitter:description" content="${data.bio}" />
301
+ </head>
302
+ <body>
303
+ <div id="root"></div>
304
+ <script type="module" src="/src/main.tsx"></script>
305
+ </body>
306
+ </html>
307
+ `;
308
+ await writeFile(path.join(targetDir, 'index.html'), indexHtml);
309
+ }
310
+ async function setupBlogStructure(targetDir) {
311
+ const blogDir = path.join(targetDir, 'src', 'content', 'blog');
312
+ await fs.ensureDir(blogDir);
313
+ const today = new Date().toISOString().split('T')[0];
314
+ const samplePost = `---
315
+ title: "Welcome to My Blog"
316
+ date: "${today}"
317
+ excerpt: "This is my first blog post using MDX. Learn how to customize and add more posts."
318
+ tags: ["welcome", "intro", "mdx"]
319
+ ---
320
+
321
+ # Welcome to My Blog!
322
+
323
+ This is a sample blog post written in **MDX**. You can use all the power of Markdown with React components.
324
+
325
+ ## Getting Started
326
+
327
+ To add a new blog post:
328
+
329
+ 1. Create a new \`.mdx\` file in \`src/content/blog/\`
330
+ 2. Add frontmatter with title, date, excerpt, and tags
331
+ 3. Write your content using Markdown and JSX
332
+
333
+ ## Code Example
334
+
335
+ \`\`\`typescript
336
+ const greeting = "Hello, World!";
337
+ console.log(greeting);
338
+ \`\`\`
339
+
340
+ ## What's Next?
341
+
342
+ Start customizing your portfolio and adding more content. Happy blogging! 🚀
343
+ `;
344
+ await writeFile(path.join(blogDir, 'welcome.mdx'), samplePost);
345
+ const blogUtils = `import { useState, useEffect } from 'react';
346
+
347
+ export interface BlogPost {
348
+ slug: string;
349
+ title: string;
350
+ date: string;
351
+ excerpt: string;
352
+ tags: string[];
353
+ content?: string;
354
+ }
355
+
356
+ export const blogPosts: BlogPost[] = [
357
+ {
358
+ slug: 'welcome',
359
+ title: 'Welcome to My Blog',
360
+ date: '${today}',
361
+ excerpt: 'This is my first blog post using MDX. Learn how to customize and add more posts.',
362
+ tags: ['welcome', 'intro', 'mdx']
363
+ }
364
+ ];
365
+
366
+ export function useBlogPosts() {
367
+ const [posts, setPosts] = useState<BlogPost[]>([]);
368
+ const [loading, setLoading] = useState(true);
369
+
370
+ useEffect(() => {
371
+ setPosts(blogPosts);
372
+ setLoading(false);
373
+ }, []);
374
+
375
+ return { posts, loading };
376
+ }
377
+
378
+ export function formatDate(dateString: string): string {
379
+ return new Date(dateString).toLocaleDateString('en-US', {
380
+ year: 'numeric',
381
+ month: 'long',
382
+ day: 'numeric'
383
+ });
384
+ }
385
+
386
+ export function getReadingTime(content: string): string {
387
+ const wordsPerMinute = 200;
388
+ const words = content.split(/\\s+/).length;
389
+ const minutes = Math.ceil(words / wordsPerMinute);
390
+ return \`\${minutes} min read\`;
391
+ }
392
+ `;
393
+ await writeFile(path.join(targetDir, 'src', 'lib', 'blog.ts'), blogUtils);
394
+ }
395
+ function generateSitemap(data) {
396
+ const siteUrl = data.siteUrl?.replace(/\/$/, '') || 'https://example.com';
397
+ const today = new Date().toISOString().split('T')[0];
398
+ let urls = `
399
+ <url>
400
+ <loc>${siteUrl}/</loc>
401
+ <lastmod>${today}</lastmod>
402
+ <changefreq>weekly</changefreq>
403
+ <priority>1.0</priority>
404
+ </url>
405
+ <url>
406
+ <loc>${siteUrl}/#projects</loc>
407
+ <lastmod>${today}</lastmod>
408
+ <changefreq>weekly</changefreq>
409
+ <priority>0.8</priority>
410
+ </url>`;
411
+ if (data.enableBlog) {
412
+ urls += `
413
+ <url>
414
+ <loc>${siteUrl}/#blog</loc>
415
+ <lastmod>${today}</lastmod>
416
+ <changefreq>daily</changefreq>
417
+ <priority>0.9</priority>
418
+ </url>`;
419
+ }
420
+ return `<?xml version="1.0" encoding="UTF-8"?>
421
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
422
+ ${urls}
423
+ </urlset>`;
424
+ }
425
+ function generateRobotsTxt(siteUrl) {
426
+ return `User-agent: *
427
+ Allow: /
428
+
429
+ Sitemap: ${siteUrl.replace(/\/$/, '')}/sitemap.xml
430
+ `;
431
+ }
432
+ function generateLicense(authorName) {
433
+ const year = new Date().getFullYear();
434
+ return `MIT License
435
+
436
+ Copyright (c) ${year} ${authorName}
437
+
438
+ Permission is hereby granted, free of charge, to any person obtaining a copy
439
+ of this software and associated documentation files (the "Software"), to deal
440
+ in the Software without restriction, including without limitation the rights
441
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
442
+ copies of the Software, and to permit persons to whom the Software is
443
+ furnished to do so, subject to the following conditions:
444
+
445
+ The above copyright notice and this permission notice shall be included in all
446
+ copies or substantial portions of the Software.
447
+
448
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
449
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
450
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
451
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
452
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
453
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
454
+ SOFTWARE.
455
+ `;
456
+ }
457
+ function generateContributing(projectName) {
458
+ return `# Contributing to ${projectName}
459
+
460
+ Thank you for your interest in contributing! 🎉
461
+
462
+ ## How to Contribute
463
+
464
+ ### Reporting Bugs
465
+
466
+ If you find a bug, please create an issue with:
467
+ - A clear title and description
468
+ - Steps to reproduce
469
+ - Expected vs actual behavior
470
+ - Screenshots if applicable
471
+
472
+ ### Suggesting Features
473
+
474
+ We love new ideas! Please create an issue with:
475
+ - A clear description of the feature
476
+ - Why it would be useful
477
+ - Any implementation ideas
478
+
479
+ ### Pull Requests
480
+
481
+ 1. Fork the repository
482
+ 2. Create a branch: \`git checkout -b feature/amazing-feature\`
483
+ 3. Make your changes
484
+ 4. Test your changes
485
+ 5. Commit: \`git commit -m 'Add amazing feature'\`
486
+ 6. Push: \`git push origin feature/amazing-feature\`
487
+ 7. Open a Pull Request
488
+
489
+ ## Development Setup
490
+
491
+ \`\`\`bash
492
+ # Install dependencies
493
+ npm install
494
+
495
+ # Start development server
496
+ npm run dev
497
+
498
+ # Build for production
499
+ npm run build
500
+ \`\`\`
501
+
502
+ ## Code Style
503
+
504
+ - Follow existing code formatting
505
+ - Write meaningful commit messages
506
+ - Add comments for complex logic
507
+ - Test your changes thoroughly
508
+
509
+ ## Questions?
510
+
511
+ Feel free to open an issue for any questions!
512
+
513
+ ---
514
+
515
+ Thank you for contributing! ❤️
516
+ `;
517
+ }
518
+ function generateReadme(projectName, data) {
519
+ return `# ${data.name}'s Portfolio
520
+
521
+ > Built with [Portfolify](https://github.com/halloffame12/portfolify) ⚡
522
+
523
+ ## 🚀 Quick Start
524
+
525
+ \`\`\`bash
526
+ # Install dependencies
527
+ npm install
528
+
529
+ # Start development server
530
+ npm run dev
531
+
532
+ # Build for production
533
+ npm run build
534
+
535
+ # Preview production build
536
+ npm run preview
537
+ \`\`\`
538
+
539
+ ## 📦 Deployment
540
+
541
+ ### Vercel
542
+ \`\`\`bash
543
+ npm install -g vercel
544
+ vercel
545
+ \`\`\`
546
+
547
+ ### Netlify
548
+ \`\`\`bash
549
+ npm install -g netlify-cli
550
+ netlify deploy
551
+ \`\`\`
552
+
553
+ ### GitHub Pages
554
+ \`\`\`bash
555
+ npm run build
556
+ # Push the dist folder to gh-pages branch
557
+ \`\`\`
558
+
559
+ ## 🎨 Customization
560
+
561
+ Edit \`src/config/portfolio.json\` to update your information.
562
+
563
+ ## 📄 License
564
+
565
+ MIT
566
+
567
+ ---
568
+
569
+ **Built with ❤️ using Portfolify**
570
+ `;
571
+ }
572
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { PortfolioConfig } from '../prompts/portfolio-prompts.js';
2
+ import { PortfolioCommandOptions } from '../commands/portfolio.js';
3
+ export declare function generatePortfolioProject(projectName: string, config: PortfolioConfig, targetDir: string, options: PortfolioCommandOptions): Promise<void>;
4
+ //# sourceMappingURL=portfolio-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portfolio-generator.d.ts","sourceRoot":"","sources":["../../src/generator/portfolio-generator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAGnE,wBAAsB,wBAAwB,CAC1C,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,uBAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CA4Bf"}