create-template-html-css 2.0.3 → 2.1.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 (74) hide show
  1. package/CHANGELOG.md +305 -0
  2. package/HTML-VS-REACT.md +289 -0
  3. package/QUICKSTART-REACT.md +293 -0
  4. package/REACT-SUPPORT-SUMMARY.md +235 -0
  5. package/README.md +193 -12
  6. package/bin/cli.js +98 -759
  7. package/bin/commands/create.js +272 -0
  8. package/bin/commands/gallery.js +42 -0
  9. package/bin/commands/insert.js +123 -0
  10. package/bin/commands/list.js +73 -0
  11. package/package.json +10 -3
  12. package/src/component-choices.js +7 -0
  13. package/src/components-registry.js +112 -0
  14. package/src/format-utils.js +49 -0
  15. package/src/generator.js +83 -594
  16. package/src/generators/color-schemes.js +78 -0
  17. package/src/generators/color-utils.js +108 -0
  18. package/src/generators/component-filters.js +151 -0
  19. package/src/generators/html-generators.js +180 -0
  20. package/src/generators/validation.js +43 -0
  21. package/src/index.js +2 -1
  22. package/src/inserter.js +55 -233
  23. package/src/inserters/backup-utils.js +20 -0
  24. package/src/inserters/component-loader.js +68 -0
  25. package/src/inserters/html-utils.js +31 -0
  26. package/src/inserters/indentation-utils.js +90 -0
  27. package/src/inserters/validation-utils.js +49 -0
  28. package/src/react-component-choices.js +45 -0
  29. package/src/react-file-operations.js +172 -0
  30. package/src/react-generator.js +208 -0
  31. package/src/react-templates.js +350 -0
  32. package/src/utils/file-utils.js +97 -0
  33. package/src/utils/path-utils.js +32 -0
  34. package/src/utils/string-utils.js +51 -0
  35. package/src/utils/template-loader.js +91 -0
  36. package/templates/_shared/PATTERNS.md +246 -0
  37. package/templates/_shared/README.md +74 -0
  38. package/templates/_shared/base.css +18 -0
  39. package/templates/blackjack/index.html +1 -1
  40. package/templates/blackjack/script.js +9 -9
  41. package/templates/breakout/index.html +1 -1
  42. package/templates/breakout/script.js +6 -6
  43. package/templates/connect-four/index.html +1 -1
  44. package/templates/connect-four/script.js +5 -5
  45. package/templates/dice-game/index.html +1 -1
  46. package/templates/dice-game/script.js +20 -20
  47. package/templates/flappy-bird/index.html +1 -1
  48. package/templates/flappy-bird/script.js +10 -10
  49. package/templates/pong/index.html +1 -1
  50. package/templates/pong/script.js +8 -8
  51. package/templates/skeleton/index.html +4 -4
  52. package/templates/slot-machine/index.html +1 -1
  53. package/templates/slot-machine/script.js +6 -6
  54. package/templates/tetris/index.html +1 -1
  55. package/templates/tetris/script.js +5 -5
  56. package/templates-react/README.md +126 -0
  57. package/templates-react/button/Button.css +88 -0
  58. package/templates-react/button/Button.example.jsx +40 -0
  59. package/templates-react/button/Button.jsx +29 -0
  60. package/templates-react/card/Card.css +86 -0
  61. package/templates-react/card/Card.example.jsx +49 -0
  62. package/templates-react/card/Card.jsx +35 -0
  63. package/templates-react/counter/Counter.css +99 -0
  64. package/templates-react/counter/Counter.example.jsx +45 -0
  65. package/templates-react/counter/Counter.jsx +70 -0
  66. package/templates-react/form/Form.css +128 -0
  67. package/templates-react/form/Form.example.jsx +65 -0
  68. package/templates-react/form/Form.jsx +125 -0
  69. package/templates-react/modal/Modal.css +152 -0
  70. package/templates-react/modal/Modal.example.jsx +90 -0
  71. package/templates-react/modal/Modal.jsx +46 -0
  72. package/templates-react/todo-list/TodoList.css +236 -0
  73. package/templates-react/todo-list/TodoList.example.jsx +15 -0
  74. package/templates-react/todo-list/TodoList.jsx +84 -0
@@ -279,15 +279,15 @@ function gameOver() {
279
279
  ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2 - 50);
280
280
 
281
281
  ctx.font = '24px Arial';
282
- ctx.strokeText(`ניקוד: ${gameState.score}`, canvas.width / 2, canvas.height / 2 + 10);
283
- ctx.fillText(`ניקוד: ${gameState.score}`, canvas.width / 2, canvas.height / 2 + 10);
282
+ ctx.strokeText(`Score: ${gameState.score}`, canvas.width / 2, canvas.height / 2 + 10);
283
+ ctx.fillText(`Score: ${gameState.score}`, canvas.width / 2, canvas.height / 2 + 10);
284
284
 
285
- ctx.strokeText(`שיא: ${gameState.highScore}`, canvas.width / 2, canvas.height / 2 + 50);
286
- ctx.fillText(`שיא: ${gameState.highScore}`, canvas.width / 2, canvas.height / 2 + 50);
285
+ ctx.strokeText(`High Score: ${gameState.highScore}`, canvas.width / 2, canvas.height / 2 + 50);
286
+ ctx.fillText(`High Score: ${gameState.highScore}`, canvas.width / 2, canvas.height / 2 + 50);
287
287
 
288
288
  ctx.font = '18px Arial';
289
- ctx.strokeText('לחץ "אתחל" להתחיל מחדש', canvas.width / 2, canvas.height / 2 + 100);
290
- ctx.fillText('לחץ "אתחל" להתחיל מחדש', canvas.width / 2, canvas.height / 2 + 100);
289
+ ctx.strokeText('Click "Reset" to restart', canvas.width / 2, canvas.height / 2 + 100);
290
+ ctx.fillText('Click "Reset" to restart', canvas.width / 2, canvas.height / 2 + 100);
291
291
 
292
292
  document.getElementById('startBtn').disabled = false;
293
293
  }
@@ -318,11 +318,11 @@ function drawStartScreen() {
318
318
  ctx.fillText('🐦 Flappy Bird', canvas.width / 2, canvas.height / 2 - 40);
319
319
 
320
320
  ctx.font = '20px Arial';
321
- ctx.strokeText('לחץ "התחל משחק"', canvas.width / 2, canvas.height / 2 + 20);
322
- ctx.fillText('לחץ "התחל משחק"', canvas.width / 2, canvas.height / 2 + 20);
321
+ ctx.strokeText('Click "Start Game"', canvas.width / 2, canvas.height / 2 + 20);
322
+ ctx.fillText('Click "Start Game"', canvas.width / 2, canvas.height / 2 + 20);
323
323
 
324
- ctx.strokeText('להתחיל!', canvas.width / 2, canvas.height / 2 + 50);
325
- ctx.fillText('להתחיל!', canvas.width / 2, canvas.height / 2 + 50);
324
+ ctx.strokeText('to begin!', canvas.width / 2, canvas.height / 2 + 50);
325
+ ctx.fillText('to begin!', canvas.width / 2, canvas.height / 2 + 50);
326
326
  }
327
327
 
328
328
  // Game loop
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Pong</title>
6
+ <title>{{name}} - Pong Game</title>
7
7
  <link rel="stylesheet" href="style.css">
8
8
  </head>
9
9
  <body>
@@ -89,10 +89,10 @@ document.querySelectorAll('.mode-btn').forEach(btn => {
89
89
 
90
90
  // Update player 2 name
91
91
  if (gameState.gameMode === 'pvc') {
92
- document.getElementById('player2Name').textContent = '🤖 מחשב';
92
+ document.getElementById('player2Name').textContent = '🤖 Computer';
93
93
  document.querySelector('.difficulty-selector').style.display = 'flex';
94
94
  } else {
95
- document.getElementById('player2Name').textContent = '👤 שחקן 2';
95
+ document.getElementById('player2Name').textContent = '👤 Player 2';
96
96
  document.querySelector('.difficulty-selector').style.display = 'none';
97
97
  }
98
98
  });
@@ -251,7 +251,7 @@ function draw() {
251
251
  ctx.fillStyle = '#FFFFFF';
252
252
  ctx.font = 'bold 36px Arial';
253
253
  ctx.textAlign = 'center';
254
- ctx.fillText('משחק מושהה', canvas.width / 2, canvas.height / 2);
254
+ ctx.fillText('Game Paused', canvas.width / 2, canvas.height / 2);
255
255
  }
256
256
  }
257
257
 
@@ -288,10 +288,10 @@ function endGame(winner) {
288
288
  gameState.running = false;
289
289
 
290
290
  const winnerName = winner === 1 ?
291
- 'שחקן 1' :
292
- (gameState.gameMode === 'pvc' ? 'המחשב' : 'שחקן 2');
291
+ 'Player 1' :
292
+ (gameState.gameMode === 'pvc' ? 'Computer' : 'Player 2');
293
293
 
294
- showMessage(`🎉 ${winnerName} ניצח ${gameState.winningScore} - ${winner === 1 ? gameState.score2 : gameState.score1}!`, 'success');
294
+ showMessage(`🎉 ${winnerName} wins ${gameState.winningScore} - ${winner === 1 ? gameState.score2 : gameState.score1}!`, 'success');
295
295
 
296
296
  document.getElementById('startBtn').disabled = false;
297
297
  document.getElementById('pauseBtn').disabled = true;
@@ -325,7 +325,7 @@ document.getElementById('pauseBtn').addEventListener('click', pauseGame);
325
325
 
326
326
  function pauseGame() {
327
327
  gameState.paused = !gameState.paused;
328
- document.getElementById('pauseBtn').textContent = gameState.paused ? 'המשך' : 'השהה';
328
+ document.getElementById('pauseBtn').textContent = gameState.paused ? 'Resume' : 'Pause';
329
329
  }
330
330
 
331
331
  // Reset game
@@ -347,7 +347,7 @@ function resetGame() {
347
347
 
348
348
  document.getElementById('startBtn').disabled = false;
349
349
  document.getElementById('pauseBtn').disabled = true;
350
- document.getElementById('pauseBtn').textContent = 'השהה';
350
+ document.getElementById('pauseBtn').textContent = 'Pause';
351
351
  document.getElementById('resultMessage').textContent = '';
352
352
  }
353
353
 
@@ -1,10 +1,10 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Skeleton Loading</title>
7
- <link rel="stylesheet" href="style.css" />
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{name}} - Skeleton Loading</title>
7
+ <link rel="stylesheet" href="style.css">
8
8
  </head>
9
9
  <body>
10
10
  <div class="skeleton-container">
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Slot Machine</title>
6
+ <title>{{name}} - Slot Machine Game</title>
7
7
  <link rel="stylesheet" href="style.css">
8
8
  </head>
9
9
  <body>
@@ -72,7 +72,7 @@ async function spin() {
72
72
  if (gameState.spinning) return;
73
73
 
74
74
  if (gameState.credits < gameState.bet) {
75
- showMessage('אין מספיק קרדיטים!', 'error');
75
+ showMessage('Not enough credits!', 'error');
76
76
  return;
77
77
  }
78
78
 
@@ -105,7 +105,7 @@ async function spin() {
105
105
  // Check if out of credits
106
106
  if (gameState.credits < 10) {
107
107
  setTimeout(() => {
108
- alert('נגמרו הקרדיטים! מקבל 1000 קרדיטים חדשים.');
108
+ alert('Out of credits! Receiving 1000 new credits.');
109
109
  gameState.credits = 1000;
110
110
  updateDisplay();
111
111
  saveGame();
@@ -171,18 +171,18 @@ function checkWin(results) {
171
171
  let type = 'success';
172
172
 
173
173
  if (first.icon === '💰') {
174
- message = `🎉 ג'קפוט! זכית ${winAmount} קרדיטים! 🎉`;
174
+ message = `🎉 Jackpot! You won ${winAmount} credits! 🎉`;
175
175
  type = 'jackpot';
176
176
  celebrate();
177
177
  } else {
178
- message = `🎊 זכייה! +${winAmount} קרדיטים!`;
178
+ message = `🎊 You Win! +${winAmount} credits!`;
179
179
  }
180
180
 
181
181
  showMessage(message, type);
182
182
  } else if (first.icon === second.icon || second.icon === third.icon || first.icon === third.icon) {
183
- showMessage('כמעט! שני סמלים תואמים!', 'info');
183
+ showMessage('Almost! Two matching symbols!', 'info');
184
184
  } else {
185
- showMessage('נסה שוב!', 'info');
185
+ showMessage('Try again!', 'info');
186
186
  }
187
187
 
188
188
  updateDisplay();
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Tetris</title>
6
+ <title>{{name}} - Tetris Game</title>
7
7
  <link rel="stylesheet" href="style.css">
8
8
  </head>
9
9
  <body>
@@ -273,10 +273,10 @@ function gameOver() {
273
273
  ctx.fillStyle = '#FFFFFF';
274
274
  ctx.font = 'bold 36px Arial';
275
275
  ctx.textAlign = 'center';
276
- ctx.fillText('משחק נגמר!', canvas.width / 2, canvas.height / 2 - 30);
276
+ ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2 - 30);
277
277
 
278
278
  ctx.font = '20px Arial';
279
- ctx.fillText(`ניקוד: ${gameState.score}`, canvas.width / 2, canvas.height / 2 + 10);
279
+ ctx.fillText(`Score: ${gameState.score}`, canvas.width / 2, canvas.height / 2 + 10);
280
280
 
281
281
  document.getElementById('startBtn').disabled = false;
282
282
  document.getElementById('pauseBtn').disabled = true;
@@ -324,7 +324,7 @@ function draw() {
324
324
  ctx.fillStyle = '#FFFFFF';
325
325
  ctx.font = 'bold 28px Arial';
326
326
  ctx.textAlign = 'center';
327
- ctx.fillText('משחק מושהה', canvas.width / 2, canvas.height / 2);
327
+ ctx.fillText('Game Paused', canvas.width / 2, canvas.height / 2);
328
328
  }
329
329
  }
330
330
 
@@ -408,7 +408,7 @@ function startGame() {
408
408
  // Pause game
409
409
  function pauseGame() {
410
410
  gameState.paused = !gameState.paused;
411
- document.getElementById('pauseBtn').textContent = gameState.paused ? 'המשך' : 'השהה';
411
+ document.getElementById('pauseBtn').textContent = gameState.paused ? 'Resume' : 'Pause';
412
412
  }
413
413
 
414
414
  // Reset game
@@ -432,7 +432,7 @@ function resetGame() {
432
432
 
433
433
  document.getElementById('startBtn').disabled = false;
434
434
  document.getElementById('pauseBtn').disabled = true;
435
- document.getElementById('pauseBtn').textContent = 'השהה';
435
+ document.getElementById('pauseBtn').textContent = 'Pause';
436
436
  }
437
437
 
438
438
  // Event listeners
@@ -0,0 +1,126 @@
1
+ # React Components Templates 🎨⚛️
2
+
3
+ This directory contains React component templates that can be generated using the `create-template` CLI tool with React support.
4
+
5
+ ## Available Components
6
+
7
+ ### 🔘 Button
8
+ A customizable button component with various styles and states:
9
+ - **Variants**: primary, secondary, success, danger
10
+ - **Sizes**: small, medium, large
11
+ - **States**: enabled, disabled
12
+ - **Props**: variant, size, disabled, onClick, type, className
13
+
14
+ ### 🎴 Card
15
+ A versatile card component for displaying content:
16
+ - **Features**: image support, title, description, footer
17
+ - **Responsive design**
18
+ - **Hover effects**
19
+ - **Dark mode support**
20
+ - **Props**: title, description, image, imageAlt, footer, onClick, className
21
+
22
+ ### 🔢 Counter
23
+ A simple counter with increment and decrement functionality:
24
+ - **Features**: customizable initial value, min/max limits, custom step
25
+ - **Animations**: smooth transitions
26
+ - **Controls**: increment, decrement, reset buttons
27
+ - **Props**: initialValue, min, max, step, onChange
28
+
29
+ ### 📝 Form
30
+ A flexible form component with validation:
31
+ - **Features**: multiple field types (text, email, textarea, select)
32
+ - **Validation**: required fields, patterns, min length
33
+ - **Error messages**
34
+ - **Dark mode support**
35
+ - **Props**: title, fields, onSubmit, submitButtonText
36
+
37
+ ### 🪟 Modal
38
+ A flexible modal dialog component:
39
+ - **Features**: overlay click to close, customizable size
40
+ - **Sizes**: small, medium, large
41
+ - **Animations**: fade in, slide up
42
+ - **Dark mode support**
43
+ - **Props**: isOpen, onClose, title, children, footer, showCloseButton, closeOnOverlayClick, size
44
+
45
+ ### ✅ Todo List
46
+ A complete todo list with add, toggle, and delete functionality:
47
+ - **Features**: add tasks, mark as complete, delete tasks
48
+ - **Statistics**: active and completed count
49
+ - **Animations**: smooth transitions
50
+ - **Dark mode support**
51
+ - **Local state management**
52
+
53
+ ## Usage
54
+
55
+ ### Creating a React Component
56
+
57
+ ```bash
58
+ # Interactive mode
59
+ npx create-template-html-css create --react
60
+
61
+ # With flags
62
+ npx create-template-html-css create --react --component button --name my-button
63
+ ```
64
+
65
+ ### Importing in Your Project
66
+
67
+ ```jsx
68
+ import Button from './components/Button/Button';
69
+ import './components/Button/Button.css';
70
+
71
+ function App() {
72
+ return (
73
+ <Button variant="primary" onClick={() => console.log('Clicked!')}>
74
+ Click Me
75
+ </Button>
76
+ );
77
+ }
78
+ ```
79
+
80
+ ## Component Structure
81
+
82
+ Each component follows this structure:
83
+ ```
84
+ component-name/
85
+ ├── ComponentName.jsx # Main component
86
+ ├── ComponentName.css # Styles
87
+ └── ComponentName.example.jsx # Usage examples
88
+ ```
89
+
90
+ ## Styling
91
+
92
+ All components support:
93
+ - ✨ Gradient backgrounds with customizable colors
94
+ - 🌙 Dark mode (prefers-color-scheme)
95
+ - 📱 Responsive design
96
+ - 🎭 Smooth animations and transitions
97
+ - 🎨 CSS color placeholders ({{primaryColor}}, {{secondaryColor}})
98
+
99
+ ## Color Customization
100
+
101
+ Colors can be customized during generation:
102
+ - `--primary-color`: Main brand color
103
+ - `--secondary-color`: Accent color
104
+ - `--color-scheme`: Predefined schemes (ocean, sunset, forest, etc.)
105
+
106
+ ## Requirements
107
+
108
+ These components are designed for use with:
109
+ - React 16.8+ (Hooks support)
110
+ - Modern browsers (ES6+)
111
+ - CSS3 support
112
+
113
+ ## Contributing
114
+
115
+ To add a new React component template:
116
+ 1. Create a new directory in `templates-react/`
117
+ 2. Add `ComponentName.jsx`, `ComponentName.css`, and `ComponentName.example.jsx`
118
+ 3. Follow the existing component structure
119
+ 4. Update this README
120
+
121
+ ## Notes
122
+
123
+ - All components use functional components with hooks
124
+ - PropTypes or TypeScript types can be added as needed
125
+ - Components are fully self-contained with their own styles
126
+ - CSS uses placeholders for color customization during generation
@@ -0,0 +1,88 @@
1
+ /* Button Styles */
2
+ .btn {
3
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
4
+ font-weight: 600;
5
+ border: none;
6
+ border-radius: 8px;
7
+ cursor: pointer;
8
+ transition: all 0.3s ease;
9
+ outline: none;
10
+ display: inline-flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ gap: 8px;
14
+ }
15
+
16
+ /* Size Variations */
17
+ .btn-small {
18
+ padding: 8px 16px;
19
+ font-size: 14px;
20
+ }
21
+
22
+ .btn-medium {
23
+ padding: 12px 24px;
24
+ font-size: 16px;
25
+ }
26
+
27
+ .btn-large {
28
+ padding: 16px 32px;
29
+ font-size: 18px;
30
+ }
31
+
32
+ /* Variant Styles - Primary */
33
+ .btn-primary {
34
+ background: linear-gradient(135deg, {{primaryColor}} 0%, {{secondaryColor}} 100%);
35
+ color: white;
36
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
37
+ }
38
+
39
+ .btn-primary:hover:not(:disabled) {
40
+ transform: translateY(-2px);
41
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
42
+ }
43
+
44
+ .btn-primary:active:not(:disabled) {
45
+ transform: translateY(0);
46
+ }
47
+
48
+ /* Variant Styles - Secondary */
49
+ .btn-secondary {
50
+ background: transparent;
51
+ color: {{primaryColor}};
52
+ border: 2px solid {{primaryColor}};
53
+ }
54
+
55
+ .btn-secondary:hover:not(:disabled) {
56
+ background: {{primaryColor}};
57
+ color: white;
58
+ }
59
+
60
+ /* Variant Styles - Danger */
61
+ .btn-danger {
62
+ background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%);
63
+ color: white;
64
+ box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3);
65
+ }
66
+
67
+ .btn-danger:hover:not(:disabled) {
68
+ transform: translateY(-2px);
69
+ box-shadow: 0 6px 20px rgba(255, 107, 107, 0.4);
70
+ }
71
+
72
+ /* Variant Styles - Success */
73
+ .btn-success {
74
+ background: linear-gradient(135deg, #51cf66 0%, #37b24d 100%);
75
+ color: white;
76
+ box-shadow: 0 4px 15px rgba(81, 207, 102, 0.3);
77
+ }
78
+
79
+ .btn-success:hover:not(:disabled) {
80
+ transform: translateY(-2px);
81
+ box-shadow: 0 6px 20px rgba(81, 207, 102, 0.4);
82
+ }
83
+
84
+ /* Disabled State */
85
+ .btn:disabled {
86
+ opacity: 0.5;
87
+ cursor: not-allowed;
88
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import Button from './Button';
3
+
4
+ /**
5
+ * Example usage of Button component
6
+ */
7
+ const ButtonExample = () => {
8
+ const handleClick = () => {
9
+ console.log('Button clicked!');
10
+ };
11
+
12
+ return (
13
+ <div style={{ padding: '40px', display: 'flex', flexDirection: 'column', gap: '20px' }}>
14
+ <h2>Button Component Examples</h2>
15
+
16
+ <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
17
+ <h3 style={{ width: '100%' }}>Variants</h3>
18
+ <Button variant="primary" onClick={handleClick}>Primary Button</Button>
19
+ <Button variant="secondary" onClick={handleClick}>Secondary Button</Button>
20
+ <Button variant="success" onClick={handleClick}>Success Button</Button>
21
+ <Button variant="danger" onClick={handleClick}>Danger Button</Button>
22
+ </div>
23
+
24
+ <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
25
+ <h3 style={{ width: '100%' }}>Sizes</h3>
26
+ <Button size="small" onClick={handleClick}>Small</Button>
27
+ <Button size="medium" onClick={handleClick}>Medium</Button>
28
+ <Button size="large" onClick={handleClick}>Large</Button>
29
+ </div>
30
+
31
+ <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
32
+ <h3 style={{ width: '100%' }}>States</h3>
33
+ <Button onClick={handleClick}>Enabled</Button>
34
+ <Button disabled>Disabled</Button>
35
+ </div>
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default ButtonExample;
@@ -0,0 +1,29 @@
1
+ import React from 'react';
2
+ import './Button.css';
3
+
4
+ /**
5
+ * Button Component
6
+ * A customizable button component with various styles and states
7
+ */
8
+ const Button = ({
9
+ children,
10
+ variant = 'primary',
11
+ size = 'medium',
12
+ disabled = false,
13
+ onClick,
14
+ type = 'button',
15
+ className = ''
16
+ }) => {
17
+ return (
18
+ <button
19
+ type={type}
20
+ className={`btn btn-${variant} btn-${size} ${className}`}
21
+ disabled={disabled}
22
+ onClick={onClick}
23
+ >
24
+ {children}
25
+ </button>
26
+ );
27
+ };
28
+
29
+ export default Button;
@@ -0,0 +1,86 @@
1
+ /* Card Styles */
2
+ .card {
3
+ background: white;
4
+ border-radius: 12px;
5
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
6
+ overflow: hidden;
7
+ transition: all 0.3s ease;
8
+ cursor: pointer;
9
+ max-width: 400px;
10
+ }
11
+
12
+ .card:hover {
13
+ transform: translateY(-5px);
14
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.15);
15
+ }
16
+
17
+ .card-image {
18
+ width: 100%;
19
+ height: 200px;
20
+ overflow: hidden;
21
+ position: relative;
22
+ }
23
+
24
+ .card-image img {
25
+ width: 100%;
26
+ height: 100%;
27
+ object-fit: cover;
28
+ transition: transform 0.3s ease;
29
+ }
30
+
31
+ .card:hover .card-image img {
32
+ transform: scale(1.05);
33
+ }
34
+
35
+ .card-content {
36
+ padding: 24px;
37
+ }
38
+
39
+ .card-title {
40
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
41
+ font-size: 24px;
42
+ font-weight: 700;
43
+ margin: 0 0 12px 0;
44
+ color: #2d3748;
45
+ background: linear-gradient(135deg, {{primaryColor}} 0%, {{secondaryColor}} 100%);
46
+ -webkit-background-clip: text;
47
+ -webkit-text-fill-color: transparent;
48
+ background-clip: text;
49
+ }
50
+
51
+ .card-description {
52
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
53
+ font-size: 16px;
54
+ line-height: 1.6;
55
+ color: #4a5568;
56
+ margin: 0;
57
+ }
58
+
59
+ .card-footer {
60
+ padding: 16px 24px;
61
+ border-top: 1px solid #e2e8f0;
62
+ background: #f7fafc;
63
+ display: flex;
64
+ justify-content: space-between;
65
+ align-items: center;
66
+ }
67
+
68
+ /* Dark Mode Support */
69
+ @media (prefers-color-scheme: dark) {
70
+ .card {
71
+ background: #2d3748;
72
+ }
73
+
74
+ .card-title {
75
+ color: #e2e8f0;
76
+ }
77
+
78
+ .card-description {
79
+ color: #cbd5e0;
80
+ }
81
+
82
+ .card-footer {
83
+ background: #1a202c;
84
+ border-top-color: #4a5568;
85
+ }
86
+ }
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import Card from './Card';
3
+
4
+ /**
5
+ * Example usage of Card component
6
+ */
7
+ const CardExample = () => {
8
+ const handleCardClick = () => {
9
+ console.log('Card clicked!');
10
+ };
11
+
12
+ return (
13
+ <div style={{ padding: '40px', display: 'flex', gap: '20px', flexWrap: 'wrap' }}>
14
+ <Card
15
+ title="Beautiful Mountain"
16
+ description="Explore the breathtaking views of mountain landscapes and discover the beauty of nature."
17
+ image="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=200&fit=crop"
18
+ imageAlt="Mountain landscape"
19
+ footer={
20
+ <button style={{ padding: '8px 16px', background: '#3182ce', color: 'white', border: 'none', borderRadius: '6px' }}>
21
+ Learn More
22
+ </button>
23
+ }
24
+ onClick={handleCardClick}
25
+ />
26
+
27
+ <Card
28
+ title="Ocean Sunset"
29
+ description="Watch the sun set over the endless horizon and feel the peaceful ocean breeze."
30
+ image="https://images.unsplash.com/photo-1505142468610-359e7d316be0?w=400&h=200&fit=crop"
31
+ imageAlt="Ocean sunset"
32
+ footer={
33
+ <button style={{ padding: '8px 16px', background: '#3182ce', color: 'white', border: 'none', borderRadius: '6px' }}>
34
+ Learn More
35
+ </button>
36
+ }
37
+ onClick={handleCardClick}
38
+ />
39
+
40
+ <Card
41
+ title="Card Without Image"
42
+ description="This card demonstrates how the component looks without an image. It still maintains the same elegant design."
43
+ footer={<span style={{ color: '#718096' }}>No image variant</span>}
44
+ />
45
+ </div>
46
+ );
47
+ };
48
+
49
+ export default CardExample;
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import './Card.css';
3
+
4
+ /**
5
+ * Card Component
6
+ * A versatile card component for displaying content
7
+ */
8
+ const Card = ({
9
+ title,
10
+ description,
11
+ image,
12
+ imageAlt = '',
13
+ footer,
14
+ onClick,
15
+ className = '',
16
+ children
17
+ }) => {
18
+ return (
19
+ <div className={`card ${className}`} onClick={onClick}>
20
+ {image && (
21
+ <div className="card-image">
22
+ <img src={image} alt={imageAlt} />
23
+ </div>
24
+ )}
25
+ <div className="card-content">
26
+ {title && <h3 className="card-title">{title}</h3>}
27
+ {description && <p className="card-description">{description}</p>}
28
+ {children}
29
+ </div>
30
+ {footer && <div className="card-footer">{footer}</div>}
31
+ </div>
32
+ );
33
+ };
34
+
35
+ export default Card;