basic initial code

This commit is contained in:
2025-06-09 00:21:41 -04:00
parent 9f99495eab
commit a711acbea8
9 changed files with 11089 additions and 7 deletions

4
.gitignore vendored
View File

@@ -1,3 +1,3 @@
node_modules
package.json
package-lock.json
dist
/.cache

31
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,31 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build TypeScript and Bundle Static Site",
"type": "shell",
"command": "cd ${workspaceFolder}; source nodetopath.sh; npm run build",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always"
}
},
{
"label": "Clean site",
"type": "shell",
"command": "cd ${workspaceFolder}; rm -rf dist",
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always"
}
}
]
}

View File

@@ -3,5 +3,8 @@
#source node binaries
. nodetopath.sh
npm install -g typescript
npm install -g ts-node
npm install --save-dev @types/node
npm install --save-dev typescript parcel-bundler
npm install chart.js@4.4.1
npm install chartjs-plugin-annotation@3.1.0

10834
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

14
package.json Normal file
View File

@@ -0,0 +1,14 @@
{
"dependencies": {
"chart.js": "^4.4.1",
"chartjs-plugin-annotation": "^3.1.0"
},
"devDependencies": {
"@types/node": "^22.15.30",
"parcel-bundler": "^1.12.5",
"typescript": "^5.8.3"
},
"scripts": {
"build": "parcel build src/roast.html --public-url=./ --out-dir dist"
}
}

19
postcss.config.js Normal file
View File

@@ -0,0 +1,19 @@
module.exports = {
plugins: [
// Other PostCSS plugins can be listed here if you use them.
],
minify: true, // Ensure this is set to true so Parcel uses the provided options
terserOptions: {
mangle: {
// Specify functions that should not be mangled by their names
reserved: [
"setPlan",
"logEvent",
"exportCSV",
"resetSystem",
"navigateTemp",
"logTemp"
]
}
}
};

124
src/roast.css Normal file
View File

@@ -0,0 +1,124 @@
body {
background-color: #e6ccff;
font-family: Arial, sans-serif;
color: #333;
margin: 0;
padding: 0;
}
#timer {
font-size: 48px;
text-align: center;
padding: 20px;
background-color: #fff;
border: 2px solid #666;
margin: 0;
}
#create-plan {
padding: 20px;
text-align: center;
}
#create-plan input {
width: 80%;
padding: 10px;
font-size: 18px;
}
#create-plan button {
margin-top: 10px;
padding: 10px 20px;
font-size: 18px;
}
#controls {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.button-group {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
margin: 10px;
}
.button-group button:not(.nav-btn) {
font-size: 20px;
border: 2px solid #666;
background-color: #fff;
color: #333;
border-radius: 10px;
cursor: pointer;
}
.button-group .nav-btn {
padding: 15px 25px;
font-size: 20px;
border: 2px solid #666;
background-color: #E8E;
color: #333;
border-radius: 10px;
cursor: pointer;
}
.button-group button:active {
background-color: #ddd;
}
#event-buttons {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
margin: 20px;
}
#event-buttons button {
padding: 15px 25px;
font-size: 20px;
border: 2px solid #666;
background-color: #afa;
color: #333;
border-radius: 10px;
cursor: pointer;
}
#event-buttons button:active {
background-color: #ddd;
}
#log-table {
width: 100%;
border-collapse: collapse;
}
#log-table table {
table-layout: fixed;
width: 90%;
margin: auto;
}
#log-table th, #log-table td {
border: 1px solid #666;
padding: 10px;
text-align: center;
}
#log-table th {
background-color: #f0e6ff;
}
#export-csv {
margin: 20px;
text-align: center;
}
#export-csv button {
padding: 10px 20px;
font-size: 18px;
border: 2px solid #666;
background-color: #fff;
color: #333;
border-radius: 10px;
cursor: pointer;
}
#export-csv button:active {
background-color: #ddd;
}
.hidden {
display: none;
}
#temp-buttons {
margin: 8px;
}
#temp-buttons button {
text-align: center;
width: 3.5em;
}

44
src/roast.html Normal file
View File

@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Stovetop Coffee Roast Logger</title>
<link rel="stylesheet" href="./roast.css">
</head>
<body>
<div id="timer">0:00</div>
<div id="create-plan">
<input type="text" id="plan-input" placeholder="Enter temperatures (comma separated)">
<button onclick="setPlan()">Set Plan</button>
</div>
<div id="controls" class="hidden">
<div id="temp-buttons" class="button-group"></div>
<div id="event-buttons" class="button-group">
<button onclick="logEvent('Charge')">Charge</button>
<button onclick="logEvent('Yellow')">Yellow</button>
<button onclick="logEvent('First Crack')">First Crack</button>
<button onclick="logEvent('Second Crack')">Second Crack</button>
<button onclick="logEvent('Drop')">Drop</button>
</div>
<div id="export-csv">
<button onclick="exportCSV()">Export CSV</button>
<button onclick="resetSystem()">Reset</button>
</div>
</div>
<div id="log-table">
<table>
<thead>
<tr>
<th>Time</th>
<th>Event</th>
<th>Temperature</th>
</tr>
</thead>
<tbody id="log-body">
<!-- Log entries will be inserted here -->
</tbody>
</table>
</div>
<script src="./roast.ts"></script>
</body>
</html>

View File

@@ -5,6 +5,7 @@ let targets: number[] = [];
let currentTargetIndex = 0;
let interval: NodeJS.Timeout | null = null;
function startTimer(): void {
if (isRunning) {
alert("Timer is already running. Click again to reset.");
@@ -36,20 +37,20 @@ function logEvent(eventName: string): void {
isRunning = false;
}
startTimer();
log.push({ time: formatTime(timer), event: eventName, temp: null });
log.push({ time: formatTime(timer), event: eventName });
updateLog();
return;
}
if (eventName === "Drop") {
stopTimer();
log.push({ time: formatTime(timer), event: eventName, temp: null });
log.push({ time: formatTime(timer), event: eventName });
updateLog();
document.getElementById("create-plan")!.classList.add("hidden");
document.getElementById("create-plan")!.classList.remove("hidden");
const tempButtons = document.getElementById("temp-buttons")!;
tempButtons.innerHTML = "";
return;
}
log.push({ time: formatTime(timer), event: eventName, temp: null });
log.push({ time: formatTime(timer), event: eventName });
updateLog();
}
@@ -57,7 +58,7 @@ function resetSystem(): void {
stopTimer();
log = [];
updateLog();
document.getElementById("create-plan")!.classList.add("hidden");
document.getElementById("create-plan")!.classList.remove("hidden");
const tempButtons = document.getElementById("temp-buttons")!;
tempButtons.innerHTML = "";
}
@@ -136,4 +137,16 @@ function exportCSV(): void {
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// Expose functions to the global scope
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;
}