Compare commits

...

23 Commits

Author SHA1 Message Date
ca4ac4c3ac Update README.md 2026-01-12 22:11:58 -05:00
6471d72b74 Merge branch 'main' of https://gitea.thewrightserver.net/josh/WorkWeekProgress 2026-01-12 22:03:33 -05:00
4e2d489632 Changes title to Day Drain 2026-01-12 22:03:30 -05:00
f964b6e344 Feeling out a name change 2026-01-12 21:49:03 -05:00
3fbf19a271 Update README.md 2026-01-12 21:44:41 -05:00
35bce6e53d Update README.md 2026-01-12 21:44:18 -05:00
4c7d05abd0 Update README.md 2026-01-12 21:43:47 -05:00
d77ed7ed31 Merge branch 'main' of https://gitea.thewrightserver.net/josh/WorkWeekProgress 2026-01-12 21:30:13 -05:00
bcf994ab7b changes how daily percent is calculated to support more precision and quicker updates 2026-01-12 21:30:11 -05:00
936ce2fc96 reduces default update interrval to 10ms 2026-01-12 21:29:37 -05:00
12c4553c81 Update README.md 2026-01-12 21:05:06 -05:00
3c2b3d1a88 Update README.md 2026-01-12 21:03:51 -05:00
e48221b1cd Merge branch 'main' of https://gitea.thewrightserver.net/josh/WorkWeekProgress 2026-01-12 21:03:16 -05:00
a3d5d2cbfa replaces hardcoded values with env var 2026-01-12 21:02:19 -05:00
2c6491137f Change refresh interval to 5 seconds 2026-01-12 11:14:56 -05:00
f16f202d3e Change update time to 10 seconds
Might reduce this further, needs to be tested first to ensure this doesn't come with performance issues.
2026-01-12 07:46:30 -05:00
83b9e9fead Update README.md 2026-01-11 23:02:26 -05:00
17feb6ad2f Update README.md 2026-01-11 23:02:17 -05:00
b167041ce2 Reduce poll time to 30s 2026-01-11 22:51:34 -05:00
0de45ef1e5 fixes repo must be lowercase 2026-01-11 22:21:32 -05:00
61d62ca2f4 placeholders be gone 2026-01-11 22:16:24 -05:00
30431709d3 Merge branch 'main' of https://gitea.thewrightserver.net/josh/WorkWeekProgress 2026-01-11 22:06:45 -05:00
e7d32152d5 adds ci cd 2026-01-11 22:06:41 -05:00
6 changed files with 158 additions and 37 deletions

14
Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
COPY templates ./templates
COPY static ./static
EXPOSE 5000
CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]

54
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,54 @@
pipeline {
agent any
environment {
REGISTRY = "gitea.thewrightserver.net"
IMAGE = "gitea.thewrightserver.net/josh/workweekprogress"
TAG = "${env.BUILD_NUMBER}"
}
stages {
stage("Checkout") {
steps {
checkout scm
}
}
stage("Build Image") {
steps {
sh """
docker build \
-t ${IMAGE}:${TAG} \
-t ${IMAGE}:latest \
.
"""
}
}
stage("Push Image") {
steps {
withCredentials([
usernamePassword(
credentialsId: 'gitea-registry-creds',
usernameVariable: 'GITEA_USER',
passwordVariable: 'GITEA_TOKEN'
)
]) {
sh """
echo "$GITEA_TOKEN" | docker login ${REGISTRY} \
-u "$GITEA_USER" --password-stdin
docker push ${IMAGE}:${TAG}
docker push ${IMAGE}:latest
"""
}
}
}
}
post {
cleanup {
sh "docker image prune -f"
}
}
}

View File

@@ -1,4 +1,4 @@
# ⏳ Work Week Progress Bar
# Day Drain
Because staring at the clock is bad for morale, but staring at a **progress bar** is somehow motivating.
@@ -8,29 +8,25 @@ This is a small Flask-powered web app that visualizes:
It progresses **only during your scheduled work hours**
---
## 🧠 What It Does
### Daily Progress Bar
- Advances **every minute**
- Only runs **SundayWednesday**
- Only between **7:00 AM 5:30 PM**
- Before work? Frozen.
- After work? Done.
- Not a workday? Blissfully idle.
- Advances **every 10ms** (configurable)
- Only runs **on workdays**
- Only during **work hours**
### Weekly Progress Bar
- Your work week is **4 days** (SunWed)
- Assumes your work week is **4 days**
- Each day = **25%**
- During the day, the bar fills smoothly
- End of Wednesday = **100% freedom**
- End of Workweek = **100% freedom**
---
### Demo Site
https://daydrain.com
## 🛠 Tech Stack
### Configuration
- **Flask** serves the page and minds its business
- **Vanilla JavaScript** handles all time logic client-side
- **HTML + CSS** gradients, glow, and just enough polish
- **Zero databases** this app remembers nothing, like a healthy coping mechanism
| Variable | Default | Description |
|--------|---------|-------------|
| WORK_START_TIME | 07:00 | Workday start (HH:MM) |
| WORK_END_TIME | 17:30 | Workday end (HH:MM) |
| WORK_DAYS | 0,1,2,3 | JS day numbers (Sun=0) |
| UPDATE_INTERVAL_MS | 10 | Update frequency |

35
app.py
View File

@@ -1,10 +1,41 @@
import os
from flask import Flask, render_template
app = Flask(__name__)
def parse_time(value, default):
try:
hour, minute = map(int, value.split(":"))
return {"hour": hour, "minute": minute}
except Exception:
return default
@app.route("/")
def index():
return render_template("index.html")
start_time = parse_time(
os.getenv("WORK_START_TIME", "07:00"),
{"hour": 7, "minute": 0}
)
end_time = parse_time(
os.getenv("WORK_END_TIME", "17:30"),
{"hour": 17, "minute": 30}
)
work_days = [
int(d.strip())
for d in os.getenv("WORK_DAYS", "0,1,2,3").split(",")
if d.strip().isdigit()
]
update_interval = int(os.getenv("UPDATE_INTERVAL_MS", "10"))
return render_template(
"index.html",
work_start=start_time,
work_end=end_time,
work_days=work_days,
update_interval=update_interval
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)
app.run(host="0.0.0.0", port=5000)

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
flask
gunicorn

View File

@@ -2,13 +2,13 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Work Week Progress</title>
<title>Day Drain</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="container">
<h1>Workday Progress</h1>
<h1>Day Drain</h1>
<div class="status" id="statusText"></div>
<!-- Daily Progress -->
@@ -25,14 +25,34 @@
<div class="percent weekly-percent" id="weeklyPercent">0%</div>
</div>
<script>
const WORK_START_HOUR = 7;
const WORK_START_MINUTE = 0;
const WORK_END_HOUR = 17;
const WORK_END_MINUTE = 30;
<!-- App configuration -->
<script id="app-config" type="application/json">
{{ {
"workStart": work_start,
"workEnd": work_end,
"workDays": work_days,
"updateInterval": update_interval
} | tojson }}
</script>
<!-- Application logic -->
<script>
const config = JSON.parse(
document.getElementById("app-config").textContent
);
const WORK_START_HOUR = config.workStart.hour;
const WORK_START_MINUTE = config.workStart.minute;
const WORK_END_HOUR = config.workEnd.hour;
const WORK_END_MINUTE = config.workEnd.minute;
const WORK_DAYS = config.workDays;
const UPDATE_INTERVAL = config.updateInterval;
const TOTAL_WORK_SECONDS =
(WORK_END_HOUR * 3600 + WORK_END_MINUTE * 60) -
(WORK_START_HOUR * 3600 + WORK_START_MINUTE * 60);
const TOTAL_WORK_MINUTES = 630; // 10.5 hours
const WORK_DAYS = [0, 1, 2, 3]; // Sunday → Wednesday
const WEEKLY_DAY_WEIGHT = 100 / WORK_DAYS.length;
function updateProgress() {
@@ -63,17 +83,21 @@
dailyPercent = 100;
statusText.textContent = "Workday complete 🎉";
} else {
const elapsedMinutes = Math.floor((now - start) / 60000);
dailyPercent = Math.min((elapsedMinutes / TOTAL_WORK_MINUTES) * 100, 100);
const elapsedSeconds = (now - start) / 1000;
dailyPercent = Math.min(
(elapsedSeconds / TOTAL_WORK_SECONDS) * 100,
100
);
statusText.textContent = "Grinding…";
}
// Apply daily progress
// Daily progress
dailyFill.style.width = dailyPercent + "%";
dailyPercentText.textContent = dailyPercent.toFixed(1) + "%";
dailyPercentText.textContent = dailyPercent.toFixed(4) + "%";
// Weekly progress
let completedDays = WORK_DAYS.filter(d => d < day).length;
const completedDays = WORK_DAYS.filter(d => d < day).length;
let weeklyPercent =
(completedDays * WEEKLY_DAY_WEIGHT) +
(isWorkday ? (dailyPercent / 100) * WEEKLY_DAY_WEIGHT : 0);
@@ -81,11 +105,11 @@
weeklyPercent = Math.min(weeklyPercent, 100);
weeklyFill.style.width = weeklyPercent + "%";
weeklyPercentText.textContent = weeklyPercent.toFixed(1) + "%";
weeklyPercentText.textContent = weeklyPercent.toFixed(4) + "%";
}
updateProgress();
setInterval(updateProgress, 60 * 1000);
setInterval(updateProgress, UPDATE_INTERVAL);
</script>
</body>
</html>