react-os-shell 1.6.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +8 -9
  2. package/dist/Browser-HGX2YS22.js +7 -0
  3. package/dist/{Browser-ELO6K7YY.js.map → Browser-HGX2YS22.js.map} +1 -1
  4. package/dist/{Calculator-X26IEHCN.js → Calculator-JJZMCBIN.js} +4 -4
  5. package/dist/{Calculator-X26IEHCN.js.map → Calculator-JJZMCBIN.js.map} +1 -1
  6. package/dist/{CurrencyConverter-5UHIRF2P.js → CurrencyConverter-VCZGTULI.js} +4 -4
  7. package/dist/{CurrencyConverter-5UHIRF2P.js.map → CurrencyConverter-VCZGTULI.js.map} +1 -1
  8. package/dist/{Documents-7KYHOORU.js → Documents-W6JNKYE3.js} +4 -4
  9. package/dist/{Documents-7KYHOORU.js.map → Documents-W6JNKYE3.js.map} +1 -1
  10. package/dist/Files-232FHLMO.js +13 -0
  11. package/dist/{Files-3455T525.js.map → Files-232FHLMO.js.map} +1 -1
  12. package/dist/{Notepad-RLQ4NXJI.js → Notepad-G2UOOZOU.js} +4 -4
  13. package/dist/{Notepad-RLQ4NXJI.js.map → Notepad-G2UOOZOU.js.map} +1 -1
  14. package/dist/{PomodoroTimer-PG4J5NNI.js → PomodoroTimer-TEZJH7E6.js} +4 -4
  15. package/dist/{PomodoroTimer-PG4J5NNI.js.map → PomodoroTimer-TEZJH7E6.js.map} +1 -1
  16. package/dist/Preview-QXM6YE7A.js +9 -0
  17. package/dist/{Preview-H5IOBX66.js.map → Preview-QXM6YE7A.js.map} +1 -1
  18. package/dist/Spreadsheet-7V6GLIIW.js +7 -0
  19. package/dist/{Spreadsheet-6C6O6BGG.js.map → Spreadsheet-7V6GLIIW.js.map} +1 -1
  20. package/dist/{Stock-TIJVSHPV.js → Stock-QVTMAGIU.js} +4 -4
  21. package/dist/{Stock-TIJVSHPV.js.map → Stock-QVTMAGIU.js.map} +1 -1
  22. package/dist/{Weather-WVDLOH74.js → Weather-PXUZW22T.js} +4 -4
  23. package/dist/{Weather-WVDLOH74.js.map → Weather-PXUZW22T.js.map} +1 -1
  24. package/dist/{WorldClock-OV4GU5J3.js → WorldClock-CRESQVKE.js} +4 -4
  25. package/dist/{WorldClock-OV4GU5J3.js.map → WorldClock-CRESQVKE.js.map} +1 -1
  26. package/dist/apps/index.d.ts +1 -20
  27. package/dist/apps/index.js +20 -35
  28. package/dist/apps/index.js.map +1 -1
  29. package/dist/{chunk-GWVVILYQ.js → chunk-5FEW4QE5.js} +3 -3
  30. package/dist/{chunk-GWVVILYQ.js.map → chunk-5FEW4QE5.js.map} +1 -1
  31. package/dist/{chunk-ISNP6BHR.js → chunk-AYTCQLZ4.js} +3 -3
  32. package/dist/{chunk-ISNP6BHR.js.map → chunk-AYTCQLZ4.js.map} +1 -1
  33. package/dist/{chunk-32CXFFKW.js → chunk-JZS5427T.js} +4 -4
  34. package/dist/{chunk-32CXFFKW.js.map → chunk-JZS5427T.js.map} +1 -1
  35. package/dist/{chunk-KKEWB6RG.js → chunk-LXCTOIXP.js} +4 -4
  36. package/dist/{chunk-KKEWB6RG.js.map → chunk-LXCTOIXP.js.map} +1 -1
  37. package/dist/{chunk-VAMMHJR3.js → chunk-Q4EH3NFS.js} +4 -4
  38. package/dist/{chunk-VAMMHJR3.js.map → chunk-Q4EH3NFS.js.map} +1 -1
  39. package/dist/{chunk-4PSDLG2P.js → chunk-QESYOYZS.js} +5 -5
  40. package/dist/{chunk-4PSDLG2P.js.map → chunk-QESYOYZS.js.map} +1 -1
  41. package/dist/{chunk-ZIV7JFJ5.js → chunk-XF7JN5E5.js} +4 -4
  42. package/dist/{chunk-ZIV7JFJ5.js.map → chunk-XF7JN5E5.js.map} +1 -1
  43. package/dist/{chunk-Q3USVEUR.js → chunk-XO4ZJAUB.js} +4 -4
  44. package/dist/{chunk-Q3USVEUR.js.map → chunk-XO4ZJAUB.js.map} +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.js +37 -11
  47. package/dist/index.js.map +1 -1
  48. package/package.json +1 -1
  49. package/dist/Browser-ELO6K7YY.js +0 -7
  50. package/dist/Checkers-MIAHIKJH.js +0 -214
  51. package/dist/Checkers-MIAHIKJH.js.map +0 -1
  52. package/dist/Chess-C5BY45NA.js +0 -190
  53. package/dist/Chess-C5BY45NA.js.map +0 -1
  54. package/dist/Files-3455T525.js +0 -13
  55. package/dist/Game2048-3RH3ELRD.js +0 -191
  56. package/dist/Game2048-3RH3ELRD.js.map +0 -1
  57. package/dist/Minesweeper-OXRRSCVF.js +0 -271
  58. package/dist/Minesweeper-OXRRSCVF.js.map +0 -1
  59. package/dist/Preview-H5IOBX66.js +0 -9
  60. package/dist/Spreadsheet-6C6O6BGG.js +0 -7
  61. package/dist/Sudoku-XHLYCEVT.js +0 -197
  62. package/dist/Sudoku-XHLYCEVT.js.map +0 -1
  63. package/dist/Tetris-ZHCZYL24.js +0 -243
  64. package/dist/Tetris-ZHCZYL24.js.map +0 -1
  65. package/dist/chunk-Y4QYGQKS.js +0 -31
  66. package/dist/chunk-Y4QYGQKS.js.map +0 -1
@@ -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":"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","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"]}
@@ -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"]}
@@ -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"]}