eaglelandsonce commited on
Commit
d015e88
·
verified ·
1 Parent(s): a5d4671

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +348 -18
index.html CHANGED
@@ -1,19 +1,349 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8"/>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>Terraform Jeopardy</title>
7
+ <style>
8
+ :root{
9
+ --blue:#0a49a6;
10
+ --blue-dark:#073a84;
11
+ --gold:#ffd24a;
12
+ --board-gap:10px;
13
+ --card-depth:28px;
14
+ }
15
+ *{box-sizing:border-box}
16
+ body{
17
+ font-family: system-ui, Arial, sans-serif;
18
+ display:flex;flex-direction:column;align-items:center;
19
+ background: radial-gradient(1200px 700px at 50% -200px, #f2f6ff 0%, #e9efff 30%, #cfdafc 100%) fixed;
20
+ margin:0; min-height:100vh;
21
+ }
22
+ h1{ color:#173e8c; margin:22px 0 6px; text-shadow:0 2px 0 #fff;}
23
+ a.source{ font-size:14px; color:#334; margin-bottom:8px; text-decoration:none}
24
+ a.source:hover{ text-decoration:underline }
25
+
26
+ /* 3D Stage */
27
+ .stage{
28
+ perspective: 1200px;
29
+ width:min(1100px, 95vw);
30
+ }
31
+
32
+ #game-board{
33
+ display:grid;
34
+ grid-template-columns: repeat(5, 1fr);
35
+ grid-auto-rows: 120px;
36
+ gap: var(--board-gap);
37
+ padding: var(--board-gap);
38
+ border-radius:18px;
39
+ background: linear-gradient(180deg, #0e1a3a, #01060f);
40
+ box-shadow:
41
+ 0 20px 45px rgba(0,0,0,.35),
42
+ inset 0 0 0 4px #000;
43
+ transform: rotateX(8deg);
44
+ transform-origin: top center;
45
+ }
46
+
47
+ .category, .card{
48
+ position:relative;
49
+ border-radius:14px;
50
+ user-select:none;
51
+ transform-style: preserve-3d;
52
+ transition: transform .2s ease, box-shadow .2s ease, filter .2s ease;
53
+ box-shadow:
54
+ 0 var(--card-depth) calc(var(--card-depth) + 12px) rgba(0,0,0,.35),
55
+ inset 0 0 0 1px rgba(255,255,255,.15);
56
+ }
57
+
58
+ .category{
59
+ background: linear-gradient(180deg, #004fbf 0%, #003d93 60%, #003684 100%);
60
+ color:#fff; font-weight:800; text-transform:uppercase; letter-spacing:.3px;
61
+ display:flex; justify-content:center; align-items:center; text-align:center;
62
+ border:1px solid #00122c;
63
+ text-shadow:0 2px 0 rgba(0,0,0,.35);
64
+ }
65
+
66
+ .card{
67
+ cursor:pointer; font-weight:900; color: var(--gold);
68
+ background:
69
+ radial-gradient(80% 80% at 50% 25%, rgba(255,255,255,.18), rgba(255,255,255,0) 60%),
70
+ linear-gradient(180deg, var(--blue) 0%, var(--blue-dark) 100%);
71
+ border:1px solid #031b3f;
72
+ display:flex; justify-content:center; align-items:center; text-align:center;
73
+ font-size: clamp(16px, 2.4vw, 26px);
74
+ text-shadow: 0 2px 0 #000, 0 0 10px rgba(255,210,74,.35);
75
+ }
76
+
77
+ /* 3D hover tilt + press */
78
+ .card.tilt:hover{
79
+ transform: translateZ(10px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));
80
+ box-shadow:
81
+ 0 24px 48px rgba(0,0,0,.4),
82
+ 0 0 24px rgba(255,210,74,.15),
83
+ inset 0 0 0 1px rgba(255,255,255,.18);
84
+ filter: saturate(1.1);
85
+ }
86
+ .card:active{
87
+ transform: translateZ(0) scale(.985);
88
+ box-shadow: 0 12px 18px rgba(0,0,0,.45), inset 0 0 0 1px rgba(255,255,255,.12);
89
+ }
90
+
91
+ .card.disabled{
92
+ cursor:default; color:#bfc7da;
93
+ background: linear-gradient(180deg,#6b7aa6,#4e5b85);
94
+ text-shadow:none; filter:grayscale(.2) brightness(.92);
95
+ }
96
+
97
+ #question-display{ width:min(1000px, 92vw); text-align:center; margin:16px 0 6px; }
98
+ #question-display h2{ margin:8px 0 6px; color:#0d2b6f }
99
+ #question-display p{ margin:8px 0 }
100
+ #score{ font-size:24px; font-weight:800; color:#0d2b6f; margin-bottom:24px }
101
+
102
+ .answer-container{ display:flex; justify-content:center; flex-wrap:wrap; gap:10px; margin-top:14px }
103
+ .answer-btn{
104
+ margin:0; padding:10px 16px; font-size:18px; cursor:pointer;
105
+ border:2px solid #0d3a85; border-radius:10px; font-weight:800; color:#fff;
106
+ background: linear-gradient(180deg,#1362ff,#0d3a85);
107
+ box-shadow: 0 8px 18px rgba(0,0,0,.25);
108
+ transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
109
+ }
110
+ .answer-btn:hover{ transform: translateY(-2px); box-shadow:0 12px 26px rgba(0,0,0,.28) }
111
+ .answer-btn:active{ transform: translateY(0); box-shadow:0 8px 18px rgba(0,0,0,.25) }
112
+ .answer-btn.disabled{ background:#aab4cc; color:#445; cursor:not-allowed; border-color:#889 }
113
+
114
+ .feedback{ margin-top:10px; font-size:18px; font-weight:800 }
115
+
116
+ /* DAILY DOUBLE overlay + flashing */
117
+ .dd-overlay{
118
+ position: fixed; inset:0; display:none; align-items:center; justify-content:center;
119
+ z-index: 9999; pointer-events:none;
120
+ background: radial-gradient(60% 60% at 50% 50%, rgba(255,255,255,.08), rgba(0,0,0,.7));
121
+ animation: dd-bg 1.2s ease-in-out 2;
122
+ }
123
+ .dd-text{
124
+ font-size: clamp(40px, 7vw, 120px);
125
+ font-weight: 900; color:#ffe17a; letter-spacing:2px;
126
+ text-shadow:
127
+ 0 0 12px rgba(255,225,122,.9),
128
+ 0 0 40px rgba(255,225,122,.6),
129
+ 0 6px 0 #000;
130
+ animation: flash 1.2s steps(2, jump-none) 2, wobble .9s ease-in-out 2;
131
+ }
132
+ @keyframes flash{
133
+ 0%, 49% { opacity:1; filter:drop-shadow(0 0 24px rgba(255,225,122,.85)); }
134
+ 50%, 100% { opacity:0; filter:none; }
135
+ }
136
+ @keyframes wobble{
137
+ 0%{ transform: scale(1) rotate(0deg) }
138
+ 50%{ transform: scale(1.06) rotate(-2deg) }
139
+ 100%{ transform: scale(1) rotate(0deg) }
140
+ }
141
+ @keyframes dd-bg{
142
+ 0%{ background: radial-gradient(40% 40% at 50% 50%, rgba(255,255,255,.12), rgba(0,0,0,.9)); }
143
+ 100%{ background: radial-gradient(60% 60% at 50% 50%, rgba(255,255,255,.08), rgba(0,0,0,.7)); }
144
+ }
145
+
146
+ /* Card flash ring */
147
+ .flash-ring{
148
+ position:absolute; inset:-3px; border-radius:14px; pointer-events:none;
149
+ box-shadow:0 0 0 3px rgba(255,225,122,.95), 0 0 30px 6px rgba(255,225,122,.6);
150
+ animation: ring 1.2s ease-in-out 2;
151
+ }
152
+ @keyframes ring{
153
+ 0%{ opacity:1; transform: scale(1) }
154
+ 50%{ opacity:.1; transform: scale(0.96) }
155
+ 100%{ opacity:1; transform: scale(1) }
156
+ }
157
+
158
+ .daily-double-banner{ color:#b30000; font-weight:900; font-size:22px; margin:8px 0 }
159
+ </style>
160
+ </head>
161
+ <body>
162
+ <h1>Terraform Jeopardy</h1>
163
+ <a class="source" href="https://learn.microsoft.com/en-us/training/modules/terraform-introduction-to-infrastructure-as-code/2-what-infrastructure-code" target="_blank">
164
+ Source: Terraform Introduction to Infrastructure as Code
165
+ </a>
166
+
167
+ <div class="stage">
168
+ <div id="game-board">
169
+ <div class="category">IaC Benefits</div>
170
+ <div class="category">Declarative vs Imperative</div>
171
+ <div class="category">Terraform Overview</div>
172
+ <div class="category">State & Providers</div>
173
+ <div class="category">Workflow & Testing</div>
174
+ <!-- cards will be injected -->
175
+ </div>
176
+ </div>
177
+
178
+ <div id="question-display"></div>
179
+ <div id="score">Score: 0</div>
180
+
181
+ <!-- Daily Double audio: place daily-double.mp3 next to this file or swap the src -->
182
+ <audio id="dd-audio" preload="auto">
183
+ <source src="daily-double.mp3" type="audio/mpeg">
184
+ </audio>
185
+
186
+ <!-- Flashing overlay -->
187
+ <div id="dd-overlay" class="dd-overlay"><div class="dd-text">DAILY&nbsp;DOUBLE!</div></div>
188
+
189
+ <script>
190
+ const categories = ["IaC Benefits", "Declarative vs Imperative", "Terraform Overview", "State & Providers", "Workflow & Testing"];
191
+ const questions = [
192
+ [
193
+ { q: "Infrastructure as Code helps reduce manual errors and enforce consistency. That is known as?", a: ["Version control", "Infrastructure drift", "Idempotence"], correct: 2 },
194
+ { q: "IaC enables rapid provisioning of multiple environments on demand. That is ideal for what?", a: ["Automation", "Drift", "Manual setup"], correct: 0 },
195
+ { q: "Tracking infrastructure via code delivers faster deployment and higher ___?", a: ["Cost", "Reliability", "Unpredictability"], correct: 1 }
196
+ ],
197
+ [
198
+ { q: "Declarative IaC describes what you want. Imperative IaC describes how to get it. Which describes desired state?", a: ["Declarative", "Imperative", "Procedural"], correct: 0 },
199
+ { q: "Terraform uses which approach for configuration?", a: ["Imperative scripting", "Declarative HCL", "Manual CLI"], correct: 1 },
200
+ { q: "Imperative IaC requires specifying each deployment step. That is more?", a: ["Flexible", "Complex", "Consistent"], correct: 1 }
201
+ ],
202
+ [
203
+ { q: "Terraform is an open-source tool created by?", a: ["Microsoft", "HashiCorp", "Google"], correct: 1 },
204
+ { q: "Terraform supports multiple cloud providers like AWS, Azure, GCP. This makes it?", a: ["Cloud-specific", "Multi-cloud", "Legacy"], correct: 1 },
205
+ { q: "Terraform files are written in HCL or optionally JSON for describing state. True or False?", a: ["True", "False", "Depends"], correct: 0 }
206
+ ],
207
+ [
208
+ { q: "Terraform keeps track of real infrastructure in a ___ file to manage changes.", a: ["Plan", "State", "Config"], correct: 1 },
209
+ { q: "Providers are plugins that let Terraform interact with cloud APIs. Which is an Azure provider?", a: ["AWSRM", "AzureRM", "GCPRM"], correct: 1 },
210
+ { q: "Remote state storage backend is recommended to support?", a: ["Team collaboration", "Single use", "Offline mode"], correct: 0 }
211
+ ],
212
+ [
213
+ { q: "What Terraform command previews changes before applying?", a: ["terraform plan", "terraform apply", "terraform init"], correct: 0 },
214
+ { q: "Integration and unit tests for Terraform might include static lint and validate steps. True?", a: ["True", "False", "Not required"], correct: 0 },
215
+ { q: "End-to-end tests typically deploy to a test environment, validate, then ___ it down.", a: ["Suspend", "Destroy", "Pause"], correct: 1 }
216
+ ]
217
+ ];
218
+
219
+ let score = 0, answered = 0, total = 15;
220
+ const board = document.getElementById("game-board"),
221
+ qdisp = document.getElementById("question-display"),
222
+ sdisp = document.getElementById("score");
223
+ const ddOverlay = document.getElementById("dd-overlay");
224
+ const ddAudio = document.getElementById("dd-audio");
225
+
226
+ // Random Daily Double location
227
+ const dailyDouble = { col: Math.floor(Math.random() * 5), row: Math.floor(Math.random() * 3) };
228
+
229
+ function createBoard() {
230
+ // inject 3 rows x 5 cols of cards after the 5 category headers
231
+ for (let row = 0; row < 3; row++) {
232
+ for (let col = 0; col < 5; col++) {
233
+ const card = document.createElement("div");
234
+ card.className = "card tilt";
235
+ card.textContent = `$${(row + 1) * 100}`;
236
+ // store coordinates on the node
237
+ card.dataset.col = col;
238
+ card.dataset.row = row;
239
+
240
+ // 3D hover tilt via mouse position
241
+ card.addEventListener("mousemove", (e) => {
242
+ const r = card.getBoundingClientRect();
243
+ const x = (e.clientX - r.left) / r.width; // 0..1
244
+ const y = (e.clientY - r.top) / r.height; // 0..1
245
+ const ry = (x - 0.5) * 10; // deg
246
+ const rx = (0.5 - y) * 10; // deg
247
+ card.style.setProperty("--ry", `${ry}deg`);
248
+ card.style.setProperty("--rx", `${rx}deg`);
249
+ });
250
+ card.addEventListener("mouseleave", () => {
251
+ card.style.removeProperty("--ry");
252
+ card.style.removeProperty("--rx");
253
+ });
254
+
255
+ card.onclick = () => handleCardClick(card);
256
+ board.appendChild(card);
257
+ }
258
+ }
259
+ }
260
+
261
+ function handleCardClick(card){
262
+ if (card.classList.contains("disabled")) return;
263
+ const col = +card.dataset.col;
264
+ const row = +card.dataset.row;
265
+ const isDD = (col === dailyDouble.col && row === dailyDouble.row);
266
+
267
+ if (isDD){
268
+ triggerDailyDouble(card, () => showQuestion(col, row, card, true));
269
+ } else {
270
+ showQuestion(col, row, card, false);
271
+ }
272
+ }
273
+
274
+ function triggerDailyDouble(card, onDone){
275
+ // visual ring on the card
276
+ const ring = document.createElement("div");
277
+ ring.className = "flash-ring";
278
+ card.appendChild(ring);
279
+
280
+ // try playing audio (may require user interaction—click qualifies)
281
+ ddAudio.currentTime = 0;
282
+ ddAudio.play().catch(()=>{ /* ignore autoplay blocks */ });
283
+
284
+ // big overlay
285
+ ddOverlay.style.display = "flex";
286
+
287
+ // after strobe finishes (~1.2s x2), continue
288
+ setTimeout(() => {
289
+ ddOverlay.style.display = "none";
290
+ ring.remove();
291
+ onDone();
292
+ }, 2400);
293
+ }
294
+
295
+ function showQuestion(categoryIndex, difficulty, card, isDailyDouble){
296
+ const q = questions[categoryIndex][difficulty];
297
+
298
+ // shuffle answers
299
+ let answerOptions = q.a.map((ans, idx) => ({ text: ans, isCorrect: idx === q.correct }));
300
+ for (let i = answerOptions.length - 1; i > 0; i--) {
301
+ const j = Math.floor(Math.random() * (i + 1));
302
+ [answerOptions[i], answerOptions[j]] = [answerOptions[j], answerOptions[i]];
303
+ }
304
+
305
+ const dailyDoubleBanner = isDailyDouble ? `<div class="daily-double-banner">🎉 DAILY DOUBLE! 🎉</div>` : "";
306
+
307
+ qdisp.innerHTML = `
308
+ ${dailyDoubleBanner}
309
+ <h2>${categories[categoryIndex]} for $${(difficulty + 1) * 100}${isDailyDouble ? " (x2)" : ""}</h2>
310
+ <p>${q.q}</p>
311
+ <div class="answer-container">
312
+ ${answerOptions.map(opt =>
313
+ `<button class="answer-btn" onclick="checkAnswer(${categoryIndex},${difficulty},${opt.isCorrect}, ${isDailyDouble})">${opt.text}</button>`
314
+ ).join("")}
315
+ </div>
316
+ `;
317
+
318
+ card.classList.add("disabled");
319
+ answered++;
320
+ }
321
+
322
+ window.checkAnswer = (cat, diff, isCorrect, isDouble) => {
323
+ const q = questions[cat][diff];
324
+ let val = (diff + 1) * 100;
325
+ if (isDouble) val *= 2;
326
+ const correctText = q.a[q.correct];
327
+
328
+ document.querySelectorAll(".answer-btn").forEach(b => {
329
+ b.disabled = true; b.classList.add("disabled");
330
+ });
331
+
332
+ if (isCorrect) {
333
+ score += val;
334
+ qdisp.innerHTML += `<p class="feedback" style="color:green;">✅ Correct! +$${val}</p>`;
335
+ } else {
336
+ score -= val;
337
+ qdisp.innerHTML += `<p class="feedback" style="color:#b00020;">❌ Wrong! −$${val}. Correct: ${correctText}</p>`;
338
+ }
339
+ sdisp.textContent = `Score: ${score}`;
340
+
341
+ if (answered === total) {
342
+ qdisp.innerHTML += `<h2 style="margin-top:12px">Game Over!</h2><p>Your final score: $${score}</p>`;
343
+ }
344
+ };
345
+
346
+ createBoard();
347
+ </script>
348
+ </body>
349
  </html>