import { loadGraph } from './tempgraph.ts'; let timer = 0; let isRunning = false; let log: Array<{ time: string, event: string, temp?: number }> = []; let targets: number[] = []; let currentTargetIndex = 0; let interval: NodeJS.Timeout | null = null; declare global { interface Window { startTimer: () => void; stopTimer: () => void; logEvent: (eventName: string) => void; resetSystem: () => void; setPlan: () => void; navigateTemp: (direction: number) => void; logTemp: (temp: number) => void; exportCSV: () => void; showGraph: () => void; hideGraph: () => void; } } function startTimer(): void { if (isRunning) { alert("Timer is already running. Click again to reset."); return; } timer = 0; updateTimerDisplay(); isRunning = true; interval = setInterval(() => { timer++; updateTimerDisplay(); }, 1000); } function stopTimer(): void { if(interval !== null){ clearInterval(interval); } isRunning = false; } function updateTimerDisplay(): void { const minutes = Math.floor(timer / 60); const seconds = timer % 60; document.getElementById("timer")!.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`; } function logEvent(eventName: string): void { if (eventName === "Charge") { if (log.length > 0 || isRunning) { if(isRunning){ stopTimer(); } log = []; timer = 0; } startTimer(); log.push({ time: formatTime(timer), event: eventName }); updateLog(); return; } if (eventName === "Drop") { stopTimer(); log.push({ time: formatTime(timer), event: eventName }); updateLog(); document.getElementById("create-plan")!.classList.remove("hidden"); const tempButtons = document.getElementById("temp-buttons")!; tempButtons.innerHTML = ""; return; } log.push({ time: formatTime(timer), event: eventName }); updateLog(); } function resetSystem(): void { stopTimer(); log = []; updateLog(); document.getElementById("create-plan")!.classList.remove("hidden"); const tempButtons = document.getElementById("temp-buttons")!; tempButtons.innerHTML = ""; } function formatTime(seconds: number): string { const minutes = Math.floor(seconds / 60); const secs = seconds % 60; return `${minutes}:${secs.toString().padStart(2, '0')}`; } function setPlan(): void { const input = (document.getElementById("plan-input") as HTMLInputElement).value; targets = input.split(',').map(Number); currentTargetIndex = 0; document.getElementById("controls")!.classList.remove("hidden"); document.getElementById("create-plan")!.classList.add("hidden"); generateTempButtons(); } function generateTempButtons(): void { const container = document.getElementById("temp-buttons")!; container.innerHTML = ""; if (targets.length === 0) { container.innerHTML = "

No temperature plan set.

"; return; } const currentTarget = targets[currentTargetIndex]; const buttons: string[] = []; buttons.push(''); for (let i = -2; i <= 2; i++) { const temp = currentTarget + i; buttons.push(``); } buttons.push(''); container.innerHTML = buttons.join(" "); } function navigateTemp(direction: number): void { currentTargetIndex += direction; if (currentTargetIndex < 0) { currentTargetIndex = 0; } else if (currentTargetIndex >= targets.length) { currentTargetIndex = targets.length - 1; } generateTempButtons(); } function logTemp(temp: number): void { log.push({ time: formatTime(timer), event: "Temp", temp }); updateLog(); currentTargetIndex++; if (currentTargetIndex >= targets.length) { currentTargetIndex = targets.length - 1; } generateTempButtons(); } function updateLog(): void { const tbody = document.getElementById("log-body")!; tbody.innerHTML = log.map(entry => ` ${entry.time} ${entry.event} ${entry.temp !== null ? entry.temp : ''} `).join(""); } // src/roast.ts /** * Generates an array of CSV strings line by line from log data. */ function createCSVData(): string[] { const header = "Time,Event,Temperature"; const logEntries = log.map(entry => `${entry.time},${entry.event}${entry.temp !== null ? `,${entry.temp}` : ''}`); return [header].concat(logEntries); } /** * Creates CSV format content as a single string from the array returned by createCSVData(). */ function generateCSVContent(): string { return createCSVData().join("\n"); } function exportCSV(): void { const csvContent = generateCSVContent(); const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" }); const link = document.createElement("a"); link.setAttribute("href", URL.createObjectURL(blob)); link.setAttribute("download", "roast_log.csv"); link.style.display = "none"; document.body.appendChild(link); link.click(); document.body.removeChild(link); } function showGraph(): void { const graphContainer = document.getElementById("graph-container"); if (graphContainer) { loadGraph(createCSVData()); graphContainer.classList.remove("hidden"); graphContainer.classList.add("graph-display-flex"); } } function hideGraph(): void { const graphContainer = document.getElementById("graph-container"); if (graphContainer) { graphContainer.classList.add("hidden"); graphContainer.classList.remove("graph-display-flex"); } } // Expose functions to the global scope (allowing html direct access) if (typeof window !== 'undefined') { window.startTimer = startTimer; window.stopTimer = stopTimer; window.logEvent = logEvent; window.resetSystem = resetSystem; window.setPlan = setPlan; window.navigateTemp = navigateTemp; window.logTemp = logTemp; window.exportCSV = exportCSV; window.showGraph = showGraph; window.hideGraph = hideGraph; } export {};