@jonelhatwell/arcade-games 1.0.1 → 1.2.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/dist/index.cjs +263 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +101 -3
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +263 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
MemoryGame: () => memorygame_default,
|
|
23
24
|
SpaceDodger: () => spacedodger_default
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -89,23 +90,34 @@ function Button({
|
|
|
89
90
|
|
|
90
91
|
// src/components/games/spacedodger/index.tsx
|
|
91
92
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
93
|
+
var config = {
|
|
94
|
+
canvasSize: {
|
|
95
|
+
width: 450,
|
|
96
|
+
height: 450
|
|
97
|
+
},
|
|
98
|
+
player: { x: 200, y: 350, width: 25, height: 50 }
|
|
99
|
+
};
|
|
92
100
|
var SpaceDodger = () => {
|
|
93
101
|
const canvasRef = (0, import_react.useRef)(null);
|
|
102
|
+
const scoreRef = (0, import_react.useRef)(0);
|
|
103
|
+
const lastBatchScoreRef = (0, import_react.useRef)(0);
|
|
94
104
|
const [score, setScore] = (0, import_react.useState)(0);
|
|
95
105
|
const [gameOver, setGameOver] = (0, import_react.useState)(false);
|
|
96
106
|
const gameStateRef = (0, import_react.useRef)({
|
|
97
|
-
player:
|
|
107
|
+
player: config.player,
|
|
98
108
|
enemies: [],
|
|
99
109
|
frame: 0,
|
|
100
110
|
keys: {}
|
|
101
111
|
});
|
|
102
112
|
const resetGame = () => {
|
|
103
113
|
gameStateRef.current = {
|
|
104
|
-
player:
|
|
114
|
+
player: config.player,
|
|
105
115
|
enemies: [],
|
|
106
116
|
frame: 0,
|
|
107
117
|
keys: {}
|
|
108
118
|
};
|
|
119
|
+
scoreRef.current = 0;
|
|
120
|
+
lastBatchScoreRef.current = 0;
|
|
109
121
|
setScore(0);
|
|
110
122
|
setGameOver(false);
|
|
111
123
|
};
|
|
@@ -123,60 +135,293 @@ var SpaceDodger = () => {
|
|
|
123
135
|
};
|
|
124
136
|
window.addEventListener("keydown", handleKeyDown);
|
|
125
137
|
window.addEventListener("keyup", handleKeyUp);
|
|
138
|
+
const randomRadius = () => 10 + Math.random() * 15;
|
|
139
|
+
const getEnemySpeed = () => {
|
|
140
|
+
const base = 3;
|
|
141
|
+
const increase = Math.floor(scoreRef.current / 20) * 0.5;
|
|
142
|
+
return base + increase;
|
|
143
|
+
};
|
|
126
144
|
let animationId;
|
|
127
145
|
const gameLoop = () => {
|
|
128
146
|
if (gameOver) return;
|
|
129
147
|
state.frame++;
|
|
130
148
|
ctx.fillStyle = "#000";
|
|
131
|
-
ctx.fillRect(0, 0,
|
|
149
|
+
ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);
|
|
132
150
|
if (state.keys["ArrowLeft"] && state.player.x > 0) state.player.x -= 5;
|
|
133
|
-
if (state.keys["ArrowRight"] && state.player.x <
|
|
151
|
+
if (state.keys["ArrowRight"] && state.player.x < config.canvasSize.width - state.player.width) state.player.x += 5;
|
|
134
152
|
if (state.keys["ArrowUp"] && state.player.y > 0) state.player.y -= 5;
|
|
135
|
-
if (state.keys["ArrowDown"] && state.player.y <
|
|
153
|
+
if (state.keys["ArrowDown"] && state.player.y < config.canvasSize.height - state.player.height) state.player.y += 5;
|
|
136
154
|
ctx.fillStyle = "#0ea5e9";
|
|
137
|
-
ctx.fillRect(
|
|
155
|
+
ctx.fillRect(
|
|
156
|
+
state.player.x,
|
|
157
|
+
state.player.y,
|
|
158
|
+
state.player.width,
|
|
159
|
+
state.player.height
|
|
160
|
+
);
|
|
138
161
|
if (state.frame % 40 === 0) {
|
|
139
|
-
|
|
162
|
+
const radius = randomRadius();
|
|
163
|
+
state.enemies.push({
|
|
164
|
+
x: radius + Math.random() * (config.canvasSize.width - radius * 2),
|
|
165
|
+
y: -radius,
|
|
166
|
+
radius
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (scoreRef.current > 0 && scoreRef.current % 20 === 0 && lastBatchScoreRef.current !== scoreRef.current) {
|
|
170
|
+
lastBatchScoreRef.current = scoreRef.current;
|
|
171
|
+
const batchCount = 2 + Math.floor(Math.random() * 3);
|
|
172
|
+
for (let i = 0; i < batchCount; i++) {
|
|
173
|
+
const radius = randomRadius();
|
|
174
|
+
state.enemies.push({
|
|
175
|
+
x: radius + Math.random() * (config.canvasSize.width - radius * 2),
|
|
176
|
+
y: -Math.random() * 100,
|
|
177
|
+
radius
|
|
178
|
+
});
|
|
179
|
+
}
|
|
140
180
|
}
|
|
141
181
|
state.enemies = state.enemies.filter((enemy) => {
|
|
142
|
-
enemy.y +=
|
|
182
|
+
enemy.y += getEnemySpeed();
|
|
143
183
|
ctx.fillStyle = "#ef4444";
|
|
144
|
-
ctx.
|
|
145
|
-
|
|
184
|
+
ctx.beginPath();
|
|
185
|
+
ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);
|
|
186
|
+
ctx.fill();
|
|
187
|
+
const closestX = Math.max(
|
|
188
|
+
state.player.x,
|
|
189
|
+
Math.min(enemy.x, state.player.x + state.player.width)
|
|
190
|
+
);
|
|
191
|
+
const closestY = Math.max(
|
|
192
|
+
state.player.y,
|
|
193
|
+
Math.min(enemy.y, state.player.y + state.player.height)
|
|
194
|
+
);
|
|
195
|
+
const dx = enemy.x - closestX;
|
|
196
|
+
const dy = enemy.y - closestY;
|
|
197
|
+
if (dx * dx + dy * dy < enemy.radius * enemy.radius) {
|
|
146
198
|
setGameOver(true);
|
|
147
199
|
return false;
|
|
148
200
|
}
|
|
149
|
-
if (enemy.y >
|
|
150
|
-
setScore((s) =>
|
|
201
|
+
if (enemy.y - enemy.radius > config.canvasSize.height) {
|
|
202
|
+
setScore((s) => {
|
|
203
|
+
scoreRef.current = s + 1;
|
|
204
|
+
return s + 1;
|
|
205
|
+
});
|
|
151
206
|
return false;
|
|
152
207
|
}
|
|
153
208
|
return true;
|
|
154
209
|
});
|
|
155
210
|
animationId = requestAnimationFrame(gameLoop);
|
|
156
211
|
};
|
|
157
|
-
|
|
212
|
+
gameLoop();
|
|
158
213
|
return () => {
|
|
159
214
|
cancelAnimationFrame(animationId);
|
|
160
215
|
window.removeEventListener("keydown", handleKeyDown);
|
|
161
216
|
window.removeEventListener("keyup", handleKeyUp);
|
|
162
217
|
};
|
|
163
218
|
}, [gameOver]);
|
|
164
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4 p-4", children: [
|
|
219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative flex flex-col items-center gap-4 p-4", children: [
|
|
165
220
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "text-xl font-bold", children: [
|
|
166
221
|
"Score: ",
|
|
167
222
|
score
|
|
168
223
|
] }),
|
|
169
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
170
|
-
|
|
171
|
-
|
|
224
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
225
|
+
"canvas",
|
|
226
|
+
{
|
|
227
|
+
ref: canvasRef,
|
|
228
|
+
width: config.canvasSize.width,
|
|
229
|
+
height: config.canvasSize.height,
|
|
230
|
+
className: "border-2 border-gray-300"
|
|
231
|
+
}
|
|
232
|
+
),
|
|
233
|
+
gameOver && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-black/60", children: [
|
|
234
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xl font-bold text-red-500 mb-3", children: "Game Over" }),
|
|
172
235
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { onClick: resetGame, children: "Play Again" })
|
|
173
236
|
] }),
|
|
174
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("
|
|
237
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "text-sm text-foreground", children: "Use arrow keys to move" })
|
|
175
238
|
] });
|
|
176
239
|
};
|
|
177
240
|
var spacedodger_default = SpaceDodger;
|
|
241
|
+
|
|
242
|
+
// src/components/games/memorygame/index.tsx
|
|
243
|
+
var import_react2 = require("react");
|
|
244
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
245
|
+
var config2 = {
|
|
246
|
+
canvasSize: { width: 450, height: 450 },
|
|
247
|
+
baseHideTime: 3e3,
|
|
248
|
+
numberRadius: 30
|
|
249
|
+
};
|
|
250
|
+
var MemoryGame = () => {
|
|
251
|
+
const canvasRef = (0, import_react2.useRef)(null);
|
|
252
|
+
const [level, setLevel] = (0, import_react2.useState)(1);
|
|
253
|
+
const [gameOver, setGameOver] = (0, import_react2.useState)(false);
|
|
254
|
+
const [message, setMessage] = (0, import_react2.useState)("");
|
|
255
|
+
const [showOverlay, setShowOverlay] = (0, import_react2.useState)({
|
|
256
|
+
visible: false,
|
|
257
|
+
text: ""
|
|
258
|
+
});
|
|
259
|
+
const gameStateRef = (0, import_react2.useRef)({
|
|
260
|
+
numbers: [],
|
|
261
|
+
sequence: [],
|
|
262
|
+
currentIndex: 0,
|
|
263
|
+
level: 1,
|
|
264
|
+
showNumbers: true,
|
|
265
|
+
phase: "memorize",
|
|
266
|
+
revealed: /* @__PURE__ */ new Set()
|
|
267
|
+
});
|
|
268
|
+
const getNumberCount = (lvl) => Math.min(4 + lvl, 9);
|
|
269
|
+
const getHideTime = (lvl) => Math.max(500, config2.baseHideTime - Math.floor((lvl - 1) / 1) * 500);
|
|
270
|
+
const generateNumbers = (lvl) => {
|
|
271
|
+
const count = getNumberCount(lvl);
|
|
272
|
+
const numbers = [];
|
|
273
|
+
const sequence = [];
|
|
274
|
+
const padding = config2.numberRadius * 2.5;
|
|
275
|
+
for (let i = 0; i < count; i++) {
|
|
276
|
+
let x, y, overlap;
|
|
277
|
+
let attempts = 0;
|
|
278
|
+
do {
|
|
279
|
+
overlap = false;
|
|
280
|
+
x = padding + Math.random() * (config2.canvasSize.width - padding * 2);
|
|
281
|
+
y = padding + Math.random() * (config2.canvasSize.height - padding * 2);
|
|
282
|
+
for (const num of numbers) {
|
|
283
|
+
const dx = x - num.x;
|
|
284
|
+
const dy = y - num.y;
|
|
285
|
+
if (Math.sqrt(dx * dx + dy * dy) < config2.numberRadius * 2.5) {
|
|
286
|
+
overlap = true;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
attempts++;
|
|
291
|
+
} while (overlap && attempts < 100);
|
|
292
|
+
numbers.push({ x, y, value: i + 1, radius: config2.numberRadius });
|
|
293
|
+
sequence.push(i + 1);
|
|
294
|
+
}
|
|
295
|
+
return { numbers, sequence };
|
|
296
|
+
};
|
|
297
|
+
const startLevel = (lvl) => {
|
|
298
|
+
const { numbers, sequence } = generateNumbers(lvl);
|
|
299
|
+
gameStateRef.current = {
|
|
300
|
+
numbers,
|
|
301
|
+
sequence,
|
|
302
|
+
currentIndex: 0,
|
|
303
|
+
level: lvl,
|
|
304
|
+
showNumbers: true,
|
|
305
|
+
phase: "memorize",
|
|
306
|
+
revealed: /* @__PURE__ */ new Set()
|
|
307
|
+
};
|
|
308
|
+
setMessage("Memorize the sequence!");
|
|
309
|
+
setTimeout(() => {
|
|
310
|
+
gameStateRef.current.showNumbers = false;
|
|
311
|
+
gameStateRef.current.phase = "recall";
|
|
312
|
+
setMessage("Click the numbers in order!");
|
|
313
|
+
}, getHideTime(lvl));
|
|
314
|
+
};
|
|
315
|
+
const resetGame = () => {
|
|
316
|
+
setLevel(1);
|
|
317
|
+
setGameOver(false);
|
|
318
|
+
setShowOverlay({ visible: false, text: "" });
|
|
319
|
+
startLevel(1);
|
|
320
|
+
};
|
|
321
|
+
const handleCanvasClick = (e) => {
|
|
322
|
+
if (gameOver || gameStateRef.current.phase !== "recall") return;
|
|
323
|
+
const canvas = canvasRef.current;
|
|
324
|
+
if (!canvas) return;
|
|
325
|
+
const rect = canvas.getBoundingClientRect();
|
|
326
|
+
const x = e.clientX - rect.left;
|
|
327
|
+
const y = e.clientY - rect.top;
|
|
328
|
+
const state = gameStateRef.current;
|
|
329
|
+
for (const num of state.numbers) {
|
|
330
|
+
const distance = Math.hypot(x - num.x, y - num.y);
|
|
331
|
+
if (distance <= num.radius) {
|
|
332
|
+
const expected = state.sequence[state.currentIndex];
|
|
333
|
+
if (num.value === expected) {
|
|
334
|
+
state.revealed.add(num.value);
|
|
335
|
+
state.currentIndex++;
|
|
336
|
+
if (state.currentIndex === state.sequence.length) {
|
|
337
|
+
const nextLevel = level + 1;
|
|
338
|
+
setLevel(nextLevel);
|
|
339
|
+
state.phase = "transition";
|
|
340
|
+
setShowOverlay({ visible: true, text: `Get Ready! Level ${nextLevel}` });
|
|
341
|
+
setTimeout(() => {
|
|
342
|
+
setShowOverlay({ visible: false, text: "" });
|
|
343
|
+
startLevel(nextLevel);
|
|
344
|
+
}, 1500);
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
setGameOver(true);
|
|
348
|
+
setMessage(`Wrong! Clicked ${num.value}, expected ${expected}`);
|
|
349
|
+
}
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
(0, import_react2.useEffect)(() => startLevel(1), []);
|
|
355
|
+
(0, import_react2.useEffect)(() => {
|
|
356
|
+
const canvas = canvasRef.current;
|
|
357
|
+
if (!canvas) return;
|
|
358
|
+
const ctx = canvas.getContext("2d");
|
|
359
|
+
if (!ctx) return;
|
|
360
|
+
let animationId;
|
|
361
|
+
const draw = () => {
|
|
362
|
+
const state = gameStateRef.current;
|
|
363
|
+
ctx.fillStyle = "#000";
|
|
364
|
+
ctx.fillRect(0, 0, config2.canvasSize.width, config2.canvasSize.height);
|
|
365
|
+
state.numbers.forEach((num, idx) => {
|
|
366
|
+
const isNext = state.phase === "recall" && level === 1 && idx === state.currentIndex;
|
|
367
|
+
ctx.fillStyle = isNext ? "#22c55e" : "#3b82f6";
|
|
368
|
+
ctx.beginPath();
|
|
369
|
+
ctx.arc(num.x, num.y, num.radius, 0, Math.PI * 2);
|
|
370
|
+
ctx.fill();
|
|
371
|
+
if (state.showNumbers || state.phase === "transition" || state.revealed.has(num.value)) {
|
|
372
|
+
ctx.fillStyle = "#fff";
|
|
373
|
+
ctx.font = "bold 24px sans-serif";
|
|
374
|
+
ctx.textAlign = "center";
|
|
375
|
+
ctx.textBaseline = "middle";
|
|
376
|
+
ctx.fillText(num.value.toString(), num.x, num.y);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
if (!gameOver) animationId = requestAnimationFrame(draw);
|
|
380
|
+
};
|
|
381
|
+
draw();
|
|
382
|
+
return () => cancelAnimationFrame(animationId);
|
|
383
|
+
}, [gameOver, level]);
|
|
384
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative flex flex-col items-center gap-4 p-4", children: [
|
|
385
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex gap-8 text-xl font-bold", children: [
|
|
386
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
387
|
+
"Level: ",
|
|
388
|
+
level
|
|
389
|
+
] }),
|
|
390
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
391
|
+
"Numbers: ",
|
|
392
|
+
getNumberCount(level)
|
|
393
|
+
] })
|
|
394
|
+
] }),
|
|
395
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-lg font-semibold text-blue-400 h-6", children: message }),
|
|
396
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
397
|
+
"canvas",
|
|
398
|
+
{
|
|
399
|
+
ref: canvasRef,
|
|
400
|
+
width: config2.canvasSize.width,
|
|
401
|
+
height: config2.canvasSize.height,
|
|
402
|
+
className: "border-2 border-gray-300 cursor-pointer",
|
|
403
|
+
onClick: handleCanvasClick
|
|
404
|
+
}
|
|
405
|
+
),
|
|
406
|
+
gameOver && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-black/60", children: [
|
|
407
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xl font-bold text-red-500 mb-2", children: "Game Over" }),
|
|
408
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "text-lg text-white mb-4", children: [
|
|
409
|
+
"Reached Level ",
|
|
410
|
+
level
|
|
411
|
+
] }),
|
|
412
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { onClick: resetGame, children: "Play Again" })
|
|
413
|
+
] }),
|
|
414
|
+
showOverlay.visible && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-black/60", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-2xl font-bold text-yellow-400", children: showOverlay.text }) }),
|
|
415
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "text-sm text-center text-foreground max-w-md", children: [
|
|
416
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: "Memorize the numbers, then click them in sequence (1, 2, 3...)" }),
|
|
417
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mt-1 text-xs text-gray-400", children: "Green circle = next number to click (level 1 only)" })
|
|
418
|
+
] })
|
|
419
|
+
] });
|
|
420
|
+
};
|
|
421
|
+
var memorygame_default = MemoryGame;
|
|
178
422
|
// Annotate the CommonJS export names for ESM import in node:
|
|
179
423
|
0 && (module.exports = {
|
|
424
|
+
MemoryGame,
|
|
180
425
|
SpaceDodger
|
|
181
426
|
});
|
|
182
427
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/games/spacedodger/index.tsx","../src/components/ui/button.tsx","../src/lib/utils.ts"],"sourcesContent":["import \"./index.css\";\r\nexport { default as SpaceDodger } from \"./components/games/spacedodger\";","\r\nimport React, { useState, useEffect, useRef } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\n\r\ninterface Position {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n\r\ninterface Enemy extends Position {\r\n width: number;\r\n height: number;\r\n}\r\n\r\ninterface Player extends Position {\r\n width: number;\r\n height: number;\r\n}\r\n\r\n\r\ninterface SpaceDodgerState {\r\n player: Player;\r\n enemies: Enemy[];\r\n frame: number;\r\n keys: Record<string, boolean>;\r\n}\r\n\r\nconst SpaceDodger: React.FC = () => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const [score, setScore] = useState<number>(0);\r\n const [gameOver, setGameOver] = useState<boolean>(false);\r\n const gameStateRef = useRef<SpaceDodgerState>({\r\n player: { x: 200, y: 350, width: 30, height: 30 },\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n });\r\n\r\n const resetGame = (): void => {\r\n gameStateRef.current = {\r\n player: { x: 200, y: 350, width: 30, height: 30 },\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n };\r\n setScore(0);\r\n setGameOver(false);\r\n };\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n const state = gameStateRef.current;\r\n\r\n const handleKeyDown = (e: KeyboardEvent): void => { \r\n state.keys[e.key] = true; \r\n };\r\n const handleKeyUp = (e: KeyboardEvent): void => { \r\n state.keys[e.key] = false; \r\n };\r\n window.addEventListener('keydown', handleKeyDown);\r\n window.addEventListener('keyup', handleKeyUp);\r\n\r\n let animationId: number;\r\n const gameLoop = (): void => {\r\n if (gameOver) return;\r\n \r\n state.frame++;\r\n ctx.fillStyle = '#000';\r\n ctx.fillRect(0, 0, 400, 400);\r\n\r\n if (state.keys['ArrowLeft'] && state.player.x > 0) state.player.x -= 5;\r\n if (state.keys['ArrowRight'] && state.player.x < 370) state.player.x += 5;\r\n if (state.keys['ArrowUp'] && state.player.y > 0) state.player.y -= 5;\r\n if (state.keys['ArrowDown'] && state.player.y < 370) state.player.y += 5;\r\n\r\n ctx.fillStyle = '#0ea5e9';\r\n ctx.fillRect(state.player.x, state.player.y, state.player.width, state.player.height);\r\n\r\n if (state.frame % 40 === 0) {\r\n state.enemies.push({ x: Math.random() * 370, y: -20, width: 30, height: 30 });\r\n }\r\n\r\n state.enemies = state.enemies.filter(enemy => {\r\n enemy.y += 3;\r\n ctx.fillStyle = '#ef4444';\r\n ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);\r\n\r\n if (enemy.x < state.player.x + state.player.width &&\r\n enemy.x + enemy.width > state.player.x &&\r\n enemy.y < state.player.y + state.player.height &&\r\n enemy.y + enemy.height > state.player.y) {\r\n setGameOver(true);\r\n return false;\r\n }\r\n\r\n if (enemy.y > 400) {\r\n setScore(s => s + 1);\r\n return false;\r\n }\r\n return true;\r\n });\r\n\r\n animationId = requestAnimationFrame(gameLoop);\r\n };\r\n \r\n if (!gameOver) gameLoop();\r\n\r\n return () => {\r\n cancelAnimationFrame(animationId);\r\n window.removeEventListener('keydown', handleKeyDown);\r\n window.removeEventListener('keyup', handleKeyUp);\r\n };\r\n }, [gameOver]);\r\n\r\n return (\r\n <div className=\"flex flex-col items-center gap-4 p-4\">\r\n <div className=\"text-xl font-bold\">Score: {score}</div>\r\n <canvas ref={canvasRef} width=\"400\" height=\"400\" className=\"border-2 border-gray-300\" />\r\n {gameOver && (\r\n <div className=\"text-center\">\r\n <p className=\"text-xl font-bold text-red-500 mb-2\">Game Over!</p>\r\n <Button onClick={resetGame}>Play Again</Button>\r\n </div>\r\n )}\r\n <p className=\"text-sm text-gray-600\">Use arrow keys to move</p>\r\n </div>\r\n );\r\n};\r\n\r\nexport default SpaceDodger;","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import { clsx, type ClassValue } from \"clsx\"\r\nimport { twMerge } from \"tailwind-merge\"\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs))\r\n}"],"mappings":"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","names":["import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/games/spacedodger/index.tsx","../src/components/ui/button.tsx","../src/lib/utils.ts","../src/components/games/memorygame/index.tsx"],"sourcesContent":["import \"./index.css\";\r\nexport { default as SpaceDodger } from \"./components/games/spacedodger\";\r\nexport { default as MemoryGame } from \"./components/games/memorygame\";","import React, { useEffect, useRef, useState } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\ninterface Position {\r\n x: number;\r\n y: number;\r\n}\r\n\r\ninterface Enemy extends Position {\r\n radius: number;\r\n}\r\n\r\ninterface Player extends Position {\r\n width: number;\r\n height: number;\r\n}\r\n\r\ninterface SpaceDodgerState {\r\n player: Player;\r\n enemies: Enemy[];\r\n frame: number;\r\n keys: Record<string, boolean>;\r\n}\r\n\r\n\r\nconst config = {\r\n canvasSize : { \r\n width: 450, \r\n height: 450 \r\n },\r\n player: { x: 200, y: 350, width: 25, height: 50 }\r\n}\r\n\r\nconst SpaceDodger: React.FC = () => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const scoreRef = useRef(0);\r\n const lastBatchScoreRef = useRef(0);\r\n\r\n const [score, setScore] = useState(0);\r\n const [gameOver, setGameOver] = useState(false);\r\n\r\n const gameStateRef = useRef<SpaceDodgerState>({\r\n player: config.player,\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n });\r\n\r\n const resetGame = () => {\r\n gameStateRef.current = {\r\n player: config.player,\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n };\r\n scoreRef.current = 0;\r\n lastBatchScoreRef.current = 0;\r\n setScore(0);\r\n setGameOver(false);\r\n };\r\n\r\n\r\n \r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n const state = gameStateRef.current;\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n state.keys[e.key] = true;\r\n };\r\n const handleKeyUp = (e: KeyboardEvent) => {\r\n state.keys[e.key] = false;\r\n };\r\n\r\n window.addEventListener('keydown', handleKeyDown);\r\n window.addEventListener('keyup', handleKeyUp);\r\n\r\n const randomRadius = () => 10 + Math.random() * 15;\r\n\r\n const getEnemySpeed = () => {\r\n const base = 3;\r\n const increase = Math.floor(scoreRef.current / 20) * 0.5;\r\n return base + increase;\r\n };\r\n\r\n let animationId: number;\r\n\r\n const gameLoop = () => {\r\n if (gameOver) return;\r\n\r\n state.frame++;\r\n\r\n ctx.fillStyle = '#000';\r\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\r\n\r\n // Player movement\r\n if (state.keys['ArrowLeft'] && state.player.x > 0) state.player.x -= 5;\r\n if (state.keys['ArrowRight'] && state.player.x < config.canvasSize.width - state.player.width) state.player.x += 5;\r\n if (state.keys['ArrowUp'] && state.player.y > 0) state.player.y -= 5;\r\n if (state.keys['ArrowDown'] && state.player.y < config.canvasSize.height - state.player.height) state.player.y += 5;\r\n\r\n // Draw player\r\n ctx.fillStyle = '#0ea5e9';\r\n ctx.fillRect(\r\n state.player.x,\r\n state.player.y,\r\n state.player.width,\r\n state.player.height\r\n );\r\n\r\n // Normal enemy spawn\r\n if (state.frame % 40 === 0) {\r\n const radius = randomRadius();\r\n state.enemies.push({\r\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\r\n y: -radius,\r\n radius,\r\n });\r\n }\r\n\r\n // Extra batch every 20 score\r\n if (\r\n scoreRef.current > 0 &&\r\n scoreRef.current % 20 === 0 &&\r\n lastBatchScoreRef.current !== scoreRef.current\r\n ) {\r\n lastBatchScoreRef.current = scoreRef.current;\r\n const batchCount = 2 + Math.floor(Math.random() * 3);\r\n\r\n for (let i = 0; i < batchCount; i++) {\r\n const radius = randomRadius();\r\n state.enemies.push({\r\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\r\n y: -Math.random() * 100,\r\n radius\r\n });\r\n }\r\n }\r\n\r\n // Enemies update\r\n state.enemies = state.enemies.filter(enemy => {\r\n enemy.y += getEnemySpeed();\r\n\r\n // Draw enemy (circle)\r\n ctx.fillStyle = '#ef4444';\r\n ctx.beginPath();\r\n ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n // Circle vs rectangle collision\r\n const closestX = Math.max(\r\n state.player.x,\r\n Math.min(enemy.x, state.player.x + state.player.width)\r\n );\r\n const closestY = Math.max(\r\n state.player.y,\r\n Math.min(enemy.y, state.player.y + state.player.height)\r\n );\r\n\r\n const dx = enemy.x - closestX;\r\n const dy = enemy.y - closestY;\r\n\r\n if (dx * dx + dy * dy < enemy.radius * enemy.radius) {\r\n setGameOver(true);\r\n return false;\r\n }\r\n\r\n // Passed screen\r\n if (enemy.y - enemy.radius > config.canvasSize.height) {\r\n setScore(s => {\r\n scoreRef.current = s + 1;\r\n return s + 1;\r\n });\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n\r\n animationId = requestAnimationFrame(gameLoop);\r\n };\r\n\r\n gameLoop();\r\n\r\n return () => {\r\n cancelAnimationFrame(animationId);\r\n window.removeEventListener('keydown', handleKeyDown);\r\n window.removeEventListener('keyup', handleKeyUp);\r\n };\r\n }, [gameOver]);\r\n\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\r\n <div className=\"text-xl font-bold\">Score: {score}</div>\r\n <canvas\r\n ref={canvasRef}\r\n width={config.canvasSize.width}\r\n height={config.canvasSize.height}\r\n className=\"border-2 border-gray-300\"\r\n />\r\n\r\n {gameOver && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-xl font-bold text-red-500 mb-3\">Game Over</p>\r\n <Button onClick={resetGame}>Play Again</Button>\r\n </div>\r\n )}\r\n\r\n <div className=\"text-sm text-foreground\">Use arrow keys to move</div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default SpaceDodger;","import * as React from \"react\"\r\nimport { Slot } from \"@radix-ui/react-slot\"\r\nimport { cva, type VariantProps } from \"class-variance-authority\"\r\n\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst buttonVariants = cva(\r\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\r\n {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n destructive:\r\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\r\n outline:\r\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\r\n secondary:\r\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n ghost:\r\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\r\n link: \"text-primary underline-offset-4 hover:underline\",\r\n },\r\n size: {\r\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\r\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\r\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\r\n icon: \"size-9\",\r\n \"icon-sm\": \"size-8\",\r\n \"icon-lg\": \"size-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n size: \"default\",\r\n },\r\n }\r\n)\r\n\r\nfunction Button({\r\n className,\r\n variant = \"default\",\r\n size = \"default\",\r\n asChild = false,\r\n ...props\r\n}: React.ComponentProps<\"button\"> &\r\n VariantProps<typeof buttonVariants> & {\r\n asChild?: boolean\r\n }) {\r\n const Comp = asChild ? Slot : \"button\"\r\n\r\n return (\r\n <Comp\r\n data-slot=\"button\"\r\n data-variant={variant}\r\n data-size={size}\r\n className={cn(buttonVariants({ variant, size, className }))}\r\n {...props}\r\n />\r\n )\r\n}\r\n\r\nexport { Button, buttonVariants }\r\n","import { clsx, type ClassValue } from \"clsx\"\r\nimport { twMerge } from \"tailwind-merge\"\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs))\r\n}","import React, { useEffect, useRef, useState } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\ninterface NumberItem {\r\n x: number;\r\n y: number;\r\n value: number;\r\n radius: number;\r\n}\r\n\r\ntype GamePhase = 'memorize' | 'recall' | 'transition';\r\n\r\ninterface GameState {\r\n numbers: NumberItem[];\r\n sequence: number[];\r\n currentIndex: number;\r\n level: number;\r\n showNumbers: boolean;\r\n phase: GamePhase;\r\n revealed: Set<number>;\r\n}\r\n\r\nconst config = {\r\n canvasSize: { width: 450, height: 450 },\r\n baseHideTime: 3000,\r\n numberRadius: 30,\r\n};\r\n\r\nconst MemoryGame: React.FC = () => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const [level, setLevel] = useState(1);\r\n const [gameOver, setGameOver] = useState(false);\r\n const [message, setMessage] = useState('');\r\n const [showOverlay, setShowOverlay] = useState<{ visible: boolean; text: string }>({\r\n visible: false,\r\n text: '',\r\n });\r\n const gameStateRef = useRef<GameState>({\r\n numbers: [],\r\n sequence: [],\r\n currentIndex: 0,\r\n level: 1,\r\n showNumbers: true,\r\n phase: 'memorize',\r\n revealed: new Set(),\r\n });\r\n\r\n // Max numbers = 9\r\n const getNumberCount = (lvl: number) => Math.min(4 + lvl, 9);\r\n\r\n // Hide time decreases as level increases, min 500ms\r\n const getHideTime = (lvl: number) =>\r\n Math.max(500, config.baseHideTime - Math.floor((lvl - 1) / 1) * 500);\r\n\r\n const generateNumbers = (lvl: number) => {\r\n const count = getNumberCount(lvl);\r\n const numbers: NumberItem[] = [];\r\n const sequence: number[] = [];\r\n const padding = config.numberRadius * 2.5;\r\n\r\n for (let i = 0; i < count; i++) {\r\n let x: number, y: number, overlap: boolean;\r\n let attempts = 0;\r\n\r\n do {\r\n overlap = false;\r\n x = padding + Math.random() * (config.canvasSize.width - padding * 2);\r\n y = padding + Math.random() * (config.canvasSize.height - padding * 2);\r\n\r\n for (const num of numbers) {\r\n const dx = x - num.x;\r\n const dy = y - num.y;\r\n if (Math.sqrt(dx * dx + dy * dy) < config.numberRadius * 2.5) {\r\n overlap = true;\r\n break;\r\n }\r\n }\r\n attempts++;\r\n } while (overlap && attempts < 100);\r\n\r\n numbers.push({ x, y, value: i + 1, radius: config.numberRadius });\r\n sequence.push(i + 1);\r\n }\r\n\r\n return { numbers, sequence };\r\n };\r\n\r\n const startLevel = (lvl: number) => {\r\n const { numbers, sequence } = generateNumbers(lvl);\r\n gameStateRef.current = {\r\n numbers,\r\n sequence,\r\n currentIndex: 0,\r\n level: lvl,\r\n showNumbers: true,\r\n phase: 'memorize',\r\n revealed: new Set(),\r\n };\r\n setMessage('Memorize the sequence!');\r\n\r\n setTimeout(() => {\r\n gameStateRef.current.showNumbers = false;\r\n gameStateRef.current.phase = 'recall';\r\n setMessage('Click the numbers in order!');\r\n }, getHideTime(lvl));\r\n };\r\n\r\n const resetGame = () => {\r\n setLevel(1);\r\n setGameOver(false);\r\n setShowOverlay({ visible: false, text: '' });\r\n startLevel(1);\r\n };\r\n\r\n const handleCanvasClick = (e: React.MouseEvent<HTMLCanvasElement>) => {\r\n if (gameOver || gameStateRef.current.phase !== 'recall') return;\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n\r\n const rect = canvas.getBoundingClientRect();\r\n const x = e.clientX - rect.left;\r\n const y = e.clientY - rect.top;\r\n const state = gameStateRef.current;\r\n\r\n for (const num of state.numbers) {\r\n const distance = Math.hypot(x - num.x, y - num.y);\r\n if (distance <= num.radius) {\r\n const expected = state.sequence[state.currentIndex];\r\n if (num.value === expected) {\r\n state.revealed.add(num.value);\r\n state.currentIndex++;\r\n\r\n if (state.currentIndex === state.sequence.length) {\r\n const nextLevel = level + 1;\r\n setLevel(nextLevel);\r\n state.phase = 'transition';\r\n setShowOverlay({ visible: true, text: `Get Ready! Level ${nextLevel}` });\r\n\r\n setTimeout(() => {\r\n setShowOverlay({ visible: false, text: '' });\r\n startLevel(nextLevel);\r\n }, 1500);\r\n }\r\n } else {\r\n setGameOver(true);\r\n setMessage(`Wrong! Clicked ${num.value}, expected ${expected}`);\r\n }\r\n break;\r\n }\r\n }\r\n };\r\n\r\n useEffect(() => startLevel(1), []);\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n let animationId: number;\r\n\r\n const draw = () => {\r\n const state = gameStateRef.current;\r\n ctx.fillStyle = '#000';\r\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\r\n\r\n state.numbers.forEach((num, idx) => {\r\n // Show green hint only in level 1\r\n const isNext = state.phase === 'recall' && level === 1 && idx === state.currentIndex;\r\n ctx.fillStyle = isNext ? '#22c55e' : '#3b82f6';\r\n ctx.beginPath();\r\n ctx.arc(num.x, num.y, num.radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n // Reveal numbers if memorizing, transitioning, or already correctly guessed\r\n if (state.showNumbers || state.phase === 'transition' || state.revealed.has(num.value)) {\r\n ctx.fillStyle = '#fff';\r\n ctx.font = 'bold 24px sans-serif';\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(num.value.toString(), num.x, num.y);\r\n }\r\n });\r\n\r\n if (!gameOver) animationId = requestAnimationFrame(draw);\r\n };\r\n\r\n draw();\r\n return () => cancelAnimationFrame(animationId);\r\n }, [gameOver, level]);\r\n\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\r\n <div className=\"flex gap-8 text-xl font-bold\">\r\n <div>Level: {level}</div>\r\n <div>Numbers: {getNumberCount(level)}</div>\r\n </div>\r\n <div className=\"text-lg font-semibold text-blue-400 h-6\">{message}</div>\r\n <canvas\r\n ref={canvasRef}\r\n width={config.canvasSize.width}\r\n height={config.canvasSize.height}\r\n className=\"border-2 border-gray-300 cursor-pointer\"\r\n onClick={handleCanvasClick}\r\n />\r\n {gameOver && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-xl font-bold text-red-500 mb-2\">Game Over</p>\r\n <p className=\"text-lg text-white mb-4\">Reached Level {level}</p>\r\n <Button onClick={resetGame}>Play Again</Button>\r\n </div>\r\n )}\r\n\r\n {showOverlay.visible && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-2xl font-bold text-yellow-400\">{showOverlay.text}</p>\r\n </div>\r\n )}\r\n\r\n <div className=\"text-sm text-center text-foreground max-w-md\">\r\n <div>Memorize the numbers, then click them in sequence (1, 2, 3...)</div>\r\n <div className=\"mt-1 text-xs text-gray-400\">Green circle = next number to click (level 1 only)</div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default MemoryGame;\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAmD;;;ACCnD,wBAAqB;AACrB,sCAAuC;;;ACFvC,kBAAsC;AACtC,4BAAwB;AAEjB,SAAS,MAAM,QAAsB;AAC1C,aAAO,mCAAQ,kBAAK,MAAM,CAAC;AAC7B;;;AD8CI;AA7CJ,IAAM,qBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aACE;AAAA,QACF,SACE;AAAA,QACF,WACE;AAAA,QACF,OACE;AAAA,QACF,MAAM;AAAA,MACR;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,OAAO;AAAA,EACd;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP,UAAU;AAAA,EACV,GAAG;AACL,GAGK;AACH,QAAM,OAAO,UAAU,yBAAO;AAE9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,aAAW;AAAA,MACX,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,UAAU,CAAC,CAAC;AAAA,MACzD,GAAG;AAAA;AAAA,EACN;AAEJ;;;AD0IY,IAAAA,sBAAA;AA5KZ,IAAM,SAAS;AAAA,EACX,YAAa;AAAA,IACT,OAAO;AAAA,IACP,QAAQ;AAAA,EACZ;AAAA,EACA,QAAQ,EAAE,GAAG,KAAK,GAAG,KAAK,OAAO,IAAI,QAAQ,GAAG;AACpD;AAEA,IAAM,cAAwB,MAAM;AAChC,QAAM,gBAAY,qBAA0B,IAAI;AAChD,QAAM,eAAW,qBAAO,CAAC;AACzB,QAAM,wBAAoB,qBAAO,CAAC;AAElC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,CAAC;AACpC,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAE9C,QAAM,mBAAe,qBAAyB;AAAA,IAC1C,QAAQ,OAAO;AAAA,IACf,SAAS,CAAC;AAAA,IACV,OAAO;AAAA,IACP,MAAM,CAAC;AAAA,EACX,CAAC;AAED,QAAM,YAAY,MAAM;AACpB,iBAAa,UAAU;AAAA,MACnB,QAAQ,OAAO;AAAA,MACf,SAAS,CAAC;AAAA,MACV,OAAO;AAAA,MACP,MAAM,CAAC;AAAA,IACX;AACA,aAAS,UAAU;AACnB,sBAAkB,UAAU;AAC5B,aAAS,CAAC;AACV,gBAAY,KAAK;AAAA,EACrB;AAIA,8BAAU,MAAM;AACZ,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK;AAEV,UAAM,QAAQ,aAAa;AAE3B,UAAM,gBAAgB,CAAC,MAAqB;AACxC,YAAM,KAAK,EAAE,GAAG,IAAI;AAAA,IACxB;AACA,UAAM,cAAc,CAAC,MAAqB;AACtC,YAAM,KAAK,EAAE,GAAG,IAAI;AAAA,IACxB;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAChD,WAAO,iBAAiB,SAAS,WAAW;AAE5C,UAAM,eAAe,MAAM,KAAK,KAAK,OAAO,IAAI;AAEhD,UAAM,gBAAgB,MAAM;AACxB,YAAM,OAAO;AACb,YAAM,WAAW,KAAK,MAAM,SAAS,UAAU,EAAE,IAAI;AACrD,aAAO,OAAO;AAAA,IAClB;AAEA,QAAI;AAEJ,UAAM,WAAW,MAAM;AACnB,UAAI,SAAU;AAEd,YAAM;AAEN,UAAI,YAAY;AAChB,UAAI,SAAS,GAAG,GAAG,OAAO,WAAW,OAAO,OAAO,WAAW,MAAM;AAGpE,UAAI,MAAM,KAAK,WAAW,KAAK,MAAM,OAAO,IAAI,EAAG,OAAM,OAAO,KAAK;AACrE,UAAI,MAAM,KAAK,YAAY,KAAK,MAAM,OAAO,IAAI,OAAO,WAAW,QAAQ,MAAM,OAAO,MAAO,OAAM,OAAO,KAAK;AACjH,UAAI,MAAM,KAAK,SAAS,KAAK,MAAM,OAAO,IAAI,EAAG,OAAM,OAAO,KAAK;AACnE,UAAI,MAAM,KAAK,WAAW,KAAK,MAAM,OAAO,IAAI,OAAO,WAAW,SAAS,MAAM,OAAO,OAAQ,OAAM,OAAO,KAAK;AAGlH,UAAI,YAAY;AAChB,UAAI;AAAA,QACA,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,QACb,MAAM,OAAO;AAAA,MACjB;AAGA,UAAI,MAAM,QAAQ,OAAO,GAAG;AACxB,cAAM,SAAS,aAAa;AAC5B,cAAM,QAAQ,KAAK;AAAA,UACf,GAAG,SAAS,KAAK,OAAO,KAAK,OAAO,WAAW,QAAQ,SAAS;AAAA,UAChE,GAAG,CAAC;AAAA,UACJ;AAAA,QACJ,CAAC;AAAA,MACL;AAGA,UACI,SAAS,UAAU,KACnB,SAAS,UAAU,OAAO,KAC1B,kBAAkB,YAAY,SAAS,SACzC;AACE,0BAAkB,UAAU,SAAS;AACrC,cAAM,aAAa,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,CAAC;AAEnD,iBAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACjC,gBAAM,SAAS,aAAa;AAC5B,gBAAM,QAAQ,KAAK;AAAA,YACf,GAAG,SAAS,KAAK,OAAO,KAAK,OAAO,WAAW,QAAQ,SAAS;AAAA,YAChE,GAAG,CAAC,KAAK,OAAO,IAAI;AAAA,YACpB;AAAA,UACJ,CAAC;AAAA,QACL;AAAA,MACJ;AAGA,YAAM,UAAU,MAAM,QAAQ,OAAO,WAAS;AAC1C,cAAM,KAAK,cAAc;AAGzB,YAAI,YAAY;AAChB,YAAI,UAAU;AACd,YAAI,IAAI,MAAM,GAAG,MAAM,GAAG,MAAM,QAAQ,GAAG,KAAK,KAAK,CAAC;AACtD,YAAI,KAAK;AAGT,cAAM,WAAW,KAAK;AAAA,UAClB,MAAM,OAAO;AAAA,UACb,KAAK,IAAI,MAAM,GAAG,MAAM,OAAO,IAAI,MAAM,OAAO,KAAK;AAAA,QACzD;AACA,cAAM,WAAW,KAAK;AAAA,UAClB,MAAM,OAAO;AAAA,UACb,KAAK,IAAI,MAAM,GAAG,MAAM,OAAO,IAAI,MAAM,OAAO,MAAM;AAAA,QAC1D;AAEA,cAAM,KAAK,MAAM,IAAI;AACrB,cAAM,KAAK,MAAM,IAAI;AAErB,YAAI,KAAK,KAAK,KAAK,KAAK,MAAM,SAAS,MAAM,QAAQ;AACjD,sBAAY,IAAI;AAChB,iBAAO;AAAA,QACX;AAGA,YAAI,MAAM,IAAI,MAAM,SAAS,OAAO,WAAW,QAAQ;AACnD,mBAAS,OAAK;AACV,qBAAS,UAAU,IAAI;AACvB,mBAAO,IAAI;AAAA,UACf,CAAC;AACD,iBAAO;AAAA,QACX;AAEA,eAAO;AAAA,MACX,CAAC;AAED,oBAAc,sBAAsB,QAAQ;AAAA,IAChD;AAEA,aAAS;AAET,WAAO,MAAM;AACT,2BAAqB,WAAW;AAChC,aAAO,oBAAoB,WAAW,aAAa;AACnD,aAAO,oBAAoB,SAAS,WAAW;AAAA,IACnD;AAAA,EACJ,GAAG,CAAC,QAAQ,CAAC;AAEb,SACI,8CAAC,SAAI,WAAU,iDACX;AAAA,kDAAC,SAAI,WAAU,qBAAoB;AAAA;AAAA,MAAQ;AAAA,OAAM;AAAA,IACjD;AAAA,MAAC;AAAA;AAAA,QACG,KAAK;AAAA,QACL,OAAO,OAAO,WAAW;AAAA,QACzB,QAAQ,OAAO,WAAW;AAAA,QAC1B,WAAU;AAAA;AAAA,IACd;AAAA,IAEC,YACG,8CAAC,SAAI,WAAU,0EACX;AAAA,mDAAC,OAAE,WAAU,uCAAsC,uBAAS;AAAA,MAC5D,6CAAC,UAAO,SAAS,WAAW,wBAAU;AAAA,OAC1C;AAAA,IAGJ,6CAAC,SAAI,WAAU,2BAA0B,oCAAsB;AAAA,KACnE;AAER;AAEA,IAAO,sBAAQ;;;AGzNf,IAAAC,gBAAmD;AAmMvC,IAAAC,sBAAA;AA7KZ,IAAMC,UAAS;AAAA,EACX,YAAY,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,EACtC,cAAc;AAAA,EACd,cAAc;AAClB;AAEA,IAAM,aAAuB,MAAM;AAC/B,QAAM,gBAAY,sBAA0B,IAAI;AAChD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,CAAC;AACpC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,KAAK;AAC9C,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,EAAE;AACzC,QAAM,CAAC,aAAa,cAAc,QAAI,wBAA6C;AAAA,IAC/E,SAAS;AAAA,IACT,MAAM;AAAA,EACV,CAAC;AACD,QAAM,mBAAe,sBAAkB;AAAA,IACnC,SAAS,CAAC;AAAA,IACV,UAAU,CAAC;AAAA,IACX,cAAc;AAAA,IACd,OAAO;AAAA,IACP,aAAa;AAAA,IACb,OAAO;AAAA,IACP,UAAU,oBAAI,IAAI;AAAA,EACtB,CAAC;AAGD,QAAM,iBAAiB,CAAC,QAAgB,KAAK,IAAI,IAAI,KAAK,CAAC;AAG3D,QAAM,cAAc,CAAC,QACjB,KAAK,IAAI,KAAKA,QAAO,eAAe,KAAK,OAAO,MAAM,KAAK,CAAC,IAAI,GAAG;AAEvE,QAAM,kBAAkB,CAAC,QAAgB;AACrC,UAAM,QAAQ,eAAe,GAAG;AAChC,UAAM,UAAwB,CAAC;AAC/B,UAAM,WAAqB,CAAC;AAC5B,UAAM,UAAUA,QAAO,eAAe;AAEtC,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAChC,UAAI,GAAW,GAAW;AAC1B,UAAI,WAAW;AAEf,SAAG;AACC,kBAAU;AACV,YAAI,UAAU,KAAK,OAAO,KAAKA,QAAO,WAAW,QAAQ,UAAU;AACnE,YAAI,UAAU,KAAK,OAAO,KAAKA,QAAO,WAAW,SAAS,UAAU;AAEpE,mBAAW,OAAO,SAAS;AAC3B,gBAAM,KAAK,IAAI,IAAI;AACnB,gBAAM,KAAK,IAAI,IAAI;AACnB,cAAI,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,IAAIA,QAAO,eAAe,KAAK;AAC1D,sBAAU;AACV;AAAA,UACJ;AAAA,QACA;AACA;AAAA,MACJ,SAAS,WAAW,WAAW;AAE/B,cAAQ,KAAK,EAAE,GAAG,GAAG,OAAO,IAAI,GAAG,QAAQA,QAAO,aAAa,CAAC;AAChE,eAAS,KAAK,IAAI,CAAC;AAAA,IACnB;AAEA,WAAO,EAAE,SAAS,SAAS;AAAA,EAC/B;AAEA,QAAM,aAAa,CAAC,QAAgB;AAChC,UAAM,EAAE,SAAS,SAAS,IAAI,gBAAgB,GAAG;AACjD,iBAAa,UAAU;AAAA,MACvB;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,OAAO;AAAA,MACP,aAAa;AAAA,MACb,OAAO;AAAA,MACP,UAAU,oBAAI,IAAI;AAAA,IAClB;AACA,eAAW,wBAAwB;AAEnC,eAAW,MAAM;AACjB,mBAAa,QAAQ,cAAc;AACnC,mBAAa,QAAQ,QAAQ;AAC7B,iBAAW,6BAA6B;AAAA,IACxC,GAAG,YAAY,GAAG,CAAC;AAAA,EACvB;AAEA,QAAM,YAAY,MAAM;AACpB,aAAS,CAAC;AACV,gBAAY,KAAK;AACjB,mBAAe,EAAE,SAAS,OAAO,MAAM,GAAG,CAAC;AAC3C,eAAW,CAAC;AAAA,EAChB;AAEA,QAAM,oBAAoB,CAAC,MAA2C;AAClE,QAAI,YAAY,aAAa,QAAQ,UAAU,SAAU;AACzD,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AAEb,UAAM,OAAO,OAAO,sBAAsB;AAC1C,UAAM,IAAI,EAAE,UAAU,KAAK;AAC3B,UAAM,IAAI,EAAE,UAAU,KAAK;AAC3B,UAAM,QAAQ,aAAa;AAE3B,eAAW,OAAO,MAAM,SAAS;AAC7B,YAAM,WAAW,KAAK,MAAM,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC;AAChD,UAAI,YAAY,IAAI,QAAQ;AACxB,cAAM,WAAW,MAAM,SAAS,MAAM,YAAY;AAClD,YAAI,IAAI,UAAU,UAAU;AACxB,gBAAM,SAAS,IAAI,IAAI,KAAK;AAC5B,gBAAM;AAEN,cAAI,MAAM,iBAAiB,MAAM,SAAS,QAAQ;AAC9C,kBAAM,YAAY,QAAQ;AAC1B,qBAAS,SAAS;AAClB,kBAAM,QAAQ;AACd,2BAAe,EAAE,SAAS,MAAM,MAAM,oBAAoB,SAAS,GAAG,CAAC;AAEvE,uBAAW,MAAM;AACjB,6BAAe,EAAE,SAAS,OAAO,MAAM,GAAG,CAAC;AAC3C,yBAAW,SAAS;AAAA,YACpB,GAAG,IAAI;AAAA,UACX;AAAA,QACJ,OAAO;AACH,sBAAY,IAAI;AAChB,qBAAW,kBAAkB,IAAI,KAAK,cAAc,QAAQ,EAAE;AAAA,QAClE;AACA;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,+BAAU,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;AAEjC,+BAAU,MAAM;AACZ,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK;AAEV,QAAI;AAEJ,UAAM,OAAO,MAAM;AACf,YAAM,QAAQ,aAAa;AAC3B,UAAI,YAAY;AAChB,UAAI,SAAS,GAAG,GAAGA,QAAO,WAAW,OAAOA,QAAO,WAAW,MAAM;AAEpE,YAAM,QAAQ,QAAQ,CAAC,KAAK,QAAQ;AAEhC,cAAM,SAAS,MAAM,UAAU,YAAY,UAAU,KAAK,QAAQ,MAAM;AACxE,YAAI,YAAY,SAAS,YAAY;AACrC,YAAI,UAAU;AACd,YAAI,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,QAAQ,GAAG,KAAK,KAAK,CAAC;AAChD,YAAI,KAAK;AAGT,YAAI,MAAM,eAAe,MAAM,UAAU,gBAAgB,MAAM,SAAS,IAAI,IAAI,KAAK,GAAG;AACpF,cAAI,YAAY;AAChB,cAAI,OAAO;AACX,cAAI,YAAY;AAChB,cAAI,eAAe;AACnB,cAAI,SAAS,IAAI,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;AAAA,QACnD;AAAA,MACJ,CAAC;AAED,UAAI,CAAC,SAAU,eAAc,sBAAsB,IAAI;AAAA,IAC3D;AAEA,SAAK;AACL,WAAO,MAAM,qBAAqB,WAAW;AAAA,EACjD,GAAG,CAAC,UAAU,KAAK,CAAC;AAEpB,SACI,8CAAC,SAAI,WAAU,iDACf;AAAA,kDAAC,SAAI,WAAU,gCACX;AAAA,oDAAC,SAAI;AAAA;AAAA,QAAQ;AAAA,SAAM;AAAA,MACnB,8CAAC,SAAI;AAAA;AAAA,QAAU,eAAe,KAAK;AAAA,SAAE;AAAA,OACzC;AAAA,IACA,6CAAC,SAAI,WAAU,2CAA2C,mBAAQ;AAAA,IAClE;AAAA,MAAC;AAAA;AAAA,QACG,KAAK;AAAA,QACL,OAAOA,QAAO,WAAW;AAAA,QACzB,QAAQA,QAAO,WAAW;AAAA,QAC1B,WAAU;AAAA,QACV,SAAS;AAAA;AAAA,IACb;AAAA,IACC,YACG,8CAAC,SAAI,WAAU,0EACf;AAAA,mDAAC,OAAE,WAAU,uCAAsC,uBAAS;AAAA,MAC5D,8CAAC,OAAE,WAAU,2BAA0B;AAAA;AAAA,QAAe;AAAA,SAAM;AAAA,MAC5D,6CAAC,UAAO,SAAS,WAAW,wBAAU;AAAA,OACtC;AAAA,IAGH,YAAY,WACT,6CAAC,SAAI,WAAU,0EACf,uDAAC,OAAE,WAAU,sCAAsC,sBAAY,MAAK,GACpE;AAAA,IAGJ,8CAAC,SAAI,WAAU,gDACX;AAAA,mDAAC,SAAI,4EAA8D;AAAA,MACnE,6CAAC,SAAI,WAAU,8BAA6B,gEAAkD;AAAA,OAClG;AAAA,KACA;AAER;AAEA,IAAO,qBAAQ;","names":["import_jsx_runtime","import_react","import_jsx_runtime","config"]}
|
package/dist/index.css
CHANGED
|
@@ -22,14 +22,24 @@
|
|
|
22
22
|
"Courier New",
|
|
23
23
|
monospace;
|
|
24
24
|
--color-red-500: oklch(63.7% 0.237 25.331);
|
|
25
|
+
--color-yellow-400: oklch(85.2% 0.199 91.936);
|
|
26
|
+
--color-blue-400: oklch(70.7% 0.165 254.624);
|
|
25
27
|
--color-gray-300: oklch(87.2% 0.01 258.338);
|
|
26
|
-
--color-gray-
|
|
28
|
+
--color-gray-400: oklch(70.7% 0.022 261.325);
|
|
29
|
+
--color-black: #000;
|
|
27
30
|
--color-white: #fff;
|
|
28
31
|
--spacing: 0.25rem;
|
|
32
|
+
--container-md: 28rem;
|
|
33
|
+
--text-xs: 0.75rem;
|
|
34
|
+
--text-xs--line-height: calc(1 / 0.75);
|
|
29
35
|
--text-sm: 0.875rem;
|
|
30
36
|
--text-sm--line-height: calc(1.25 / 0.875);
|
|
37
|
+
--text-lg: 1.125rem;
|
|
38
|
+
--text-lg--line-height: calc(1.75 / 1.125);
|
|
31
39
|
--text-xl: 1.25rem;
|
|
32
40
|
--text-xl--line-height: calc(1.75 / 1.25);
|
|
41
|
+
--text-2xl: 1.5rem;
|
|
42
|
+
--text-2xl--line-height: calc(2 / 1.5);
|
|
33
43
|
--font-weight-medium: 500;
|
|
34
44
|
--font-weight-semibold: 600;
|
|
35
45
|
--font-weight-bold: 700;
|
|
@@ -233,6 +243,18 @@
|
|
|
233
243
|
container-type: inline-size;
|
|
234
244
|
container-name: card-header;
|
|
235
245
|
}
|
|
246
|
+
.visible {
|
|
247
|
+
visibility: visible;
|
|
248
|
+
}
|
|
249
|
+
.absolute {
|
|
250
|
+
position: absolute;
|
|
251
|
+
}
|
|
252
|
+
.relative {
|
|
253
|
+
position: relative;
|
|
254
|
+
}
|
|
255
|
+
.inset-0 {
|
|
256
|
+
inset: calc(var(--spacing) * 0);
|
|
257
|
+
}
|
|
236
258
|
.col-start-2 {
|
|
237
259
|
grid-column-start: 2;
|
|
238
260
|
}
|
|
@@ -242,9 +264,18 @@
|
|
|
242
264
|
.row-start-1 {
|
|
243
265
|
grid-row-start: 1;
|
|
244
266
|
}
|
|
267
|
+
.mt-1 {
|
|
268
|
+
margin-top: calc(var(--spacing) * 1);
|
|
269
|
+
}
|
|
245
270
|
.mb-2 {
|
|
246
271
|
margin-bottom: calc(var(--spacing) * 2);
|
|
247
272
|
}
|
|
273
|
+
.mb-3 {
|
|
274
|
+
margin-bottom: calc(var(--spacing) * 3);
|
|
275
|
+
}
|
|
276
|
+
.mb-4 {
|
|
277
|
+
margin-bottom: calc(var(--spacing) * 4);
|
|
278
|
+
}
|
|
248
279
|
.flex {
|
|
249
280
|
display: flex;
|
|
250
281
|
}
|
|
@@ -266,6 +297,9 @@
|
|
|
266
297
|
width: calc(var(--spacing) * 10);
|
|
267
298
|
height: calc(var(--spacing) * 10);
|
|
268
299
|
}
|
|
300
|
+
.h-6 {
|
|
301
|
+
height: calc(var(--spacing) * 6);
|
|
302
|
+
}
|
|
269
303
|
.h-8 {
|
|
270
304
|
height: calc(var(--spacing) * 8);
|
|
271
305
|
}
|
|
@@ -275,9 +309,15 @@
|
|
|
275
309
|
.h-10 {
|
|
276
310
|
height: calc(var(--spacing) * 10);
|
|
277
311
|
}
|
|
312
|
+
.max-w-md {
|
|
313
|
+
max-width: var(--container-md);
|
|
314
|
+
}
|
|
278
315
|
.shrink-0 {
|
|
279
316
|
flex-shrink: 0;
|
|
280
317
|
}
|
|
318
|
+
.cursor-pointer {
|
|
319
|
+
cursor: pointer;
|
|
320
|
+
}
|
|
281
321
|
.auto-rows-min {
|
|
282
322
|
grid-auto-rows: min-content;
|
|
283
323
|
}
|
|
@@ -308,6 +348,9 @@
|
|
|
308
348
|
.gap-6 {
|
|
309
349
|
gap: calc(var(--spacing) * 6);
|
|
310
350
|
}
|
|
351
|
+
.gap-8 {
|
|
352
|
+
gap: calc(var(--spacing) * 8);
|
|
353
|
+
}
|
|
311
354
|
.self-start {
|
|
312
355
|
align-self: flex-start;
|
|
313
356
|
}
|
|
@@ -334,6 +377,12 @@
|
|
|
334
377
|
.bg-background {
|
|
335
378
|
background-color: var(--background);
|
|
336
379
|
}
|
|
380
|
+
.bg-black\/60 {
|
|
381
|
+
background-color: color-mix(in srgb, #000 60%, transparent);
|
|
382
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
383
|
+
background-color: color-mix(in oklab, var(--color-black) 60%, transparent);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
337
386
|
.bg-card {
|
|
338
387
|
background-color: var(--card);
|
|
339
388
|
}
|
|
@@ -367,6 +416,14 @@
|
|
|
367
416
|
.text-center {
|
|
368
417
|
text-align: center;
|
|
369
418
|
}
|
|
419
|
+
.text-2xl {
|
|
420
|
+
font-size: var(--text-2xl);
|
|
421
|
+
line-height: var(--tw-leading, var(--text-2xl--line-height));
|
|
422
|
+
}
|
|
423
|
+
.text-lg {
|
|
424
|
+
font-size: var(--text-lg);
|
|
425
|
+
line-height: var(--tw-leading, var(--text-lg--line-height));
|
|
426
|
+
}
|
|
370
427
|
.text-sm {
|
|
371
428
|
font-size: var(--text-sm);
|
|
372
429
|
line-height: var(--tw-leading, var(--text-sm--line-height));
|
|
@@ -375,6 +432,10 @@
|
|
|
375
432
|
font-size: var(--text-xl);
|
|
376
433
|
line-height: var(--tw-leading, var(--text-xl--line-height));
|
|
377
434
|
}
|
|
435
|
+
.text-xs {
|
|
436
|
+
font-size: var(--text-xs);
|
|
437
|
+
line-height: var(--tw-leading, var(--text-xs--line-height));
|
|
438
|
+
}
|
|
378
439
|
.leading-none {
|
|
379
440
|
--tw-leading: 1;
|
|
380
441
|
line-height: 1;
|
|
@@ -394,11 +455,17 @@
|
|
|
394
455
|
.whitespace-nowrap {
|
|
395
456
|
white-space: nowrap;
|
|
396
457
|
}
|
|
458
|
+
.text-blue-400 {
|
|
459
|
+
color: var(--color-blue-400);
|
|
460
|
+
}
|
|
397
461
|
.text-card-foreground {
|
|
398
462
|
color: var(--card-foreground);
|
|
399
463
|
}
|
|
400
|
-
.text-
|
|
401
|
-
color: var(--
|
|
464
|
+
.text-foreground {
|
|
465
|
+
color: var(--foreground);
|
|
466
|
+
}
|
|
467
|
+
.text-gray-400 {
|
|
468
|
+
color: var(--color-gray-400);
|
|
402
469
|
}
|
|
403
470
|
.text-muted-foreground {
|
|
404
471
|
color: var(--muted-foreground);
|
|
@@ -418,6 +485,9 @@
|
|
|
418
485
|
.text-white {
|
|
419
486
|
color: var(--color-white);
|
|
420
487
|
}
|
|
488
|
+
.text-yellow-400 {
|
|
489
|
+
color: var(--color-yellow-400);
|
|
490
|
+
}
|
|
421
491
|
.underline-offset-4 {
|
|
422
492
|
text-underline-offset: 4px;
|
|
423
493
|
}
|
|
@@ -443,6 +513,34 @@
|
|
|
443
513
|
outline-style: var(--tw-outline-style);
|
|
444
514
|
outline-width: 1px;
|
|
445
515
|
}
|
|
516
|
+
.transition {
|
|
517
|
+
transition-property:
|
|
518
|
+
color,
|
|
519
|
+
background-color,
|
|
520
|
+
border-color,
|
|
521
|
+
outline-color,
|
|
522
|
+
text-decoration-color,
|
|
523
|
+
fill,
|
|
524
|
+
stroke,
|
|
525
|
+
--tw-gradient-from,
|
|
526
|
+
--tw-gradient-via,
|
|
527
|
+
--tw-gradient-to,
|
|
528
|
+
opacity,
|
|
529
|
+
box-shadow,
|
|
530
|
+
transform,
|
|
531
|
+
translate,
|
|
532
|
+
scale,
|
|
533
|
+
rotate,
|
|
534
|
+
filter,
|
|
535
|
+
-webkit-backdrop-filter,
|
|
536
|
+
backdrop-filter,
|
|
537
|
+
display,
|
|
538
|
+
content-visibility,
|
|
539
|
+
overlay,
|
|
540
|
+
pointer-events;
|
|
541
|
+
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
|
542
|
+
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
|
543
|
+
}
|
|
446
544
|
.transition-all {
|
|
447
545
|
transition-property: all;
|
|
448
546
|
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|