react-os-shell 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/Browser-I5OETCZP.js +7 -0
- package/dist/Browser-I5OETCZP.js.map +1 -0
- package/dist/{Calculator-TGBQ6CZ5.js → Calculator-X26IEHCN.js} +4 -4
- package/dist/{Calculator-TGBQ6CZ5.js.map → Calculator-X26IEHCN.js.map} +1 -1
- package/dist/{CurrencyConverter-VIED4YVG.js → CurrencyConverter-5UHIRF2P.js} +4 -4
- package/dist/{CurrencyConverter-VIED4YVG.js.map → CurrencyConverter-5UHIRF2P.js.map} +1 -1
- package/dist/{Documents-EKFJA35K.js → Documents-XXR5APHQ.js} +5 -3
- package/dist/Documents-XXR5APHQ.js.map +1 -0
- package/dist/Files-62UEOWMR.js +13 -0
- package/dist/{Files-DCBTCKHR.js.map → Files-62UEOWMR.js.map} +1 -1
- package/dist/{Minesweeper-JEQS36AX.js → Minesweeper-OXRRSCVF.js} +3 -3
- package/dist/{Minesweeper-JEQS36AX.js.map → Minesweeper-OXRRSCVF.js.map} +1 -1
- package/dist/{Notepad-PTFPOQFG.js → Notepad-ITUWSJKY.js} +84 -80
- package/dist/Notepad-ITUWSJKY.js.map +1 -0
- package/dist/{PomodoroTimer-ALPSQRXI.js → PomodoroTimer-PG4J5NNI.js} +4 -4
- package/dist/{PomodoroTimer-ALPSQRXI.js.map → PomodoroTimer-PG4J5NNI.js.map} +1 -1
- package/dist/Preview-ABEQRCDE.js +9 -0
- package/dist/{Preview-SVY4T4PL.js.map → Preview-ABEQRCDE.js.map} +1 -1
- package/dist/Spreadsheet-7AMQIX6U.js +7 -0
- package/dist/{Spreadsheet-MITVBEDX.js.map → Spreadsheet-7AMQIX6U.js.map} +1 -1
- package/dist/{Stock-HPG5RWLL.js → Stock-TIJVSHPV.js} +4 -4
- package/dist/{Stock-HPG5RWLL.js.map → Stock-TIJVSHPV.js.map} +1 -1
- package/dist/{Weather-JC3RBPGD.js → Weather-WVDLOH74.js} +4 -4
- package/dist/{Weather-JC3RBPGD.js.map → Weather-WVDLOH74.js.map} +1 -1
- package/dist/{WorldClock-XWFU7PQE.js → WorldClock-OV4GU5J3.js} +4 -4
- package/dist/{WorldClock-XWFU7PQE.js.map → WorldClock-OV4GU5J3.js.map} +1 -1
- package/dist/apps/index.d.ts +55 -1
- package/dist/apps/index.js +20 -18
- package/dist/apps/index.js.map +1 -1
- package/dist/chunk-2YSJRDKZ.js +81 -0
- package/dist/chunk-2YSJRDKZ.js.map +1 -0
- package/dist/{chunk-4TNNWBYP.js → chunk-6IQJSIAR.js} +4 -4
- package/dist/{chunk-4TNNWBYP.js.map → chunk-6IQJSIAR.js.map} +1 -1
- package/dist/{chunk-PR23BBD7.js → chunk-BPPG7CVR.js} +10 -4
- package/dist/chunk-BPPG7CVR.js.map +1 -0
- package/dist/{chunk-BAVXM63E.js → chunk-CF3SUKOS.js} +6 -4
- package/dist/chunk-CF3SUKOS.js.map +1 -0
- package/dist/{chunk-JHQDV7SP.js → chunk-GWVVILYQ.js} +15 -8
- package/dist/chunk-GWVVILYQ.js.map +1 -0
- package/dist/{chunk-HMTXSXYU.js → chunk-ISNP6BHR.js} +3 -3
- package/dist/{chunk-HMTXSXYU.js.map → chunk-ISNP6BHR.js.map} +1 -1
- package/dist/{chunk-3MB2IRBY.js → chunk-LAAGWPMR.js} +11 -5
- package/dist/chunk-LAAGWPMR.js.map +1 -0
- package/dist/{Browser-NNPSNU35.js → chunk-P7OBFXLO.js} +23 -7
- package/dist/chunk-P7OBFXLO.js.map +1 -0
- package/dist/index.js +9 -11
- package/dist/index.js.map +1 -1
- package/dist/styles.css +12 -0
- package/package.json +1 -1
- package/dist/Browser-NNPSNU35.js.map +0 -1
- package/dist/Documents-EKFJA35K.js.map +0 -1
- package/dist/Files-DCBTCKHR.js +0 -12
- package/dist/Notepad-PTFPOQFG.js.map +0 -1
- package/dist/Preview-SVY4T4PL.js +0 -8
- package/dist/Spreadsheet-MITVBEDX.js +0 -6
- package/dist/chunk-3MB2IRBY.js.map +0 -1
- package/dist/chunk-BAVXM63E.js.map +0 -1
- package/dist/chunk-JHQDV7SP.js.map +0 -1
- package/dist/chunk-PR23BBD7.js.map +0 -1
package/README.md
CHANGED
|
@@ -210,6 +210,7 @@ All exports are named — `import { Modal, ... } from 'react-os-shell'`.
|
|
|
210
210
|
| `bundledApps` | `WindowRegistry` — 12 ready-to-mount apps. |
|
|
211
211
|
| `utilityApps`, `gameApps`, `documentApps`, `webApps` | Subsets of `bundledApps`. |
|
|
212
212
|
| `Calculator`, `Spreadsheet`, `Weather`, `CurrencyConverter`, `PomodoroTimer`, `Chess`, `Checkers`, `Sudoku`, `Tetris`, `Game2048`, `TodoList`, `Browser` | Lazy components — use directly in custom registry entries. |
|
|
213
|
+
| `BUILTIN_APP_INFO` | Per-app metadata for the document/web apps (Spreadsheets, Notepad, Documents, Preview, Files, Browser): display name, independent app version and one-line description. Drives each app's "About" dialog (window title menu → About <App>), which also shows the shell version. |
|
|
213
214
|
|
|
214
215
|
### Misc
|
|
215
216
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Browser as default, setBrowserStartUrl } from './chunk-P7OBFXLO.js';
|
|
2
|
+
import './chunk-2YSJRDKZ.js';
|
|
3
|
+
import './chunk-GWVVILYQ.js';
|
|
4
|
+
import './chunk-UBN4IUDE.js';
|
|
5
|
+
import './chunk-ZF6AYO4G.js';
|
|
6
|
+
//# sourceMappingURL=Browser-I5OETCZP.js.map
|
|
7
|
+
//# sourceMappingURL=Browser-I5OETCZP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"Browser-I5OETCZP.js"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { loadAppearance, WidgetSettingsModal } from './chunk-
|
|
2
|
-
import { useWidgetSettings } from './chunk-
|
|
1
|
+
import { loadAppearance, WidgetSettingsModal } from './chunk-ISNP6BHR.js';
|
|
2
|
+
import { useWidgetSettings } from './chunk-GWVVILYQ.js';
|
|
3
3
|
import './chunk-UBN4IUDE.js';
|
|
4
4
|
import './chunk-ZF6AYO4G.js';
|
|
5
5
|
import { useState, useCallback, useEffect } from 'react';
|
|
@@ -181,5 +181,5 @@ function Calculator() {
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
export { Calculator as default };
|
|
184
|
-
//# sourceMappingURL=Calculator-
|
|
185
|
-
//# sourceMappingURL=Calculator-
|
|
184
|
+
//# sourceMappingURL=Calculator-X26IEHCN.js.map
|
|
185
|
+
//# sourceMappingURL=Calculator-X26IEHCN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/Calculator.tsx"],"names":[],"mappings":"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","file":"Calculator-TGBQ6CZ5.js","sourcesContent":["import { useState, useCallback, useEffect } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\ntype Op = '+' | '-' | '×' | '÷' | null;\nconst CALC_SETTINGS_KEY = 'calc_appearance';\n\nexport default function Calculator() {\n const [display, setDisplay] = useState('0');\n const [prev, setPrev] = useState<number | null>(null);\n const [op, setOp] = useState<Op>(null);\n const [resetNext, setResetNext] = useState(false);\n const [lastExpr, setLastExpr] = useState('');\n const [history, setHistory] = useState<string[]>([]);\n const [copied, setCopied] = useState(false);\n const [appearance, setAppearance] = useState(() => loadAppearance(CALC_SETTINGS_KEY));\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n\n useWidgetSettings(useCallback(() => {\n setConfigAppearance({ ...appearance });\n setSettingsOpen(true);\n }, [appearance]));\n\n const append = useCallback((ch: string) => {\n setLastExpr('');\n setDisplay(d => {\n if (resetNext || d === '0') {\n setResetNext(false);\n return ch === '.' ? '0.' : ch;\n }\n if (ch === '.' && d.includes('.')) return d;\n return d + ch;\n });\n }, [resetNext]);\n\n const clear = useCallback(() => {\n setDisplay('0');\n setPrev(null);\n setOp(null);\n setResetNext(false);\n }, []);\n\n const compute = useCallback((a: number, b: number, operator: Op): number => {\n switch (operator) {\n case '+': return a + b;\n case '-': return a - b;\n case '×': return a * b;\n case '÷': return b === 0 ? 0 : a / b;\n default: return b;\n }\n }, []);\n\n const handleOp = useCallback((nextOp: Op) => {\n const current = parseFloat(display);\n if (prev !== null && op && !resetNext) {\n const result = compute(prev, current, op);\n setDisplay(String(result));\n setPrev(result);\n setHistory(h => [`${prev} ${op} ${current} = ${result}`, ...h].slice(0, 20));\n } else {\n setPrev(current);\n }\n setOp(nextOp);\n setResetNext(true);\n }, [display, prev, op, resetNext, compute]);\n\n const equals = useCallback(() => {\n if (prev === null || !op) return;\n const current = parseFloat(display);\n const result = compute(prev, current, op);\n const expr = `${prev} ${op} ${current} =`;\n setHistory(h => [`${expr} ${result}`, ...h].slice(0, 20));\n setLastExpr(expr);\n setDisplay(String(result));\n setPrev(null);\n setOp(null);\n setResetNext(true);\n }, [display, prev, op, compute]);\n\n const percent = useCallback(() => {\n setDisplay(d => String(parseFloat(d) / 100));\n }, []);\n\n const negate = useCallback(() => {\n setDisplay(d => d.startsWith('-') ? d.slice(1) : d === '0' ? d : '-' + d);\n }, []);\n\n // Keyboard support\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n const tag = (e.target as HTMLElement).tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n if (e.key >= '0' && e.key <= '9') append(e.key);\n else if (e.key === '.') append('.');\n else if (e.key === '+') handleOp('+');\n else if (e.key === '-') handleOp('-');\n else if (e.key === '*') handleOp('×');\n else if (e.key === '/') { e.preventDefault(); handleOp('÷'); }\n else if (e.key === 'Enter' || e.key === '=') equals();\n else if (e.key === 'Escape') clear();\n else if (e.key === 'Backspace') setDisplay(d => d.length > 1 ? d.slice(0, -1) : '0');\n else if (e.key === '%') percent();\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [append, handleOp, equals, clear, percent]);\n\n const btn = 'flex items-center justify-center rounded-lg text-sm font-medium transition-colors';\n const numBtn = `${btn} bg-white border border-gray-200 text-gray-900 hover:bg-gray-50 active:bg-gray-100`;\n const opBtn = `${btn} bg-blue-50 border border-blue-200 text-blue-700 hover:bg-blue-100 active:bg-blue-200`;\n const fnBtn = `${btn} bg-gray-100 border border-gray-200 text-gray-600 hover:bg-gray-200 active:bg-gray-300`;\n const eqBtn = `${btn} bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800`;\n\n // Format display for readability\n const formatDisplay = (val: string) => {\n const num = parseFloat(val);\n if (isNaN(num)) return val;\n if (val.endsWith('.') || val.endsWith('.0')) return val;\n if (Math.abs(num) < 1e15 && val.length < 16) return val;\n return num.toExponential(6);\n };\n\n return (\n <>\n <div className=\"flex flex-col h-full\" style={{\n opacity: appearance.activeOpacity / 100,\n backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined,\n }}>\n {/* Display — 5-line area with history + current value */}\n <div className=\"bg-slate-200 rounded-t-lg px-4 py-2 group/display relative flex flex-col justify-end min-h-[120px] border-b border-slate-300\">\n {/* History lines (most recent at bottom, above current) */}\n <div className=\"flex flex-col justify-end flex-1 overflow-hidden\">\n {history.slice(0, 3).reverse().map((h, i) => (\n <div key={i} className=\"text-[11px] text-slate-400 text-right font-mono truncate\">{h}</div>\n ))}\n </div>\n {/* Current expression */}\n {(lastExpr || (op && prev !== null)) && (\n <div className=\"text-base text-slate-600 text-right font-mono\">\n {lastExpr || `${prev} ${op} ${!resetNext ? display : ''}`}\n </div>\n )}\n {/* Current value */}\n <div className=\"flex items-center gap-2\">\n <button onClick={() => { navigator.clipboard.writeText(display); setCopied(true); setTimeout(() => setCopied(false), 1200); }}\n title=\"Copy result\"\n className=\"shrink-0 text-slate-300 hover:text-slate-500 transition-colors opacity-0 group-hover/display:opacity-100\">\n {copied\n ? <svg className=\"h-5 w-5 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" /></svg>\n : <svg className=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" /></svg>\n }\n </button>\n <div className=\"text-right text-4xl font-mono font-bold text-slate-800 truncate flex-1\">\n {formatDisplay(display)}\n </div>\n </div>\n </div>\n\n {/* Buttons */}\n <div className=\"grid grid-cols-4 grid-rows-5 gap-1.5 flex-1 min-h-0 p-2\">\n <button onClick={clear} className={fnBtn}>AC</button>\n <button onClick={negate} className={fnBtn}>+/−</button>\n <button onClick={percent} className={fnBtn}>%</button>\n <button onClick={() => handleOp('÷')} className={`${opBtn} ${op === '÷' ? 'ring-2 ring-blue-400' : ''}`}>÷</button>\n\n <button onClick={() => append('7')} className={numBtn}>7</button>\n <button onClick={() => append('8')} className={numBtn}>8</button>\n <button onClick={() => append('9')} className={numBtn}>9</button>\n <button onClick={() => handleOp('×')} className={`${opBtn} ${op === '×' ? 'ring-2 ring-blue-400' : ''}`}>×</button>\n\n <button onClick={() => append('4')} className={numBtn}>4</button>\n <button onClick={() => append('5')} className={numBtn}>5</button>\n <button onClick={() => append('6')} className={numBtn}>6</button>\n <button onClick={() => handleOp('-')} className={`${opBtn} ${op === '-' ? 'ring-2 ring-blue-400' : ''}`}>−</button>\n\n <button onClick={() => append('1')} className={numBtn}>1</button>\n <button onClick={() => append('2')} className={numBtn}>2</button>\n <button onClick={() => append('3')} className={numBtn}>3</button>\n <button onClick={() => handleOp('+')} className={`${opBtn} ${op === '+' ? 'ring-2 ring-blue-400' : ''}`}>+</button>\n\n <button onClick={() => append('0')} className={`${numBtn} col-span-2`}>0</button>\n <button onClick={() => append('.')} className={numBtn}>.</button>\n <button onClick={equals} className={eqBtn}>=</button>\n </div>\n\n </div>\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Calculator Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance}\n onSave={() => { setAppearance(configAppearance); localStorage.setItem(CALC_SETTINGS_KEY, JSON.stringify(configAppearance)); setSettingsOpen(false); }} />\n </>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/apps/Calculator.tsx"],"names":[],"mappings":"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","file":"Calculator-X26IEHCN.js","sourcesContent":["import { useState, useCallback, useEffect } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\ntype Op = '+' | '-' | '×' | '÷' | null;\nconst CALC_SETTINGS_KEY = 'calc_appearance';\n\nexport default function Calculator() {\n const [display, setDisplay] = useState('0');\n const [prev, setPrev] = useState<number | null>(null);\n const [op, setOp] = useState<Op>(null);\n const [resetNext, setResetNext] = useState(false);\n const [lastExpr, setLastExpr] = useState('');\n const [history, setHistory] = useState<string[]>([]);\n const [copied, setCopied] = useState(false);\n const [appearance, setAppearance] = useState(() => loadAppearance(CALC_SETTINGS_KEY));\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n\n useWidgetSettings(useCallback(() => {\n setConfigAppearance({ ...appearance });\n setSettingsOpen(true);\n }, [appearance]));\n\n const append = useCallback((ch: string) => {\n setLastExpr('');\n setDisplay(d => {\n if (resetNext || d === '0') {\n setResetNext(false);\n return ch === '.' ? '0.' : ch;\n }\n if (ch === '.' && d.includes('.')) return d;\n return d + ch;\n });\n }, [resetNext]);\n\n const clear = useCallback(() => {\n setDisplay('0');\n setPrev(null);\n setOp(null);\n setResetNext(false);\n }, []);\n\n const compute = useCallback((a: number, b: number, operator: Op): number => {\n switch (operator) {\n case '+': return a + b;\n case '-': return a - b;\n case '×': return a * b;\n case '÷': return b === 0 ? 0 : a / b;\n default: return b;\n }\n }, []);\n\n const handleOp = useCallback((nextOp: Op) => {\n const current = parseFloat(display);\n if (prev !== null && op && !resetNext) {\n const result = compute(prev, current, op);\n setDisplay(String(result));\n setPrev(result);\n setHistory(h => [`${prev} ${op} ${current} = ${result}`, ...h].slice(0, 20));\n } else {\n setPrev(current);\n }\n setOp(nextOp);\n setResetNext(true);\n }, [display, prev, op, resetNext, compute]);\n\n const equals = useCallback(() => {\n if (prev === null || !op) return;\n const current = parseFloat(display);\n const result = compute(prev, current, op);\n const expr = `${prev} ${op} ${current} =`;\n setHistory(h => [`${expr} ${result}`, ...h].slice(0, 20));\n setLastExpr(expr);\n setDisplay(String(result));\n setPrev(null);\n setOp(null);\n setResetNext(true);\n }, [display, prev, op, compute]);\n\n const percent = useCallback(() => {\n setDisplay(d => String(parseFloat(d) / 100));\n }, []);\n\n const negate = useCallback(() => {\n setDisplay(d => d.startsWith('-') ? d.slice(1) : d === '0' ? d : '-' + d);\n }, []);\n\n // Keyboard support\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n const tag = (e.target as HTMLElement).tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return;\n if (e.key >= '0' && e.key <= '9') append(e.key);\n else if (e.key === '.') append('.');\n else if (e.key === '+') handleOp('+');\n else if (e.key === '-') handleOp('-');\n else if (e.key === '*') handleOp('×');\n else if (e.key === '/') { e.preventDefault(); handleOp('÷'); }\n else if (e.key === 'Enter' || e.key === '=') equals();\n else if (e.key === 'Escape') clear();\n else if (e.key === 'Backspace') setDisplay(d => d.length > 1 ? d.slice(0, -1) : '0');\n else if (e.key === '%') percent();\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [append, handleOp, equals, clear, percent]);\n\n const btn = 'flex items-center justify-center rounded-lg text-sm font-medium transition-colors';\n const numBtn = `${btn} bg-white border border-gray-200 text-gray-900 hover:bg-gray-50 active:bg-gray-100`;\n const opBtn = `${btn} bg-blue-50 border border-blue-200 text-blue-700 hover:bg-blue-100 active:bg-blue-200`;\n const fnBtn = `${btn} bg-gray-100 border border-gray-200 text-gray-600 hover:bg-gray-200 active:bg-gray-300`;\n const eqBtn = `${btn} bg-blue-600 text-white hover:bg-blue-700 active:bg-blue-800`;\n\n // Format display for readability\n const formatDisplay = (val: string) => {\n const num = parseFloat(val);\n if (isNaN(num)) return val;\n if (val.endsWith('.') || val.endsWith('.0')) return val;\n if (Math.abs(num) < 1e15 && val.length < 16) return val;\n return num.toExponential(6);\n };\n\n return (\n <>\n <div className=\"flex flex-col h-full\" style={{\n opacity: appearance.activeOpacity / 100,\n backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined,\n }}>\n {/* Display — 5-line area with history + current value */}\n <div className=\"bg-slate-200 rounded-t-lg px-4 py-2 group/display relative flex flex-col justify-end min-h-[120px] border-b border-slate-300\">\n {/* History lines (most recent at bottom, above current) */}\n <div className=\"flex flex-col justify-end flex-1 overflow-hidden\">\n {history.slice(0, 3).reverse().map((h, i) => (\n <div key={i} className=\"text-[11px] text-slate-400 text-right font-mono truncate\">{h}</div>\n ))}\n </div>\n {/* Current expression */}\n {(lastExpr || (op && prev !== null)) && (\n <div className=\"text-base text-slate-600 text-right font-mono\">\n {lastExpr || `${prev} ${op} ${!resetNext ? display : ''}`}\n </div>\n )}\n {/* Current value */}\n <div className=\"flex items-center gap-2\">\n <button onClick={() => { navigator.clipboard.writeText(display); setCopied(true); setTimeout(() => setCopied(false), 1200); }}\n title=\"Copy result\"\n className=\"shrink-0 text-slate-300 hover:text-slate-500 transition-colors opacity-0 group-hover/display:opacity-100\">\n {copied\n ? <svg className=\"h-5 w-5 text-green-500\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" /></svg>\n : <svg className=\"h-5 w-5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" /></svg>\n }\n </button>\n <div className=\"text-right text-4xl font-mono font-bold text-slate-800 truncate flex-1\">\n {formatDisplay(display)}\n </div>\n </div>\n </div>\n\n {/* Buttons */}\n <div className=\"grid grid-cols-4 grid-rows-5 gap-1.5 flex-1 min-h-0 p-2\">\n <button onClick={clear} className={fnBtn}>AC</button>\n <button onClick={negate} className={fnBtn}>+/−</button>\n <button onClick={percent} className={fnBtn}>%</button>\n <button onClick={() => handleOp('÷')} className={`${opBtn} ${op === '÷' ? 'ring-2 ring-blue-400' : ''}`}>÷</button>\n\n <button onClick={() => append('7')} className={numBtn}>7</button>\n <button onClick={() => append('8')} className={numBtn}>8</button>\n <button onClick={() => append('9')} className={numBtn}>9</button>\n <button onClick={() => handleOp('×')} className={`${opBtn} ${op === '×' ? 'ring-2 ring-blue-400' : ''}`}>×</button>\n\n <button onClick={() => append('4')} className={numBtn}>4</button>\n <button onClick={() => append('5')} className={numBtn}>5</button>\n <button onClick={() => append('6')} className={numBtn}>6</button>\n <button onClick={() => handleOp('-')} className={`${opBtn} ${op === '-' ? 'ring-2 ring-blue-400' : ''}`}>−</button>\n\n <button onClick={() => append('1')} className={numBtn}>1</button>\n <button onClick={() => append('2')} className={numBtn}>2</button>\n <button onClick={() => append('3')} className={numBtn}>3</button>\n <button onClick={() => handleOp('+')} className={`${opBtn} ${op === '+' ? 'ring-2 ring-blue-400' : ''}`}>+</button>\n\n <button onClick={() => append('0')} className={`${numBtn} col-span-2`}>0</button>\n <button onClick={() => append('.')} className={numBtn}>.</button>\n <button onClick={equals} className={eqBtn}>=</button>\n </div>\n\n </div>\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Calculator Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance}\n onSave={() => { setAppearance(configAppearance); localStorage.setItem(CALC_SETTINGS_KEY, JSON.stringify(configAppearance)); setSettingsOpen(false); }} />\n </>\n );\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { loadAppearance, WidgetSettingsModal } from './chunk-
|
|
2
|
-
import { useWidgetSettings } from './chunk-
|
|
1
|
+
import { loadAppearance, WidgetSettingsModal } from './chunk-ISNP6BHR.js';
|
|
2
|
+
import { useWidgetSettings } from './chunk-GWVVILYQ.js';
|
|
3
3
|
import './chunk-UBN4IUDE.js';
|
|
4
4
|
import './chunk-ZF6AYO4G.js';
|
|
5
5
|
import { useState, useCallback, useEffect } from 'react';
|
|
@@ -226,5 +226,5 @@ function CurrencyConverter() {
|
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
export { CurrencyConverter as default };
|
|
229
|
-
//# sourceMappingURL=CurrencyConverter-
|
|
230
|
-
//# sourceMappingURL=CurrencyConverter-
|
|
229
|
+
//# sourceMappingURL=CurrencyConverter-5UHIRF2P.js.map
|
|
230
|
+
//# sourceMappingURL=CurrencyConverter-5UHIRF2P.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/CurrencyConverter.tsx"],"names":[],"mappings":"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","file":"CurrencyConverter-VIED4YVG.js","sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\nconst ALL_CURRENCIES = ['USD', 'CNY', 'AUD', 'GBP', 'EUR', 'JPY', 'CAD', 'THB', 'NZD', 'SGD', 'HKD', 'CHF', 'KRW', 'INR', 'MXN', 'BRL'];\n\n/** Cap the rate list at 4 — keeps the widget compact and avoids\n * overwhelming the user with currencies they don't actually track. */\nconst MAX_PAIRS = 4;\n\nconst DEFAULT_PAIRS: [string, string][] = [\n ['USD', 'CNY'], ['USD', 'AUD'], ['GBP', 'USD'], ['USD', 'JPY'],\n];\n\nconst PAIRS_KEY = 'currency_pairs';\nconst SETTINGS_KEY = 'currency_appearance';\nconst CACHE_KEY = 'currency_rates_cache';\nconst CACHE_TTL = 3600000;\n\ntype CacheEntry = { rates: Record<string, number>; timestamp: number };\n\nfunction getCached(base: string): Record<string, number> | null {\n try { const c: Record<string, CacheEntry> = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); const e = c[base]; if (e && Date.now() - e.timestamp < CACHE_TTL) return e.rates; } catch {} return null;\n}\nfunction setCache(base: string, rates: Record<string, number>) {\n try { const c = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); c[base] = { rates, timestamp: Date.now() }; localStorage.setItem(CACHE_KEY, JSON.stringify(c)); } catch {}\n}\nfunction loadPairs(): [string, string][] {\n try {\n const s = JSON.parse(localStorage.getItem(PAIRS_KEY) || '');\n if (Array.isArray(s) && s.length) return s.slice(0, MAX_PAIRS);\n } catch {}\n return DEFAULT_PAIRS;\n}\n\nconst FLAG: Record<string, string> = {\n USD: '\\u{1F1FA}\\u{1F1F8}', CNY: '\\u{1F1E8}\\u{1F1F3}', AUD: '\\u{1F1E6}\\u{1F1FA}',\n GBP: '\\u{1F1EC}\\u{1F1E7}', JPY: '\\u{1F1EF}\\u{1F1F5}', CAD: '\\u{1F1E8}\\u{1F1E6}',\n EUR: '\\u{1F1EA}\\u{1F1FA}', THB: '\\u{1F1F9}\\u{1F1ED}', NZD: '\\u{1F1F3}\\u{1F1FF}',\n SGD: '\\u{1F1F8}\\u{1F1EC}', HKD: '\\u{1F1ED}\\u{1F1F0}', CHF: '\\u{1F1E8}\\u{1F1ED}',\n KRW: '\\u{1F1F0}\\u{1F1F7}', INR: '\\u{1F1EE}\\u{1F1F3}', MXN: '\\u{1F1F2}\\u{1F1FD}',\n BRL: '\\u{1F1E7}\\u{1F1F7}',\n};\n\nexport default function CurrencyConverter() {\n const [pairs, setPairs] = useState(loadPairs);\n const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));\n const [allRates, setAllRates] = useState<Record<string, Record<string, number>>>({});\n const [loading, setLoading] = useState(false);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configPairs, setConfigPairs] = useState<[string, string][]>([]);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n const [newFrom, setNewFrom] = useState('USD');\n const [newTo, setNewTo] = useState('CNY');\n\n useWidgetSettings(useCallback(() => {\n setConfigPairs([...pairs]);\n setConfigAppearance({ ...appearance });\n setSettingsOpen(true);\n }, [pairs, appearance]));\n\n useEffect(() => {\n const bases = [...new Set(pairs.map(([from]) => from))];\n let mounted = true;\n async function fetchAll() {\n setLoading(true);\n const result: Record<string, Record<string, number>> = {};\n for (const base of bases) {\n const cached = getCached(base);\n if (cached) { result[base] = cached; continue; }\n try { const res = await fetch(`https://open.er-api.com/v6/latest/${base}`); const data = await res.json(); if (data.rates) { result[base] = data.rates; setCache(base, data.rates); } } catch {}\n }\n if (mounted) { setAllRates(result); setLoading(false); }\n }\n fetchAll();\n return () => { mounted = false; };\n }, [pairs]);\n\n const saveSettings = () => {\n if (configPairs.length === 0) return;\n const capped = configPairs.slice(0, MAX_PAIRS);\n setPairs(capped); setAppearance(configAppearance);\n localStorage.setItem(PAIRS_KEY, JSON.stringify(capped));\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));\n setSettingsOpen(false);\n };\n\n return (\n <>\n {/* Theme-aware panel — pulls the same `--taskbar-bg-rgb` colour the\n * taskbar uses so the widget matches it across all themes\n * (gray-100-ish on light, Catppuccin mantle in dark). Tailwind\n * gray-* text/border classes auto-invert in dark via the existing\n * `[data-theme=\"dark\"]` overrides in styles.css. */}\n <div className=\"flex flex-col h-full\"\n style={{ backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${appearance.activeOpacity / 100})`, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined }}>\n <div className=\"px-4 py-3 space-y-1 flex-1\">\n {loading && <div className=\"text-xs text-gray-400 text-center py-4\">Loading rates...</div>}\n {pairs.map(([from, to], idx) => {\n const rate = allRates[from]?.[to];\n return (\n <button key={`${from}-${to}-${idx}`} onClick={() => {\n const swapped: [string, string][] = pairs.map((p, i) => i === idx ? [p[1], p[0]] : p);\n setPairs(swapped);\n localStorage.setItem(PAIRS_KEY, JSON.stringify(swapped));\n }}\n className=\"flex items-center justify-between px-2 py-2 border-b border-gray-200 last:border-0 w-full hover:bg-gray-100 rounded transition-colors cursor-pointer\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-base\">{FLAG[from] || ''}</span>\n <span className=\"text-sm font-semibold text-gray-700\">{from}</span>\n <svg className=\"h-3 w-3 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" /></svg>\n <span className=\"text-base\">{FLAG[to] || ''}</span>\n <span className=\"text-sm font-semibold text-gray-700\">{to}</span>\n </div>\n <div className=\"text-base font-mono font-semibold text-gray-900 tabular-nums\">\n {rate != null ? rate.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 4 }) : '—'}\n </div>\n </button>\n );\n })}\n </div>\n </div>\n\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Currency Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance} onSave={saveSettings}>\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2\">Currency Pairs <span className=\"text-[11px] font-normal text-gray-400\">({configPairs.length}/{MAX_PAIRS})</span></h3>\n <div className=\"space-y-1 mb-2\">\n {configPairs.map(([f, t], i) => (\n <div key={i} className=\"flex items-center justify-between py-1 px-2 bg-gray-50 rounded\">\n <span className=\"text-sm\">{FLAG[f] || ''} {f} → {FLAG[t] || ''} {t}</span>\n <button onClick={() => setConfigPairs(p => p.filter((_, idx) => idx !== i))} className=\"text-red-400 hover:text-red-600\">×</button>\n </div>\n ))}\n </div>\n {configPairs.length < MAX_PAIRS ? (\n <div className=\"flex items-center gap-2\">\n <select value={newFrom} onChange={e => setNewFrom(e.target.value)}\n className=\"bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500\">\n {ALL_CURRENCIES.map(c => <option key={c}>{c}</option>)}\n </select>\n <span className=\"text-gray-400\">→</span>\n <select value={newTo} onChange={e => setNewTo(e.target.value)}\n className=\"bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500\">\n {ALL_CURRENCIES.map(c => <option key={c}>{c}</option>)}\n </select>\n <button onClick={() => { if (newFrom !== newTo && configPairs.length < MAX_PAIRS) setConfigPairs(p => [...p, [newFrom, newTo]]); }}\n className=\"text-sm font-medium text-blue-600 hover:text-blue-800 px-2\">+ Add</button>\n </div>\n ) : (\n <p className=\"text-[11px] text-gray-400 italic\">Max {MAX_PAIRS} pairs — remove one to add another.</p>\n )}\n </div>\n </WidgetSettingsModal>\n </>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/apps/CurrencyConverter.tsx"],"names":[],"mappings":"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","file":"CurrencyConverter-5UHIRF2P.js","sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useWidgetSettings } from '../shell/Modal';\nimport WidgetSettingsModal, { loadAppearance, type WidgetAppearance } from '../shell/WidgetSettingsModal';\n\nconst ALL_CURRENCIES = ['USD', 'CNY', 'AUD', 'GBP', 'EUR', 'JPY', 'CAD', 'THB', 'NZD', 'SGD', 'HKD', 'CHF', 'KRW', 'INR', 'MXN', 'BRL'];\n\n/** Cap the rate list at 4 — keeps the widget compact and avoids\n * overwhelming the user with currencies they don't actually track. */\nconst MAX_PAIRS = 4;\n\nconst DEFAULT_PAIRS: [string, string][] = [\n ['USD', 'CNY'], ['USD', 'AUD'], ['GBP', 'USD'], ['USD', 'JPY'],\n];\n\nconst PAIRS_KEY = 'currency_pairs';\nconst SETTINGS_KEY = 'currency_appearance';\nconst CACHE_KEY = 'currency_rates_cache';\nconst CACHE_TTL = 3600000;\n\ntype CacheEntry = { rates: Record<string, number>; timestamp: number };\n\nfunction getCached(base: string): Record<string, number> | null {\n try { const c: Record<string, CacheEntry> = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); const e = c[base]; if (e && Date.now() - e.timestamp < CACHE_TTL) return e.rates; } catch {} return null;\n}\nfunction setCache(base: string, rates: Record<string, number>) {\n try { const c = JSON.parse(localStorage.getItem(CACHE_KEY) || '{}'); c[base] = { rates, timestamp: Date.now() }; localStorage.setItem(CACHE_KEY, JSON.stringify(c)); } catch {}\n}\nfunction loadPairs(): [string, string][] {\n try {\n const s = JSON.parse(localStorage.getItem(PAIRS_KEY) || '');\n if (Array.isArray(s) && s.length) return s.slice(0, MAX_PAIRS);\n } catch {}\n return DEFAULT_PAIRS;\n}\n\nconst FLAG: Record<string, string> = {\n USD: '\\u{1F1FA}\\u{1F1F8}', CNY: '\\u{1F1E8}\\u{1F1F3}', AUD: '\\u{1F1E6}\\u{1F1FA}',\n GBP: '\\u{1F1EC}\\u{1F1E7}', JPY: '\\u{1F1EF}\\u{1F1F5}', CAD: '\\u{1F1E8}\\u{1F1E6}',\n EUR: '\\u{1F1EA}\\u{1F1FA}', THB: '\\u{1F1F9}\\u{1F1ED}', NZD: '\\u{1F1F3}\\u{1F1FF}',\n SGD: '\\u{1F1F8}\\u{1F1EC}', HKD: '\\u{1F1ED}\\u{1F1F0}', CHF: '\\u{1F1E8}\\u{1F1ED}',\n KRW: '\\u{1F1F0}\\u{1F1F7}', INR: '\\u{1F1EE}\\u{1F1F3}', MXN: '\\u{1F1F2}\\u{1F1FD}',\n BRL: '\\u{1F1E7}\\u{1F1F7}',\n};\n\nexport default function CurrencyConverter() {\n const [pairs, setPairs] = useState(loadPairs);\n const [appearance, setAppearance] = useState(() => loadAppearance(SETTINGS_KEY));\n const [allRates, setAllRates] = useState<Record<string, Record<string, number>>>({});\n const [loading, setLoading] = useState(false);\n const [settingsOpen, setSettingsOpen] = useState(false);\n const [configPairs, setConfigPairs] = useState<[string, string][]>([]);\n const [configAppearance, setConfigAppearance] = useState<WidgetAppearance>(appearance);\n const [newFrom, setNewFrom] = useState('USD');\n const [newTo, setNewTo] = useState('CNY');\n\n useWidgetSettings(useCallback(() => {\n setConfigPairs([...pairs]);\n setConfigAppearance({ ...appearance });\n setSettingsOpen(true);\n }, [pairs, appearance]));\n\n useEffect(() => {\n const bases = [...new Set(pairs.map(([from]) => from))];\n let mounted = true;\n async function fetchAll() {\n setLoading(true);\n const result: Record<string, Record<string, number>> = {};\n for (const base of bases) {\n const cached = getCached(base);\n if (cached) { result[base] = cached; continue; }\n try { const res = await fetch(`https://open.er-api.com/v6/latest/${base}`); const data = await res.json(); if (data.rates) { result[base] = data.rates; setCache(base, data.rates); } } catch {}\n }\n if (mounted) { setAllRates(result); setLoading(false); }\n }\n fetchAll();\n return () => { mounted = false; };\n }, [pairs]);\n\n const saveSettings = () => {\n if (configPairs.length === 0) return;\n const capped = configPairs.slice(0, MAX_PAIRS);\n setPairs(capped); setAppearance(configAppearance);\n localStorage.setItem(PAIRS_KEY, JSON.stringify(capped));\n localStorage.setItem(SETTINGS_KEY, JSON.stringify(configAppearance));\n setSettingsOpen(false);\n };\n\n return (\n <>\n {/* Theme-aware panel — pulls the same `--taskbar-bg-rgb` colour the\n * taskbar uses so the widget matches it across all themes\n * (gray-100-ish on light, Catppuccin mantle in dark). Tailwind\n * gray-* text/border classes auto-invert in dark via the existing\n * `[data-theme=\"dark\"]` overrides in styles.css. */}\n <div className=\"flex flex-col h-full\"\n style={{ backgroundColor: `rgb(var(--taskbar-bg-rgb, 243 244 246) / ${appearance.activeOpacity / 100})`, backdropFilter: appearance.activeBlur > 0 ? `blur(${appearance.activeBlur}px)` : undefined }}>\n <div className=\"px-4 py-3 space-y-1 flex-1\">\n {loading && <div className=\"text-xs text-gray-400 text-center py-4\">Loading rates...</div>}\n {pairs.map(([from, to], idx) => {\n const rate = allRates[from]?.[to];\n return (\n <button key={`${from}-${to}-${idx}`} onClick={() => {\n const swapped: [string, string][] = pairs.map((p, i) => i === idx ? [p[1], p[0]] : p);\n setPairs(swapped);\n localStorage.setItem(PAIRS_KEY, JSON.stringify(swapped));\n }}\n className=\"flex items-center justify-between px-2 py-2 border-b border-gray-200 last:border-0 w-full hover:bg-gray-100 rounded transition-colors cursor-pointer\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-base\">{FLAG[from] || ''}</span>\n <span className=\"text-sm font-semibold text-gray-700\">{from}</span>\n <svg className=\"h-3 w-3 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4\" /></svg>\n <span className=\"text-base\">{FLAG[to] || ''}</span>\n <span className=\"text-sm font-semibold text-gray-700\">{to}</span>\n </div>\n <div className=\"text-base font-mono font-semibold text-gray-900 tabular-nums\">\n {rate != null ? rate.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 4 }) : '—'}\n </div>\n </button>\n );\n })}\n </div>\n </div>\n\n <WidgetSettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} title=\"Currency Settings\"\n appearance={configAppearance} onAppearanceChange={setConfigAppearance} onSave={saveSettings}>\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-2\">Currency Pairs <span className=\"text-[11px] font-normal text-gray-400\">({configPairs.length}/{MAX_PAIRS})</span></h3>\n <div className=\"space-y-1 mb-2\">\n {configPairs.map(([f, t], i) => (\n <div key={i} className=\"flex items-center justify-between py-1 px-2 bg-gray-50 rounded\">\n <span className=\"text-sm\">{FLAG[f] || ''} {f} → {FLAG[t] || ''} {t}</span>\n <button onClick={() => setConfigPairs(p => p.filter((_, idx) => idx !== i))} className=\"text-red-400 hover:text-red-600\">×</button>\n </div>\n ))}\n </div>\n {configPairs.length < MAX_PAIRS ? (\n <div className=\"flex items-center gap-2\">\n <select value={newFrom} onChange={e => setNewFrom(e.target.value)}\n className=\"bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500\">\n {ALL_CURRENCIES.map(c => <option key={c}>{c}</option>)}\n </select>\n <span className=\"text-gray-400\">→</span>\n <select value={newTo} onChange={e => setNewTo(e.target.value)}\n className=\"bg-gray-50 border border-gray-200 rounded px-2 py-1 text-sm focus:outline-none focus:ring-1 focus:ring-blue-500\">\n {ALL_CURRENCIES.map(c => <option key={c}>{c}</option>)}\n </select>\n <button onClick={() => { if (newFrom !== newTo && configPairs.length < MAX_PAIRS) setConfigPairs(p => [...p, [newFrom, newTo]]); }}\n className=\"text-sm font-medium text-blue-600 hover:text-blue-800 px-2\">+ Add</button>\n </div>\n ) : (\n <p className=\"text-[11px] text-gray-400 italic\">Max {MAX_PAIRS} pairs — remove one to add another.</p>\n )}\n </div>\n </WidgetSettingsModal>\n </>\n );\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
2
|
-
import {
|
|
2
|
+
import { AboutApp } from './chunk-2YSJRDKZ.js';
|
|
3
|
+
import { WindowTitle } from './chunk-GWVVILYQ.js';
|
|
3
4
|
import './chunk-UBN4IUDE.js';
|
|
4
5
|
import './chunk-ZF6AYO4G.js';
|
|
5
6
|
import { useState, useRef } from 'react';
|
|
@@ -160,6 +161,7 @@ function Documents() {
|
|
|
160
161
|
onDrop: handleDrop,
|
|
161
162
|
children: [
|
|
162
163
|
/* @__PURE__ */ jsx(WindowTitle, { title: `${titleName}${edited ? " \u2022" : ""} - Documents` }),
|
|
164
|
+
/* @__PURE__ */ jsx(AboutApp, { app: "documents" }),
|
|
163
165
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-gray-200 bg-gray-50 shrink-0", children: [
|
|
164
166
|
/* @__PURE__ */ jsx(
|
|
165
167
|
"input",
|
|
@@ -298,5 +300,5 @@ function Documents() {
|
|
|
298
300
|
}
|
|
299
301
|
|
|
300
302
|
export { Documents as default };
|
|
301
|
-
//# sourceMappingURL=Documents-
|
|
302
|
-
//# sourceMappingURL=Documents-
|
|
303
|
+
//# sourceMappingURL=Documents-XXR5APHQ.js.map
|
|
304
|
+
//# sourceMappingURL=Documents-XXR5APHQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/apps/Documents.tsx"],"names":[],"mappings":"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","file":"Documents-XXR5APHQ.js","sourcesContent":["/**\n * Documents — windowed viewer / light editor for plain-text and Word\n * documents. TXT-family files (.txt, .md, .csv, .log, .json, .xml,\n * .html, .css, .ts, .tsx, .js, .jsx, .py, .yml, .yaml, .toml, .sh)\n * open in an editable textarea. Word .docx files are converted to\n * read-only HTML via mammoth (an optional peer dep).\n *\n * Open files via the toolbar's Open button or by dragging them onto\n * the window.\n */\nimport { useState, useRef, useEffect } from 'react';\nimport { WindowTitle } from '../shell/Modal';\nimport toast from '../shell/toast';\nimport AboutApp from './_about';\n\nconst TITLE_DISPLAY_MAX = 24;\nfunction truncateForTitle(s: string) {\n return s.length > TITLE_DISPLAY_MAX ? `${s.slice(0, TITLE_DISPLAY_MAX - 1)}…` : s;\n}\n\nfunction escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, c => ({\n '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''',\n }[c] || c));\n}\n\nconst TEXT_EXTS = new Set([\n 'txt', 'md', 'markdown', 'csv', 'tsv', 'log', 'json', 'xml',\n 'html', 'htm', 'css', 'js', 'jsx', 'ts', 'tsx', 'py', 'rb',\n 'go', 'rs', 'java', 'c', 'h', 'cpp', 'hpp', 'sh', 'bash',\n 'yml', 'yaml', 'toml', 'ini', 'conf', 'env', 'sql',\n]);\nconst DOCX_EXTS = new Set(['docx']);\n\ninterface DocData {\n filename: string;\n kind: 'text' | 'docx';\n content: string;\n /** Original mime / extension hint for the download button. */\n ext: string;\n}\n\nconst BLANK_DOC: DocData = { filename: 'Untitled', kind: 'docx', content: '', ext: 'docx' };\n\nexport default function Documents() {\n // Documents is for editing — open with a blank paper-style canvas so the\n // user can start typing immediately. Loading a file replaces this state.\n const [data, setData] = useState<DocData>(BLANK_DOC);\n const [busy, setBusy] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n const [edited, setEdited] = useState(false);\n const fileRef = useRef<HTMLInputElement>(null);\n const editorRef = useRef<HTMLDivElement>(null);\n\n // Apply a formatting command to the current selection in the editor.\n const exec = (cmd: string, value?: string) => {\n editorRef.current?.focus();\n document.execCommand(cmd, false, value);\n setEdited(true);\n };\n\n // Pull current HTML out of the editor (for save).\n const getEditorHtml = () => editorRef.current?.innerHTML ?? '';\n const getEditorText = () => editorRef.current?.innerText ?? '';\n\n const ingestFile = async (file: File) => {\n const ext = (file.name.split('.').pop() || '').toLowerCase();\n setBusy(true);\n try {\n if (TEXT_EXTS.has(ext) || (!DOCX_EXTS.has(ext) && file.type.startsWith('text/'))) {\n const text = await file.text();\n // Convert plain text → HTML so the contenteditable shows\n // line breaks correctly. Escape HTML special chars first.\n const html = escapeHtml(text).replace(/\\n/g, '<br>');\n setData({ filename: file.name, kind: 'text', content: html, ext });\n setEdited(false);\n } else if (DOCX_EXTS.has(ext)) {\n try {\n // mammoth is an optional peer dep — convert .docx → HTML.\n const mammoth = await import(/* @vite-ignore */ 'mammoth' as any);\n const buf = await file.arrayBuffer();\n const result = await mammoth.convertToHtml({ arrayBuffer: buf });\n setData({ filename: file.name, kind: 'docx', content: result.value || '<p><em>(empty document)</em></p>', ext });\n setEdited(false);\n } catch (err) {\n toast.error('Install the optional \"mammoth\" peer dep to read .docx files.');\n }\n } else if (ext === 'doc') {\n toast.error('.doc is the legacy Word binary format — convert to .docx first.');\n } else {\n toast.error(`Unsupported file type: .${ext || 'unknown'}`);\n }\n } finally {\n setBusy(false);\n }\n };\n\n const handlePick = () => fileRef.current?.click();\n const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) ingestFile(file);\n if (fileRef.current) fileRef.current.value = '';\n };\n const handleDrop = (e: React.DragEvent) => {\n e.preventDefault();\n setIsDragging(false);\n const file = e.dataTransfer.files?.[0];\n if (file) ingestFile(file);\n };\n\n const downloadCurrent = () => {\n if (!data) return;\n const html = getEditorHtml();\n if (data.kind === 'text') {\n // If the user added formatting, save as .html alongside; otherwise\n // strip back to plain text so the original .txt round-trips cleanly.\n const hasFormatting = /<(b|strong|i|em|u|font|span style)/i.test(html);\n if (hasFormatting) {\n const blob = new Blob([`<!doctype html><meta charset=\"utf-8\"><title>${escapeHtml(data.filename)}</title><body style=\"font-family:ui-monospace,monospace;white-space:pre-wrap\">${html}`], { type: 'text/html' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a'); a.href = url; a.download = `${data.filename.replace(/\\.[^.]+$/, '')}.html`; a.click();\n URL.revokeObjectURL(url);\n } else {\n const text = getEditorText();\n const blob = new Blob([text], { type: 'text/plain' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a'); a.href = url; a.download = data.filename; a.click();\n URL.revokeObjectURL(url);\n }\n } else {\n const blob = new Blob([`<!doctype html><meta charset=\"utf-8\"><title>${escapeHtml(data.filename)}</title>${html}`], { type: 'text/html' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url; a.download = `${data.filename.replace(/\\.docx$/i, '')}.html`; a.click();\n URL.revokeObjectURL(url);\n }\n };\n\n const titleName = data?.filename ? truncateForTitle(data.filename) : 'Untitled';\n\n return (\n <div\n className=\"relative flex flex-col h-full\"\n onDragOver={(e) => { e.preventDefault(); if (!isDragging) setIsDragging(true); }}\n onDragLeave={(e) => { if (e.currentTarget === e.target) setIsDragging(false); }}\n onDrop={handleDrop}\n >\n <WindowTitle title={`${titleName}${edited ? ' •' : ''} - Documents`} />\n <AboutApp app=\"documents\" />\n\n {/* Toolbar */}\n <div className=\"flex items-center gap-2 px-3 py-2 border-b border-gray-200 bg-gray-50 shrink-0\">\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".txt,.md,.csv,.tsv,.log,.json,.xml,.html,.htm,.css,.js,.jsx,.ts,.tsx,.py,.rb,.go,.rs,.java,.c,.h,.cpp,.hpp,.sh,.bash,.yml,.yaml,.toml,.ini,.conf,.env,.sql,.docx,text/*\"\n onChange={handleFile}\n className=\"hidden\"\n />\n <button onClick={handlePick} className=\"text-xs text-gray-700 hover:text-gray-900 px-2 py-1 rounded hover:bg-gray-200 transition-colors flex items-center gap-1\">\n <svg className=\"h-3.5 w-3.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 00-1.883 2.542l.857 6a2.25 2.25 0 002.227 1.932H19.05a2.25 2.25 0 002.227-1.932l.857-6a2.25 2.25 0 00-1.883-2.542m-16.5 0V6A2.25 2.25 0 016 3.75h3.879a1.5 1.5 0 011.06.44l2.122 2.12a1.5 1.5 0 001.06.44H18A2.25 2.25 0 0120.25 9v.776\" />\n </svg>\n Open\n </button>\n <button onClick={downloadCurrent} className=\"text-xs text-gray-700 hover:text-gray-900 px-2 py-1 rounded hover:bg-gray-200 transition-colors\">\n Save\n </button>\n <span className=\"text-[10px] text-gray-400 ml-1\">TXT · DOCX · Code</span>\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <span className=\"text-xs font-medium text-gray-700 truncate max-w-[200px]\" title={data.filename}>\n {data.filename}{edited ? ' •' : ''}\n </span>\n\n {/* Formatting toolbar */}\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <div className=\"flex items-center gap-0.5\">\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('bold')}\n className=\"px-2 py-1 text-xs rounded font-bold text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Bold\">B</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('italic')}\n className=\"px-2 py-1 text-xs rounded italic text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Italic\">I</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('underline')}\n className=\"px-2 py-1 text-xs rounded underline text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Underline\">U</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('strikeThrough')}\n className=\"px-2 py-1 text-xs rounded line-through text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Strikethrough\">S</button>\n </div>\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <select onMouseDown={e => e.preventDefault()} onChange={e => { exec('fontSize', e.target.value); e.currentTarget.value = ''; }}\n defaultValue=\"\" className=\"text-xs border border-gray-300 rounded px-1 py-0.5 bg-white\">\n <option value=\"\" disabled>Size</option>\n <option value=\"1\">XS</option>\n <option value=\"2\">S</option>\n <option value=\"3\">M</option>\n <option value=\"4\">L</option>\n <option value=\"5\">XL</option>\n <option value=\"6\">2XL</option>\n </select>\n <input type=\"color\" defaultValue=\"#000000\" onChange={e => exec('foreColor', e.target.value)}\n className=\"w-7 h-6 border border-gray-300 rounded cursor-pointer\" title=\"Text color\" />\n <div className=\"h-4 w-px bg-gray-300 mx-1\" />\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('insertUnorderedList')}\n className=\"px-2 py-1 text-xs rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Bulleted list\">• List</button>\n <button onMouseDown={e => e.preventDefault()} onClick={() => exec('insertOrderedList')}\n className=\"px-2 py-1 text-xs rounded text-gray-700 hover:bg-gray-200 transition-colors\" title=\"Numbered list\">1.</button>\n </div>\n\n {/* Body */}\n <div className=\"flex-1 min-h-0 overflow-hidden\">\n {busy ? (\n <div className=\"flex items-center justify-center h-full text-sm text-gray-400\">Loading…</div>\n ) : (\n <div className={`h-full overflow-auto ${data.kind === 'docx' ? 'bg-gray-100 px-12 py-10' : 'bg-white'}`}>\n <div\n ref={editorRef}\n contentEditable\n suppressContentEditableWarning\n spellCheck={false}\n onInput={() => setEdited(true)}\n dangerouslySetInnerHTML={{ __html: data.content }}\n className={\n data.kind === 'docx'\n ? 'mx-auto max-w-[760px] bg-white p-12 shadow text-[14px] leading-relaxed text-gray-800 outline-none focus:ring-2 focus:ring-blue-400/40 prose prose-sm'\n : 'block w-full min-h-full p-4 font-mono text-[13px] leading-relaxed text-gray-800 bg-white outline-none whitespace-pre-wrap'\n }\n />\n </div>\n )}\n </div>\n\n {isDragging && (\n <div className=\"absolute inset-0 bg-blue-500/15 border-4 border-dashed border-blue-500 pointer-events-none flex items-center justify-center z-20\">\n <div className=\"px-4 py-2 rounded-md bg-blue-600 text-white text-sm font-medium shadow-lg\">\n Drop to open\n </div>\n </div>\n )}\n </div>\n );\n}\n\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { Files as default, openFilesInTrashMode, setFilesDemoTree } from './chunk-CF3SUKOS.js';
|
|
2
|
+
import './chunk-6IQJSIAR.js';
|
|
3
|
+
import './chunk-VGTEM5RZ.js';
|
|
4
|
+
import './chunk-LAAGWPMR.js';
|
|
5
|
+
import './chunk-KUIPWCTJ.js';
|
|
6
|
+
import './chunk-WIJ45SYD.js';
|
|
7
|
+
import './chunk-BPPG7CVR.js';
|
|
8
|
+
import './chunk-2YSJRDKZ.js';
|
|
9
|
+
import './chunk-GWVVILYQ.js';
|
|
10
|
+
import './chunk-UBN4IUDE.js';
|
|
11
|
+
import './chunk-ZF6AYO4G.js';
|
|
12
|
+
//# sourceMappingURL=Files-62UEOWMR.js.map
|
|
13
|
+
//# sourceMappingURL=Files-62UEOWMR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"Files-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"Files-62UEOWMR.js"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formatDate } from './chunk-Y4QYGQKS.js';
|
|
2
2
|
import { toast_default } from './chunk-WIJ45SYD.js';
|
|
3
|
-
import { useWindowMenuItem, Modal, client_default } from './chunk-
|
|
3
|
+
import { useWindowMenuItem, Modal, client_default } from './chunk-GWVVILYQ.js';
|
|
4
4
|
import './chunk-UBN4IUDE.js';
|
|
5
5
|
import './chunk-ZF6AYO4G.js';
|
|
6
6
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
@@ -267,5 +267,5 @@ function Minesweeper() {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
export { Minesweeper as default };
|
|
270
|
-
//# sourceMappingURL=Minesweeper-
|
|
271
|
-
//# sourceMappingURL=Minesweeper-
|
|
270
|
+
//# sourceMappingURL=Minesweeper-OXRRSCVF.js.map
|
|
271
|
+
//# sourceMappingURL=Minesweeper-OXRRSCVF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/analytics.ts","../src/apps/Minesweeper.tsx"],"names":["c"],"mappings":"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","file":"Minesweeper-JEQS36AX.js","sourcesContent":["/** Game analytics — Minesweeper leaderboard routes through the\n * consumer-supplied apiClient (see setShellApiClient). */\nimport apiClient from './client';\nexport const submitGameScore = (data: { game: string; won: boolean; time_seconds: number; clicks: number }) =>\n apiClient.post(`/analytics/games/${data.game}/scores/`, data).then((r: any) => r.data);\nexport const getGameLeaderboard = (game: string) =>\n apiClient.get(`/analytics/games/${game}/leaderboard/`).then((r: any) => r.data);\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport { submitGameScore, getGameLeaderboard } from '../api/analytics';\nimport Modal, { useWindowMenuItem } from '../shell/Modal';\nimport toast from '../shell/toast';\nimport { formatDate } from '../utils/date';\n\nconst ROWS = 9, COLS = 9, MINES = 10;\nconst DIRS = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];\nconst NUM_COLORS: Record<number,string> = {1:'text-blue-700',2:'text-green-700',3:'text-red-600',4:'text-purple-700',5:'text-red-900',6:'text-teal-600',7:'text-black',8:'text-gray-500'};\n\ntype Cell = { mine: boolean; revealed: boolean; flagged: boolean; adjacent: number };\ntype Status = 'playing' | 'won' | 'lost';\n\nfunction createBoard(): Cell[][] {\n return Array.from({length:ROWS},()=>Array.from({length:COLS},()=>({mine:false,revealed:false,flagged:false,adjacent:0})));\n}\n\nfunction placeMines(board: Cell[][], safeR: number, safeC: number) {\n const b = board.map(r=>r.map(c=>({...c})));\n let placed = 0;\n while (placed < MINES) {\n const r = Math.floor(Math.random()*ROWS), c = Math.floor(Math.random()*COLS);\n if (b[r][c].mine || (Math.abs(r-safeR)<=1 && Math.abs(c-safeC)<=1)) continue;\n b[r][c].mine = true;\n placed++;\n }\n for (let r=0;r<ROWS;r++) for (let c=0;c<COLS;c++) {\n if (b[r][c].mine) continue;\n b[r][c].adjacent = DIRS.reduce((s,[dr,dc])=>{\n const nr=r+dr,nc=c+dc;\n return s+(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&b[nr][nc].mine?1:0);\n },0);\n }\n return b;\n}\n\nfunction floodFill(board: Cell[][], r: number, c: number) {\n const b = board.map(row=>row.map(cell=>({...cell})));\n const stack: [number,number][] = [[r,c]];\n while (stack.length) {\n const [cr,cc] = stack.pop()!;\n if (cr<0||cr>=ROWS||cc<0||cc>=COLS||b[cr][cc].revealed||b[cr][cc].flagged||b[cr][cc].mine) continue;\n b[cr][cc].revealed = true;\n if (b[cr][cc].adjacent === 0) DIRS.forEach(([dr,dc])=>stack.push([cr+dr,cc+dc]));\n }\n return b;\n}\n\nfunction checkWin(board: Cell[][]): boolean {\n return board.every(row=>row.every(c=>c.mine||c.revealed));\n}\n\nexport default function Minesweeper() {\n const [board, setBoard] = useState(createBoard);\n const [status, setStatus] = useState<Status>('playing');\n const [started, setStarted] = useState(false);\n const [time, setTime] = useState(0); // in centiseconds (hundredths)\n const timerRef = useRef<ReturnType<typeof setInterval>|null>(null);\n const startTimeRef = useRef(0);\n const [clicks, setClicks] = useState(0);\n const [showLeaderboard, setShowLeaderboard] = useState(false);\n const [leaderboard, setLeaderboard] = useState<{ rank: number; player_name: string; time_seconds: number; clicks: number; played_at: string }[]>([]);\n const [loadingLb, setLoadingLb] = useState(false);\n const scoreSubmitted = useRef(false);\n\n const flagCount = board.reduce((s,r)=>s+r.reduce((s2,c)=>s2+(c.flagged?1:0),0),0);\n\n const timeSeconds = time / 100; // convert centiseconds to seconds with 2 decimals\n\n useEffect(()=>{\n if (started && status==='playing') {\n startTimeRef.current = performance.now() - time * 10;\n timerRef.current = setInterval(()=>{\n const elapsed = Math.floor((performance.now() - startTimeRef.current) / 10);\n setTime(Math.min(elapsed, 99999));\n }, 10);\n } else if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n return ()=>{if(timerRef.current)clearInterval(timerRef.current)};\n },[started,status]);\n\n const restart = useCallback(()=>{\n setBoard(createBoard());\n setStatus('playing');\n setStarted(false);\n setTime(0);\n startTimeRef.current = 0;\n setClicks(0);\n scoreSubmitted.current = false;\n },[]);\n\n const handleClick = useCallback((r:number,c:number)=>{\n if (status!=='playing') return;\n setBoard(prev=>{\n let b = prev;\n if (!started) {\n b = placeMines(prev,r,c);\n setStarted(true);\n }\n const cell = b[r][c];\n if (cell.revealed||cell.flagged) return b;\n if (cell.mine) {\n const lost = b.map(row=>row.map(c=>({...c,revealed:c.mine?true:c.revealed})));\n lost[r][c] = {...lost[r][c], revealed:true};\n setStatus('lost');\n return lost;\n }\n const next = floodFill(b,r,c);\n if (checkWin(next)) setStatus('won');\n return next;\n });\n },[status,started]);\n\n const handleContext = useCallback((e:React.MouseEvent,r:number,c:number)=>{\n e.preventDefault();\n if (status!=='playing') return;\n setBoard(prev=>{\n if (prev[r][c].revealed) return prev;\n const b = prev.map(row=>row.map(cell=>({...cell})));\n b[r][c].flagged = !b[r][c].flagged;\n return b;\n });\n },[status]);\n\n // Chord click: both buttons on a revealed number — auto-reveal adjacent if flags match\n const handleChord = useCallback((r:number,c:number)=>{\n if (status!=='playing') return;\n setBoard(prev=>{\n const cell = prev[r][c];\n if (!cell.revealed || cell.adjacent === 0) return prev;\n // Count adjacent flags\n const adjFlags = DIRS.reduce((s,[dr,dc])=>{\n const nr=r+dr,nc=c+dc;\n return s+(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&prev[nr][nc].flagged?1:0);\n },0);\n if (adjFlags !== cell.adjacent) return prev;\n // Reveal all unflagged adjacent cells\n let b = prev.map(row=>row.map(c=>({...c})));\n let hitMine = false;\n for (const [dr,dc] of DIRS) {\n const nr=r+dr,nc=c+dc;\n if (nr<0||nr>=ROWS||nc<0||nc>=COLS||b[nr][nc].revealed||b[nr][nc].flagged) continue;\n if (b[nr][nc].mine) { hitMine = true; b[nr][nc].revealed = true; }\n else b = floodFill(b,nr,nc);\n }\n if (hitMine) {\n b = b.map(row=>row.map(c=>({...c,revealed:c.mine?true:c.revealed})));\n setStatus('lost');\n } else if (checkWin(b)) setStatus('won');\n return b;\n });\n },[status]);\n\n const buttonsDown = useRef(0);\n\n // Capture precise time on win/loss\n const finalTimeRef = useRef(0);\n useEffect(() => {\n if (status === 'won' || status === 'lost') {\n // Capture the exact elapsed time when game ends\n if (startTimeRef.current > 0) {\n finalTimeRef.current = Math.round((performance.now() - startTimeRef.current) / 10) / 100; // seconds with 2 decimals\n } else {\n finalTimeRef.current = timeSeconds;\n }\n }\n }, [status]);\n\n // Submit score on win\n useEffect(() => {\n if (status === 'won' && !scoreSubmitted.current) {\n scoreSubmitted.current = true;\n const t = finalTimeRef.current || timeSeconds;\n const tFixed = parseFloat(t.toFixed(2));\n submitGameScore({ game: 'minesweeper', won: true, time_seconds: tFixed, clicks })\n .then(res => { toast.success(`You won! Rank #${res.rank} with ${tFixed}s and ${clicks} clicks`); })\n .catch(() => { toast.success(`You won! ${tFixed}s and ${clicks} clicks`); });\n }\n }, [status, clicks]);\n\n // Fetch leaderboard (no-op when apiClient isn't wired)\n const fetchLeaderboard = useCallback(() => {\n setLoadingLb(true);\n getGameLeaderboard('minesweeper')\n .then(res => setLeaderboard(res.results || []))\n .catch(() => setLeaderboard([]))\n .finally(() => setLoadingLb(false));\n }, []);\n\n // Register \"Leaderboard\" in the window title menu\n const openLb = useCallback(() => { fetchLeaderboard(); setShowLeaderboard(true); }, [fetchLeaderboard]);\n useWindowMenuItem('Leaderboard', openLb, <svg className=\"h-4 w-4 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.5 18.75h-9m9 0a3 3 0 013 3h-15a3 3 0 013-3m9 0v-3.375c0-.621-.503-1.125-1.125-1.125h-.871M7.5 18.75v-3.375c0-.621.504-1.125 1.125-1.125h.872m5.007 0H9.497m5.007 0a7.454 7.454 0 01-.982-3.172M9.497 14.25a7.454 7.454 0 00.981-3.172M5.25 4.236c-.982.143-1.954.317-2.916.52A6.003 6.003 0 007.73 9.728M5.25 4.236V4.5c0 2.108.966 3.99 2.48 5.228M5.25 4.236V2.721C7.456 2.41 9.71 2.25 12 2.25c2.291 0 4.545.16 6.75.47v1.516M18.75 4.236c.982.143 1.954.317 2.916.52A6.003 6.003 0 0016.27 9.728M18.75 4.236V4.5c0 2.108-.966 3.99-2.48 5.228m0 0a6.003 6.003 0 01-2.27.853m0 0h.008v.008h-.008v-.008z\" /></svg>);\n\n const face = status==='lost'?'😵':status==='won'?'😎':'🙂';\n\n return (\n <div className=\"flex flex-col items-center select-none\" onContextMenu={e => e.preventDefault()}>\n <div className=\"bg-gray-300 border-4 border-t-white border-l-white border-r-gray-500 border-b-gray-500 p-2\">\n {/* Header */}\n <div className=\"flex items-center justify-between bg-gray-300 border-2 border-t-gray-500 border-l-gray-500 border-r-white border-b-white p-1 mb-2\">\n <div className=\"bg-black text-red-500 font-mono font-bold text-xl px-1 w-14 text-center tracking-wider\">\n {String(Math.max(MINES-flagCount,0)).padStart(3,'0')}\n </div>\n <button onClick={restart} className=\"text-xl w-8 h-8 flex items-center justify-center bg-gray-300 border-2 border-t-white border-l-white border-r-gray-500 border-b-gray-500 active:border-t-gray-500 active:border-l-gray-500 active:border-r-white active:border-b-white cursor-pointer\">\n {face}\n </button>\n <div className=\"bg-black text-red-500 font-mono font-bold text-base px-1 w-[70px] text-center tracking-wider\">\n {timeSeconds.toFixed(2)}\n </div>\n </div>\n {/* Grid */}\n <div className=\"border-2 border-t-gray-500 border-l-gray-500 border-r-white border-b-white\">\n {board.map((row,r)=>(\n <div key={r} className=\"flex\">\n {row.map((cell,c)=>{\n const revealed = cell.revealed;\n const base = revealed\n ? 'w-[35px] h-[35px] flex items-center justify-center text-sm font-bold border border-gray-400'\n : 'w-[35px] h-[35px] flex items-center justify-center text-sm font-bold border-2 border-t-white border-l-white border-r-gray-500 border-b-gray-500 cursor-pointer active:border active:border-gray-400';\n const bg = revealed && cell.mine && status==='lost' ? 'bg-red-500' : revealed ? 'bg-gray-300' : 'bg-gray-300';\n let content: React.ReactNode = null;\n let color = '';\n if (revealed && cell.mine) { content = '💣'; }\n else if (revealed && cell.adjacent > 0) { content = cell.adjacent; color = NUM_COLORS[cell.adjacent]||''; }\n else if (!revealed && cell.flagged) { content = '🚩'; }\n return (\n <div key={c} className={`${base} ${bg} ${color}`}\n onClick={()=>{setClicks(n=>n+1);handleClick(r,c);}}\n onContextMenu={e=>{setClicks(n=>n+1);handleContext(e,r,c);}}\n onMouseDown={e=>{buttonsDown.current|=(1<<e.button);if((buttonsDown.current&0b101)===0b101||(buttonsDown.current&0b011)===0b011)handleChord(r,c);}}\n onMouseUp={e=>{buttonsDown.current&=~(1<<e.button)}}\n onMouseLeave={()=>{buttonsDown.current=0}}>\n {content}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n\n {/* Stats + Leaderboard button */}\n <div className=\"flex items-center justify-between w-full mt-1 px-1\">\n <span className=\"text-[10px] text-gray-400 font-mono\">{clicks} clicks</span>\n <button onClick={() => { fetchLeaderboard(); setShowLeaderboard(true); }}\n className=\"text-[10px] text-blue-600 hover:text-blue-800 font-medium\">\n Leaderboard\n </button>\n </div>\n\n {/* Leaderboard Modal */}\n {showLeaderboard && (\n <Modal open onClose={() => setShowLeaderboard(false)} title=\"Minesweeper Leaderboard\" size=\"md\">\n {loadingLb ? (\n <div className=\"text-center py-8 text-sm text-gray-400\">Loading...</div>\n ) : leaderboard.length === 0 ? (\n <div className=\"text-center py-8 text-sm text-gray-400\">No wins recorded yet. Be the first!</div>\n ) : (\n <div className=\"overflow-y-auto max-h-[60vh]\">\n <table className=\"w-full text-sm\">\n <thead className=\"sticky top-0 bg-white\">\n <tr className=\"border-b border-gray-200\">\n <th className=\"text-left py-2 px-2 text-xs font-medium text-gray-500 w-12\">#</th>\n <th className=\"text-left py-2 px-2 text-xs font-medium text-gray-500\">Player</th>\n <th className=\"text-right py-2 px-2 text-xs font-medium text-gray-500 w-16\">Time</th>\n <th className=\"text-right py-2 px-2 text-xs font-medium text-gray-500 w-16\">Clicks</th>\n <th className=\"text-right py-2 px-2 text-xs font-medium text-gray-500 w-24\">Date</th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-gray-100\">\n {leaderboard.map((s, i) => (\n <tr key={i} className={i < 3 ? 'bg-yellow-50/50' : ''}>\n <td className=\"py-1.5 px-2 font-mono text-gray-400\">\n {s.rank === 1 ? '🥇' : s.rank === 2 ? '🥈' : s.rank === 3 ? '🥉' : s.rank}\n </td>\n <td className=\"py-1.5 px-2 font-medium text-gray-900\">{s.player_name}</td>\n <td className=\"py-1.5 px-2 text-right font-mono text-gray-700\">{Number(s.time_seconds).toFixed(2)}s</td>\n <td className=\"py-1.5 px-2 text-right font-mono text-gray-500\">{s.clicks}</td>\n <td className=\"py-1.5 px-2 text-right text-xs text-gray-400\">\n {formatDate(s.played_at)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </Modal>\n )}\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/api/analytics.ts","../src/apps/Minesweeper.tsx"],"names":["c"],"mappings":"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","file":"Minesweeper-OXRRSCVF.js","sourcesContent":["/** Game analytics — Minesweeper leaderboard routes through the\n * consumer-supplied apiClient (see setShellApiClient). */\nimport apiClient from './client';\nexport const submitGameScore = (data: { game: string; won: boolean; time_seconds: number; clicks: number }) =>\n apiClient.post(`/analytics/games/${data.game}/scores/`, data).then((r: any) => r.data);\nexport const getGameLeaderboard = (game: string) =>\n apiClient.get(`/analytics/games/${game}/leaderboard/`).then((r: any) => r.data);\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport { submitGameScore, getGameLeaderboard } from '../api/analytics';\nimport Modal, { useWindowMenuItem } from '../shell/Modal';\nimport toast from '../shell/toast';\nimport { formatDate } from '../utils/date';\n\nconst ROWS = 9, COLS = 9, MINES = 10;\nconst DIRS = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];\nconst NUM_COLORS: Record<number,string> = {1:'text-blue-700',2:'text-green-700',3:'text-red-600',4:'text-purple-700',5:'text-red-900',6:'text-teal-600',7:'text-black',8:'text-gray-500'};\n\ntype Cell = { mine: boolean; revealed: boolean; flagged: boolean; adjacent: number };\ntype Status = 'playing' | 'won' | 'lost';\n\nfunction createBoard(): Cell[][] {\n return Array.from({length:ROWS},()=>Array.from({length:COLS},()=>({mine:false,revealed:false,flagged:false,adjacent:0})));\n}\n\nfunction placeMines(board: Cell[][], safeR: number, safeC: number) {\n const b = board.map(r=>r.map(c=>({...c})));\n let placed = 0;\n while (placed < MINES) {\n const r = Math.floor(Math.random()*ROWS), c = Math.floor(Math.random()*COLS);\n if (b[r][c].mine || (Math.abs(r-safeR)<=1 && Math.abs(c-safeC)<=1)) continue;\n b[r][c].mine = true;\n placed++;\n }\n for (let r=0;r<ROWS;r++) for (let c=0;c<COLS;c++) {\n if (b[r][c].mine) continue;\n b[r][c].adjacent = DIRS.reduce((s,[dr,dc])=>{\n const nr=r+dr,nc=c+dc;\n return s+(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&b[nr][nc].mine?1:0);\n },0);\n }\n return b;\n}\n\nfunction floodFill(board: Cell[][], r: number, c: number) {\n const b = board.map(row=>row.map(cell=>({...cell})));\n const stack: [number,number][] = [[r,c]];\n while (stack.length) {\n const [cr,cc] = stack.pop()!;\n if (cr<0||cr>=ROWS||cc<0||cc>=COLS||b[cr][cc].revealed||b[cr][cc].flagged||b[cr][cc].mine) continue;\n b[cr][cc].revealed = true;\n if (b[cr][cc].adjacent === 0) DIRS.forEach(([dr,dc])=>stack.push([cr+dr,cc+dc]));\n }\n return b;\n}\n\nfunction checkWin(board: Cell[][]): boolean {\n return board.every(row=>row.every(c=>c.mine||c.revealed));\n}\n\nexport default function Minesweeper() {\n const [board, setBoard] = useState(createBoard);\n const [status, setStatus] = useState<Status>('playing');\n const [started, setStarted] = useState(false);\n const [time, setTime] = useState(0); // in centiseconds (hundredths)\n const timerRef = useRef<ReturnType<typeof setInterval>|null>(null);\n const startTimeRef = useRef(0);\n const [clicks, setClicks] = useState(0);\n const [showLeaderboard, setShowLeaderboard] = useState(false);\n const [leaderboard, setLeaderboard] = useState<{ rank: number; player_name: string; time_seconds: number; clicks: number; played_at: string }[]>([]);\n const [loadingLb, setLoadingLb] = useState(false);\n const scoreSubmitted = useRef(false);\n\n const flagCount = board.reduce((s,r)=>s+r.reduce((s2,c)=>s2+(c.flagged?1:0),0),0);\n\n const timeSeconds = time / 100; // convert centiseconds to seconds with 2 decimals\n\n useEffect(()=>{\n if (started && status==='playing') {\n startTimeRef.current = performance.now() - time * 10;\n timerRef.current = setInterval(()=>{\n const elapsed = Math.floor((performance.now() - startTimeRef.current) / 10);\n setTime(Math.min(elapsed, 99999));\n }, 10);\n } else if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n return ()=>{if(timerRef.current)clearInterval(timerRef.current)};\n },[started,status]);\n\n const restart = useCallback(()=>{\n setBoard(createBoard());\n setStatus('playing');\n setStarted(false);\n setTime(0);\n startTimeRef.current = 0;\n setClicks(0);\n scoreSubmitted.current = false;\n },[]);\n\n const handleClick = useCallback((r:number,c:number)=>{\n if (status!=='playing') return;\n setBoard(prev=>{\n let b = prev;\n if (!started) {\n b = placeMines(prev,r,c);\n setStarted(true);\n }\n const cell = b[r][c];\n if (cell.revealed||cell.flagged) return b;\n if (cell.mine) {\n const lost = b.map(row=>row.map(c=>({...c,revealed:c.mine?true:c.revealed})));\n lost[r][c] = {...lost[r][c], revealed:true};\n setStatus('lost');\n return lost;\n }\n const next = floodFill(b,r,c);\n if (checkWin(next)) setStatus('won');\n return next;\n });\n },[status,started]);\n\n const handleContext = useCallback((e:React.MouseEvent,r:number,c:number)=>{\n e.preventDefault();\n if (status!=='playing') return;\n setBoard(prev=>{\n if (prev[r][c].revealed) return prev;\n const b = prev.map(row=>row.map(cell=>({...cell})));\n b[r][c].flagged = !b[r][c].flagged;\n return b;\n });\n },[status]);\n\n // Chord click: both buttons on a revealed number — auto-reveal adjacent if flags match\n const handleChord = useCallback((r:number,c:number)=>{\n if (status!=='playing') return;\n setBoard(prev=>{\n const cell = prev[r][c];\n if (!cell.revealed || cell.adjacent === 0) return prev;\n // Count adjacent flags\n const adjFlags = DIRS.reduce((s,[dr,dc])=>{\n const nr=r+dr,nc=c+dc;\n return s+(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&prev[nr][nc].flagged?1:0);\n },0);\n if (adjFlags !== cell.adjacent) return prev;\n // Reveal all unflagged adjacent cells\n let b = prev.map(row=>row.map(c=>({...c})));\n let hitMine = false;\n for (const [dr,dc] of DIRS) {\n const nr=r+dr,nc=c+dc;\n if (nr<0||nr>=ROWS||nc<0||nc>=COLS||b[nr][nc].revealed||b[nr][nc].flagged) continue;\n if (b[nr][nc].mine) { hitMine = true; b[nr][nc].revealed = true; }\n else b = floodFill(b,nr,nc);\n }\n if (hitMine) {\n b = b.map(row=>row.map(c=>({...c,revealed:c.mine?true:c.revealed})));\n setStatus('lost');\n } else if (checkWin(b)) setStatus('won');\n return b;\n });\n },[status]);\n\n const buttonsDown = useRef(0);\n\n // Capture precise time on win/loss\n const finalTimeRef = useRef(0);\n useEffect(() => {\n if (status === 'won' || status === 'lost') {\n // Capture the exact elapsed time when game ends\n if (startTimeRef.current > 0) {\n finalTimeRef.current = Math.round((performance.now() - startTimeRef.current) / 10) / 100; // seconds with 2 decimals\n } else {\n finalTimeRef.current = timeSeconds;\n }\n }\n }, [status]);\n\n // Submit score on win\n useEffect(() => {\n if (status === 'won' && !scoreSubmitted.current) {\n scoreSubmitted.current = true;\n const t = finalTimeRef.current || timeSeconds;\n const tFixed = parseFloat(t.toFixed(2));\n submitGameScore({ game: 'minesweeper', won: true, time_seconds: tFixed, clicks })\n .then(res => { toast.success(`You won! Rank #${res.rank} with ${tFixed}s and ${clicks} clicks`); })\n .catch(() => { toast.success(`You won! ${tFixed}s and ${clicks} clicks`); });\n }\n }, [status, clicks]);\n\n // Fetch leaderboard (no-op when apiClient isn't wired)\n const fetchLeaderboard = useCallback(() => {\n setLoadingLb(true);\n getGameLeaderboard('minesweeper')\n .then(res => setLeaderboard(res.results || []))\n .catch(() => setLeaderboard([]))\n .finally(() => setLoadingLb(false));\n }, []);\n\n // Register \"Leaderboard\" in the window title menu\n const openLb = useCallback(() => { fetchLeaderboard(); setShowLeaderboard(true); }, [fetchLeaderboard]);\n useWindowMenuItem('Leaderboard', openLb, <svg className=\"h-4 w-4 text-gray-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={1.5}><path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M16.5 18.75h-9m9 0a3 3 0 013 3h-15a3 3 0 013-3m9 0v-3.375c0-.621-.503-1.125-1.125-1.125h-.871M7.5 18.75v-3.375c0-.621.504-1.125 1.125-1.125h.872m5.007 0H9.497m5.007 0a7.454 7.454 0 01-.982-3.172M9.497 14.25a7.454 7.454 0 00.981-3.172M5.25 4.236c-.982.143-1.954.317-2.916.52A6.003 6.003 0 007.73 9.728M5.25 4.236V4.5c0 2.108.966 3.99 2.48 5.228M5.25 4.236V2.721C7.456 2.41 9.71 2.25 12 2.25c2.291 0 4.545.16 6.75.47v1.516M18.75 4.236c.982.143 1.954.317 2.916.52A6.003 6.003 0 0016.27 9.728M18.75 4.236V4.5c0 2.108-.966 3.99-2.48 5.228m0 0a6.003 6.003 0 01-2.27.853m0 0h.008v.008h-.008v-.008z\" /></svg>);\n\n const face = status==='lost'?'😵':status==='won'?'😎':'🙂';\n\n return (\n <div className=\"flex flex-col items-center select-none\" onContextMenu={e => e.preventDefault()}>\n <div className=\"bg-gray-300 border-4 border-t-white border-l-white border-r-gray-500 border-b-gray-500 p-2\">\n {/* Header */}\n <div className=\"flex items-center justify-between bg-gray-300 border-2 border-t-gray-500 border-l-gray-500 border-r-white border-b-white p-1 mb-2\">\n <div className=\"bg-black text-red-500 font-mono font-bold text-xl px-1 w-14 text-center tracking-wider\">\n {String(Math.max(MINES-flagCount,0)).padStart(3,'0')}\n </div>\n <button onClick={restart} className=\"text-xl w-8 h-8 flex items-center justify-center bg-gray-300 border-2 border-t-white border-l-white border-r-gray-500 border-b-gray-500 active:border-t-gray-500 active:border-l-gray-500 active:border-r-white active:border-b-white cursor-pointer\">\n {face}\n </button>\n <div className=\"bg-black text-red-500 font-mono font-bold text-base px-1 w-[70px] text-center tracking-wider\">\n {timeSeconds.toFixed(2)}\n </div>\n </div>\n {/* Grid */}\n <div className=\"border-2 border-t-gray-500 border-l-gray-500 border-r-white border-b-white\">\n {board.map((row,r)=>(\n <div key={r} className=\"flex\">\n {row.map((cell,c)=>{\n const revealed = cell.revealed;\n const base = revealed\n ? 'w-[35px] h-[35px] flex items-center justify-center text-sm font-bold border border-gray-400'\n : 'w-[35px] h-[35px] flex items-center justify-center text-sm font-bold border-2 border-t-white border-l-white border-r-gray-500 border-b-gray-500 cursor-pointer active:border active:border-gray-400';\n const bg = revealed && cell.mine && status==='lost' ? 'bg-red-500' : revealed ? 'bg-gray-300' : 'bg-gray-300';\n let content: React.ReactNode = null;\n let color = '';\n if (revealed && cell.mine) { content = '💣'; }\n else if (revealed && cell.adjacent > 0) { content = cell.adjacent; color = NUM_COLORS[cell.adjacent]||''; }\n else if (!revealed && cell.flagged) { content = '🚩'; }\n return (\n <div key={c} className={`${base} ${bg} ${color}`}\n onClick={()=>{setClicks(n=>n+1);handleClick(r,c);}}\n onContextMenu={e=>{setClicks(n=>n+1);handleContext(e,r,c);}}\n onMouseDown={e=>{buttonsDown.current|=(1<<e.button);if((buttonsDown.current&0b101)===0b101||(buttonsDown.current&0b011)===0b011)handleChord(r,c);}}\n onMouseUp={e=>{buttonsDown.current&=~(1<<e.button)}}\n onMouseLeave={()=>{buttonsDown.current=0}}>\n {content}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n\n {/* Stats + Leaderboard button */}\n <div className=\"flex items-center justify-between w-full mt-1 px-1\">\n <span className=\"text-[10px] text-gray-400 font-mono\">{clicks} clicks</span>\n <button onClick={() => { fetchLeaderboard(); setShowLeaderboard(true); }}\n className=\"text-[10px] text-blue-600 hover:text-blue-800 font-medium\">\n Leaderboard\n </button>\n </div>\n\n {/* Leaderboard Modal */}\n {showLeaderboard && (\n <Modal open onClose={() => setShowLeaderboard(false)} title=\"Minesweeper Leaderboard\" size=\"md\">\n {loadingLb ? (\n <div className=\"text-center py-8 text-sm text-gray-400\">Loading...</div>\n ) : leaderboard.length === 0 ? (\n <div className=\"text-center py-8 text-sm text-gray-400\">No wins recorded yet. Be the first!</div>\n ) : (\n <div className=\"overflow-y-auto max-h-[60vh]\">\n <table className=\"w-full text-sm\">\n <thead className=\"sticky top-0 bg-white\">\n <tr className=\"border-b border-gray-200\">\n <th className=\"text-left py-2 px-2 text-xs font-medium text-gray-500 w-12\">#</th>\n <th className=\"text-left py-2 px-2 text-xs font-medium text-gray-500\">Player</th>\n <th className=\"text-right py-2 px-2 text-xs font-medium text-gray-500 w-16\">Time</th>\n <th className=\"text-right py-2 px-2 text-xs font-medium text-gray-500 w-16\">Clicks</th>\n <th className=\"text-right py-2 px-2 text-xs font-medium text-gray-500 w-24\">Date</th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-gray-100\">\n {leaderboard.map((s, i) => (\n <tr key={i} className={i < 3 ? 'bg-yellow-50/50' : ''}>\n <td className=\"py-1.5 px-2 font-mono text-gray-400\">\n {s.rank === 1 ? '🥇' : s.rank === 2 ? '🥈' : s.rank === 3 ? '🥉' : s.rank}\n </td>\n <td className=\"py-1.5 px-2 font-medium text-gray-900\">{s.player_name}</td>\n <td className=\"py-1.5 px-2 text-right font-mono text-gray-700\">{Number(s.time_seconds).toFixed(2)}s</td>\n <td className=\"py-1.5 px-2 text-right font-mono text-gray-500\">{s.clicks}</td>\n <td className=\"py-1.5 px-2 text-right text-xs text-gray-400\">\n {formatDate(s.played_at)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </Modal>\n )}\n </div>\n );\n}\n"]}
|