feat: streak counter to count how many days a user has posted consecutively
This commit is contained in:
@@ -42,6 +42,40 @@ def init_db():
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def calculate_streak():
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT date FROM journal_entry ORDER BY date DESC")
|
||||||
|
dates = [row[0] for row in cursor.fetchall()]
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
if not dates:
|
||||||
|
return 0
|
||||||
|
streak = 0
|
||||||
|
today = datetime.now(tz).date()
|
||||||
|
from datetime import timedelta
|
||||||
|
for i, entry_date in enumerate(dates):
|
||||||
|
# entry_date is a date object or string, ensure date object
|
||||||
|
if isinstance(entry_date, str):
|
||||||
|
entry_date = dt.strptime(entry_date, "%Y-%m-%d").date()
|
||||||
|
if i == 0:
|
||||||
|
# First entry: must be today or yesterday to start streak
|
||||||
|
if entry_date == today:
|
||||||
|
streak = 1
|
||||||
|
elif entry_date == today - timedelta(days=1):
|
||||||
|
streak = 1
|
||||||
|
today = entry_date
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
expected = today - timedelta(days=1)
|
||||||
|
if entry_date == expected:
|
||||||
|
streak += 1
|
||||||
|
today = entry_date
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
return streak
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
page = request.args.get('page', 1, type=int)
|
page = request.args.get('page', 1, type=int)
|
||||||
@@ -61,7 +95,8 @@ def index():
|
|||||||
has_prev = page > 1
|
has_prev = page > 1
|
||||||
has_next = offset + per_page < total
|
has_next = offset + per_page < total
|
||||||
now = datetime.now(tz)
|
now = datetime.now(tz)
|
||||||
return render_template('index.html', entries=entries, today=today, page=page, has_prev=has_prev, has_next=has_next, now=now, todays_entry=todays_entry)
|
streak = calculate_streak()
|
||||||
|
return render_template('index.html', entries=entries, today=today, page=page, has_prev=has_prev, has_next=has_next, now=now, todays_entry=todays_entry, streak=streak)
|
||||||
|
|
||||||
@app.route('/add', methods=['POST'])
|
@app.route('/add', methods=['POST'])
|
||||||
def add_entry():
|
def add_entry():
|
||||||
@@ -192,4 +227,7 @@ def delete_entry(entry_id):
|
|||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
init_db()
|
init_db()
|
||||||
logging.info('EchoLog started up successfully.')
|
logging.info('EchoLog started up successfully.')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host='0.0.0.0', port='5000')
|
||||||
@@ -4,4 +4,4 @@ echo "Generating CSS..."
|
|||||||
./tailwindcss -i ./static/input.css -o ./static/output.css --content "./templates/*.html" --minify
|
./tailwindcss -i ./static/input.css -o ./static/output.css --content "./templates/*.html" --minify
|
||||||
|
|
||||||
echo "Starting app..."
|
echo "Starting app..."
|
||||||
gunicorn --workers 2 --bind 0.0.0.0:5000 app:app --log-level warning
|
python app.py
|
||||||
+60
-8
@@ -23,16 +23,68 @@
|
|||||||
</head>
|
</head>
|
||||||
<body class="bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 min-h-screen text-white">
|
<body class="bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 min-h-screen text-white">
|
||||||
<div class="container mx-auto max-w-2xl p-6">
|
<div class="container mx-auto max-w-2xl p-6">
|
||||||
<header class="mb-8 flex items-center justify-between">
|
<style>
|
||||||
<div>
|
@media (max-width: 767px) {
|
||||||
<a href="/"><h1 class="text-4xl font-extrabold tracking-tight bg-gradient-to-r from-blue-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">EchoLog</h1></a>
|
.logout-mobile {
|
||||||
<p class="text-gray-400 mt-1">Your personal homelab journal</p>
|
position: absolute;
|
||||||
</div>
|
top: 0.75rem;
|
||||||
|
right: 0.75rem;
|
||||||
|
z-index: 10;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.streak-mobile {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 1rem;
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
.streak-desktop {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.logout-mobile {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.streak-mobile {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.streak-desktop {
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<header class="mb-8 relative">
|
||||||
{% if session.logged_in %}
|
{% if session.logged_in %}
|
||||||
<a href="/logout" class="text-gray-300 hover:text-pink-400 transition text-xl" title="Logout">
|
<div class="logout-mobile mt-6">
|
||||||
<i class="fas fa-sign-out-alt"></i>
|
<a href="/logout" class="text-gray-300 hover:text-pink-400 transition text-xl" title="Logout">
|
||||||
</a>
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<div class="flex flex-col items-center md:flex-row md:items-center md:justify-between md:gap-6">
|
||||||
|
<div class="w-full md:w-auto">
|
||||||
|
<a href="/"><h1 class="text-4xl font-extrabold tracking-tight leading-normal bg-gradient-to-r from-blue-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">EchoLog</h1></a>
|
||||||
|
<p class="text-gray-400">Your personal homelab journal</p>
|
||||||
|
</div>
|
||||||
|
<div class="streak-mobile">
|
||||||
|
<i class="fas fa-fire text-pink-400 text-2xl animate-pulse mr-0.2 mt-1"></i>
|
||||||
|
<span class="text-2xl font-extrabold text-blue-400 mr-0.2">{{ streak }}</span>
|
||||||
|
<span class="text-lg font-bold text-blue-400 mt-1">day{{ 's' if streak != 1 else '' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="streak-desktop">
|
||||||
|
<i class="fas fa-fire text-pink-400 text-2xl animate-pulse mr-2 mt-1" title="Streak Count"></i>
|
||||||
|
<span class="text-2xl font-extrabold text-blue-400 mr-2">{{ streak }}</span>
|
||||||
|
<span class="text-lg font-bold text-blue-400 mt-1">day{{ 's' if streak != 1 else '' }}</span>
|
||||||
|
{% if session.logged_in %}
|
||||||
|
<a href="/logout" class="text-gray-300 hover:text-pink-400 transition text-xl ml-16 mt-1" title="Logout">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<form action="/add" method="POST" class="mb-8 bg-gray-800/80 rounded-xl shadow-lg p-6 border border-gray-700">
|
<form action="/add" method="POST" class="mb-8 bg-gray-800/80 rounded-xl shadow-lg p-6 border border-gray-700">
|
||||||
|
|||||||
Reference in New Issue
Block a user