create-foliokit 0.0.0-stage → 1.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.
- package/LICENSE +21 -0
- package/README.md +377 -2
- package/bin/index.js +6 -0
- package/package.json +50 -4
- package/src/cli.js +111 -0
- package/src/generator.js +133 -0
- package/src/prompts.js +44 -0
- package/src/utils/errors.js +7 -0
- package/src/utils/paths.js +12 -0
- package/src/utils/progress.js +5 -0
- package/src/utils/project-name.js +30 -0
- package/templates/default/.gitignore +20 -0
- package/templates/default/data.ts +227 -0
- package/templates/default/index.html +23 -0
- package/templates/default/package-lock.json +1280 -0
- package/templates/default/package.json +28 -0
- package/templates/default/public/avatar-placeholder.svg +10 -0
- package/templates/default/public/footer-heart.png +0 -0
- package/templates/default/public/love-always-wins.png +0 -0
- package/templates/default/public/project-placeholder.svg +10 -0
- package/templates/default/public/robots.txt +2 -0
- package/templates/default/public/stars-foreground-landscape.svg +202 -0
- package/templates/default/public/stars-foreground-portrait.svg +202 -0
- package/templates/default/public/stars-landscape.svg +322 -0
- package/templates/default/public/stars-portrait.svg +322 -0
- package/templates/default/scripts/generate-seo.mjs +34 -0
- package/templates/default/src/App.tsx +552 -0
- package/templates/default/src/BrandIcon.tsx +36 -0
- package/templates/default/src/ProjectMagazineGallery.css +90 -0
- package/templates/default/src/ProjectMagazineGallery.tsx +210 -0
- package/templates/default/src/main.tsx +10 -0
- package/templates/default/src/styles.css +536 -0
- package/templates/default/src/utils.ts +2 -0
- package/templates/default/src/vite-env.d.ts +1 -0
- package/templates/default/tests/portfolio.test.js +96 -0
- package/templates/default/tsconfig.app.json +21 -0
- package/templates/default/tsconfig.json +7 -0
- package/templates/default/tsconfig.node.json +16 -0
- package/templates/default/vite.config.ts +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Saurabh Pandey
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,378 @@
|
|
|
1
|
-
#
|
|
1
|
+
# FolioKit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](package.json)
|
|
5
|
+
[](https://www.npmjs.com/package/foliokit)
|
|
6
|
+
|
|
7
|
+
> A modern, zero-config CLI generator that scaffolds high-performance, customizable developer portfolios built with React 19, TypeScript, and Vite.
|
|
8
|
+
|
|
9
|
+
FolioKit enables developers to launch a sleek, production-ready portfolio in seconds. Instead of wrestling with complex UI code, your entire website—from bio and skills to featured projects and social links—is managed cleanly through a single configuration file: [`data.ts`](templates/default/data.ts).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **Instant Scaffolding** — Create a complete portfolio project with one command (`npx foliokit`).
|
|
16
|
+
- **Single-File Customization** — Edit `data.ts` to update all content, projects, bio, skills, and layout ordering without touching React components.
|
|
17
|
+
- **Modern Tech Stack** — Built with React 19, TypeScript, and Vite for fast development and lightweight production bundles (~80 kB gzip).
|
|
18
|
+
- **Aesthetic Obsidian Theme** — Designed with a dark graphite palette, atmospheric canvas starfields, and metallic typography accents.
|
|
19
|
+
- **Interactive 3D Magazine Carousel** — Showcase featured projects in a perspective-lifted cover gallery with mouse-tilt, touch swipe, trackpad wheel gestures, and keyboard navigation.
|
|
20
|
+
- **Automatic Skill Icons** — Integrates with [Skill Icons](https://skillicons.dev) and Simple Icons for crisp vector technology and brand badges.
|
|
21
|
+
- **Dynamic Local Time & Clock** — Real-time digital clock synced to your configured IANA time zone.
|
|
22
|
+
- **Pre-Configured Content Sections** — Hero, About, Skills, Featured Projects, Work Experience, Education, Testimonials, and Contact.
|
|
23
|
+
- **Automated SEO & Social Sharing** — Build script automatically injects personalized OpenGraph tags, Twitter cards, canonical links, and generates a valid `sitemap.xml` and `robots.txt`.
|
|
24
|
+
- **Accessible & Responsive** — Verified across mobile (320px+), tablet, laptop, and ultra-wide screens. Full support for `prefers-reduced-motion` and WCAG touch targets.
|
|
25
|
+
- **Static Hosting Ready** — Zero-config static deployment on Vercel, Netlify, Cloudflare Pages, and GitHub Pages.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Preview
|
|
30
|
+
|
|
31
|
+
<!-- Portfolio UI Preview Screenshot Placeholder -->
|
|
32
|
+
<!-- Place your screenshot here:  -->
|
|
33
|
+
|
|
34
|
+
The generated portfolio features a dark obsidian background (`#000000`), subtle starfield overlays, golden metallic accent highlights, and clean dotted framing inspired by modern developer terminals and developer tool aesthetic.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
Before running FolioKit, ensure your environment meets these requirements:
|
|
41
|
+
|
|
42
|
+
- **Node.js**: Version `22.12.0` or higher
|
|
43
|
+
- **npm**: Version `10.0.0` or higher (or compatible `pnpm` / `yarn`)
|
|
44
|
+
- **Operating Systems**: macOS, Linux, and Windows 10/11
|
|
45
|
+
|
|
46
|
+
To verify your installed Node.js version, run:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node --version
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Quick Start
|
|
55
|
+
|
|
56
|
+
Generate your developer portfolio in three steps:
|
|
57
|
+
|
|
58
|
+
### 1. Run the CLI
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx foliokit
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
*Or install globally:*
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install -g foliokit
|
|
68
|
+
foliokit
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2. Answer the Interactive Prompts
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
FOLIOKIT
|
|
75
|
+
Developer Portfolio Generator
|
|
76
|
+
|
|
77
|
+
? What should your project be called? my-portfolio
|
|
78
|
+
? Install dependencies? (Y/n) y
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- **Project name**: Enter a folder name using lowercase letters, numbers, and single hyphens (default: `my-portfolio`).
|
|
82
|
+
- **Install dependencies**: Choose whether FolioKit should automatically run `npm install` inside the created folder.
|
|
83
|
+
|
|
84
|
+
### 3. Start Developing
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cd my-portfolio
|
|
88
|
+
npm run dev
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Open [http://localhost:5173](http://localhost:5173) in your browser to view your live portfolio.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## CLI Commands & Options
|
|
96
|
+
|
|
97
|
+
FolioKit provides a straightforward command-line interface:
|
|
98
|
+
|
|
99
|
+
| Command / Option | Description |
|
|
100
|
+
| :--- | :--- |
|
|
101
|
+
| `npx foliokit` | Runs the interactive project creation wizard in the current directory. |
|
|
102
|
+
| `foliokit create` | Explicit subcommand to start the setup wizard. |
|
|
103
|
+
| `-v, --version` | Outputs the current installed FolioKit version. |
|
|
104
|
+
| `-h, --help` | Displays help information, available flags, and usage syntax. |
|
|
105
|
+
|
|
106
|
+
### Examples
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Check installed CLI version
|
|
110
|
+
foliokit --version
|
|
111
|
+
|
|
112
|
+
# View usage guidelines
|
|
113
|
+
foliokit --help
|
|
114
|
+
|
|
115
|
+
# Create a new project
|
|
116
|
+
foliokit create
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Customization Guide (`data.ts`)
|
|
122
|
+
|
|
123
|
+
All portfolio content is centralized in the root `data.ts` file of your generated project. Open `data.ts` in your code editor to personalize your site.
|
|
124
|
+
|
|
125
|
+
### 1. Personal Details & Hero
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
profile: {
|
|
129
|
+
name: 'Alex Rivera',
|
|
130
|
+
headline: 'Full Stack Engineer & Open Source Contributor',
|
|
131
|
+
introduction: "Hey, there! I'm a",
|
|
132
|
+
about: `I build scalable web applications and developer tools.
|
|
133
|
+
|
|
134
|
+
I specialize in React, Node.js, and distributed systems.`,
|
|
135
|
+
location: 'San Francisco, CA',
|
|
136
|
+
timeZone: 'America/Los_Angeles',
|
|
137
|
+
timeZoneLabel: 'PST',
|
|
138
|
+
profileImage: '/avatar-placeholder.svg', // or '/my-photo.jpg' placed in public/
|
|
139
|
+
quote: 'Build with curiosity. Share what you learn.',
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 2. Social Links
|
|
144
|
+
|
|
145
|
+
Add or update your social media profiles in the `socialIcons` array:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
socialIcons: [
|
|
149
|
+
{ label: 'GitHub', icon: 'github', url: 'https://github.com/your-username', color: '#f2f0e9' },
|
|
150
|
+
{ label: 'LinkedIn', icon: 'linkedin', url: 'https://linkedin.com/in/your-username', color: '#0a66c2' },
|
|
151
|
+
{ label: 'X', icon: 'x', url: 'https://x.com/your-username', color: '#f2f0e9' },
|
|
152
|
+
]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 3. Technical Skills
|
|
156
|
+
|
|
157
|
+
Add, remove, or reorder technologies. Icons are automatically fetched from [Skill Icons](https://skillicons.dev) using the `icon` identifier:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
skills: [
|
|
161
|
+
{ name: 'React', icon: 'react', category: 'Frontend' },
|
|
162
|
+
{ name: 'TypeScript', icon: 'ts', category: 'Frontend' },
|
|
163
|
+
{ name: 'Node.js', icon: 'nodejs', category: 'Backend' },
|
|
164
|
+
{ name: 'PostgreSQL', icon: 'postgres', category: 'Backend' },
|
|
165
|
+
{ name: 'Docker', icon: 'docker', category: 'Tools' },
|
|
166
|
+
]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 4. Featured Projects
|
|
170
|
+
|
|
171
|
+
Projects with `featured: true` appear prominently in the interactive 3D magazine gallery as well as the detailed project cards below:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
projects: [
|
|
175
|
+
{
|
|
176
|
+
name: 'DevFlow',
|
|
177
|
+
category: 'DEVELOPER TOOLING',
|
|
178
|
+
description: 'An open-source terminal workflow engine designed to automate repetitive task pipelines.',
|
|
179
|
+
image: '/project-placeholder.svg', // Place your thumbnail in public/
|
|
180
|
+
imageAlt: 'DevFlow terminal preview',
|
|
181
|
+
technologies: [
|
|
182
|
+
{ name: 'TypeScript', icon: 'ts' },
|
|
183
|
+
{ name: 'Node.js', icon: 'nodejs' },
|
|
184
|
+
],
|
|
185
|
+
liveUrl: 'https://devflow.example',
|
|
186
|
+
githubUrl: 'https://github.com/your-username/devflow',
|
|
187
|
+
featured: true,
|
|
188
|
+
},
|
|
189
|
+
]
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 5. Work Experience & Education
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
experience: [
|
|
196
|
+
{
|
|
197
|
+
title: 'Senior Software Engineer',
|
|
198
|
+
organization: 'Acme Corp',
|
|
199
|
+
date: '2023 – Present',
|
|
200
|
+
description: 'Architected microservices and improved core API latency by 35%.',
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
education: [
|
|
204
|
+
{
|
|
205
|
+
title: 'B.S. in Computer Science',
|
|
206
|
+
organization: 'University of California, Berkeley',
|
|
207
|
+
date: '2019 – 2023',
|
|
208
|
+
description: 'Focused on algorithms, distributed databases, and software engineering.',
|
|
209
|
+
},
|
|
210
|
+
]
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 6. Optional Sections (Testimonials, Experience, Education)
|
|
214
|
+
|
|
215
|
+
Content sections render dynamically based on whether items exist in their array. To omit any optional section from the portfolio, simply leave its array empty:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// Leave empty to omit this section from the portfolio:
|
|
219
|
+
testimonials: [],
|
|
220
|
+
experience: [],
|
|
221
|
+
education: [],
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Images and Assets
|
|
227
|
+
|
|
228
|
+
All static visual assets live inside the `public/` directory of your generated project:
|
|
229
|
+
|
|
230
|
+
```text
|
|
231
|
+
my-portfolio/
|
|
232
|
+
└── public/
|
|
233
|
+
├── avatar-placeholder.svg
|
|
234
|
+
├── project-placeholder.svg
|
|
235
|
+
├── footer-heart.png
|
|
236
|
+
├── love-always-wins.png
|
|
237
|
+
└── robots.txt
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### How to Use Your Own Images:
|
|
241
|
+
|
|
242
|
+
1. Copy your image into the `public/` folder (e.g. `public/my-photo.jpg`).
|
|
243
|
+
2. In `data.ts`, reference the image with a leading slash:
|
|
244
|
+
```typescript
|
|
245
|
+
profileImage: '/my-photo.jpg'
|
|
246
|
+
```
|
|
247
|
+
3. For project thumbnails, copy images to `public/` (recommended aspect ratio: `16:9` or `1200x675` px) and set `image: '/project-one.png'`.
|
|
248
|
+
4. **Supported Formats**: SVG, WebP, PNG, JPG/JPEG.
|
|
249
|
+
5. **Fallbacks**: If an image fails to load or is omitted, FolioKit automatically renders accessible fallback elements (e.g., initial-letter monogram badges for avatars).
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Project Structure
|
|
254
|
+
|
|
255
|
+
A portfolio generated by FolioKit has the following clean structure:
|
|
256
|
+
|
|
257
|
+
```text
|
|
258
|
+
my-portfolio/
|
|
259
|
+
├── data.ts # Central content configuration (edit this!)
|
|
260
|
+
├── index.html # HTML entry point (title & metadata injected from data.ts)
|
|
261
|
+
├── package.json # Project scripts and dependencies
|
|
262
|
+
├── vite.config.ts # Vite configuration with automated metadata plugin
|
|
263
|
+
├── tsconfig.json # TypeScript configuration
|
|
264
|
+
├── public/ # Static assets (images, avatars, icons, robots.txt)
|
|
265
|
+
│ ├── avatar-placeholder.svg
|
|
266
|
+
│ └── project-placeholder.svg
|
|
267
|
+
├── scripts/
|
|
268
|
+
│ └── generate-seo.mjs # Production SEO, canonical URL, and sitemap generator
|
|
269
|
+
└── src/
|
|
270
|
+
├── main.tsx # React application entry point
|
|
271
|
+
├── App.tsx # Main portfolio layout and section renderers
|
|
272
|
+
├── styles.css # Responsive styles and theme variables
|
|
273
|
+
├── utils.ts # Lightweight DOM helpers
|
|
274
|
+
├── BrandIcon.tsx # Vector brand logo helper with fallbacks
|
|
275
|
+
├── ProjectMagazineGallery.tsx # 3D interactive carousel
|
|
276
|
+
└── ProjectMagazineGallery.css # 3D perspective & carousel styling
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Tech Stack
|
|
282
|
+
|
|
283
|
+
### FolioKit CLI
|
|
284
|
+
- **Runtime**: [Node.js](https://nodejs.org) (>= 22.12.0)
|
|
285
|
+
- **CLI Framework**: [Commander.js](https://github.com/tj/commander.js)
|
|
286
|
+
- **Interactive Prompts**: [Inquirer.js](https://github.com/SBoudrias/Inquirer.js)
|
|
287
|
+
- **Terminal Styling**: [Chalk](https://github.com/chalk/chalk)
|
|
288
|
+
- **Terminal Spinners**: [Ora](https://github.com/sindresorhus/ora)
|
|
289
|
+
|
|
290
|
+
### Generated Portfolio
|
|
291
|
+
- **UI Framework**: [React 19](https://react.dev)
|
|
292
|
+
- **Language**: [TypeScript](https://www.typescriptlang.org)
|
|
293
|
+
- **Bundler & Dev Server**: [Vite 8](https://vitejs.dev)
|
|
294
|
+
- **Icons**: [Lucide React](https://lucide.dev) & [Simple Icons](https://simpleicons.org)
|
|
295
|
+
- **Styling**: Native Modern CSS (CSS Grid, Flexbox, CSS Variables, 3D Transforms)
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Troubleshooting
|
|
300
|
+
|
|
301
|
+
### 1. "Node.js version must be >=22.12.0"
|
|
302
|
+
- **Cause**: An older Node.js runtime is active in your terminal.
|
|
303
|
+
- **Solution**: Install or activate Node.js 22.12.0 or newer using [nvm](https://github.com/nvm-sh/nvm) or [fnm](https://github.com/Schniz/fnm):
|
|
304
|
+
```bash
|
|
305
|
+
nvm install 22
|
|
306
|
+
nvm use 22
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 2. Destination Folder Already Exists
|
|
310
|
+
- **Cause**: A folder with the specified project name already exists in your current directory.
|
|
311
|
+
- **Solution**: Choose a different name when prompted, or confirm the prompt to overwrite the existing folder.
|
|
312
|
+
|
|
313
|
+
### 3. Dependency Installation Failed
|
|
314
|
+
- **Cause**: Network timeout or strict corporate proxy blocked `npm install`.
|
|
315
|
+
- **Solution**: Your generated project files are safely preserved. Navigate into the folder and manually install dependencies:
|
|
316
|
+
```bash
|
|
317
|
+
cd my-portfolio
|
|
318
|
+
npm install
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### 4. Development Port 5173 in Use
|
|
322
|
+
- **Cause**: Another local development server is running on port 5173.
|
|
323
|
+
- **Solution**: Vite automatically attempts the next available port (e.g. 5174). You can also specify a custom port:
|
|
324
|
+
```bash
|
|
325
|
+
npm run dev -- --port 3000
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### 5. TypeScript Error After Editing `data.ts`
|
|
329
|
+
- **Cause**: A required field was removed or a type mismatch was introduced.
|
|
330
|
+
- **Solution**: Check the terminal output or editor diagnostics. Run `npm test` inside the portfolio directory to validate your `data.ts` structure against the test suite.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Contributing
|
|
335
|
+
|
|
336
|
+
Contributions, issues, and feature requests are welcome!
|
|
337
|
+
|
|
338
|
+
### Development Workflow
|
|
339
|
+
|
|
340
|
+
1. Fork the repository on GitHub.
|
|
341
|
+
2. Clone your fork locally:
|
|
342
|
+
```bash
|
|
343
|
+
git clone https://github.com/saurabhhdev/foliokit.git
|
|
344
|
+
cd foliokit
|
|
345
|
+
```
|
|
346
|
+
3. Install dependencies:
|
|
347
|
+
```bash
|
|
348
|
+
npm install
|
|
349
|
+
```
|
|
350
|
+
4. Run CLI and generator tests:
|
|
351
|
+
```bash
|
|
352
|
+
npm test
|
|
353
|
+
```
|
|
354
|
+
5. Test the default template:
|
|
355
|
+
```bash
|
|
356
|
+
cd templates/default
|
|
357
|
+
npm test
|
|
358
|
+
npm run build
|
|
359
|
+
cd ../..
|
|
360
|
+
```
|
|
361
|
+
6. Create a feature branch (`git checkout -b feature/amazing-idea`), commit your changes, and submit a pull request.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## License
|
|
366
|
+
|
|
367
|
+
Distributed under the **MIT License**. See [`LICENSE`](LICENSE) for complete details.
|
|
368
|
+
|
|
369
|
+
Copyright (c) 2026 **Saurabh Pandey**.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Author & Links
|
|
374
|
+
|
|
375
|
+
- **Author**: Saurabh Pandey
|
|
376
|
+
- **GitHub**: [@saurabhhdev](https://github.com/saurabhhdev)
|
|
377
|
+
- **Repository**: [https://github.com/saurabhhdev/foliokit](https://github.com/saurabhhdev/foliokit)
|
|
378
|
+
- **Issue Tracker**: [https://github.com/saurabhhdev/foliokit/issues](https://github.com/saurabhhdev/foliokit/issues)
|
package/bin/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-foliokit",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Generate customizable React and TypeScript developer portfolios",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/cli.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/cli.js",
|
|
9
|
+
"./generator": "./src/generator.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"author": "Saurabh Pandey",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "node --test tests"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"foliokit": "./bin/index.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin/",
|
|
21
|
+
"src/",
|
|
22
|
+
"templates/",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22.12.0"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"portfolio",
|
|
31
|
+
"developer-portfolio",
|
|
32
|
+
"react",
|
|
33
|
+
"typescript",
|
|
34
|
+
"cli",
|
|
35
|
+
"generator"
|
|
36
|
+
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/saurabhhdev/foliokit.git"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/saurabhhdev/foliokit#readme",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/saurabhhdev/foliokit/issues"
|
|
44
|
+
},
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"chalk": "^6.0.1",
|
|
48
|
+
"commander": "^15.0.0",
|
|
49
|
+
"inquirer": "^14.2.5",
|
|
50
|
+
"ora": "^9.4.1"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { spawn } from 'node:child_process'
|
|
3
|
+
import { Command } from 'commander'
|
|
4
|
+
import chalk from 'chalk'
|
|
5
|
+
import inquirer from 'inquirer'
|
|
6
|
+
import { generatePortfolio } from './generator.js'
|
|
7
|
+
import { promptForProjectOptions } from './prompts.js'
|
|
8
|
+
import { getPackagePath } from './utils/paths.js'
|
|
9
|
+
import { createProgress } from './utils/progress.js'
|
|
10
|
+
|
|
11
|
+
const packageMetadata = JSON.parse(readFileSync(getPackagePath('package.json'), 'utf8'))
|
|
12
|
+
|
|
13
|
+
function showWelcome() {
|
|
14
|
+
console.log(chalk.bold.cyan('FOLIOKIT'))
|
|
15
|
+
console.log(chalk.dim('Developer Portfolio Generator'))
|
|
16
|
+
console.log()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function startSetup() {
|
|
20
|
+
showWelcome()
|
|
21
|
+
const options = await promptForProjectOptions()
|
|
22
|
+
|
|
23
|
+
if (!options) {
|
|
24
|
+
console.log(chalk.yellow('Setup cancelled.'))
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let projectPath
|
|
29
|
+
try {
|
|
30
|
+
projectPath = await generatePortfolio(options)
|
|
31
|
+
} catch (error) {
|
|
32
|
+
if (!(error instanceof Error) || error.code !== 'EEXIST') throw error
|
|
33
|
+
let overwrite
|
|
34
|
+
try {
|
|
35
|
+
({ overwrite } = await inquirer.prompt([{
|
|
36
|
+
type: 'confirm',
|
|
37
|
+
name: 'overwrite',
|
|
38
|
+
message: `The folder ${options.projectName} already exists. Replace it?`,
|
|
39
|
+
default: false,
|
|
40
|
+
}]))
|
|
41
|
+
} catch (promptError) {
|
|
42
|
+
if (promptError instanceof Error && promptError.name === 'ExitPromptError') {
|
|
43
|
+
console.log(chalk.yellow('Setup cancelled. Existing project was left unchanged.'))
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
throw promptError
|
|
47
|
+
}
|
|
48
|
+
if (!overwrite) {
|
|
49
|
+
console.log(chalk.yellow('Existing project was left unchanged.'))
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
projectPath = await generatePortfolio({ ...options, overwrite: true })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let dependenciesInstalled = false
|
|
56
|
+
if (options.installDependencies) {
|
|
57
|
+
const windows = process.platform === 'win32'
|
|
58
|
+
const install = spawn(windows ? (process.env.ComSpec || 'cmd.exe') : 'npm', windows ? ['/d', '/s', '/c', 'npm.cmd install'] : ['install'], {
|
|
59
|
+
cwd: projectPath,
|
|
60
|
+
stdio: 'inherit',
|
|
61
|
+
shell: false,
|
|
62
|
+
})
|
|
63
|
+
const installation = createProgress('Installing dependencies...').start()
|
|
64
|
+
const result = await new Promise((resolve) => {
|
|
65
|
+
install.once('error', (error) => resolve({ code: 1, error }))
|
|
66
|
+
install.once('close', (code) => resolve({ code: code ?? 1 }))
|
|
67
|
+
})
|
|
68
|
+
dependenciesInstalled = result.code === 0
|
|
69
|
+
if (dependenciesInstalled) installation.succeed('Dependencies installed')
|
|
70
|
+
else installation.fail('Dependency installation failed')
|
|
71
|
+
if (!dependenciesInstalled) {
|
|
72
|
+
console.error(chalk.red('Dependency installation failed. Your generated project is still available.'))
|
|
73
|
+
if (result.error) console.error(chalk.dim(result.error.message))
|
|
74
|
+
console.error(`Run ${chalk.bold('npm install')} inside ${options.projectName} to try again.`)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const configuration = { ...options, projectPath }
|
|
79
|
+
console.log()
|
|
80
|
+
console.log(chalk.green('✔ Portfolio generated successfully!'))
|
|
81
|
+
console.log()
|
|
82
|
+
console.log(chalk.bold('Next steps:'))
|
|
83
|
+
console.log(` cd ${configuration.projectName}`)
|
|
84
|
+
if (!dependenciesInstalled) console.log(' npm install')
|
|
85
|
+
console.log(' npm run dev')
|
|
86
|
+
console.log()
|
|
87
|
+
console.log(`Customize your portfolio by editing ${chalk.bold('data.ts')}.`)
|
|
88
|
+
if (options.installDependencies && !dependenciesInstalled) process.exitCode = 1
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function createCli() {
|
|
92
|
+
const program = new Command()
|
|
93
|
+
|
|
94
|
+
program
|
|
95
|
+
.name('foliokit')
|
|
96
|
+
.description('Generate customizable developer portfolio websites')
|
|
97
|
+
.version(packageMetadata.version, '-v, --version')
|
|
98
|
+
.showHelpAfterError()
|
|
99
|
+
.action(startSetup)
|
|
100
|
+
|
|
101
|
+
program
|
|
102
|
+
.command('create')
|
|
103
|
+
.description('Create a portfolio project')
|
|
104
|
+
.action(startSetup)
|
|
105
|
+
|
|
106
|
+
return program
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function runCli(argv = process.argv) {
|
|
110
|
+
await createCli().parseAsync(argv)
|
|
111
|
+
}
|