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.
- package/CHANGELOG.md +305 -0
- package/HTML-VS-REACT.md +289 -0
- package/QUICKSTART-REACT.md +293 -0
- package/REACT-SUPPORT-SUMMARY.md +235 -0
- package/README.md +193 -12
- package/bin/cli.js +98 -759
- package/bin/commands/create.js +272 -0
- package/bin/commands/gallery.js +42 -0
- package/bin/commands/insert.js +123 -0
- package/bin/commands/list.js +73 -0
- package/package.json +10 -3
- package/src/component-choices.js +7 -0
- package/src/components-registry.js +112 -0
- package/src/format-utils.js +49 -0
- package/src/generator.js +83 -594
- package/src/generators/color-schemes.js +78 -0
- package/src/generators/color-utils.js +108 -0
- package/src/generators/component-filters.js +151 -0
- package/src/generators/html-generators.js +180 -0
- package/src/generators/validation.js +43 -0
- package/src/index.js +2 -1
- package/src/inserter.js +55 -233
- package/src/inserters/backup-utils.js +20 -0
- package/src/inserters/component-loader.js +68 -0
- package/src/inserters/html-utils.js +31 -0
- package/src/inserters/indentation-utils.js +90 -0
- package/src/inserters/validation-utils.js +49 -0
- package/src/react-component-choices.js +45 -0
- package/src/react-file-operations.js +172 -0
- package/src/react-generator.js +208 -0
- package/src/react-templates.js +350 -0
- package/src/utils/file-utils.js +97 -0
- package/src/utils/path-utils.js +32 -0
- package/src/utils/string-utils.js +51 -0
- package/src/utils/template-loader.js +91 -0
- package/templates/_shared/PATTERNS.md +246 -0
- package/templates/_shared/README.md +74 -0
- package/templates/_shared/base.css +18 -0
- package/templates/blackjack/index.html +1 -1
- package/templates/blackjack/script.js +9 -9
- package/templates/breakout/index.html +1 -1
- package/templates/breakout/script.js +6 -6
- package/templates/connect-four/index.html +1 -1
- package/templates/connect-four/script.js +5 -5
- package/templates/dice-game/index.html +1 -1
- package/templates/dice-game/script.js +20 -20
- package/templates/flappy-bird/index.html +1 -1
- package/templates/flappy-bird/script.js +10 -10
- package/templates/pong/index.html +1 -1
- package/templates/pong/script.js +8 -8
- package/templates/skeleton/index.html +4 -4
- package/templates/slot-machine/index.html +1 -1
- package/templates/slot-machine/script.js +6 -6
- package/templates/tetris/index.html +1 -1
- package/templates/tetris/script.js +5 -5
- package/templates-react/README.md +126 -0
- package/templates-react/button/Button.css +88 -0
- package/templates-react/button/Button.example.jsx +40 -0
- package/templates-react/button/Button.jsx +29 -0
- package/templates-react/card/Card.css +86 -0
- package/templates-react/card/Card.example.jsx +49 -0
- package/templates-react/card/Card.jsx +35 -0
- package/templates-react/counter/Counter.css +99 -0
- package/templates-react/counter/Counter.example.jsx +45 -0
- package/templates-react/counter/Counter.jsx +70 -0
- package/templates-react/form/Form.css +128 -0
- package/templates-react/form/Form.example.jsx +65 -0
- package/templates-react/form/Form.jsx +125 -0
- package/templates-react/modal/Modal.css +152 -0
- package/templates-react/modal/Modal.example.jsx +90 -0
- package/templates-react/modal/Modal.jsx +46 -0
- package/templates-react/todo-list/TodoList.css +236 -0
- package/templates-react/todo-list/TodoList.example.jsx +15 -0
- package/templates-react/todo-list/TodoList.jsx +84 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Template Code Patterns
|
|
2
|
+
|
|
3
|
+
This document catalogs common code patterns found across templates. These patterns are intentionally duplicated in each template to maintain independence.
|
|
4
|
+
|
|
5
|
+
## JavaScript Patterns
|
|
6
|
+
|
|
7
|
+
### DOM Selection Patterns
|
|
8
|
+
|
|
9
|
+
**querySelector/querySelectorAll** - Used in 40+ templates
|
|
10
|
+
```javascript
|
|
11
|
+
const element = document.querySelector('.class-name');
|
|
12
|
+
const elements = document.querySelectorAll('.multiple-items');
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**getElementById** - Used in 35+ templates (especially games and interactive components)
|
|
16
|
+
```javascript
|
|
17
|
+
const button = document.getElementById('myButton');
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Event Listener Patterns
|
|
21
|
+
|
|
22
|
+
**Click Handlers** - Found in all interactive templates
|
|
23
|
+
```javascript
|
|
24
|
+
button.addEventListener('click', handleClick);
|
|
25
|
+
|
|
26
|
+
// Or inline
|
|
27
|
+
button.addEventListener('click', () => {
|
|
28
|
+
// Handle click
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Common Event Setup**
|
|
33
|
+
```javascript
|
|
34
|
+
// Multiple elements
|
|
35
|
+
buttons.forEach(button => {
|
|
36
|
+
button.addEventListener('click', handler);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Delegation pattern
|
|
40
|
+
document.addEventListener('click', function(e) {
|
|
41
|
+
if (e.target.matches('.selector')) {
|
|
42
|
+
// Handle
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Game Control Patterns
|
|
48
|
+
|
|
49
|
+
Found in 12 game templates (snake, tetris, pong, etc.):
|
|
50
|
+
```javascript
|
|
51
|
+
let gameActive = false;
|
|
52
|
+
let score = 0;
|
|
53
|
+
|
|
54
|
+
function startGame() {
|
|
55
|
+
gameActive = true;
|
|
56
|
+
score = 0;
|
|
57
|
+
// Initialize game
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function pauseGame() {
|
|
61
|
+
gameActive = false;
|
|
62
|
+
// Pause logic
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function resetGame() {
|
|
66
|
+
gameActive = false;
|
|
67
|
+
score = 0;
|
|
68
|
+
// Reset logic
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Button bindings
|
|
72
|
+
startBtn.addEventListener('click', startGame);
|
|
73
|
+
pauseBtn.addEventListener('click', pauseGame);
|
|
74
|
+
resetBtn.addEventListener('click', resetGame);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Update Display Pattern
|
|
78
|
+
|
|
79
|
+
Common in counters, scores, and dynamic content:
|
|
80
|
+
```javascript
|
|
81
|
+
function updateDisplay() {
|
|
82
|
+
element.textContent = value;
|
|
83
|
+
// Update other UI elements
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## CSS Patterns
|
|
88
|
+
|
|
89
|
+
### Layout Patterns
|
|
90
|
+
|
|
91
|
+
**Centered Container** (30+ templates)
|
|
92
|
+
```css
|
|
93
|
+
body {
|
|
94
|
+
display: flex;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
align-items: center;
|
|
97
|
+
min-height: 100vh;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.container {
|
|
101
|
+
background: white;
|
|
102
|
+
padding: 40px;
|
|
103
|
+
border-radius: 15px;
|
|
104
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Grid Layout** (15+ templates)
|
|
109
|
+
```css
|
|
110
|
+
.grid {
|
|
111
|
+
display: grid;
|
|
112
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
113
|
+
gap: 20px;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Flexbox Layout** (20+ templates)
|
|
118
|
+
```css
|
|
119
|
+
.flex-container {
|
|
120
|
+
display: flex;
|
|
121
|
+
gap: 15px;
|
|
122
|
+
flex-wrap: wrap;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Animation Patterns
|
|
127
|
+
|
|
128
|
+
**Hover Transitions** (35+ templates)
|
|
129
|
+
```css
|
|
130
|
+
.element {
|
|
131
|
+
transition: all 0.3s ease;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.element:hover {
|
|
135
|
+
transform: translateY(-5px);
|
|
136
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Fade Animations**
|
|
141
|
+
```css
|
|
142
|
+
@keyframes fadeIn {
|
|
143
|
+
from { opacity: 0; }
|
|
144
|
+
to { opacity: 1; }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.animated {
|
|
148
|
+
animation: fadeIn 0.5s ease-in-out;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Button Patterns
|
|
153
|
+
|
|
154
|
+
Found in 40+ templates:
|
|
155
|
+
```css
|
|
156
|
+
.btn {
|
|
157
|
+
padding: 12px 24px;
|
|
158
|
+
border: none;
|
|
159
|
+
border-radius: 8px;
|
|
160
|
+
cursor: pointer;
|
|
161
|
+
font-size: 16px;
|
|
162
|
+
transition: all 0.3s ease;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.btn:hover {
|
|
166
|
+
transform: translateY(-2px);
|
|
167
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.btn:active {
|
|
171
|
+
transform: translateY(0);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## HTML Patterns
|
|
176
|
+
|
|
177
|
+
### Semantic Structure
|
|
178
|
+
|
|
179
|
+
**Container → Card → Content** (25+ templates)
|
|
180
|
+
```html
|
|
181
|
+
<div class="container">
|
|
182
|
+
<div class="card">
|
|
183
|
+
<h1>Title</h1>
|
|
184
|
+
<p>Content</p>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Form Structure** (form, login, register templates)
|
|
190
|
+
```html
|
|
191
|
+
<form class="form">
|
|
192
|
+
<h1 class="form-title">Title</h1>
|
|
193
|
+
<div class="form-group">
|
|
194
|
+
<label for="input">Label</label>
|
|
195
|
+
<input type="text" id="input" name="input">
|
|
196
|
+
</div>
|
|
197
|
+
<button type="submit">Submit</button>
|
|
198
|
+
</form>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Canvas for Games (10 game templates)
|
|
202
|
+
```html
|
|
203
|
+
<canvas id="gameCanvas" width="400" height="400"></canvas>
|
|
204
|
+
<div class="game-controls">
|
|
205
|
+
<button id="startBtn">Start</button>
|
|
206
|
+
<button id="pauseBtn">Pause</button>
|
|
207
|
+
<button id="resetBtn">Reset</button>
|
|
208
|
+
</div>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Why These Patterns Repeat
|
|
212
|
+
|
|
213
|
+
1. **Consistency**: Users recognize familiar patterns across templates
|
|
214
|
+
2. **Learning**: Patterns reinforce best practices
|
|
215
|
+
3. **Copy-Paste Ready**: Each template works standalone
|
|
216
|
+
4. **No Dependencies**: No shared libraries to break
|
|
217
|
+
|
|
218
|
+
## Best Practices for New Templates
|
|
219
|
+
|
|
220
|
+
When creating new templates, follow these patterns:
|
|
221
|
+
|
|
222
|
+
✅ **DO**:
|
|
223
|
+
- Use semantic HTML5 elements
|
|
224
|
+
- Include comprehensive comments
|
|
225
|
+
- Follow existing naming conventions
|
|
226
|
+
- Keep JavaScript vanilla (no frameworks)
|
|
227
|
+
- Make it work without any build process
|
|
228
|
+
|
|
229
|
+
❌ **DON'T**:
|
|
230
|
+
- Import from other templates
|
|
231
|
+
- Require external libraries (unless clearly documented)
|
|
232
|
+
- Use complex build tools
|
|
233
|
+
- Break the self-contained principle
|
|
234
|
+
|
|
235
|
+
## Statistics
|
|
236
|
+
|
|
237
|
+
- **Total Templates**: 42
|
|
238
|
+
- **JavaScript Files**: 42
|
|
239
|
+
- **CSS Files**: 42
|
|
240
|
+
- **HTML Files**: 42
|
|
241
|
+
- **Average File Size**: ~150 lines per file
|
|
242
|
+
- **Common Patterns**: 15+ recurring patterns across templates
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
*These patterns ensure consistency while maintaining template independence.*
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Shared Template Resources
|
|
2
|
+
|
|
3
|
+
This directory contains shared resources and documentation for templates.
|
|
4
|
+
|
|
5
|
+
## Philosophy: Self-Contained Templates
|
|
6
|
+
|
|
7
|
+
**Each template is intentionally self-contained and standalone.** This means:
|
|
8
|
+
- ✅ Every template includes its own complete HTML, CSS, and JS
|
|
9
|
+
- ✅ No external dependencies between templates
|
|
10
|
+
- ✅ Users can copy a single template folder and it "just works"
|
|
11
|
+
- ✅ Perfect for learning, prototyping, and quick integration
|
|
12
|
+
|
|
13
|
+
## Why Not Use Shared CSS?
|
|
14
|
+
|
|
15
|
+
While we have `base.css` with common styles, **we deliberately duplicate** them in each template because:
|
|
16
|
+
|
|
17
|
+
1. **Portability**: Users can grab one folder and go
|
|
18
|
+
2. **Independence**: No broken links if files are moved
|
|
19
|
+
3. **Customization**: Users can modify without affecting others
|
|
20
|
+
4. **Simplicity**: No build process or import management needed
|
|
21
|
+
|
|
22
|
+
## Common Patterns (For Reference)
|
|
23
|
+
|
|
24
|
+
### CSS Reset (42/42 templates)
|
|
25
|
+
```css
|
|
26
|
+
* {
|
|
27
|
+
margin: 0;
|
|
28
|
+
padding: 0;
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Gradient Body (37/42 templates)
|
|
34
|
+
```css
|
|
35
|
+
body {
|
|
36
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
37
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
38
|
+
min-height: 100vh;
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Common Container Pattern
|
|
43
|
+
```css
|
|
44
|
+
.container {
|
|
45
|
+
background: white;
|
|
46
|
+
padding: 40px;
|
|
47
|
+
border-radius: 15px;
|
|
48
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Files
|
|
53
|
+
|
|
54
|
+
### base.css
|
|
55
|
+
Reference implementation of common CSS patterns. Use this as a template when creating new components.
|
|
56
|
+
|
|
57
|
+
## Creating New Templates
|
|
58
|
+
|
|
59
|
+
When adding new templates:
|
|
60
|
+
1. Copy the full CSS reset and base styles (don't import)
|
|
61
|
+
2. Follow existing naming conventions
|
|
62
|
+
3. Keep it self-contained
|
|
63
|
+
4. Test that the folder works in isolation
|
|
64
|
+
|
|
65
|
+
## Statistics
|
|
66
|
+
|
|
67
|
+
- **Total Templates**: 42
|
|
68
|
+
- **Templates with CSS Reset**: 42 (100%)
|
|
69
|
+
- **Templates with Gradient Background**: 37 (88%)
|
|
70
|
+
- **Duplication is intentional** for better user experience
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
*Note: This duplication is a feature, not a bug. It optimizes for end-user experience over DRY principles.*
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CSS Reset and Base Styles
|
|
3
|
+
* This file contains common styles used across all templates
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* CSS Reset */
|
|
7
|
+
* {
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Base Body Styles - Common gradient background and font */
|
|
14
|
+
body {
|
|
15
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
}
|
|
@@ -156,7 +156,7 @@ document.querySelectorAll('.bet-btn').forEach(btn => {
|
|
|
156
156
|
updateDisplay();
|
|
157
157
|
document.getElementById('dealBtn').disabled = false;
|
|
158
158
|
} else {
|
|
159
|
-
showMessage('
|
|
159
|
+
showMessage('Not enough credits!', 'error');
|
|
160
160
|
}
|
|
161
161
|
});
|
|
162
162
|
});
|
|
@@ -166,7 +166,7 @@ document.getElementById('dealBtn').addEventListener('click', startGame);
|
|
|
166
166
|
|
|
167
167
|
function startGame() {
|
|
168
168
|
if (gameState.currentBet === 0) {
|
|
169
|
-
showMessage('
|
|
169
|
+
showMessage('Choose a bet first!', 'error');
|
|
170
170
|
return;
|
|
171
171
|
}
|
|
172
172
|
|
|
@@ -261,7 +261,7 @@ document.getElementById('doubleBtn').addEventListener('click', () => {
|
|
|
261
261
|
stand();
|
|
262
262
|
}
|
|
263
263
|
} else {
|
|
264
|
-
showMessage('
|
|
264
|
+
showMessage('Not enough credits to double down!', 'error');
|
|
265
265
|
}
|
|
266
266
|
});
|
|
267
267
|
|
|
@@ -301,23 +301,23 @@ function endGame(result) {
|
|
|
301
301
|
switch (result) {
|
|
302
302
|
case 'blackjack':
|
|
303
303
|
winAmount = Math.floor(gameState.currentBet * 2.5); // 3:2 payout
|
|
304
|
-
message = '🎉 BLACKJACK!
|
|
304
|
+
message = '🎉 BLACKJACK! You win!';
|
|
305
305
|
gameState.wins++;
|
|
306
306
|
break;
|
|
307
307
|
case 'win':
|
|
308
308
|
winAmount = gameState.currentBet * 2;
|
|
309
|
-
message = '🎉
|
|
309
|
+
message = '🎉 You won!';
|
|
310
310
|
gameState.wins++;
|
|
311
311
|
break;
|
|
312
312
|
case 'lose':
|
|
313
|
-
message = '😢
|
|
313
|
+
message = '😢 You lost!';
|
|
314
314
|
break;
|
|
315
315
|
case 'push':
|
|
316
316
|
winAmount = gameState.currentBet;
|
|
317
|
-
message = '🤝
|
|
317
|
+
message = '🤝 Push!';
|
|
318
318
|
break;
|
|
319
319
|
case 'bust':
|
|
320
|
-
message = '💥
|
|
320
|
+
message = '💥 Busted! You lost!';
|
|
321
321
|
break;
|
|
322
322
|
}
|
|
323
323
|
|
|
@@ -337,7 +337,7 @@ function endGame(result) {
|
|
|
337
337
|
// Check if out of credits
|
|
338
338
|
if (gameState.credits < 10) {
|
|
339
339
|
setTimeout(() => {
|
|
340
|
-
alert('
|
|
340
|
+
alert('Out of credits! Receiving 1000 new credits.');
|
|
341
341
|
gameState.credits = 1000;
|
|
342
342
|
updateDisplay();
|
|
343
343
|
saveGame();
|
|
@@ -263,11 +263,11 @@ function gameOver() {
|
|
|
263
263
|
ctx.fillStyle = '#FFFFFF';
|
|
264
264
|
ctx.font = 'bold 48px Arial';
|
|
265
265
|
ctx.textAlign = 'center';
|
|
266
|
-
ctx.fillText('
|
|
266
|
+
ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2 - 40);
|
|
267
267
|
|
|
268
268
|
ctx.font = '24px Arial';
|
|
269
|
-
ctx.fillText(
|
|
270
|
-
ctx.fillText('
|
|
269
|
+
ctx.fillText(`Final Score: ${gameState.score}`, canvas.width / 2, canvas.height / 2 + 20);
|
|
270
|
+
ctx.fillText('Click "Reset" to restart', canvas.width / 2, canvas.height / 2 + 60);
|
|
271
271
|
|
|
272
272
|
document.getElementById('startBtn').disabled = false;
|
|
273
273
|
document.getElementById('pauseBtn').disabled = true;
|
|
@@ -306,7 +306,7 @@ function draw() {
|
|
|
306
306
|
ctx.fillStyle = '#FFFFFF';
|
|
307
307
|
ctx.font = 'bold 36px Arial';
|
|
308
308
|
ctx.textAlign = 'center';
|
|
309
|
-
ctx.fillText('
|
|
309
|
+
ctx.fillText('Game Paused', canvas.width / 2, canvas.height / 2);
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
|
|
@@ -349,7 +349,7 @@ function startGame() {
|
|
|
349
349
|
// Pause game
|
|
350
350
|
function pauseGame() {
|
|
351
351
|
gameState.paused = !gameState.paused;
|
|
352
|
-
document.getElementById('pauseBtn').textContent = gameState.paused ? '
|
|
352
|
+
document.getElementById('pauseBtn').textContent = gameState.paused ? 'Resume' : 'Pause';
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
// Reset game
|
|
@@ -372,7 +372,7 @@ function resetGame() {
|
|
|
372
372
|
|
|
373
373
|
document.getElementById('startBtn').disabled = false;
|
|
374
374
|
document.getElementById('pauseBtn').disabled = true;
|
|
375
|
-
document.getElementById('pauseBtn').textContent = '
|
|
375
|
+
document.getElementById('pauseBtn').textContent = 'Pause';
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
// Event listeners
|
|
@@ -331,15 +331,15 @@ function endGame(winner) {
|
|
|
331
331
|
gameState.score1++;
|
|
332
332
|
localStorage.setItem('connect4Score1', gameState.score1);
|
|
333
333
|
updateScore();
|
|
334
|
-
showMessage('🎉
|
|
334
|
+
showMessage('🎉 Player 1 wins!', 'player1');
|
|
335
335
|
} else if (winner === PLAYER2) {
|
|
336
336
|
gameState.score2++;
|
|
337
337
|
localStorage.setItem('connect4Score2', gameState.score2);
|
|
338
338
|
updateScore();
|
|
339
|
-
const message = gameState.gameMode === 'pvc' ? '🤖
|
|
339
|
+
const message = gameState.gameMode === 'pvc' ? '🤖 Computer wins!' : '🎉 Player 2 wins!';
|
|
340
340
|
showMessage(message, 'player2');
|
|
341
341
|
} else {
|
|
342
|
-
showMessage('🤝
|
|
342
|
+
showMessage('🤝 Draw!', 'draw');
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|
|
@@ -354,10 +354,10 @@ function showMessage(text, type) {
|
|
|
354
354
|
function updateTurnIndicator() {
|
|
355
355
|
const turnIndicator = document.getElementById('turnIndicator');
|
|
356
356
|
if (gameState.currentPlayer === PLAYER1) {
|
|
357
|
-
turnIndicator.textContent = '
|
|
357
|
+
turnIndicator.textContent = 'Player 1\'s Turn';
|
|
358
358
|
turnIndicator.className = 'player1-turn';
|
|
359
359
|
} else {
|
|
360
|
-
const text = gameState.gameMode === 'pvc' ? '
|
|
360
|
+
const text = gameState.gameMode === 'pvc' ? 'Computer\'s Turn' : 'Player 2\'s Turn';
|
|
361
361
|
turnIndicator.textContent = text;
|
|
362
362
|
turnIndicator.className = 'player2-turn';
|
|
363
363
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Game state
|
|
2
2
|
let gameState = {
|
|
3
3
|
players: [
|
|
4
|
-
{ total: 0, current: 0, name: '
|
|
5
|
-
{ total: 0, current: 0, name: '
|
|
4
|
+
{ total: 0, current: 0, name: 'Player 1' },
|
|
5
|
+
{ total: 0, current: 0, name: 'Player 2' }
|
|
6
6
|
],
|
|
7
7
|
currentPlayer: 0,
|
|
8
8
|
gameActive: true,
|
|
@@ -34,13 +34,13 @@ function updateDisplay() {
|
|
|
34
34
|
if (gameState.currentPlayer === 0) {
|
|
35
35
|
player1Card.classList.add('active');
|
|
36
36
|
player2Card.classList.remove('active');
|
|
37
|
-
player1Card.querySelector('.current-turn').textContent = '
|
|
38
|
-
player2Card.querySelector('.current-turn').textContent = '
|
|
37
|
+
player1Card.querySelector('.current-turn').textContent = 'Your Turn!';
|
|
38
|
+
player2Card.querySelector('.current-turn').textContent = 'Wait...';
|
|
39
39
|
} else {
|
|
40
40
|
player1Card.classList.remove('active');
|
|
41
41
|
player2Card.classList.add('active');
|
|
42
|
-
player1Card.querySelector('.current-turn').textContent = '
|
|
43
|
-
player2Card.querySelector('.current-turn').textContent = gameState.gameMode === 'pvc' ? '
|
|
42
|
+
player1Card.querySelector('.current-turn').textContent = 'Wait...';
|
|
43
|
+
player2Card.querySelector('.current-turn').textContent = gameState.gameMode === 'pvc' ? 'Computer\'s Turn...' : 'Your Turn!';
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -96,7 +96,7 @@ document.getElementById('rollBtn').addEventListener('click', async () => {
|
|
|
96
96
|
if (roll === 1) {
|
|
97
97
|
// Lost turn
|
|
98
98
|
gameState.players[gameState.currentPlayer].current = 0;
|
|
99
|
-
showMessage(`💥
|
|
99
|
+
showMessage(`💥 Rolled 1! You lost all turn points!`, 'error');
|
|
100
100
|
|
|
101
101
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
102
102
|
switchPlayer();
|
|
@@ -104,7 +104,7 @@ document.getElementById('rollBtn').addEventListener('click', async () => {
|
|
|
104
104
|
// Add to current
|
|
105
105
|
gameState.players[gameState.currentPlayer].current += roll;
|
|
106
106
|
updateDisplay();
|
|
107
|
-
showMessage(`🎲
|
|
107
|
+
showMessage(`🎲 Rolled ${roll}!`, 'info');
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
|
|
@@ -115,7 +115,7 @@ document.getElementById('holdBtn').addEventListener('click', () => {
|
|
|
115
115
|
const player = gameState.players[gameState.currentPlayer];
|
|
116
116
|
|
|
117
117
|
if (player.current === 0) {
|
|
118
|
-
showMessage('
|
|
118
|
+
showMessage('Nothing to save! Roll the dice first.', 'error');
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -128,7 +128,7 @@ document.getElementById('holdBtn').addEventListener('click', () => {
|
|
|
128
128
|
if (player.total >= 100) {
|
|
129
129
|
endGame();
|
|
130
130
|
} else {
|
|
131
|
-
showMessage(`✅
|
|
131
|
+
showMessage(`✅ Saved! ${player.total} points total.`, 'success');
|
|
132
132
|
setTimeout(() => {
|
|
133
133
|
switchPlayer();
|
|
134
134
|
}, 1000);
|
|
@@ -161,7 +161,7 @@ async function computerTurn() {
|
|
|
161
161
|
|
|
162
162
|
if (roll === 1) {
|
|
163
163
|
player.current = 0;
|
|
164
|
-
showMessage(`🤖
|
|
164
|
+
showMessage(`🤖 Computer rolled 1! Lost the turn!`, 'error');
|
|
165
165
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
166
166
|
switchPlayer();
|
|
167
167
|
return;
|
|
@@ -169,7 +169,7 @@ async function computerTurn() {
|
|
|
169
169
|
|
|
170
170
|
player.current += roll;
|
|
171
171
|
updateDisplay();
|
|
172
|
-
showMessage(`🤖
|
|
172
|
+
showMessage(`🤖 Computer rolled ${roll}!`, 'info');
|
|
173
173
|
|
|
174
174
|
// AI decision logic
|
|
175
175
|
const shouldHold =
|
|
@@ -189,7 +189,7 @@ async function computerTurn() {
|
|
|
189
189
|
return;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
showMessage(`🤖
|
|
192
|
+
showMessage(`🤖 Computer saves ${player.total} points!`, 'success');
|
|
193
193
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
194
194
|
switchPlayer();
|
|
195
195
|
return;
|
|
@@ -203,10 +203,10 @@ function endGame() {
|
|
|
203
203
|
|
|
204
204
|
const winner = gameState.players[gameState.currentPlayer];
|
|
205
205
|
const winnerName = gameState.currentPlayer === 0 ?
|
|
206
|
-
'
|
|
207
|
-
(gameState.gameMode === 'pvc' ? '
|
|
206
|
+
'Player 1' :
|
|
207
|
+
(gameState.gameMode === 'pvc' ? 'Computer' : 'Player 2');
|
|
208
208
|
|
|
209
|
-
showMessage(`🎉 ${winnerName}
|
|
209
|
+
showMessage(`🎉 ${winnerName} won with ${winner.total} points!`, 'success');
|
|
210
210
|
|
|
211
211
|
// Celebrate
|
|
212
212
|
celebrate();
|
|
@@ -217,8 +217,8 @@ document.getElementById('newGameBtn').addEventListener('click', newGame);
|
|
|
217
217
|
|
|
218
218
|
function newGame() {
|
|
219
219
|
gameState.players = [
|
|
220
|
-
{ total: 0, current: 0, name: '
|
|
221
|
-
{ total: 0, current: 0, name: '
|
|
220
|
+
{ total: 0, current: 0, name: 'Player 1' },
|
|
221
|
+
{ total: 0, current: 0, name: 'Player 2' }
|
|
222
222
|
];
|
|
223
223
|
gameState.currentPlayer = 0;
|
|
224
224
|
gameState.gameActive = true;
|
|
@@ -241,9 +241,9 @@ document.querySelectorAll('.mode-btn').forEach(btn => {
|
|
|
241
241
|
|
|
242
242
|
// Update player 2 name
|
|
243
243
|
if (gameState.gameMode === 'pvc') {
|
|
244
|
-
document.querySelector('#player2Card h3').textContent = '🤖
|
|
244
|
+
document.querySelector('#player2Card h3').textContent = '🤖 Computer';
|
|
245
245
|
} else {
|
|
246
|
-
document.querySelector('#player2Card h3').textContent = '👤
|
|
246
|
+
document.querySelector('#player2Card h3').textContent = '👤 Player 2';
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
newGame();
|