@dev.aldrindc/zirr-cli 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 +15 -0
- package/README.md +477 -0
- package/bin/zirr.js +57 -0
- package/package.json +40 -0
- package/src/index.js +379 -0
- package/src/templates/App.jsx +142 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dev-adelacruz
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
# ⚡ Zirr - Modern React Starter CLI
|
|
2
|
+
|
|
3
|
+
[](https://github.com/dev-adelacruz/zirr)
|
|
4
|
+
[](https://www.npmjs.com/package/@dev.aldrindc/zirr-cli)
|
|
5
|
+
[](https://opensource.org/licenses/ISC)
|
|
6
|
+
[](https://nodejs.org/)
|
|
7
|
+
[](https://www.npmjs.com/package/@dev.aldrindc/zirr-cli)
|
|
8
|
+
|
|
9
|
+
A professional command-line tool to scaffold modern React applications with production-ready configurations. Based on the elegant template from the `wifi_qr` project, Zirr provides a beautiful foundation for any React application with zero configuration overhead.
|
|
10
|
+
|
|
11
|
+
## ✨ Why Zirr?
|
|
12
|
+
|
|
13
|
+
Zirr eliminates the tedious setup process for modern React projects. Instead of spending hours configuring build tools, styling frameworks, and code quality tools, Zirr gives you a complete, polished starting point in seconds.
|
|
14
|
+
|
|
15
|
+
### Key Advantages
|
|
16
|
+
|
|
17
|
+
- **🚀 Zero Configuration**: All tools pre-configured and working together
|
|
18
|
+
- **🎨 Beautiful Design System**: Professional UI with Tailwind CSS and Lucide icons
|
|
19
|
+
- **⚡ Production Ready**: ESLint, optimized build, and modern React practices
|
|
20
|
+
- **📱 Fully Responsive**: Mobile-first design that works on all devices
|
|
21
|
+
- **🔧 Extensible**: Easy to customize and extend for any project type
|
|
22
|
+
|
|
23
|
+
## 📦 What's Included
|
|
24
|
+
|
|
25
|
+
| Technology | Version | Purpose |
|
|
26
|
+
|------------|---------|---------|
|
|
27
|
+
| **React** | 19.2.0 | UI library with latest features |
|
|
28
|
+
| **Vite** | 7.2.4 | Lightning-fast build tool and dev server |
|
|
29
|
+
| **Tailwind CSS** | 4.1.18 | Utility-first CSS framework |
|
|
30
|
+
| **ESLint** | 9.39.1 | Code quality and consistency |
|
|
31
|
+
| **Lucide React** | 0.562.0 | Beautiful, consistent icon set |
|
|
32
|
+
| **PostCSS** | 8.5.6 | CSS processing with autoprefixer |
|
|
33
|
+
| **TypeScript Types** | Latest | Type definitions for React and DOM |
|
|
34
|
+
|
|
35
|
+
## 🚀 Quick Start
|
|
36
|
+
|
|
37
|
+
### Installation Options
|
|
38
|
+
|
|
39
|
+
#### Option 1: Install from npm (Recommended)
|
|
40
|
+
```bash
|
|
41
|
+
# Install globally from npm
|
|
42
|
+
npm install -g @dev.aldrindc/zirr-cli
|
|
43
|
+
|
|
44
|
+
# Verify installation
|
|
45
|
+
zirr --version
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### Option 2: Install from GitHub
|
|
49
|
+
```bash
|
|
50
|
+
# Install directly from GitHub
|
|
51
|
+
npm install -g github:dev-adelacruz/zirr
|
|
52
|
+
|
|
53
|
+
# Or clone and install locally
|
|
54
|
+
git clone https://github.com/dev-adelacruz/zirr.git
|
|
55
|
+
cd zirr
|
|
56
|
+
npm install
|
|
57
|
+
npm link
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### Option 3: Direct Usage (No Installation)
|
|
61
|
+
```bash
|
|
62
|
+
# Run with npx (no installation needed)
|
|
63
|
+
npx @dev.aldrindc/zirr-cli my-app
|
|
64
|
+
|
|
65
|
+
# Or run directly from GitHub
|
|
66
|
+
npx github:dev-adelacruz/zirr my-app
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Creating Your First Project
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Interactive mode (recommended)
|
|
73
|
+
zirr my-awesome-app
|
|
74
|
+
|
|
75
|
+
# Auto mode (skip prompts)
|
|
76
|
+
zirr my-awesome-app --yes
|
|
77
|
+
|
|
78
|
+
# Specify different directory
|
|
79
|
+
cd ~/projects
|
|
80
|
+
zirr new-project
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 📖 Detailed Usage
|
|
84
|
+
|
|
85
|
+
### Command Line Options
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
zirr <project-name> [options]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
| Option | Alias | Description | Example |
|
|
92
|
+
|--------|-------|-------------|---------|
|
|
93
|
+
| `--yes` | `-y` | Skip all prompts, use defaults | `zirr my-app -y` |
|
|
94
|
+
| `--help` | `-h` | Show help message | `zirr --help` |
|
|
95
|
+
| `--version` | `-v` | Show version information | `zirr --version` |
|
|
96
|
+
|
|
97
|
+
### Interactive Prompts
|
|
98
|
+
|
|
99
|
+
When running without `--yes`, Zirr will ask:
|
|
100
|
+
|
|
101
|
+
1. **Project Name**: Must be lowercase with hyphens (e.g., `my-awesome-app`)
|
|
102
|
+
2. **Project Title**: Human-readable title (auto-generated from name)
|
|
103
|
+
|
|
104
|
+
Example session:
|
|
105
|
+
```bash
|
|
106
|
+
$ zirr my-awesome-app
|
|
107
|
+
⚡ Zirr - Modern React Starter
|
|
108
|
+
|
|
109
|
+
? Project name: (my-awesome-app)
|
|
110
|
+
? Project title: (My Awesome App)
|
|
111
|
+
|
|
112
|
+
Creating project: my-awesome-app
|
|
113
|
+
✓ App.jsx
|
|
114
|
+
✓ vite.config.js
|
|
115
|
+
✓ tailwind.config.js
|
|
116
|
+
... (more files)
|
|
117
|
+
|
|
118
|
+
✅ Project created successfully!
|
|
119
|
+
|
|
120
|
+
Next steps:
|
|
121
|
+
cd my-awesome-app
|
|
122
|
+
npm install
|
|
123
|
+
npm run dev
|
|
124
|
+
|
|
125
|
+
Happy coding! 🚀
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## 📁 Generated Project Structure
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
my-awesome-app/
|
|
132
|
+
├── 📄 package.json # Project dependencies and scripts
|
|
133
|
+
├── 📄 index.html # HTML entry point with meta tags
|
|
134
|
+
├── ⚙️ vite.config.js # Vite configuration (dev server, build)
|
|
135
|
+
├── 🎨 tailwind.config.js # Tailwind CSS customization
|
|
136
|
+
├── 🛠️ postcss.config.js # PostCSS plugins (Tailwind + autoprefixer)
|
|
137
|
+
├── ✅ eslint.config.js # ESLint configuration with React rules
|
|
138
|
+
├── 🙈 .gitignore # Comprehensive Git ignore file
|
|
139
|
+
├── 📁 src/
|
|
140
|
+
│ ├── 🎭 App.jsx # Main React component (sample UI)
|
|
141
|
+
│ ├── 🚀 main.jsx # React DOM rendering entry point
|
|
142
|
+
│ └── 🎨 index.css # Global styles with Tailwind imports
|
|
143
|
+
└── 📁 public/
|
|
144
|
+
└── 🖼️ vite.svg # Default favicon (replace with your logo)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 🎭 Sample Application Preview
|
|
148
|
+
|
|
149
|
+
The generated `App.jsx` includes a fully functional demo that showcases:
|
|
150
|
+
|
|
151
|
+
### 1. **Modern Design Patterns**
|
|
152
|
+
- Gradient backgrounds and smooth shadows
|
|
153
|
+
- Rounded corners and responsive spacing
|
|
154
|
+
- Consistent color palette using Tailwind
|
|
155
|
+
- Animated interactive elements
|
|
156
|
+
|
|
157
|
+
### 2. **React Best Practices**
|
|
158
|
+
- Functional components with hooks (`useState`)
|
|
159
|
+
- Proper component structure and organization
|
|
160
|
+
- Event handling and state management
|
|
161
|
+
- Conditional rendering and list mapping
|
|
162
|
+
|
|
163
|
+
### 3. **Interactive Features**
|
|
164
|
+
- Live counter with increment/reset functionality
|
|
165
|
+
- Responsive grid layout (mobile → desktop)
|
|
166
|
+
- Icon buttons with hover states
|
|
167
|
+
- Feature cards with Lucide icons
|
|
168
|
+
|
|
169
|
+
### 4. **Developer Experience**
|
|
170
|
+
- Getting started instructions
|
|
171
|
+
- Ready-to-use code snippets
|
|
172
|
+
- Development commands reference
|
|
173
|
+
- Clear file structure comments
|
|
174
|
+
|
|
175
|
+
## 🛠️ Development Workflow
|
|
176
|
+
|
|
177
|
+
### Available Scripts
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Start development server with hot reload
|
|
181
|
+
npm run dev
|
|
182
|
+
# Open http://localhost:5173 in your browser
|
|
183
|
+
|
|
184
|
+
# Build for production (optimized)
|
|
185
|
+
npm run build
|
|
186
|
+
# Outputs to `dist/` directory
|
|
187
|
+
|
|
188
|
+
# Lint code for errors and warnings
|
|
189
|
+
npm run lint
|
|
190
|
+
|
|
191
|
+
# Preview production build locally
|
|
192
|
+
npm run preview
|
|
193
|
+
|
|
194
|
+
# Run all three: dev + lint + type check (custom)
|
|
195
|
+
npm start
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Development Server Features
|
|
199
|
+
|
|
200
|
+
- **⚡ Instant HMR**: Changes appear without page reload
|
|
201
|
+
- **📱 Network Access**: Access from other devices on network
|
|
202
|
+
- **🔍 Source Maps**: Debug original source code in browser
|
|
203
|
+
- **📦 Optimized Builds**: Tree-shaking and code splitting
|
|
204
|
+
|
|
205
|
+
## 🎨 Customization Guide
|
|
206
|
+
|
|
207
|
+
### Tailwind CSS Configuration
|
|
208
|
+
|
|
209
|
+
Edit `tailwind.config.js` to customize:
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
/** @type {import('tailwindcss').Config} */
|
|
213
|
+
export default {
|
|
214
|
+
content: [
|
|
215
|
+
"./index.html",
|
|
216
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
217
|
+
],
|
|
218
|
+
theme: {
|
|
219
|
+
extend: {
|
|
220
|
+
colors: {
|
|
221
|
+
brand: {
|
|
222
|
+
primary: '#3B82F6',
|
|
223
|
+
secondary: '#10B981',
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
fontFamily: {
|
|
227
|
+
sans: ['Inter', 'system-ui', 'sans-serif'],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
plugins: [],
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Adding New Dependencies
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Install additional packages
|
|
239
|
+
npm install axios date-fns
|
|
240
|
+
|
|
241
|
+
# Install dev dependencies
|
|
242
|
+
npm install -D @types/node @testing-library/react
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Modifying Vite Configuration
|
|
246
|
+
|
|
247
|
+
Update `vite.config.js` for advanced needs:
|
|
248
|
+
|
|
249
|
+
```javascript
|
|
250
|
+
import { defineConfig } from 'vite'
|
|
251
|
+
import react from '@vitejs/plugin-react'
|
|
252
|
+
import svgr from 'vite-plugin-svgr' // Example: Add SVG support
|
|
253
|
+
|
|
254
|
+
export default defineConfig({
|
|
255
|
+
plugins: [react(), svgr()],
|
|
256
|
+
server: {
|
|
257
|
+
port: 3000,
|
|
258
|
+
open: true, // Auto-open browser
|
|
259
|
+
},
|
|
260
|
+
build: {
|
|
261
|
+
outDir: 'build', // Change output directory
|
|
262
|
+
},
|
|
263
|
+
})
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 🔍 Template Source & Philosophy
|
|
267
|
+
|
|
268
|
+
Zirr is based on the production-tested template from the `wifi_qr` project, which demonstrates:
|
|
269
|
+
|
|
270
|
+
- **Real-world usability**: Battle-tested in an actual application
|
|
271
|
+
- **Performance optimization**: Fast loading and smooth interactions
|
|
272
|
+
- **Accessibility considerations**: Semantic HTML and ARIA attributes
|
|
273
|
+
- **Print styles**: CSS media queries for printing
|
|
274
|
+
- **Cross-browser compatibility**: Works on modern browsers
|
|
275
|
+
|
|
276
|
+
### What We Changed
|
|
277
|
+
|
|
278
|
+
| Original (wifi_qr) | Zirr Version | Reason |
|
|
279
|
+
|-------------------|--------------|---------|
|
|
280
|
+
| WiFi QR generator | Generic starter | Broader applicability |
|
|
281
|
+
| Network forms | Interactive demo | Showcase React capabilities |
|
|
282
|
+
| Print-specific UI | Responsive design | Better mobile experience |
|
|
283
|
+
| External QR API | Self-contained | No external dependencies |
|
|
284
|
+
|
|
285
|
+
## 🧪 Testing the CLI
|
|
286
|
+
|
|
287
|
+
### Smoke Test
|
|
288
|
+
```bash
|
|
289
|
+
# Clean test
|
|
290
|
+
cd /Users/aldrindelacruz/workspace
|
|
291
|
+
rm -rf test-project
|
|
292
|
+
node zirr-cli/bin/zirr.js test-project --yes
|
|
293
|
+
|
|
294
|
+
# Verify files were created
|
|
295
|
+
ls -la test-project
|
|
296
|
+
cat test-project/package.json
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Interactive Test
|
|
300
|
+
```bash
|
|
301
|
+
# Test with prompts (requires manual input)
|
|
302
|
+
node zirr-cli/bin/zirr.js interactive-test
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Project Validation
|
|
306
|
+
```bash
|
|
307
|
+
# Test if generated project works
|
|
308
|
+
cd test-project
|
|
309
|
+
npm install
|
|
310
|
+
npm run dev &
|
|
311
|
+
# Check if server starts on http://localhost:5173
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## 📚 Advanced Topics
|
|
315
|
+
|
|
316
|
+
### Git Integration
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
# Initialize git repository
|
|
320
|
+
cd my-awesome-app
|
|
321
|
+
git init
|
|
322
|
+
git add .
|
|
323
|
+
git commit -m "Initial commit from Zirr"
|
|
324
|
+
|
|
325
|
+
# Connect to remote repository
|
|
326
|
+
git remote add origin https://github.com/username/repo.git
|
|
327
|
+
git branch -M main
|
|
328
|
+
git push -u origin main
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Adding TypeScript
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# Install TypeScript
|
|
335
|
+
npm install -D typescript @types/react @types/react-dom
|
|
336
|
+
|
|
337
|
+
# Create tsconfig.json
|
|
338
|
+
npx tsc --init
|
|
339
|
+
|
|
340
|
+
# Rename files from .jsx to .tsx
|
|
341
|
+
mv src/App.jsx src/App.tsx
|
|
342
|
+
mv src/main.jsx src/main.tsx
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Environment Variables
|
|
346
|
+
|
|
347
|
+
Create `.env` file:
|
|
348
|
+
```env
|
|
349
|
+
VITE_API_URL=https://api.example.com
|
|
350
|
+
VITE_APP_TITLE=My Awesome App
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Access in code:
|
|
354
|
+
```javascript
|
|
355
|
+
const apiUrl = import.meta.env.VITE_API_URL;
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## 🐛 Troubleshooting
|
|
359
|
+
|
|
360
|
+
### Common Issues
|
|
361
|
+
|
|
362
|
+
#### "Project name can only contain lowercase letters, numbers, and hyphens"
|
|
363
|
+
- **Solution**: Use `my-app` instead of `MyApp` or `my_app`
|
|
364
|
+
- **Example**: `zirr my-project` ✓, `zirr MyProject` ✗
|
|
365
|
+
|
|
366
|
+
#### "Directory already exists"
|
|
367
|
+
- **Solution**: Choose a different name or delete existing directory
|
|
368
|
+
- **Example**: `rm -rf existing-app && zirr existing-app`
|
|
369
|
+
|
|
370
|
+
#### Node.js Version Warnings
|
|
371
|
+
- **Solution**: The CLI works with Node 12+, but generated projects need Node 18+
|
|
372
|
+
- **Fix**: Install Node 18+ from [nodejs.org](https://nodejs.org/)
|
|
373
|
+
|
|
374
|
+
#### Permission Errors
|
|
375
|
+
- **Solution**: Use `sudo` for global installation or fix npm permissions
|
|
376
|
+
- **Alternative**: Use `npm link` for development without sudo
|
|
377
|
+
|
|
378
|
+
### Getting Help
|
|
379
|
+
|
|
380
|
+
1. Check the help: `zirr --help`
|
|
381
|
+
2. Verify Node version: `node --version`
|
|
382
|
+
3. Check npm version: `npm --version`
|
|
383
|
+
4. Review generated files for errors
|
|
384
|
+
|
|
385
|
+
## 🚀 Deployment
|
|
386
|
+
|
|
387
|
+
### Static Hosting (Vercel, Netlify, GitHub Pages)
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
# Build the project
|
|
391
|
+
npm run build
|
|
392
|
+
|
|
393
|
+
# The `dist/` folder contains static files
|
|
394
|
+
# Upload to your preferred hosting service
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Docker Deployment
|
|
398
|
+
|
|
399
|
+
Create `Dockerfile`:
|
|
400
|
+
```dockerfile
|
|
401
|
+
FROM node:18-alpine AS builder
|
|
402
|
+
WORKDIR /app
|
|
403
|
+
COPY package*.json ./
|
|
404
|
+
RUN npm ci
|
|
405
|
+
COPY . .
|
|
406
|
+
RUN npm run build
|
|
407
|
+
|
|
408
|
+
FROM nginx:alpine
|
|
409
|
+
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
410
|
+
EXPOSE 80
|
|
411
|
+
CMD ["nginx", "-g", "daemon off;"]
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## 📈 Performance Metrics
|
|
415
|
+
|
|
416
|
+
The generated project includes:
|
|
417
|
+
|
|
418
|
+
- **🎯 Code Splitting**: Automatic route-based splitting with React.lazy
|
|
419
|
+
- **📦 Tree Shaking**: Unused code eliminated from production bundle
|
|
420
|
+
- **🖼️ Asset Optimization**: Images and fonts optimized during build
|
|
421
|
+
- **⚡ Fast Refresh**: Sub-second updates during development
|
|
422
|
+
|
|
423
|
+
## 🤝 Contributing
|
|
424
|
+
|
|
425
|
+
Want to improve Zirr? Here's how:
|
|
426
|
+
|
|
427
|
+
1. Fork the repository
|
|
428
|
+
2. Create a feature branch: `git checkout -b feature/amazing-feature`
|
|
429
|
+
3. Make your changes
|
|
430
|
+
4. Test thoroughly: `node bin/zirr.js test-project --yes`
|
|
431
|
+
5. Commit changes: `git commit -m 'Add amazing feature'`
|
|
432
|
+
6. Push to branch: `git push origin feature/amazing-feature`
|
|
433
|
+
7. Open a Pull Request
|
|
434
|
+
|
|
435
|
+
### Development Setup
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
# Clone and setup
|
|
439
|
+
git clone <repository>
|
|
440
|
+
cd zirr-cli
|
|
441
|
+
npm install
|
|
442
|
+
|
|
443
|
+
# Make changes to src/ and templates/
|
|
444
|
+
|
|
445
|
+
# Test changes
|
|
446
|
+
node bin/zirr.js test-changes
|
|
447
|
+
|
|
448
|
+
# Link for global testing
|
|
449
|
+
npm link
|
|
450
|
+
zirr test-global
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
## 📄 License
|
|
454
|
+
|
|
455
|
+
This project is licensed under the ISC License - see the [LICENSE](LICENSE) file for details.
|
|
456
|
+
|
|
457
|
+
## 🙏 Acknowledgments
|
|
458
|
+
|
|
459
|
+
- **React Team** for the amazing library
|
|
460
|
+
- **Vite Team** for the incredible build tool
|
|
461
|
+
- **Tailwind CSS** for the utility-first approach
|
|
462
|
+
- **Lucide** for the beautiful icon set
|
|
463
|
+
- **Original wifi_qr project** for the design inspiration
|
|
464
|
+
|
|
465
|
+
## 📞 Support
|
|
466
|
+
|
|
467
|
+
- **Issues**: Report bugs or request features
|
|
468
|
+
- **Questions**: Check the troubleshooting section first
|
|
469
|
+
- **Contributions**: Pull requests welcome!
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
<div align="center">
|
|
474
|
+
Made with ⚡ by <b>Zirr</b> • Modern React Starter
|
|
475
|
+
<br>
|
|
476
|
+
Get started: <code>zirr your-project-name</code>
|
|
477
|
+
</div>
|
package/bin/zirr.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const createProject = require('../src/index.js');
|
|
4
|
+
|
|
5
|
+
// Parse command line arguments
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
let projectName = '';
|
|
8
|
+
let options = { yes: false };
|
|
9
|
+
|
|
10
|
+
for (let i = 0; i < args.length; i++) {
|
|
11
|
+
const arg = args[i];
|
|
12
|
+
if (arg === '-y' || arg === '--yes') {
|
|
13
|
+
options.yes = true;
|
|
14
|
+
} else if (arg === '-h' || arg === '--help') {
|
|
15
|
+
showHelp();
|
|
16
|
+
process.exit(0);
|
|
17
|
+
} else if (arg === '-v' || arg === '--version') {
|
|
18
|
+
showVersion();
|
|
19
|
+
process.exit(0);
|
|
20
|
+
} else if (!arg.startsWith('-')) {
|
|
21
|
+
projectName = arg;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// If no project name provided and not in auto mode, show help
|
|
26
|
+
if (!projectName && !options.yes) {
|
|
27
|
+
showHelp();
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Execute the main function
|
|
32
|
+
createProject(projectName, options).catch((error) => {
|
|
33
|
+
console.error('Error:', error.message);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
function showHelp() {
|
|
38
|
+
console.log(`
|
|
39
|
+
⚡ Zirr - Modern React Starter
|
|
40
|
+
|
|
41
|
+
Usage:
|
|
42
|
+
zirr <project-name> [options]
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
-y, --yes Skip prompts and use default values
|
|
46
|
+
-h, --help Show this help message
|
|
47
|
+
-v, --version Show version
|
|
48
|
+
|
|
49
|
+
Example:
|
|
50
|
+
zirr my-app
|
|
51
|
+
zirr my-app --yes
|
|
52
|
+
`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function showVersion() {
|
|
56
|
+
console.log('zirr v1.0.0');
|
|
57
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dev.aldrindc/zirr-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool to generate modern React + Vite + Tailwind CSS projects",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"zirr": "bin/zirr.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node src/index.js",
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"cli",
|
|
15
|
+
"react",
|
|
16
|
+
"vite",
|
|
17
|
+
"tailwind",
|
|
18
|
+
"template",
|
|
19
|
+
"starter"
|
|
20
|
+
],
|
|
21
|
+
"author": "dev-adelacruz",
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/dev-adelacruz/zirr.git"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/dev-adelacruz/zirr#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/dev-adelacruz/zirr/issues"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"chalk": "^4.1.2",
|
|
33
|
+
"commander": "^9.5.0",
|
|
34
|
+
"fs-extra": "^10.1.0",
|
|
35
|
+
"inquirer": "^8.2.6"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=12.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
|
|
6
|
+
// Simple prompt function
|
|
7
|
+
function prompt(question, defaultValue = '') {
|
|
8
|
+
const rl = readline.createInterface({
|
|
9
|
+
input: process.stdin,
|
|
10
|
+
output: process.stdout
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
rl.question(chalk.blue(`? ${question} `) + (defaultValue ? `(${defaultValue}) ` : ''), (answer) => {
|
|
15
|
+
rl.close();
|
|
16
|
+
resolve(answer.trim() || defaultValue);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function createProject(projectName, options) {
|
|
22
|
+
console.log(chalk.blue.bold('\n⚡ Zirr - Modern React Starter\n'));
|
|
23
|
+
|
|
24
|
+
// Get project details
|
|
25
|
+
let projectDetails = {
|
|
26
|
+
name: projectName,
|
|
27
|
+
title: projectName ? projectName.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ') : ''
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// If not in auto mode, prompt for details
|
|
31
|
+
if (!options.yes) {
|
|
32
|
+
const name = await prompt('Project name:', projectName || 'my-app');
|
|
33
|
+
|
|
34
|
+
// Validate project name
|
|
35
|
+
if (!name.trim()) {
|
|
36
|
+
console.log(chalk.red('Error: Project name is required'));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
if (!/^[a-z0-9-]+$/.test(name)) {
|
|
40
|
+
console.log(chalk.red('Error: Project name can only contain lowercase letters, numbers, and hyphens'));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const title = await prompt('Project title:',
|
|
45
|
+
name.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ')
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
projectDetails = { name, title };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const projectDir = path.resolve(process.cwd(), projectDetails.name);
|
|
52
|
+
|
|
53
|
+
// Check if directory exists
|
|
54
|
+
if (fs.existsSync(projectDir)) {
|
|
55
|
+
console.log(chalk.red(`Error: Directory "${projectDetails.name}" already exists.`));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
console.log(chalk.cyan(`\nCreating project: ${chalk.bold(projectDetails.name)}`));
|
|
61
|
+
|
|
62
|
+
// Create project directory
|
|
63
|
+
fs.ensureDirSync(projectDir);
|
|
64
|
+
|
|
65
|
+
// Read template files
|
|
66
|
+
const templateDir = path.join(__dirname, 'templates');
|
|
67
|
+
const templateFiles = fs.readdirSync(templateDir, { recursive: true });
|
|
68
|
+
|
|
69
|
+
// Process and copy each template file
|
|
70
|
+
for (const templateFile of templateFiles) {
|
|
71
|
+
const sourcePath = path.join(templateDir, templateFile);
|
|
72
|
+
const targetPath = path.join(projectDir, templateFile);
|
|
73
|
+
|
|
74
|
+
if (fs.statSync(sourcePath).isDirectory()) {
|
|
75
|
+
fs.ensureDirSync(targetPath);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Read template content
|
|
80
|
+
let content = fs.readFileSync(sourcePath, 'utf-8');
|
|
81
|
+
|
|
82
|
+
// Replace placeholders
|
|
83
|
+
content = content.replace(/{{PROJECT_NAME}}/g, projectDetails.name);
|
|
84
|
+
content = content.replace(/{{PROJECT_TITLE}}/g, projectDetails.title);
|
|
85
|
+
|
|
86
|
+
// Write to target
|
|
87
|
+
fs.ensureDirSync(path.dirname(targetPath));
|
|
88
|
+
fs.writeFileSync(targetPath, content);
|
|
89
|
+
|
|
90
|
+
console.log(chalk.gray(` ✓ ${templateFile}`));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Create additional required files
|
|
94
|
+
createAdditionalFiles(projectDir, projectDetails);
|
|
95
|
+
|
|
96
|
+
console.log(chalk.green('\n✅ Project created successfully!\n'));
|
|
97
|
+
|
|
98
|
+
// Show next steps
|
|
99
|
+
console.log(chalk.bold('Next steps:'));
|
|
100
|
+
console.log(chalk.cyan(` cd ${projectDetails.name}`));
|
|
101
|
+
console.log(chalk.cyan(' npm install'));
|
|
102
|
+
console.log(chalk.cyan(' npm run dev\n'));
|
|
103
|
+
|
|
104
|
+
console.log(chalk.gray('Happy coding! 🚀'));
|
|
105
|
+
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error(chalk.red('Error creating project:'), error);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function createAdditionalFiles(projectDir, projectDetails) {
|
|
113
|
+
// Create package.json from template
|
|
114
|
+
const packageJson = {
|
|
115
|
+
name: projectDetails.name,
|
|
116
|
+
private: true,
|
|
117
|
+
version: '0.0.0',
|
|
118
|
+
type: 'module',
|
|
119
|
+
engines: {
|
|
120
|
+
node: '>=18.0.0'
|
|
121
|
+
},
|
|
122
|
+
scripts: {
|
|
123
|
+
dev: 'vite',
|
|
124
|
+
build: 'vite build',
|
|
125
|
+
lint: 'eslint .',
|
|
126
|
+
preview: 'vite preview'
|
|
127
|
+
},
|
|
128
|
+
dependencies: {
|
|
129
|
+
'lucide-react': '^0.562.0',
|
|
130
|
+
'react': '^19.2.0',
|
|
131
|
+
'react-dom': '^19.2.0'
|
|
132
|
+
},
|
|
133
|
+
devDependencies: {
|
|
134
|
+
'@eslint/js': '^9.39.1',
|
|
135
|
+
'@tailwindcss/postcss': '^4.1.18',
|
|
136
|
+
'@types/react': '^19.2.5',
|
|
137
|
+
'@types/react-dom': '^19.2.3',
|
|
138
|
+
'@vitejs/plugin-react': '^5.1.1',
|
|
139
|
+
'autoprefixer': '^10.4.24',
|
|
140
|
+
'eslint': '^9.39.1',
|
|
141
|
+
'eslint-plugin-react-hooks': '^7.0.1',
|
|
142
|
+
'eslint-plugin-react-refresh': '^0.4.24',
|
|
143
|
+
'globals': '^16.5.0',
|
|
144
|
+
'postcss': '^8.5.6',
|
|
145
|
+
'tailwindcss': '^4.1.18',
|
|
146
|
+
'vite': '^7.2.4'
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
fs.writeFileSync(
|
|
151
|
+
path.join(projectDir, 'package.json'),
|
|
152
|
+
JSON.stringify(packageJson, null, 2)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Create index.html
|
|
156
|
+
const indexHtml = `<!doctype html>
|
|
157
|
+
<html lang="en">
|
|
158
|
+
<head>
|
|
159
|
+
<meta charset="UTF-8" />
|
|
160
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
161
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
162
|
+
<title>${projectDetails.title} - Modern React App</title>
|
|
163
|
+
</head>
|
|
164
|
+
<body>
|
|
165
|
+
<div id="root"></div>
|
|
166
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
167
|
+
</body>
|
|
168
|
+
</html>`;
|
|
169
|
+
|
|
170
|
+
fs.writeFileSync(
|
|
171
|
+
path.join(projectDir, 'index.html'),
|
|
172
|
+
indexHtml
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// Create configuration files
|
|
176
|
+
const configFiles = {
|
|
177
|
+
'vite.config.js': `import { defineConfig } from 'vite'
|
|
178
|
+
import react from '@vitejs/plugin-react'
|
|
179
|
+
|
|
180
|
+
// https://vite.dev/config/
|
|
181
|
+
export default defineConfig({
|
|
182
|
+
plugins: [react()],
|
|
183
|
+
})`,
|
|
184
|
+
|
|
185
|
+
'tailwind.config.js': `/** @type {import('tailwindcss').Config} */
|
|
186
|
+
export default {
|
|
187
|
+
content: [
|
|
188
|
+
"./index.html",
|
|
189
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
190
|
+
],
|
|
191
|
+
theme: {
|
|
192
|
+
extend: {},
|
|
193
|
+
},
|
|
194
|
+
plugins: [],
|
|
195
|
+
}`,
|
|
196
|
+
|
|
197
|
+
'postcss.config.js': `export default {
|
|
198
|
+
plugins: {
|
|
199
|
+
"@tailwindcss/postcss": {},
|
|
200
|
+
autoprefixer: {},
|
|
201
|
+
},
|
|
202
|
+
}`,
|
|
203
|
+
|
|
204
|
+
'eslint.config.js': `import js from '@eslint/js'
|
|
205
|
+
import globals from 'globals'
|
|
206
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
207
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
208
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
209
|
+
|
|
210
|
+
export default defineConfig([
|
|
211
|
+
globalIgnores(['dist']),
|
|
212
|
+
{
|
|
213
|
+
files: ['**/*.{js,jsx}'],
|
|
214
|
+
extends: [
|
|
215
|
+
js.configs.recommended,
|
|
216
|
+
reactHooks.configs.flat.recommended,
|
|
217
|
+
reactRefresh.configs.vite,
|
|
218
|
+
],
|
|
219
|
+
languageOptions: {
|
|
220
|
+
ecmaVersion: 2020,
|
|
221
|
+
globals: globals.browser,
|
|
222
|
+
parserOptions: {
|
|
223
|
+
ecmaVersion: 'latest',
|
|
224
|
+
ecmaFeatures: { jsx: true },
|
|
225
|
+
sourceType: 'module',
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
rules: {
|
|
229
|
+
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
])`,
|
|
233
|
+
|
|
234
|
+
'src/index.css': `@import "tailwindcss";
|
|
235
|
+
|
|
236
|
+
body {
|
|
237
|
+
margin: 0;
|
|
238
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
239
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
240
|
+
sans-serif;
|
|
241
|
+
-webkit-font-smoothing: antialiased;
|
|
242
|
+
-moz-osx-font-smoothing: grayscale;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
code {
|
|
246
|
+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
247
|
+
monospace;
|
|
248
|
+
}`,
|
|
249
|
+
|
|
250
|
+
'src/main.jsx': `import React from 'react'
|
|
251
|
+
import ReactDOM from 'react-dom/client'
|
|
252
|
+
import './index.css'
|
|
253
|
+
import App from './App.jsx'
|
|
254
|
+
|
|
255
|
+
ReactDOM.createRoot(document.getElementById('root')).render(
|
|
256
|
+
<React.StrictMode>
|
|
257
|
+
<App />
|
|
258
|
+
</React.StrictMode>,
|
|
259
|
+
)`,
|
|
260
|
+
|
|
261
|
+
'.gitignore': `# Logs
|
|
262
|
+
logs
|
|
263
|
+
*.log
|
|
264
|
+
npm-debug.log*
|
|
265
|
+
yarn-debug.log*
|
|
266
|
+
yarn-error.log*
|
|
267
|
+
lerna-debug.log*
|
|
268
|
+
|
|
269
|
+
# Runtime data
|
|
270
|
+
pids
|
|
271
|
+
*.pid
|
|
272
|
+
*.seed
|
|
273
|
+
*.pid.lock
|
|
274
|
+
|
|
275
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
276
|
+
lib-cov
|
|
277
|
+
|
|
278
|
+
# Coverage directory used by tools like istanbul
|
|
279
|
+
coverage
|
|
280
|
+
*.lcov
|
|
281
|
+
|
|
282
|
+
# nyc test coverage
|
|
283
|
+
.nyc_output
|
|
284
|
+
|
|
285
|
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
286
|
+
.grunt
|
|
287
|
+
|
|
288
|
+
# Bower dependency directory (https://bower.io/)
|
|
289
|
+
bower_components
|
|
290
|
+
|
|
291
|
+
# node-waf configuration
|
|
292
|
+
.lock-wscript
|
|
293
|
+
|
|
294
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
295
|
+
build/Release
|
|
296
|
+
|
|
297
|
+
# Dependency directories
|
|
298
|
+
node_modules/
|
|
299
|
+
jspm_packages/
|
|
300
|
+
|
|
301
|
+
# TypeScript v1 declaration files
|
|
302
|
+
typings/
|
|
303
|
+
|
|
304
|
+
# TypeScript cache
|
|
305
|
+
*.tsbuildinfo
|
|
306
|
+
|
|
307
|
+
# Optional npm cache directory
|
|
308
|
+
.npm
|
|
309
|
+
|
|
310
|
+
# Optional eslint cache
|
|
311
|
+
.eslintcache
|
|
312
|
+
|
|
313
|
+
# Microbundle cache
|
|
314
|
+
.rpt2_cache/
|
|
315
|
+
.rts2_cache_cjs/
|
|
316
|
+
.rts2_cache_es/
|
|
317
|
+
.rts2_cache_umd/
|
|
318
|
+
|
|
319
|
+
# Optional REPL history
|
|
320
|
+
.node_repl_history
|
|
321
|
+
|
|
322
|
+
# Output of 'npm pack'
|
|
323
|
+
*.tgz
|
|
324
|
+
|
|
325
|
+
# Yarn Integrity file
|
|
326
|
+
.yarn-integrity
|
|
327
|
+
|
|
328
|
+
# dotenv environment variables file
|
|
329
|
+
.env
|
|
330
|
+
.env.test
|
|
331
|
+
|
|
332
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
333
|
+
.cache
|
|
334
|
+
.parcel-cache
|
|
335
|
+
|
|
336
|
+
# Next.js build output
|
|
337
|
+
.next
|
|
338
|
+
|
|
339
|
+
# Nuxt.js build / generate output
|
|
340
|
+
.nuxt
|
|
341
|
+
dist
|
|
342
|
+
|
|
343
|
+
# Gatsby files
|
|
344
|
+
.cache/
|
|
345
|
+
public
|
|
346
|
+
|
|
347
|
+
# Vuepress build output
|
|
348
|
+
.vuepress/dist
|
|
349
|
+
|
|
350
|
+
# Serverless directories
|
|
351
|
+
.serverless/
|
|
352
|
+
|
|
353
|
+
# FuseBox cache
|
|
354
|
+
.fusebox/
|
|
355
|
+
|
|
356
|
+
# DynamoDB Local files
|
|
357
|
+
.dynamodb/
|
|
358
|
+
|
|
359
|
+
# TernJS port file
|
|
360
|
+
.tern-port
|
|
361
|
+
|
|
362
|
+
# Stores VSCode versions used for testing VSCode extensions
|
|
363
|
+
.vscode-test
|
|
364
|
+
|
|
365
|
+
# Temporary folders
|
|
366
|
+
tmp/
|
|
367
|
+
temp/`
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// Write all config files
|
|
371
|
+
for (const [filePath, content] of Object.entries(configFiles)) {
|
|
372
|
+
const fullPath = path.join(projectDir, filePath);
|
|
373
|
+
fs.ensureDirSync(path.dirname(fullPath));
|
|
374
|
+
fs.writeFileSync(fullPath, content);
|
|
375
|
+
console.log(chalk.gray(` ✓ ${filePath}`));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
module.exports = createProject;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Zap, Sparkles, Rocket, Star, ChevronRight, ExternalLink } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
const App = () => {
|
|
5
|
+
const [count, setCount] = useState(0);
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50 text-slate-900 font-sans p-4 md:p-8">
|
|
9
|
+
<main className="max-w-6xl mx-auto">
|
|
10
|
+
{/* Header */}
|
|
11
|
+
<header className="py-8 md:py-12">
|
|
12
|
+
<div className="flex items-center gap-3 mb-4">
|
|
13
|
+
<div className="w-12 h-12 bg-gradient-to-br from-blue-600 to-indigo-700 rounded-2xl flex items-center justify-center text-white shadow-xl shadow-blue-200/50">
|
|
14
|
+
<Zap size={28} strokeWidth={2.5} />
|
|
15
|
+
</div>
|
|
16
|
+
<div>
|
|
17
|
+
<h1 className="text-4xl font-black tracking-tighter text-slate-900">
|
|
18
|
+
{{PROJECT_TITLE}}
|
|
19
|
+
</h1>
|
|
20
|
+
<div className="h-1 w-12 bg-gradient-to-r from-blue-600 to-indigo-600 rounded-full mt-1"></div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
<p className="text-slate-500 font-medium text-lg max-w-2xl">
|
|
24
|
+
A modern React + Vite + Tailwind CSS starter template. Build beautiful applications faster.
|
|
25
|
+
</p>
|
|
26
|
+
</header>
|
|
27
|
+
|
|
28
|
+
{/* Main Content */}
|
|
29
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-16">
|
|
30
|
+
{/* Left Column: Features */}
|
|
31
|
+
<div className="space-y-6">
|
|
32
|
+
<div className="bg-white p-8 rounded-[2.5rem] shadow-2xl shadow-slate-200/60 border border-slate-100">
|
|
33
|
+
<h2 className="text-2xl font-black text-slate-900 mb-6 flex items-center gap-3">
|
|
34
|
+
<Sparkles className="text-yellow-500" />
|
|
35
|
+
Features Included
|
|
36
|
+
</h2>
|
|
37
|
+
<div className="space-y-4">
|
|
38
|
+
{[
|
|
39
|
+
{ icon: <Rocket className="text-blue-500" />, text: 'React 19 with Vite 7' },
|
|
40
|
+
{ icon: <Zap className="text-purple-500" />, text: 'Tailwind CSS 4 + PostCSS' },
|
|
41
|
+
{ icon: <Sparkles className="text-green-500" />, text: 'ESLint 9 with React Hooks' },
|
|
42
|
+
{ icon: <Star className="text-amber-500" />, text: 'Lucide React Icons' },
|
|
43
|
+
].map((feature, index) => (
|
|
44
|
+
<div key={index} className="flex items-center gap-4 p-3 bg-slate-50 rounded-2xl hover:bg-slate-100 transition-colors">
|
|
45
|
+
<div className="w-10 h-10 bg-white rounded-xl flex items-center justify-center shadow-sm">
|
|
46
|
+
{feature.icon}
|
|
47
|
+
</div>
|
|
48
|
+
<span className="font-bold text-slate-700">{feature.text}</span>
|
|
49
|
+
</div>
|
|
50
|
+
))}
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
{/* Interactive Demo */}
|
|
55
|
+
<div className="bg-gradient-to-br from-blue-600 to-indigo-700 p-8 rounded-[2.5rem] text-white">
|
|
56
|
+
<h3 className="text-xl font-black mb-4 flex items-center gap-2">
|
|
57
|
+
<Zap size={20} />
|
|
58
|
+
Interactive Demo
|
|
59
|
+
</h3>
|
|
60
|
+
<div className="flex items-center justify-between mb-6">
|
|
61
|
+
<div>
|
|
62
|
+
<p className="text-blue-100 font-medium">Counter Value</p>
|
|
63
|
+
<p className="text-5xl font-black mt-2">{count}</p>
|
|
64
|
+
</div>
|
|
65
|
+
<button
|
|
66
|
+
onClick={() => setCount(count + 1)}
|
|
67
|
+
className="bg-white text-blue-700 hover:bg-blue-50 px-6 py-3 rounded-2xl font-bold text-lg flex items-center gap-2 transition-all active:scale-95"
|
|
68
|
+
>
|
|
69
|
+
<Zap size={20} />
|
|
70
|
+
Increment
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
<button
|
|
74
|
+
onClick={() => setCount(0)}
|
|
75
|
+
className="text-blue-100 hover:text-white font-medium text-sm flex items-center gap-1"
|
|
76
|
+
>
|
|
77
|
+
Reset counter
|
|
78
|
+
<ChevronRight size={14} />
|
|
79
|
+
</button>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{/* Right Column: Getting Started */}
|
|
84
|
+
<div className="space-y-6">
|
|
85
|
+
<div className="bg-white p-8 rounded-[2.5rem] shadow-2xl shadow-slate-200/60 border border-slate-100">
|
|
86
|
+
<h2 className="text-2xl font-black text-slate-900 mb-6">Getting Started</h2>
|
|
87
|
+
<div className="space-y-4">
|
|
88
|
+
<div className="p-4 bg-slate-50 rounded-2xl border border-slate-200">
|
|
89
|
+
<p className="text-sm text-slate-500 font-bold mb-2">Development Server</p>
|
|
90
|
+
<code className="text-sm bg-slate-900 text-slate-100 px-3 py-2 rounded-xl font-mono block">
|
|
91
|
+
npm run dev
|
|
92
|
+
</code>
|
|
93
|
+
</div>
|
|
94
|
+
<div className="p-4 bg-slate-50 rounded-2xl border border-slate-200">
|
|
95
|
+
<p className="text-sm text-slate-500 font-bold mb-2">Build for Production</p>
|
|
96
|
+
<code className="text-sm bg-slate-900 text-slate-100 px-3 py-2 rounded-xl font-mono block">
|
|
97
|
+
npm run build
|
|
98
|
+
</code>
|
|
99
|
+
</div>
|
|
100
|
+
<div className="p-4 bg-slate-50 rounded-2xl border border-slate-200">
|
|
101
|
+
<p className="text-sm text-slate-500 font-bold mb-2">Lint Code</p>
|
|
102
|
+
<code className="text-sm bg-slate-900 text-slate-100 px-3 py-2 rounded-xl font-mono block">
|
|
103
|
+
npm run lint
|
|
104
|
+
</code>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div className="bg-gradient-to-br from-emerald-500 to-green-600 p-8 rounded-[2.5rem] text-white">
|
|
110
|
+
<h3 className="text-xl font-black mb-4">Ready to Build</h3>
|
|
111
|
+
<p className="text-emerald-100 mb-6">
|
|
112
|
+
This template includes everything you need to start building modern web applications.
|
|
113
|
+
Customize the colors, components, and layout to match your project.
|
|
114
|
+
</p>
|
|
115
|
+
<div className="flex gap-4">
|
|
116
|
+
<button className="bg-white text-emerald-700 hover:bg-emerald-50 px-5 py-3 rounded-2xl font-bold flex items-center gap-2 transition-all">
|
|
117
|
+
<ExternalLink size={18} />
|
|
118
|
+
View Docs
|
|
119
|
+
</button>
|
|
120
|
+
<button className="bg-emerald-800/30 hover:bg-emerald-800/50 text-white px-5 py-3 rounded-2xl font-bold border border-emerald-400/20 transition-all">
|
|
121
|
+
Learn More
|
|
122
|
+
</button>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
{/* Footer */}
|
|
129
|
+
<footer className="py-8 border-t border-slate-200 text-center">
|
|
130
|
+
<p className="text-slate-500 font-medium">
|
|
131
|
+
Built with <span className="text-blue-600 font-bold">Zirr</span> • Modern React Starter
|
|
132
|
+
</p>
|
|
133
|
+
<p className="text-sm text-slate-400 mt-2">
|
|
134
|
+
Get started by editing <code className="text-slate-600 bg-slate-100 px-2 py-1 rounded">src/App.jsx</code>
|
|
135
|
+
</p>
|
|
136
|
+
</footer>
|
|
137
|
+
</main>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export default App;
|