Added packages and worked on getting it to work

This commit is contained in:
End 2025-10-15 11:52:47 -07:00
parent 3e294c376e
commit e5dcdf29fc
No known key found for this signature in database
5 changed files with 2477 additions and 47 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/node_modules

184
index.html Normal file
View file

@ -0,0 +1,184 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Mood Tracker</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
sans-serif;
background: transparent;
overflow: hidden;
}
.container {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16px;
padding: 24px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
color: white;
}
h2 {
margin-bottom: 20px;
font-size: 20px;
font-weight: 600;
}
.moods {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12px;
margin-bottom: 20px;
}
.mood-btn {
background: rgba(255, 255, 255, 0.2);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 12px;
padding: 12px;
font-size: 32px;
cursor: pointer;
transition: all 0.2s;
}
.mood-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: scale(1.1);
}
.controls {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 16px;
}
button {
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 8px 16px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
}
button:hover {
background: rgba(255, 255, 255, 0.3);
}
select {
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 8px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
}
select option {
background: #667eea;
color: white;
}
.settings {
display: none;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid rgba(255, 255, 255, 0.3);
}
.settings.active {
display: block;
}
.setting-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
label {
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<h2>How are you feeling?</h2>
<div class="moods">
<button class="mood-btn" onclick="saveMood('😊')">😊</button>
<button class="mood-btn" onclick="saveMood('😐')">😐</button>
<button class="mood-btn" onclick="saveMood('😔')">😔</button>
<button class="mood-btn" onclick="saveMood('😫')">😫</button>
<button class="mood-btn" onclick="saveMood('😴')">😴</button>
</div>
<div class="controls">
<button onclick="dismiss()">Dismiss</button>
<button onclick="toggleSettings()">⚙️ Settings</button>
</div>
<div class="settings" id="settings">
<div class="setting-row">
<label>Position:</label>
<select id="position" onchange="updateConfig()">
<option value="top-left">Top Left</option>
<option value="top-right">Top Right</option>
<option value="bottom-left">Bottom Left</option>
<option value="bottom-right">Bottom Right</option>
</select>
</div>
<div class="setting-row">
<label>Idle time (minutes):</label>
<select id="idleMinutes" onchange="updateConfig()">
<option value="1">1</option>
<option value="2">2</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
</div>
</div>
</div>
<script>
const { ipcRenderer } = require("electron");
// load config when started
const config = ipcRenderer.sendSync("get-config");
document.getElementById("position").value = config.position;
document.getElementById("idleMinutes").value = config.idleMinutes;
function saveMood(mood) {
ipcRenderer.send("save-mood", mood);
}
function dismiss() {
ipcRenderer.send("dismiss");
}
function toggleSettings() {
document.getElementById("settings").classList.toggle("active");
}
function updateConfig() {
const config = {
position: document.getElementById("position").value,
idleMinutes: parseInt(document.getElementById("idleMinutes").value),
};
ipcRenderer.send("save-config", config);
}
</script>
</body>
</html>

171
main.js
View file

@ -1,18 +1,24 @@
const { app, BrowserWindows, powerMonitor, icpMain, screen} = require('electron'); const {
const path = require('path'); app,
const fs=require('fs'); BrowserWindow,
const sqlite3 = require('sqlite3').verbose(); powerMonitor,
ipcMain,
screen,
} = require("electron");
const path = require("path");
const fs = require("fs");
const sqlite3 = require("sqlite3").verbose();
let mainWindow; let mainWindow;
let db; let db;
const IDLE_THRESHOLD = 480; //seconds (8 minutes) const IDLE_THRESHOLD = 120; // seconds (2 minutes)
const CONFIG_PATH = path.join(app.getPath('userData'), 'config.json'); const CONFIG_PATH = path.join(app.getPath("userData"), "config.json");
const DB_PATH = path.join(app.getPath('userData'), 'moods.db'); const DB_PATH = path.join(app.getPath("userData"), "moods.db");
// Initialize database // Initialize database
function initDatabase() { function initDatabase() {
db = new sqlite3.Database(DB_PATH); db = new sqlite3.Database(DB_PATH);
db.run(` db.run(`
CREATE TABLE IF NOT EXISTS moods ( CREATE TABLE IF NOT EXISTS moods (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
mood TEXT NOT NULL, mood TEXT NOT NULL,
@ -23,54 +29,125 @@ function initDatabase() {
// Load or create config // Load or create config
function loadConfig() { function loadConfig() {
try { try {
return JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')); return JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
} catch { } catch {
return { position: 'bottom-right', idleMinutes: 8}; return { position: "bottom-right", idleMinutes: 2 };
} }
} }
function saveConfig(config) { function saveConfig(config) {
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2)); fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
} }
// Calc window pos based on config // Calculate window position based on config
function getWindowPosition(position) { function getWindowPosition(position) {
const {width, height} = screen.getPrimaryDisplay().workareaSize; const { width, height } = screen.getPrimaryDisplay().workAreaSize;
const windowWidth = 350; const windowWidth = 350;
const windowHeight = 250; const windowHeight = 250;
const padding = 20; const padding = 20;
const position = { const positions = {
'top-left': { x: padding, y: padding }, "top-left": { x: padding, y: padding },
'top-right': { x: width - windowWidth - padding, y: padding}, "top-right": { x: width - windowWidth - padding, y: padding },
'bottom-left': { x: padding, y: height = windowsHeight - padding }, "bottom-left": { x: padding, y: height - windowHeight - padding },
'bottom-right': { x: width - windowWidth - padding}, "bottom-right": {
}; x: width - windowWidth - padding,
y: height - windowHeight - padding,
},
};
return positions[position] || positions['bottom-right']; return positions[position] || positions["bottom-right"];
} }
function createWindow() { function createWindow() {
const config = loadConfig(); const config = loadConfig();
const position = getWindowsPosition(config); const position = getWindowPosition(config.position);
mainWindow = new BrowserWindows({ mainWindow = new BrowserWindow({
width: 350, width: 350,
height: 250, height: 250,
x: position.x, x: position.x,
y: position.y, y: position.y,
frame: false, frame: false,
transparent: true, transparent: true,
alwaysOnTop: true, alwaysOnTop: true,
skipTaskbar: true, skipTaskbar: true,
resizable: true, resizable: false,
show: false, show: false,
webPrefrences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
contextIsolation: false, contextIsolation: false,
}, },
}); });
mainWindow.loadFile("index.html");
} }
// Check for idle state
function checkIdleState() {
const idleTime = powerMonitor.getSystemIdleTime();
const config = loadConfig();
const threshold = (config.idleMinutes || 2) * 60;
if (idleTime >= threshold && !mainWindow.isVisible()) {
mainWindow.show();
}
}
app.whenReady().then(() => {
initDatabase();
createWindow();
// Check idle state every 30 seconds
setInterval(checkIdleState, 30000);
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
// IPC handlers
ipcMain.on("save-mood", (event, mood) => {
db.run(
"INSERT INTO moods (mood, timestamp) VALUES (?, ?)",
[mood, Date.now()],
(err) => {
if (err) console.error(err);
mainWindow.hide();
}
);
});
ipcMain.on("dismiss", () => {
mainWindow.hide();
});
ipcMain.on("get-config", (event) => {
event.returnValue = loadConfig();
});
ipcMain.on("save-config", (event, config) => {
saveConfig(config);
const position = getWindowPosition(config.position);
mainWindow.setPosition(position.x, position.y);
});
ipcMain.on("get-moods", (event, days = 7) => {
const since = Date.now() - days * 24 * 60 * 60 * 1000;
db.all(
"SELECT * FROM moods WHERE timestamp > ? ORDER BY timestamp DESC",
[since],
(err, rows) => {
event.reply("moods-data", rows);
}
);
});

2156
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

12
package.json Normal file
View file

@ -0,0 +1,12 @@
{
"name": "mood-tracker",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"dependencies": {
"electron": "^28.0.0",
"sqlite3": "^5.1.6"
}
}