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()
|
||||
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('/')
|
||||
def index():
|
||||
page = request.args.get('page', 1, type=int)
|
||||
@@ -61,7 +95,8 @@ def index():
|
||||
has_prev = page > 1
|
||||
has_next = offset + per_page < total
|
||||
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'])
|
||||
def add_entry():
|
||||
@@ -192,4 +227,7 @@ def delete_entry(entry_id):
|
||||
return redirect(url_for('index'))
|
||||
|
||||
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
|
||||
|
||||
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>
|
||||
<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">
|
||||
<header class="mb-8 flex items-center justify-between">
|
||||
<div>
|
||||
<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>
|
||||
<p class="text-gray-400 mt-1">Your personal homelab journal</p>
|
||||
</div>
|
||||
<style>
|
||||
@media (max-width: 767px) {
|
||||
.logout-mobile {
|
||||
position: absolute;
|
||||
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 %}
|
||||
<a href="/logout" class="text-gray-300 hover:text-pink-400 transition text-xl" title="Logout">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</a>
|
||||
<div class="logout-mobile mt-6">
|
||||
<a href="/logout" class="text-gray-300 hover:text-pink-400 transition text-xl" title="Logout">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% 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>
|
||||
|
||||
<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