react-os-shell 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -9
- package/dist/{Browser-MYVYM7YM.js → Browser-WXHEE7GC.js} +4 -4
- package/dist/{Browser-MYVYM7YM.js.map → Browser-WXHEE7GC.js.map} +1 -1
- package/dist/{Documents-SLODLCU4.js → Documents-DRKELHI6.js} +148 -11
- package/dist/Documents-DRKELHI6.js.map +1 -0
- package/dist/{Files-NE4YZTRX.js → Files-TJTUA2LV.js} +7 -7
- package/dist/{Files-NE4YZTRX.js.map → Files-TJTUA2LV.js.map} +1 -1
- package/dist/{Notepad-F3TLHMWJ.js → Notepad-H6LI3MUZ.js} +3 -3
- package/dist/{Notepad-F3TLHMWJ.js.map → Notepad-H6LI3MUZ.js.map} +1 -1
- package/dist/Preview-J63FQ336.js +9 -0
- package/dist/{Preview-HFGTMXE7.js.map → Preview-J63FQ336.js.map} +1 -1
- package/dist/{Spreadsheet-WF34DA44.js → Spreadsheet-Q5VPXFJK.js} +4 -4
- package/dist/{Spreadsheet-WF34DA44.js.map → Spreadsheet-Q5VPXFJK.js.map} +1 -1
- package/dist/apps/index.d.ts +1 -20
- package/dist/apps/index.js +13 -28
- package/dist/apps/index.js.map +1 -1
- package/dist/{chunk-W5ARJ7PU.js → chunk-2N4EEBHF.js} +5 -5
- package/dist/{chunk-W5ARJ7PU.js.map → chunk-2N4EEBHF.js.map} +1 -1
- package/dist/{chunk-PTRHYPXO.js → chunk-7FNPV6CE.js} +3 -3
- package/dist/{chunk-PTRHYPXO.js.map → chunk-7FNPV6CE.js.map} +1 -1
- package/dist/{chunk-RE2FEWBE.js → chunk-DOSYYJSP.js} +4 -4
- package/dist/{chunk-RE2FEWBE.js.map → chunk-DOSYYJSP.js.map} +1 -1
- package/dist/{chunk-XHBHCL5I.js → chunk-HMYEAOUF.js} +3 -3
- package/dist/{chunk-XHBHCL5I.js.map → chunk-HMYEAOUF.js.map} +1 -1
- package/dist/{chunk-F6NIGZTF.js → chunk-OMY5HWY2.js} +4 -4
- package/dist/{chunk-F6NIGZTF.js.map → chunk-OMY5HWY2.js.map} +1 -1
- package/dist/{chunk-IJ5Y4EGQ.js → chunk-ROSSX5DN.js} +3 -3
- package/dist/{chunk-IJ5Y4EGQ.js.map → chunk-ROSSX5DN.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +35 -9
- package/dist/index.js.map +1 -1
- package/dist/styles.css +12 -0
- package/package.json +1 -1
- package/dist/Checkers-MIAHIKJH.js +0 -214
- package/dist/Checkers-MIAHIKJH.js.map +0 -1
- package/dist/Chess-C5BY45NA.js +0 -190
- package/dist/Chess-C5BY45NA.js.map +0 -1
- package/dist/Documents-SLODLCU4.js.map +0 -1
- package/dist/Game2048-3RH3ELRD.js +0 -191
- package/dist/Game2048-3RH3ELRD.js.map +0 -1
- package/dist/Minesweeper-OXRRSCVF.js +0 -271
- package/dist/Minesweeper-OXRRSCVF.js.map +0 -1
- package/dist/Preview-HFGTMXE7.js +0 -9
- package/dist/Sudoku-XHLYCEVT.js +0 -197
- package/dist/Sudoku-XHLYCEVT.js.map +0 -1
- package/dist/Tetris-ZHCZYL24.js +0 -243
- package/dist/Tetris-ZHCZYL24.js.map +0 -1
- package/dist/chunk-Y4QYGQKS.js +0 -31
- package/dist/chunk-Y4QYGQKS.js.map +0 -1
package/dist/Sudoku-XHLYCEVT.js
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
2
|
-
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
3
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
-
|
|
5
|
-
function shuffle(arr) {
|
|
6
|
-
for (let i = arr.length - 1; i > 0; i--) {
|
|
7
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
8
|
-
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
9
|
-
}
|
|
10
|
-
return arr;
|
|
11
|
-
}
|
|
12
|
-
function emptyBoard() {
|
|
13
|
-
return Array.from({ length: 9 }, () => Array(9).fill(null));
|
|
14
|
-
}
|
|
15
|
-
function isValid(board, r, c, num) {
|
|
16
|
-
for (let i = 0; i < 9; i++) {
|
|
17
|
-
if (board[r][i] === num || board[i][c] === num) return false;
|
|
18
|
-
}
|
|
19
|
-
const br = Math.floor(r / 3) * 3, bc = Math.floor(c / 3) * 3;
|
|
20
|
-
for (let i = br; i < br + 3; i++)
|
|
21
|
-
for (let j = bc; j < bc + 3; j++)
|
|
22
|
-
if (board[i][j] === num) return false;
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
function solve(board) {
|
|
26
|
-
for (let r = 0; r < 9; r++)
|
|
27
|
-
for (let c = 0; c < 9; c++) {
|
|
28
|
-
if (board[r][c] !== null) continue;
|
|
29
|
-
const nums = shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
30
|
-
for (const n of nums) {
|
|
31
|
-
if (isValid(board, r, c, n)) {
|
|
32
|
-
board[r][c] = n;
|
|
33
|
-
if (solve(board)) return true;
|
|
34
|
-
board[r][c] = null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
function generatePuzzle() {
|
|
42
|
-
const board = emptyBoard();
|
|
43
|
-
solve(board);
|
|
44
|
-
const givens = Array.from({ length: 9 }, () => Array(9).fill(true));
|
|
45
|
-
const cells = shuffle(
|
|
46
|
-
Array.from({ length: 81 }, (_, i) => [Math.floor(i / 9), i % 9])
|
|
47
|
-
);
|
|
48
|
-
let removed = 0;
|
|
49
|
-
for (const [r, c] of cells) {
|
|
50
|
-
if (removed >= 51) break;
|
|
51
|
-
board[r][c] = null;
|
|
52
|
-
givens[r][c] = false;
|
|
53
|
-
removed++;
|
|
54
|
-
}
|
|
55
|
-
return { puzzle: board, givens };
|
|
56
|
-
}
|
|
57
|
-
function hasConflict(board, r, c) {
|
|
58
|
-
const val = board[r][c];
|
|
59
|
-
if (val === null) return false;
|
|
60
|
-
for (let i = 0; i < 9; i++) {
|
|
61
|
-
if (i !== c && board[r][i] === val) return true;
|
|
62
|
-
if (i !== r && board[i][c] === val) return true;
|
|
63
|
-
}
|
|
64
|
-
const br = Math.floor(r / 3) * 3, bc = Math.floor(c / 3) * 3;
|
|
65
|
-
for (let i = br; i < br + 3; i++)
|
|
66
|
-
for (let j = bc; j < bc + 3; j++)
|
|
67
|
-
if ((i !== r || j !== c) && board[i][j] === val) return true;
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
function formatTime(s) {
|
|
71
|
-
const m = Math.floor(s / 60);
|
|
72
|
-
const sec = s % 60;
|
|
73
|
-
return `${m}:${sec.toString().padStart(2, "0")}`;
|
|
74
|
-
}
|
|
75
|
-
function Sudoku() {
|
|
76
|
-
const [board, setBoard] = useState(emptyBoard());
|
|
77
|
-
const [givens, setGivens] = useState(Array.from({ length: 9 }, () => Array(9).fill(false)));
|
|
78
|
-
const [selected, setSelected] = useState(null);
|
|
79
|
-
const [seconds, setSeconds] = useState(0);
|
|
80
|
-
const [running, setRunning] = useState(false);
|
|
81
|
-
const timerRef = useRef(null);
|
|
82
|
-
const startGame = useCallback(() => {
|
|
83
|
-
const { puzzle, givens: g } = generatePuzzle();
|
|
84
|
-
setBoard(puzzle);
|
|
85
|
-
setGivens(g);
|
|
86
|
-
setSelected(null);
|
|
87
|
-
setSeconds(0);
|
|
88
|
-
setRunning(true);
|
|
89
|
-
}, []);
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
startGame();
|
|
92
|
-
}, [startGame]);
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
if (running) {
|
|
95
|
-
timerRef.current = setInterval(() => setSeconds((s) => s + 1), 1e3);
|
|
96
|
-
} else if (timerRef.current) {
|
|
97
|
-
clearInterval(timerRef.current);
|
|
98
|
-
}
|
|
99
|
-
return () => {
|
|
100
|
-
if (timerRef.current) clearInterval(timerRef.current);
|
|
101
|
-
};
|
|
102
|
-
}, [running]);
|
|
103
|
-
const handleKey = useCallback((e) => {
|
|
104
|
-
if (!selected) return;
|
|
105
|
-
const [r, c] = selected;
|
|
106
|
-
if (givens[r][c]) return;
|
|
107
|
-
if (e.key >= "1" && e.key <= "9") {
|
|
108
|
-
setBoard((b) => {
|
|
109
|
-
const nb = b.map((row) => [...row]);
|
|
110
|
-
nb[r][c] = parseInt(e.key);
|
|
111
|
-
return nb;
|
|
112
|
-
});
|
|
113
|
-
} else if (e.key === "Backspace" || e.key === "Delete") {
|
|
114
|
-
setBoard((b) => {
|
|
115
|
-
const nb = b.map((row) => [...row]);
|
|
116
|
-
nb[r][c] = null;
|
|
117
|
-
return nb;
|
|
118
|
-
});
|
|
119
|
-
} else if (e.key === "ArrowUp" && r > 0) setSelected([r - 1, c]);
|
|
120
|
-
else if (e.key === "ArrowDown" && r < 8) setSelected([r + 1, c]);
|
|
121
|
-
else if (e.key === "ArrowLeft" && c > 0) setSelected([r, c - 1]);
|
|
122
|
-
else if (e.key === "ArrowRight" && c < 8) setSelected([r, c + 1]);
|
|
123
|
-
}, [selected, givens]);
|
|
124
|
-
const checkSolution = useCallback(() => {
|
|
125
|
-
let hasEmpty = false, hasError = false;
|
|
126
|
-
for (let r = 0; r < 9; r++)
|
|
127
|
-
for (let c = 0; c < 9; c++) {
|
|
128
|
-
if (board[r][c] === null) hasEmpty = true;
|
|
129
|
-
else if (hasConflict(board, r, c)) hasError = true;
|
|
130
|
-
}
|
|
131
|
-
if (hasError) toast_default.error("There are conflicts on the board.");
|
|
132
|
-
else if (hasEmpty) toast_default.info("Board is not yet complete.");
|
|
133
|
-
else {
|
|
134
|
-
toast_default.success("Congratulations! Puzzle solved!");
|
|
135
|
-
setRunning(false);
|
|
136
|
-
}
|
|
137
|
-
}, [board]);
|
|
138
|
-
const inSameGroup = (r, c) => {
|
|
139
|
-
if (!selected) return false;
|
|
140
|
-
const [sr, sc] = selected;
|
|
141
|
-
return r === sr || c === sc || Math.floor(r / 3) === Math.floor(sr / 3) && Math.floor(c / 3) === Math.floor(sc / 3);
|
|
142
|
-
};
|
|
143
|
-
const cellBg = (r, c) => {
|
|
144
|
-
const isSelected = selected && selected[0] === r && selected[1] === c;
|
|
145
|
-
const val = board[r][c];
|
|
146
|
-
const conflict = val !== null && hasConflict(board, r, c);
|
|
147
|
-
if (conflict) return "bg-red-100";
|
|
148
|
-
if (isSelected) return "bg-blue-200";
|
|
149
|
-
const sameNum = selected && val !== null && val === board[selected[0]][selected[1]];
|
|
150
|
-
if (sameNum) return "bg-blue-100";
|
|
151
|
-
if (inSameGroup(r, c)) return "bg-gray-100";
|
|
152
|
-
return "bg-white";
|
|
153
|
-
};
|
|
154
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4 p-6 select-none", onKeyDown: handleKey, tabIndex: 0, children: [
|
|
155
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6", children: [
|
|
156
|
-
/* @__PURE__ */ jsx("span", { className: "text-lg font-mono font-semibold text-gray-700", children: formatTime(seconds) }),
|
|
157
|
-
/* @__PURE__ */ jsx(
|
|
158
|
-
"button",
|
|
159
|
-
{
|
|
160
|
-
onClick: startGame,
|
|
161
|
-
className: "px-3 py-1.5 text-sm font-medium bg-blue-600 text-white rounded hover:bg-blue-700",
|
|
162
|
-
children: "New Game"
|
|
163
|
-
}
|
|
164
|
-
),
|
|
165
|
-
/* @__PURE__ */ jsx(
|
|
166
|
-
"button",
|
|
167
|
-
{
|
|
168
|
-
onClick: checkSolution,
|
|
169
|
-
className: "px-3 py-1.5 text-sm font-medium bg-green-600 text-white rounded hover:bg-green-700",
|
|
170
|
-
children: "Check"
|
|
171
|
-
}
|
|
172
|
-
)
|
|
173
|
-
] }),
|
|
174
|
-
/* @__PURE__ */ jsx("div", { className: "border-2 border-gray-800 inline-grid grid-cols-9", style: { lineHeight: 0 }, children: board.map(
|
|
175
|
-
(row, r) => row.map((val, c) => {
|
|
176
|
-
const borderR = c % 3 === 2 && c < 8 ? "border-r-2 border-r-gray-800" : "border-r border-r-gray-300";
|
|
177
|
-
const borderB = r % 3 === 2 && r < 8 ? "border-b-2 border-b-gray-800" : "border-b border-b-gray-300";
|
|
178
|
-
return /* @__PURE__ */ jsx(
|
|
179
|
-
"div",
|
|
180
|
-
{
|
|
181
|
-
className: `w-10 h-10 flex items-center justify-center text-lg cursor-pointer
|
|
182
|
-
${borderR} ${borderB} ${cellBg(r, c)}
|
|
183
|
-
${givens[r][c] ? "font-bold text-gray-900" : "text-blue-600"}`,
|
|
184
|
-
onClick: () => setSelected([r, c]),
|
|
185
|
-
children: val ?? ""
|
|
186
|
-
},
|
|
187
|
-
`${r}-${c}`
|
|
188
|
-
);
|
|
189
|
-
})
|
|
190
|
-
) }),
|
|
191
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-400", children: "Click a cell, type 1-9 to fill, Backspace to clear. Arrow keys to navigate." })
|
|
192
|
-
] });
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export { Sudoku as default };
|
|
196
|
-
//# sourceMappingURL=Sudoku-XHLYCEVT.js.map
|
|
197
|
-
//# sourceMappingURL=Sudoku-XHLYCEVT.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/Sudoku.tsx"],"names":[],"mappings":";;;;AAMA,SAAS,QAAW,GAAA,EAAe;AACjC,EAAA,KAAA,IAAS,IAAI,GAAA,CAAI,MAAA,GAAS,CAAA,EAAG,CAAA,GAAI,GAAG,CAAA,EAAA,EAAK;AACvC,IAAA,MAAM,IAAI,IAAA,CAAK,KAAA,CAAM,KAAK,MAAA,EAAO,IAAK,IAAI,CAAA,CAAE,CAAA;AAC5C,IAAA,CAAC,GAAA,CAAI,CAAC,CAAA,EAAG,GAAA,CAAI,CAAC,CAAC,CAAA,GAAI,CAAC,GAAA,CAAI,CAAC,CAAA,EAAG,GAAA,CAAI,CAAC,CAAC,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,UAAA,GAAoB;AAC3B,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA,EAAE,EAAG,MAAM,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAC5D;AAEA,SAAS,OAAA,CAAQ,KAAA,EAAc,CAAA,EAAW,CAAA,EAAW,GAAA,EAAsB;AACzE,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,IAAI,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA,KAAM,GAAA,IAAO,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA,KAAM,GAAA,EAAK,OAAO,KAAA;AAAA,EACzD;AACA,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA,EAAG,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA;AAC3D,EAAA,KAAA,IAAS,CAAA,GAAI,EAAA,EAAI,CAAA,GAAI,EAAA,GAAK,CAAA,EAAG,CAAA,EAAA;AAC3B,IAAA,KAAA,IAAS,CAAA,GAAI,EAAA,EAAI,CAAA,GAAI,EAAA,GAAK,CAAA,EAAG,CAAA,EAAA;AAC3B,MAAA,IAAI,MAAM,CAAC,CAAA,CAAE,CAAC,CAAA,KAAM,KAAK,OAAO,KAAA;AACpC,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,MAAM,KAAA,EAAuB;AACpC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA;AACrB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,MAAA,IAAI,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,MAAM,IAAA,EAAM;AAC1B,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAC,CAAA;AAChD,MAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AACpB,QAAA,IAAI,OAAA,CAAQ,KAAA,EAAO,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,EAAG;AAC3B,UAAA,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACd,UAAA,IAAI,KAAA,CAAM,KAAK,CAAA,EAAG,OAAO,IAAA;AACzB,UAAA,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA;AAAA,QAChB;AAAA,MACF;AACA,MAAA,OAAO,KAAA;AAAA,IACT;AACF,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,cAAA,GAAoD;AAC3D,EAAA,MAAM,QAAQ,UAAA,EAAW;AACzB,EAAA,KAAA,CAAM,KAAK,CAAA;AACX,EAAA,MAAM,MAAA,GAAiB,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA,EAAE,EAAG,MAAM,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA;AAC1E,EAAA,MAAM,KAAA,GAAQ,OAAA;AAAA,IACZ,MAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,EAAA,IAAM,CAAC,CAAA,EAAG,CAAA,KAAM,CAAC,KAAK,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,EAAG,CAAA,GAAI,CAAC,CAAqB;AAAA,GACrF;AACA,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,CAAA,IAAK,KAAA,EAAO;AAC1B,IAAA,IAAI,WAAW,EAAA,EAAI;AACnB,IAAA,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA;AACd,IAAA,MAAA,CAAO,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,KAAA;AACf,IAAA,OAAA,EAAA;AAAA,EACF;AACA,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAO;AACjC;AAEA,SAAS,WAAA,CAAY,KAAA,EAAc,CAAA,EAAW,CAAA,EAAoB;AAChE,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA;AACtB,EAAA,IAAI,GAAA,KAAQ,MAAM,OAAO,KAAA;AACzB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,IAAI,CAAA,KAAM,KAAK,KAAA,CAAM,CAAC,EAAE,CAAC,CAAA,KAAM,KAAK,OAAO,IAAA;AAC3C,IAAA,IAAI,CAAA,KAAM,KAAK,KAAA,CAAM,CAAC,EAAE,CAAC,CAAA,KAAM,KAAK,OAAO,IAAA;AAAA,EAC7C;AACA,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA,EAAG,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA;AAC3D,EAAA,KAAA,IAAS,CAAA,GAAI,EAAA,EAAI,CAAA,GAAI,EAAA,GAAK,CAAA,EAAG,CAAA,EAAA;AAC3B,IAAA,KAAA,IAAS,CAAA,GAAI,EAAA,EAAI,CAAA,GAAI,EAAA,GAAK,CAAA,EAAG,CAAA,EAAA;AAC3B,MAAA,IAAA,CAAK,CAAA,KAAM,CAAA,IAAK,CAAA,KAAM,CAAA,KAAM,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA,KAAM,GAAA,EAAK,OAAO,IAAA;AAC5D,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,WAAW,CAAA,EAAmB;AACrC,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,EAAE,CAAA;AAC3B,EAAA,MAAM,MAAM,CAAA,GAAI,EAAA;AAChB,EAAA,OAAO,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,UAAS,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAChD;AAEe,SAAR,MAAA,GAA0B;AAC/B,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAAA,CAAgB,YAAY,CAAA;AACtD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,IAAI,QAAA,CAAiB,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,CAAA,EAAE,EAAG,MAAM,KAAA,CAAM,CAAC,EAAE,IAAA,CAAK,KAAK,CAAC,CAAC,CAAA;AAClG,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAkC,IAAI,CAAA;AACtE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,CAAC,CAAA;AACxC,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,QAAA,GAAW,OAA8C,IAAI,CAAA;AAEnE,EAAA,MAAM,SAAA,GAAY,YAAY,MAAM;AAClC,IAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAQ,CAAA,KAAM,cAAA,EAAe;AAC7C,IAAA,QAAA,CAAS,MAAM,CAAA;AACf,IAAA,SAAA,CAAU,CAAC,CAAA;AACX,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,UAAA,CAAW,CAAC,CAAA;AACZ,IAAA,UAAA,CAAW,IAAI,CAAA;AAAA,EACjB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AAAE,IAAA,SAAA,EAAU;AAAA,EAAG,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAE7C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAA,EAAS;AACX,MAAA,QAAA,CAAS,OAAA,GAAU,YAAY,MAAM,UAAA,CAAW,OAAK,CAAA,GAAI,CAAC,GAAG,GAAI,CAAA;AAAA,IACnE,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAC3B,MAAA,aAAA,CAAc,SAAS,OAAO,CAAA;AAAA,IAChC;AACA,IAAA,OAAO,MAAM;AAAE,MAAA,IAAI,QAAA,CAAS,OAAA,EAAS,aAAA,CAAc,QAAA,CAAS,OAAO,CAAA;AAAA,IAAG,CAAA;AAAA,EACxE,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,CAAC,CAAA,KAA2B;AACxD,IAAA,IAAI,CAAC,QAAA,EAAU;AACf,IAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,QAAA;AACf,IAAA,IAAI,MAAA,CAAO,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG;AAClB,IAAA,IAAI,CAAA,CAAE,GAAA,IAAO,GAAA,IAAO,CAAA,CAAE,OAAO,GAAA,EAAK;AAChC,MAAA,QAAA,CAAS,CAAA,CAAA,KAAK;AAAE,QAAA,MAAM,KAAK,CAAA,CAAE,GAAA,CAAI,SAAO,CAAC,GAAG,GAAG,CAAC,CAAA;AAAG,QAAA,EAAA,CAAG,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,QAAA,CAAS,EAAE,GAAG,CAAA;AAAG,QAAA,OAAO,EAAA;AAAA,MAAI,CAAC,CAAA;AAAA,IAC7F,WAAW,CAAA,CAAE,GAAA,KAAQ,WAAA,IAAe,CAAA,CAAE,QAAQ,QAAA,EAAU;AACtD,MAAA,QAAA,CAAS,CAAA,CAAA,KAAK;AAAE,QAAA,MAAM,KAAK,CAAA,CAAE,GAAA,CAAI,SAAO,CAAC,GAAG,GAAG,CAAC,CAAA;AAAG,QAAA,EAAA,CAAG,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA;AAAM,QAAA,OAAO,EAAA;AAAA,MAAI,CAAC,CAAA;AAAA,IAClF,CAAA,MAAA,IAAW,CAAA,CAAE,GAAA,KAAQ,SAAA,IAAa,CAAA,GAAI,CAAA,EAAG,WAAA,CAAY,CAAC,CAAA,GAAI,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,SAAA,IACtD,CAAA,CAAE,GAAA,KAAQ,WAAA,IAAe,CAAA,GAAI,CAAA,cAAe,CAAC,CAAA,GAAI,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,SAAA,IACtD,CAAA,CAAE,GAAA,KAAQ,WAAA,IAAe,CAAA,GAAI,CAAA,cAAe,CAAC,CAAA,EAAG,CAAA,GAAI,CAAC,CAAC,CAAA;AAAA,SAAA,IACtD,CAAA,CAAE,GAAA,KAAQ,YAAA,IAAgB,CAAA,GAAI,CAAA,cAAe,CAAC,CAAA,EAAG,CAAA,GAAI,CAAC,CAAC,CAAA;AAAA,EAClE,CAAA,EAAG,CAAC,QAAA,EAAU,MAAM,CAAC,CAAA;AAErB,EAAA,MAAM,aAAA,GAAgB,YAAY,MAAM;AACtC,IAAA,IAAI,QAAA,GAAW,OAAO,QAAA,GAAW,KAAA;AACjC,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA;AACrB,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,QAAA,IAAI,MAAM,CAAC,CAAA,CAAE,CAAC,CAAA,KAAM,MAAM,QAAA,GAAW,IAAA;AAAA,aAAA,IAC5B,WAAA,CAAY,KAAA,EAAO,CAAA,EAAG,CAAC,GAAG,QAAA,GAAW,IAAA;AAAA,MAChD;AACF,IAAA,IAAI,QAAA,EAAU,aAAA,CAAM,KAAA,CAAM,mCAAmC,CAAA;AAAA,SAAA,IACpD,QAAA,EAAU,aAAA,CAAM,IAAA,CAAK,4BAA4B,CAAA;AAAA,SACrD;AAAE,MAAA,aAAA,CAAM,QAAQ,iCAAiC,CAAA;AAAG,MAAA,UAAA,CAAW,KAAK,CAAA;AAAA,IAAG;AAAA,EAC9E,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,MAAM,WAAA,GAAc,CAAC,CAAA,EAAW,CAAA,KAAuB;AACrD,IAAA,IAAI,CAAC,UAAU,OAAO,KAAA;AACtB,IAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,QAAA;AACjB,IAAA,OAAO,CAAA,KAAM,MAAM,CAAA,KAAM,EAAA,IACtB,KAAK,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,KAAM,IAAA,CAAK,KAAA,CAAM,KAAK,CAAC,CAAA,IAAK,KAAK,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,KAAM,IAAA,CAAK,KAAA,CAAM,EAAA,GAAK,CAAC,CAAA;AAAA,EACxF,CAAA;AAEA,EAAA,MAAM,MAAA,GAAS,CAAC,CAAA,EAAW,CAAA,KAAsB;AAC/C,IAAA,MAAM,UAAA,GAAa,YAAY,QAAA,CAAS,CAAC,MAAM,CAAA,IAAK,QAAA,CAAS,CAAC,CAAA,KAAM,CAAA;AACpE,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,CAAC,CAAA,CAAE,CAAC,CAAA;AACtB,IAAA,MAAM,WAAW,GAAA,KAAQ,IAAA,IAAQ,WAAA,CAAY,KAAA,EAAO,GAAG,CAAC,CAAA;AACxD,IAAA,IAAI,UAAU,OAAO,YAAA;AACrB,IAAA,IAAI,YAAY,OAAO,aAAA;AACvB,IAAA,MAAM,OAAA,GAAU,QAAA,IAAY,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,KAAA,CAAM,QAAA,CAAS,CAAC,CAAC,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA;AAClF,IAAA,IAAI,SAAS,OAAO,aAAA;AACpB,IAAA,IAAI,WAAA,CAAY,CAAA,EAAG,CAAC,CAAA,EAAG,OAAO,aAAA;AAC9B,IAAA,OAAO,UAAA;AAAA,EACT,CAAA;AAEA,EAAA,4BACG,KAAA,EAAA,EAAI,SAAA,EAAU,oDAAmD,SAAA,EAAW,SAAA,EAAW,UAAU,CAAA,EAChG,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yBAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,+CAAA,EAAiD,QAAA,EAAA,UAAA,CAAW,OAAO,CAAA,EAAE,CAAA;AAAA,sBACrF,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UAAO,OAAA,EAAS,SAAA;AAAA,UACf,SAAA,EAAU,kFAAA;AAAA,UAAmF,QAAA,EAAA;AAAA;AAAA,OAE/F;AAAA,sBACA,GAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UAAO,OAAA,EAAS,aAAA;AAAA,UACf,SAAA,EAAU,oFAAA;AAAA,UAAqF,QAAA,EAAA;AAAA;AAAA;AAEjG,KAAA,EACF,CAAA;AAAA,oBACA,GAAA,CAAC,SAAI,SAAA,EAAU,kDAAA,EAAmD,OAAO,EAAE,UAAA,EAAY,CAAA,EAAE,EACtF,QAAA,EAAA,KAAA,CAAM,GAAA;AAAA,MAAI,CAAC,GAAA,EAAK,CAAA,KACf,IAAI,GAAA,CAAI,CAAC,KAAK,CAAA,KAAM;AAClB,QAAA,MAAM,UAAU,CAAA,GAAI,CAAA,KAAM,CAAA,IAAK,CAAA,GAAI,IAAI,8BAAA,GAAiC,4BAAA;AACxE,QAAA,MAAM,UAAU,CAAA,GAAI,CAAA,KAAM,CAAA,IAAK,CAAA,GAAI,IAAI,8BAAA,GAAiC,4BAAA;AACxE,QAAA,uBACE,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,CAAA;AAAA,kBAAA,EACP,OAAO,CAAA,CAAA,EAAI,OAAO,IAAI,MAAA,CAAO,CAAA,EAAG,CAAC,CAAC;AAAA,kBAAA,EAClC,OAAO,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,4BAA4B,eAAe,CAAA,CAAA;AAAA,YAC9D,SAAS,MAAM,WAAA,CAAY,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,YAChC,QAAA,EAAA,GAAA,IAAO;AAAA,WAAA;AAAA,UALA,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA;AAAA,SAMnB;AAAA,MAEJ,CAAC;AAAA,KACH,EACF,CAAA;AAAA,oBACA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,uBAAA,EAAwB,QAAA,EAAA,6EAAA,EAA2E;AAAA,GAAA,EAClH,CAAA;AAEJ","file":"Sudoku-XHLYCEVT.js","sourcesContent":["import { useState, useCallback, useEffect, useRef } from 'react';\nimport toast from '../shell/toast';\n\ntype Board = (number | null)[][];\ntype Givens = boolean[][];\n\nfunction shuffle<T>(arr: T[]): T[] {\n for (let i = arr.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [arr[i], arr[j]] = [arr[j], arr[i]];\n }\n return arr;\n}\n\nfunction emptyBoard(): Board {\n return Array.from({ length: 9 }, () => Array(9).fill(null));\n}\n\nfunction isValid(board: Board, r: number, c: number, num: number): boolean {\n for (let i = 0; i < 9; i++) {\n if (board[r][i] === num || board[i][c] === num) return false;\n }\n const br = Math.floor(r / 3) * 3, bc = Math.floor(c / 3) * 3;\n for (let i = br; i < br + 3; i++)\n for (let j = bc; j < bc + 3; j++)\n if (board[i][j] === num) return false;\n return true;\n}\n\nfunction solve(board: Board): boolean {\n for (let r = 0; r < 9; r++)\n for (let c = 0; c < 9; c++) {\n if (board[r][c] !== null) continue;\n const nums = shuffle([1, 2, 3, 4, 5, 6, 7, 8, 9]);\n for (const n of nums) {\n if (isValid(board, r, c, n)) {\n board[r][c] = n;\n if (solve(board)) return true;\n board[r][c] = null;\n }\n }\n return false;\n }\n return true;\n}\n\nfunction generatePuzzle(): { puzzle: Board; givens: Givens } {\n const board = emptyBoard();\n solve(board);\n const givens: Givens = Array.from({ length: 9 }, () => Array(9).fill(true));\n const cells = shuffle(\n Array.from({ length: 81 }, (_, i) => [Math.floor(i / 9), i % 9] as [number, number])\n );\n let removed = 0;\n for (const [r, c] of cells) {\n if (removed >= 51) break; // 81 - 51 = 30 givens\n board[r][c] = null;\n givens[r][c] = false;\n removed++;\n }\n return { puzzle: board, givens };\n}\n\nfunction hasConflict(board: Board, r: number, c: number): boolean {\n const val = board[r][c];\n if (val === null) return false;\n for (let i = 0; i < 9; i++) {\n if (i !== c && board[r][i] === val) return true;\n if (i !== r && board[i][c] === val) return true;\n }\n const br = Math.floor(r / 3) * 3, bc = Math.floor(c / 3) * 3;\n for (let i = br; i < br + 3; i++)\n for (let j = bc; j < bc + 3; j++)\n if ((i !== r || j !== c) && board[i][j] === val) return true;\n return false;\n}\n\nfunction formatTime(s: number): string {\n const m = Math.floor(s / 60);\n const sec = s % 60;\n return `${m}:${sec.toString().padStart(2, '0')}`;\n}\n\nexport default function Sudoku() {\n const [board, setBoard] = useState<Board>(emptyBoard());\n const [givens, setGivens] = useState<Givens>(Array.from({ length: 9 }, () => Array(9).fill(false)));\n const [selected, setSelected] = useState<[number, number] | null>(null);\n const [seconds, setSeconds] = useState(0);\n const [running, setRunning] = useState(false);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const startGame = useCallback(() => {\n const { puzzle, givens: g } = generatePuzzle();\n setBoard(puzzle);\n setGivens(g);\n setSelected(null);\n setSeconds(0);\n setRunning(true);\n }, []);\n\n useEffect(() => { startGame(); }, [startGame]);\n\n useEffect(() => {\n if (running) {\n timerRef.current = setInterval(() => setSeconds(s => s + 1), 1000);\n } else if (timerRef.current) {\n clearInterval(timerRef.current);\n }\n return () => { if (timerRef.current) clearInterval(timerRef.current); };\n }, [running]);\n\n const handleKey = useCallback((e: React.KeyboardEvent) => {\n if (!selected) return;\n const [r, c] = selected;\n if (givens[r][c]) return;\n if (e.key >= '1' && e.key <= '9') {\n setBoard(b => { const nb = b.map(row => [...row]); nb[r][c] = parseInt(e.key); return nb; });\n } else if (e.key === 'Backspace' || e.key === 'Delete') {\n setBoard(b => { const nb = b.map(row => [...row]); nb[r][c] = null; return nb; });\n } else if (e.key === 'ArrowUp' && r > 0) setSelected([r - 1, c]);\n else if (e.key === 'ArrowDown' && r < 8) setSelected([r + 1, c]);\n else if (e.key === 'ArrowLeft' && c > 0) setSelected([r, c - 1]);\n else if (e.key === 'ArrowRight' && c < 8) setSelected([r, c + 1]);\n }, [selected, givens]);\n\n const checkSolution = useCallback(() => {\n let hasEmpty = false, hasError = false;\n for (let r = 0; r < 9; r++)\n for (let c = 0; c < 9; c++) {\n if (board[r][c] === null) hasEmpty = true;\n else if (hasConflict(board, r, c)) hasError = true;\n }\n if (hasError) toast.error('There are conflicts on the board.');\n else if (hasEmpty) toast.info('Board is not yet complete.');\n else { toast.success('Congratulations! Puzzle solved!'); setRunning(false); }\n }, [board]);\n\n const inSameGroup = (r: number, c: number): boolean => {\n if (!selected) return false;\n const [sr, sc] = selected;\n return r === sr || c === sc ||\n (Math.floor(r / 3) === Math.floor(sr / 3) && Math.floor(c / 3) === Math.floor(sc / 3));\n };\n\n const cellBg = (r: number, c: number): string => {\n const isSelected = selected && selected[0] === r && selected[1] === c;\n const val = board[r][c];\n const conflict = val !== null && hasConflict(board, r, c);\n if (conflict) return 'bg-red-100';\n if (isSelected) return 'bg-blue-200';\n const sameNum = selected && val !== null && val === board[selected[0]][selected[1]];\n if (sameNum) return 'bg-blue-100';\n if (inSameGroup(r, c)) return 'bg-gray-100';\n return 'bg-white';\n };\n\n return (\n <div className=\"flex flex-col items-center gap-4 p-6 select-none\" onKeyDown={handleKey} tabIndex={0}>\n <div className=\"flex items-center gap-6\">\n <span className=\"text-lg font-mono font-semibold text-gray-700\">{formatTime(seconds)}</span>\n <button onClick={startGame}\n className=\"px-3 py-1.5 text-sm font-medium bg-blue-600 text-white rounded hover:bg-blue-700\">\n New Game\n </button>\n <button onClick={checkSolution}\n className=\"px-3 py-1.5 text-sm font-medium bg-green-600 text-white rounded hover:bg-green-700\">\n Check\n </button>\n </div>\n <div className=\"border-2 border-gray-800 inline-grid grid-cols-9\" style={{ lineHeight: 0 }}>\n {board.map((row, r) =>\n row.map((val, c) => {\n const borderR = c % 3 === 2 && c < 8 ? 'border-r-2 border-r-gray-800' : 'border-r border-r-gray-300';\n const borderB = r % 3 === 2 && r < 8 ? 'border-b-2 border-b-gray-800' : 'border-b border-b-gray-300';\n return (\n <div key={`${r}-${c}`}\n className={`w-10 h-10 flex items-center justify-center text-lg cursor-pointer\n ${borderR} ${borderB} ${cellBg(r, c)}\n ${givens[r][c] ? 'font-bold text-gray-900' : 'text-blue-600'}`}\n onClick={() => setSelected([r, c])}>\n {val ?? ''}\n </div>\n );\n })\n )}\n </div>\n <p className=\"text-xs text-gray-400\">Click a cell, type 1-9 to fill, Backspace to clear. Arrow keys to navigate.</p>\n </div>\n );\n}\n"]}
|
package/dist/Tetris-ZHCZYL24.js
DELETED
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
-
|
|
4
|
-
// src/apps/Tetris.tsx
|
|
5
|
-
var COLS = 10;
|
|
6
|
-
var ROWS = 20;
|
|
7
|
-
var CELL = 28;
|
|
8
|
-
var SHAPES = [
|
|
9
|
-
[[1, 1, 1, 1]],
|
|
10
|
-
// I
|
|
11
|
-
[[1, 1], [1, 1]],
|
|
12
|
-
// O
|
|
13
|
-
[[0, 1, 0], [1, 1, 1]],
|
|
14
|
-
// T
|
|
15
|
-
[[0, 1, 1], [1, 1, 0]],
|
|
16
|
-
// S
|
|
17
|
-
[[1, 1, 0], [0, 1, 1]],
|
|
18
|
-
// Z
|
|
19
|
-
[[1, 0, 0], [1, 1, 1]],
|
|
20
|
-
// J
|
|
21
|
-
[[0, 0, 1], [1, 1, 1]]
|
|
22
|
-
// L
|
|
23
|
-
];
|
|
24
|
-
var COLORS = ["#00f0f0", "#f0f000", "#a000f0", "#00f000", "#f00000", "#0000f0", "#f0a000"];
|
|
25
|
-
var rotate = (m) => m[0].map((_, i) => m.map((r) => r[i]).reverse());
|
|
26
|
-
var newPiece = (idx) => ({
|
|
27
|
-
shape: SHAPES[idx],
|
|
28
|
-
color: COLORS[idx],
|
|
29
|
-
idx,
|
|
30
|
-
x: Math.floor((COLS - SHAPES[idx][0].length) / 2),
|
|
31
|
-
y: 0
|
|
32
|
-
});
|
|
33
|
-
var randIdx = () => Math.floor(Math.random() * 7);
|
|
34
|
-
var valid = (board, shape, x, y) => shape.every(
|
|
35
|
-
(row, dy) => row.every(
|
|
36
|
-
(v, dx) => !v || x + dx >= 0 && x + dx < COLS && y + dy < ROWS && (y + dy < 0 || !board[y + dy][x + dx])
|
|
37
|
-
)
|
|
38
|
-
);
|
|
39
|
-
var merge = (board, piece) => board.map(
|
|
40
|
-
(row, r) => row.map((cell, c) => {
|
|
41
|
-
const dy = r - piece.y, dx = c - piece.x;
|
|
42
|
-
if (dy >= 0 && dy < piece.shape.length && dx >= 0 && dx < piece.shape[0].length && piece.shape[dy][dx])
|
|
43
|
-
return piece.color;
|
|
44
|
-
return cell;
|
|
45
|
-
})
|
|
46
|
-
);
|
|
47
|
-
var emptyBoard = () => Array.from({ length: ROWS }, () => Array(COLS).fill(""));
|
|
48
|
-
function Tetris() {
|
|
49
|
-
const [board, setBoard] = useState(emptyBoard);
|
|
50
|
-
const [piece, setPiece] = useState(() => newPiece(randIdx()));
|
|
51
|
-
const [nextIdx, setNextIdx] = useState(randIdx);
|
|
52
|
-
const [score, setScore] = useState(0);
|
|
53
|
-
const [lines, setLines] = useState(0);
|
|
54
|
-
const [level, setLevel] = useState(0);
|
|
55
|
-
const [gameOver, setGameOver] = useState(false);
|
|
56
|
-
const [paused, setPaused] = useState(false);
|
|
57
|
-
const [started, setStarted] = useState(false);
|
|
58
|
-
const tickRef = useRef();
|
|
59
|
-
const pieceRef = useRef(piece);
|
|
60
|
-
const boardRef = useRef(board);
|
|
61
|
-
pieceRef.current = piece;
|
|
62
|
-
boardRef.current = board;
|
|
63
|
-
const lockPiece = useCallback(() => {
|
|
64
|
-
const p = pieceRef.current;
|
|
65
|
-
let b = merge(boardRef.current, p);
|
|
66
|
-
const full = b.reduce((acc, row, i) => row.every((c) => c) ? [...acc, i] : acc, []);
|
|
67
|
-
if (full.length) {
|
|
68
|
-
full.forEach((i) => {
|
|
69
|
-
b.splice(i, 1);
|
|
70
|
-
b.unshift(Array(COLS).fill(""));
|
|
71
|
-
});
|
|
72
|
-
const pts = [0, 100, 300, 500, 800][full.length] || 800;
|
|
73
|
-
setScore((s) => s + pts * (level + 1));
|
|
74
|
-
setLines((l) => {
|
|
75
|
-
const nl = l + full.length;
|
|
76
|
-
setLevel(Math.floor(nl / 10));
|
|
77
|
-
return nl;
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
setBoard(b);
|
|
81
|
-
const np = newPiece(nextIdx);
|
|
82
|
-
if (!valid(b, np.shape, np.x, np.y)) {
|
|
83
|
-
setGameOver(true);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
setPiece(np);
|
|
87
|
-
setNextIdx(randIdx());
|
|
88
|
-
}, [nextIdx, level]);
|
|
89
|
-
const drop = useCallback(() => {
|
|
90
|
-
const p = pieceRef.current;
|
|
91
|
-
if (valid(boardRef.current, p.shape, p.x, p.y + 1)) {
|
|
92
|
-
setPiece({ ...p, y: p.y + 1 });
|
|
93
|
-
} else {
|
|
94
|
-
lockPiece();
|
|
95
|
-
}
|
|
96
|
-
}, [lockPiece]);
|
|
97
|
-
useEffect(() => {
|
|
98
|
-
if (gameOver || paused || !started) return;
|
|
99
|
-
clearInterval(tickRef.current);
|
|
100
|
-
tickRef.current = setInterval(drop, Math.max(100, 800 - level * 70));
|
|
101
|
-
return () => clearInterval(tickRef.current);
|
|
102
|
-
}, [drop, level, gameOver, paused, started]);
|
|
103
|
-
const move = useCallback((dx, dy) => {
|
|
104
|
-
const p = pieceRef.current;
|
|
105
|
-
if (valid(boardRef.current, p.shape, p.x + dx, p.y + dy))
|
|
106
|
-
setPiece({ ...p, x: p.x + dx, y: p.y + dy });
|
|
107
|
-
}, []);
|
|
108
|
-
const rotatePiece = useCallback(() => {
|
|
109
|
-
const p = pieceRef.current;
|
|
110
|
-
const r = rotate(p.shape);
|
|
111
|
-
for (const dx of [0, -1, 1, -2, 2]) {
|
|
112
|
-
if (valid(boardRef.current, r, p.x + dx, p.y)) {
|
|
113
|
-
setPiece({ ...p, shape: r, x: p.x + dx });
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}, []);
|
|
118
|
-
const hardDrop = useCallback(() => {
|
|
119
|
-
const p = pieceRef.current;
|
|
120
|
-
let ny = p.y;
|
|
121
|
-
while (valid(boardRef.current, p.shape, p.x, ny + 1)) ny++;
|
|
122
|
-
setPiece({ ...p, y: ny });
|
|
123
|
-
setTimeout(() => lockPiece(), 0);
|
|
124
|
-
}, [lockPiece]);
|
|
125
|
-
const restart = useCallback(() => {
|
|
126
|
-
setBoard(emptyBoard());
|
|
127
|
-
const idx = randIdx();
|
|
128
|
-
setPiece(newPiece(idx));
|
|
129
|
-
setNextIdx(randIdx());
|
|
130
|
-
setScore(0);
|
|
131
|
-
setLines(0);
|
|
132
|
-
setLevel(0);
|
|
133
|
-
setGameOver(false);
|
|
134
|
-
setPaused(false);
|
|
135
|
-
setStarted(true);
|
|
136
|
-
}, []);
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
const handler = (e) => {
|
|
139
|
-
if (e.key === "p" || e.key === "P") {
|
|
140
|
-
if (started && !gameOver) setPaused((v) => !v);
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
if (gameOver || paused || !started) return;
|
|
144
|
-
switch (e.key) {
|
|
145
|
-
case "ArrowLeft":
|
|
146
|
-
e.preventDefault();
|
|
147
|
-
move(-1, 0);
|
|
148
|
-
break;
|
|
149
|
-
case "ArrowRight":
|
|
150
|
-
e.preventDefault();
|
|
151
|
-
move(1, 0);
|
|
152
|
-
break;
|
|
153
|
-
case "ArrowDown":
|
|
154
|
-
e.preventDefault();
|
|
155
|
-
move(0, 1);
|
|
156
|
-
break;
|
|
157
|
-
case "ArrowUp":
|
|
158
|
-
e.preventDefault();
|
|
159
|
-
rotatePiece();
|
|
160
|
-
break;
|
|
161
|
-
case " ":
|
|
162
|
-
e.preventDefault();
|
|
163
|
-
hardDrop();
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
window.addEventListener("keydown", handler);
|
|
168
|
-
return () => window.removeEventListener("keydown", handler);
|
|
169
|
-
}, [move, rotatePiece, hardDrop, gameOver, paused, started]);
|
|
170
|
-
let ghostY = piece.y;
|
|
171
|
-
while (valid(board, piece.shape, piece.x, ghostY + 1)) ghostY++;
|
|
172
|
-
const display = board.map(
|
|
173
|
-
(row, r) => row.map((cell, c) => {
|
|
174
|
-
const dy = r - piece.y, dx = c - piece.x;
|
|
175
|
-
const inPiece = dy >= 0 && dy < piece.shape.length && dx >= 0 && dx < piece.shape[0].length && piece.shape[dy][dx];
|
|
176
|
-
if (inPiece) return piece.color;
|
|
177
|
-
const gdy = r - ghostY, gdx = c - piece.x;
|
|
178
|
-
const inGhost = gdy >= 0 && gdy < piece.shape.length && gdx >= 0 && gdx < piece.shape[0].length && piece.shape[gdy][gdx];
|
|
179
|
-
if (inGhost && !cell) return "ghost";
|
|
180
|
-
return cell;
|
|
181
|
-
})
|
|
182
|
-
);
|
|
183
|
-
const nextShape = SHAPES[nextIdx];
|
|
184
|
-
const nextColor = COLORS[nextIdx];
|
|
185
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center select-none", tabIndex: 0, children: [
|
|
186
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
187
|
-
/* @__PURE__ */ jsx("div", { className: "border-2 border-gray-600", style: { width: COLS * CELL, height: ROWS * CELL }, children: display.map((row, r) => /* @__PURE__ */ jsx("div", { className: "flex", children: row.map((cell, c) => /* @__PURE__ */ jsx(
|
|
188
|
-
"div",
|
|
189
|
-
{
|
|
190
|
-
style: {
|
|
191
|
-
width: CELL,
|
|
192
|
-
height: CELL,
|
|
193
|
-
backgroundColor: cell === "ghost" ? "rgba(255,255,255,0.08)" : cell || "#111",
|
|
194
|
-
border: "1px solid #222",
|
|
195
|
-
opacity: cell && cell !== "ghost" ? 0.9 : 1
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
c
|
|
199
|
-
)) }, r)) }),
|
|
200
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 text-white w-28", children: [
|
|
201
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
202
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 uppercase", children: "Next" }),
|
|
203
|
-
/* @__PURE__ */ jsx("div", { className: "mt-1 p-1 bg-gray-800 rounded flex flex-col items-center justify-center", style: { minHeight: 5 * CELL }, children: nextShape.map((row, r) => /* @__PURE__ */ jsx("div", { className: "flex", children: row.map((v, c) => /* @__PURE__ */ jsx("div", { style: {
|
|
204
|
-
width: CELL,
|
|
205
|
-
height: CELL,
|
|
206
|
-
backgroundColor: v ? nextColor : "transparent",
|
|
207
|
-
border: v ? "1px solid rgba(0,0,0,0.3)" : "none"
|
|
208
|
-
} }, c)) }, r)) })
|
|
209
|
-
] }),
|
|
210
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
211
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 uppercase", children: "Score" }),
|
|
212
|
-
/* @__PURE__ */ jsx("div", { className: "text-lg font-bold", children: score })
|
|
213
|
-
] }),
|
|
214
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
215
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 uppercase", children: "Level" }),
|
|
216
|
-
/* @__PURE__ */ jsx("div", { className: "text-lg font-bold", children: level })
|
|
217
|
-
] }),
|
|
218
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
219
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-400 uppercase", children: "Lines" }),
|
|
220
|
-
/* @__PURE__ */ jsx("div", { className: "text-lg font-bold", children: lines })
|
|
221
|
-
] }),
|
|
222
|
-
/* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500 mt-2 space-y-0.5", children: [
|
|
223
|
-
/* @__PURE__ */ jsx("div", { children: "Arrows: Move/Rotate" }),
|
|
224
|
-
/* @__PURE__ */ jsx("div", { children: "Space: Hard Drop" }),
|
|
225
|
-
/* @__PURE__ */ jsx("div", { children: "P: Pause" })
|
|
226
|
-
] }),
|
|
227
|
-
(!started || gameOver) && /* @__PURE__ */ jsx("button", { onClick: restart, className: "mt-2 px-3 py-1.5 bg-blue-600 hover:bg-blue-500 rounded text-sm font-medium", children: gameOver ? "Play Again" : "Start" })
|
|
228
|
-
] })
|
|
229
|
-
] }),
|
|
230
|
-
paused && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsx("div", { className: "text-white text-3xl font-bold", children: "PAUSED" }) }),
|
|
231
|
-
gameOver && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/60", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
232
|
-
/* @__PURE__ */ jsx("div", { className: "text-white text-3xl font-bold", children: "GAME OVER" }),
|
|
233
|
-
/* @__PURE__ */ jsxs("div", { className: "text-gray-300 mt-2", children: [
|
|
234
|
-
"Score: ",
|
|
235
|
-
score
|
|
236
|
-
] })
|
|
237
|
-
] }) })
|
|
238
|
-
] });
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
export { Tetris as default };
|
|
242
|
-
//# sourceMappingURL=Tetris-ZHCZYL24.js.map
|
|
243
|
-
//# sourceMappingURL=Tetris-ZHCZYL24.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/Tetris.tsx"],"names":[],"mappings":"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","file":"Tetris-ZHCZYL24.js","sourcesContent":["import { useState, useCallback, useEffect, useRef } from 'react';\n\nconst COLS = 10, ROWS = 20, CELL = 28;\nconst SHAPES: number[][][] = [\n [[1,1,1,1]], // I\n [[1,1],[1,1]], // O\n [[0,1,0],[1,1,1]], // T\n [[0,1,1],[1,1,0]], // S\n [[1,1,0],[0,1,1]], // Z\n [[1,0,0],[1,1,1]], // J\n [[0,0,1],[1,1,1]], // L\n];\nconst COLORS = ['#00f0f0','#f0f000','#a000f0','#00f000','#f00000','#0000f0','#f0a000'];\n\ntype Piece = { shape: number[][]; color: string; x: number; y: number; idx: number };\n\nconst rotate = (m: number[][]): number[][] =>\n m[0].map((_, i) => m.map(r => r[i]).reverse());\n\nconst newPiece = (idx: number): Piece => ({\n shape: SHAPES[idx], color: COLORS[idx], idx,\n x: Math.floor((COLS - SHAPES[idx][0].length) / 2), y: 0,\n});\n\nconst randIdx = () => Math.floor(Math.random() * 7);\n\nconst valid = (board: string[][], shape: number[][], x: number, y: number) =>\n shape.every((row, dy) =>\n row.every((v, dx) =>\n !v || (x + dx >= 0 && x + dx < COLS && y + dy < ROWS && (y + dy < 0 || !board[y + dy][x + dx]))\n )\n );\n\nconst merge = (board: string[][], piece: Piece): string[][] =>\n board.map((row, r) =>\n row.map((cell, c) => {\n const dy = r - piece.y, dx = c - piece.x;\n if (dy >= 0 && dy < piece.shape.length && dx >= 0 && dx < piece.shape[0].length && piece.shape[dy][dx])\n return piece.color;\n return cell;\n })\n );\n\nconst emptyBoard = (): string[][] => Array.from({ length: ROWS }, () => Array(COLS).fill(''));\n\nexport default function Tetris() {\n const [board, setBoard] = useState(emptyBoard);\n const [piece, setPiece] = useState<Piece>(() => newPiece(randIdx()));\n const [nextIdx, setNextIdx] = useState(randIdx);\n const [score, setScore] = useState(0);\n const [lines, setLines] = useState(0);\n const [level, setLevel] = useState(0);\n const [gameOver, setGameOver] = useState(false);\n const [paused, setPaused] = useState(false);\n const [started, setStarted] = useState(false);\n const tickRef = useRef<ReturnType<typeof setInterval>>();\n const pieceRef = useRef(piece);\n const boardRef = useRef(board);\n pieceRef.current = piece;\n boardRef.current = board;\n\n const lockPiece = useCallback(() => {\n const p = pieceRef.current;\n let b = merge(boardRef.current, p);\n // Clear lines\n const full = b.reduce<number[]>((acc, row, i) => (row.every(c => c) ? [...acc, i] : acc), []);\n if (full.length) {\n full.forEach(i => { b.splice(i, 1); b.unshift(Array(COLS).fill('')); });\n const pts = [0, 100, 300, 500, 800][full.length] || 800;\n setScore(s => s + pts * (level + 1));\n setLines(l => {\n const nl = l + full.length;\n setLevel(Math.floor(nl / 10));\n return nl;\n });\n }\n setBoard(b);\n // Spawn next\n const np = newPiece(nextIdx);\n if (!valid(b, np.shape, np.x, np.y)) {\n setGameOver(true);\n return;\n }\n setPiece(np);\n setNextIdx(randIdx());\n }, [nextIdx, level]);\n\n const drop = useCallback(() => {\n const p = pieceRef.current;\n if (valid(boardRef.current, p.shape, p.x, p.y + 1)) {\n setPiece({ ...p, y: p.y + 1 });\n } else {\n lockPiece();\n }\n }, [lockPiece]);\n\n // Tick\n useEffect(() => {\n if (gameOver || paused || !started) return;\n clearInterval(tickRef.current);\n tickRef.current = setInterval(drop, Math.max(100, 800 - level * 70));\n return () => clearInterval(tickRef.current);\n }, [drop, level, gameOver, paused, started]);\n\n const move = useCallback((dx: number, dy: number) => {\n const p = pieceRef.current;\n if (valid(boardRef.current, p.shape, p.x + dx, p.y + dy))\n setPiece({ ...p, x: p.x + dx, y: p.y + dy });\n }, []);\n\n const rotatePiece = useCallback(() => {\n const p = pieceRef.current;\n const r = rotate(p.shape);\n // Wall kick offsets\n for (const dx of [0, -1, 1, -2, 2]) {\n if (valid(boardRef.current, r, p.x + dx, p.y)) {\n setPiece({ ...p, shape: r, x: p.x + dx });\n return;\n }\n }\n }, []);\n\n const hardDrop = useCallback(() => {\n const p = pieceRef.current;\n let ny = p.y;\n while (valid(boardRef.current, p.shape, p.x, ny + 1)) ny++;\n setPiece({ ...p, y: ny });\n // Use setTimeout to ensure state is set before lock\n setTimeout(() => lockPiece(), 0);\n }, [lockPiece]);\n\n const restart = useCallback(() => {\n setBoard(emptyBoard());\n const idx = randIdx();\n setPiece(newPiece(idx));\n setNextIdx(randIdx());\n setScore(0);\n setLines(0);\n setLevel(0);\n setGameOver(false);\n setPaused(false);\n setStarted(true);\n }, []);\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'p' || e.key === 'P') { if (started && !gameOver) setPaused(v => !v); return; }\n if (gameOver || paused || !started) return;\n switch (e.key) {\n case 'ArrowLeft': e.preventDefault(); move(-1, 0); break;\n case 'ArrowRight': e.preventDefault(); move(1, 0); break;\n case 'ArrowDown': e.preventDefault(); move(0, 1); break;\n case 'ArrowUp': e.preventDefault(); rotatePiece(); break;\n case ' ': e.preventDefault(); hardDrop(); break;\n }\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [move, rotatePiece, hardDrop, gameOver, paused, started]);\n\n // Ghost piece\n let ghostY = piece.y;\n while (valid(board, piece.shape, piece.x, ghostY + 1)) ghostY++;\n\n // Render board with piece & ghost\n const display = board.map((row, r) =>\n row.map((cell, c) => {\n const dy = r - piece.y, dx = c - piece.x;\n const inPiece = dy >= 0 && dy < piece.shape.length && dx >= 0 && dx < piece.shape[0].length && piece.shape[dy][dx];\n if (inPiece) return piece.color;\n const gdy = r - ghostY, gdx = c - piece.x;\n const inGhost = gdy >= 0 && gdy < piece.shape.length && gdx >= 0 && gdx < piece.shape[0].length && piece.shape[gdy][gdx];\n if (inGhost && !cell) return 'ghost';\n return cell;\n })\n );\n\n const nextShape = SHAPES[nextIdx];\n const nextColor = COLORS[nextIdx];\n\n return (\n <div className=\"flex items-center justify-center select-none\" tabIndex={0}>\n <div className=\"flex gap-4\">\n {/* Board */}\n <div className=\"border-2 border-gray-600\" style={{ width: COLS * CELL, height: ROWS * CELL }}>\n {display.map((row, r) => (\n <div key={r} className=\"flex\">\n {row.map((cell, c) => (\n <div\n key={c}\n style={{\n width: CELL, height: CELL,\n backgroundColor: cell === 'ghost' ? 'rgba(255,255,255,0.08)' : cell || '#111',\n border: '1px solid #222',\n opacity: cell && cell !== 'ghost' ? 0.9 : 1,\n }}\n />\n ))}\n </div>\n ))}\n </div>\n {/* Side panel */}\n <div className=\"flex flex-col gap-3 text-white w-28\">\n <div>\n <div className=\"text-xs text-gray-400 uppercase\">Next</div>\n <div className=\"mt-1 p-1 bg-gray-800 rounded flex flex-col items-center justify-center\" style={{ minHeight: 5 * CELL }}>\n {nextShape.map((row, r) => (\n <div key={r} className=\"flex\">\n {row.map((v, c) => (\n <div key={c} style={{\n width: CELL, height: CELL,\n backgroundColor: v ? nextColor : 'transparent',\n border: v ? '1px solid rgba(0,0,0,0.3)' : 'none',\n }} />\n ))}\n </div>\n ))}\n </div>\n </div>\n <div>\n <div className=\"text-xs text-gray-400 uppercase\">Score</div>\n <div className=\"text-lg font-bold\">{score}</div>\n </div>\n <div>\n <div className=\"text-xs text-gray-400 uppercase\">Level</div>\n <div className=\"text-lg font-bold\">{level}</div>\n </div>\n <div>\n <div className=\"text-xs text-gray-400 uppercase\">Lines</div>\n <div className=\"text-lg font-bold\">{lines}</div>\n </div>\n <div className=\"text-xs text-gray-500 mt-2 space-y-0.5\">\n <div>Arrows: Move/Rotate</div>\n <div>Space: Hard Drop</div>\n <div>P: Pause</div>\n </div>\n {(!started || gameOver) && (\n <button onClick={restart} className=\"mt-2 px-3 py-1.5 bg-blue-600 hover:bg-blue-500 rounded text-sm font-medium\">\n {gameOver ? 'Play Again' : 'Start'}\n </button>\n )}\n </div>\n </div>\n {/* Overlays */}\n {paused && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/60\">\n <div className=\"text-white text-3xl font-bold\">PAUSED</div>\n </div>\n )}\n {gameOver && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/60\">\n <div className=\"text-center\">\n <div className=\"text-white text-3xl font-bold\">GAME OVER</div>\n <div className=\"text-gray-300 mt-2\">Score: {score}</div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"]}
|
package/dist/chunk-Y4QYGQKS.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// src/utils/date.ts
|
|
2
|
-
function getUserDateFormat() {
|
|
3
|
-
return localStorage.getItem("user_date_format") || "DD/MM/YYYY";
|
|
4
|
-
}
|
|
5
|
-
function formatDate(value) {
|
|
6
|
-
if (!value) return "\u2014";
|
|
7
|
-
const dateStr = value.includes("T") ? value.split("T")[0] : value;
|
|
8
|
-
const [y, m, d] = dateStr.split("-").map(Number);
|
|
9
|
-
if (!y || !m || !d) return value;
|
|
10
|
-
const dd = String(d).padStart(2, "0");
|
|
11
|
-
const mm = String(m).padStart(2, "0");
|
|
12
|
-
const yyyy = String(y);
|
|
13
|
-
const fmt = getUserDateFormat();
|
|
14
|
-
switch (fmt) {
|
|
15
|
-
case "MM/DD/YYYY":
|
|
16
|
-
return `${mm}/${dd}/${yyyy}`;
|
|
17
|
-
case "YYYY-MM-DD":
|
|
18
|
-
return `${yyyy}-${mm}-${dd}`;
|
|
19
|
-
case "DD-MM-YYYY":
|
|
20
|
-
return `${dd}-${mm}-${yyyy}`;
|
|
21
|
-
case "DD.MM.YYYY":
|
|
22
|
-
return `${dd}.${mm}.${yyyy}`;
|
|
23
|
-
case "DD/MM/YYYY":
|
|
24
|
-
default:
|
|
25
|
-
return `${dd}/${mm}/${yyyy}`;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export { formatDate };
|
|
30
|
-
//# sourceMappingURL=chunk-Y4QYGQKS.js.map
|
|
31
|
-
//# sourceMappingURL=chunk-Y4QYGQKS.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/date.ts"],"names":[],"mappings":";AAwBO,SAAS,iBAAA,GAAmC;AACjD,EAAA,OAAQ,YAAA,CAAa,OAAA,CAAQ,kBAAkB,CAAA,IAAuB,YAAA;AACxE;AAUO,SAAS,WAAW,KAAA,EAA0C;AACnE,EAAA,IAAI,CAAC,OAAO,OAAO,QAAA;AAEnB,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,QAAA,CAAS,GAAG,CAAA,GAAI,MAAM,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,GAAI,KAAA;AAC5D,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,QAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA;AAC/C,EAAA,IAAI,CAAC,CAAA,IAAK,CAAC,CAAA,IAAK,CAAC,GAAG,OAAO,KAAA;AAE3B,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,MAAM,KAAK,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,OAAO,CAAC,CAAA;AAErB,EAAA,MAAM,MAAM,iBAAA,EAAkB;AAC9B,EAAA,QAAQ,GAAA;AAAK,IACX,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,EAAE,IAAI,EAAE,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA,IAC7C,KAAK,YAAA;AAAA,IACL;AAAmB,MAAA,OAAO,CAAA,EAAG,EAAE,CAAA,CAAA,EAAI,EAAE,IAAI,IAAI,CAAA,CAAA;AAAA;AAEjD","file":"chunk-Y4QYGQKS.js","sourcesContent":["/**\n * Shared date formatting utility.\n *\n * Reads the user's preferred date format from localStorage (`user_date_format`)\n * and formats all dates consistently across the app.\n *\n * Supported formats:\n * 'DD/MM/YYYY' — 24/04/2026\n * 'MM/DD/YYYY' — 04/24/2026\n * 'YYYY-MM-DD' — 2026-04-24\n * 'DD-MM-YYYY' — 24-04-2026\n * 'DD.MM.YYYY' — 24.04.2026\n */\n\nexport type DateFormatKey = 'DD/MM/YYYY' | 'MM/DD/YYYY' | 'YYYY-MM-DD' | 'DD-MM-YYYY' | 'DD.MM.YYYY';\n\nexport const DATE_FORMAT_OPTIONS: { key: DateFormatKey; example: string }[] = [\n { key: 'DD/MM/YYYY', example: '24/04/2026' },\n { key: 'MM/DD/YYYY', example: '04/24/2026' },\n { key: 'YYYY-MM-DD', example: '2026-04-24' },\n { key: 'DD-MM-YYYY', example: '24-04-2026' },\n { key: 'DD.MM.YYYY', example: '24.04.2026' },\n];\n\nexport function getUserDateFormat(): DateFormatKey {\n return (localStorage.getItem('user_date_format') as DateFormatKey) || 'DD/MM/YYYY';\n}\n\nexport function setUserDateFormat(fmt: DateFormatKey) {\n localStorage.setItem('user_date_format', fmt);\n}\n\n/**\n * Format a date string (YYYY-MM-DD or ISO timestamp) for display.\n * Returns '—' for null/empty values.\n */\nexport function formatDate(value: string | null | undefined): string {\n if (!value) return '—';\n // Parse — handle both \"YYYY-MM-DD\" and ISO timestamps\n const dateStr = value.includes('T') ? value.split('T')[0] : value;\n const [y, m, d] = dateStr.split('-').map(Number);\n if (!y || !m || !d) return value; // fallback if unparseable\n\n const dd = String(d).padStart(2, '0');\n const mm = String(m).padStart(2, '0');\n const yyyy = String(y);\n\n const fmt = getUserDateFormat();\n switch (fmt) {\n case 'MM/DD/YYYY': return `${mm}/${dd}/${yyyy}`;\n case 'YYYY-MM-DD': return `${yyyy}-${mm}-${dd}`;\n case 'DD-MM-YYYY': return `${dd}-${mm}-${yyyy}`;\n case 'DD.MM.YYYY': return `${dd}.${mm}.${yyyy}`;\n case 'DD/MM/YYYY':\n default: return `${dd}/${mm}/${yyyy}`;\n }\n}\n\n/**\n * Format a datetime string (ISO timestamp) for display, including time.\n * Returns '—' for null/empty values.\n */\nexport function formatDateTime(value: string | null | undefined): string {\n if (!value) return '—';\n const dt = new Date(value);\n if (isNaN(dt.getTime())) return value;\n const dateStr = `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}-${String(dt.getDate()).padStart(2, '0')}`;\n const time = dt.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n return `${formatDate(dateStr)}, ${time}`;\n}\n"]}
|