generated from nathanwoodburn/python-webserver-template
feat: Add highlighing for upcoming week
All checks were successful
Build Docker / BuildImage (push) Successful in 1m44s
All checks were successful
Build Docker / BuildImage (push) Successful in 1m44s
This commit is contained in:
73
server.py
73
server.py
@@ -12,6 +12,7 @@ import requests
|
||||
import dotenv
|
||||
import csv
|
||||
from io import StringIO
|
||||
from datetime import date, datetime
|
||||
|
||||
dotenv.load_dotenv()
|
||||
|
||||
@@ -86,6 +87,69 @@ SCHEDULE_DATA = load_schedule_data()
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
def parse_schedule_date(raw_date: str) -> date | None:
|
||||
"""Parse a schedule date string using common formats."""
|
||||
if not raw_date:
|
||||
return None
|
||||
|
||||
cleaned = raw_date.strip()
|
||||
|
||||
# Try ISO date first.
|
||||
try:
|
||||
return date.fromisoformat(cleaned)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
formats = [
|
||||
"%d/%m/%Y",
|
||||
"%m/%d/%Y",
|
||||
"%d/%m/%y",
|
||||
"%m/%d/%y",
|
||||
"%d-%m-%Y",
|
||||
"%m-%d-%Y",
|
||||
"%d %b %Y",
|
||||
"%d %B %Y",
|
||||
"%b %d, %Y",
|
||||
"%B %d, %Y",
|
||||
"%a %d %b %Y",
|
||||
"%A %d %B %Y",
|
||||
]
|
||||
|
||||
for fmt in formats:
|
||||
try:
|
||||
return datetime.strptime(cleaned, fmt).date()
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
month_day_formats = [
|
||||
"%B %d",
|
||||
"%b %d",
|
||||
"%B %d,",
|
||||
"%b %d,",
|
||||
]
|
||||
|
||||
current_year = date.today().year
|
||||
for fmt in month_day_formats:
|
||||
try:
|
||||
# Add current year to the end of the string for parsing
|
||||
date_str_with_year = f"{cleaned} {current_year}"
|
||||
return datetime.strptime(date_str_with_year, fmt + " %Y").date()
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def find_upcoming_week_index(schedule: list[dict]) -> int | None:
|
||||
"""Return the index of the next schedule item that is today or later."""
|
||||
today = date.today()
|
||||
for index, item in enumerate(schedule):
|
||||
parsed_date = parse_schedule_date(item.get("date", ""))
|
||||
if parsed_date and parsed_date >= today:
|
||||
return index
|
||||
return None
|
||||
|
||||
|
||||
def find(name, path):
|
||||
for root, dirs, files in os.walk(path):
|
||||
if name in files:
|
||||
@@ -140,7 +204,12 @@ def wellknown(path):
|
||||
# region Main routes
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("schedule.html", schedule=SCHEDULE_DATA)
|
||||
upcoming_week_index = find_upcoming_week_index(SCHEDULE_DATA)
|
||||
return render_template(
|
||||
"schedule.html",
|
||||
schedule=SCHEDULE_DATA,
|
||||
upcoming_week_index=upcoming_week_index,
|
||||
)
|
||||
|
||||
|
||||
@app.route("/<path:path>")
|
||||
@@ -196,4 +265,4 @@ def not_found(e):
|
||||
|
||||
# endregion
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True, port=5000, host="0.0.0.0")
|
||||
app.run(debug=True, port=5000, host="127.0.0.1")
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
--empty-leader-color: #666;
|
||||
--select-bg: rgba(50, 50, 50, 0.8);
|
||||
--select-border: #666;
|
||||
--upcoming-accent: #7dd3fc;
|
||||
--upcoming-row-bg: rgba(125, 211, 252, 0.14);
|
||||
--upcoming-glow: rgba(125, 211, 252, 0.28);
|
||||
}
|
||||
|
||||
[data-theme="pink"] {
|
||||
@@ -34,6 +37,9 @@
|
||||
--empty-leader-color: #996677;
|
||||
--select-bg: rgba(80, 40, 60, 0.8);
|
||||
--select-border: #a55577;
|
||||
--upcoming-accent: #f9a8d4;
|
||||
--upcoming-row-bg: rgba(249, 168, 212, 0.16);
|
||||
--upcoming-glow: rgba(249, 168, 212, 0.32);
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -207,6 +213,36 @@ h1 {
|
||||
background-color: var(--special-event-hover);
|
||||
}
|
||||
|
||||
.upcoming-week {
|
||||
background: linear-gradient(90deg, var(--upcoming-row-bg) 0%, transparent 72%);
|
||||
box-shadow: inset 4px 0 0 var(--upcoming-accent), inset 0 0 0 1px var(--upcoming-glow);
|
||||
}
|
||||
|
||||
.upcoming-week:hover {
|
||||
background: linear-gradient(90deg, var(--upcoming-row-bg) 0%, var(--row-hover-bg) 72%);
|
||||
}
|
||||
|
||||
.upcoming-date {
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.upcoming-date::before {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.upcoming-date::after {
|
||||
content: "next up";
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
letter-spacing: 1.2px;
|
||||
text-transform: uppercase;
|
||||
color: var(--upcoming-accent);
|
||||
}
|
||||
|
||||
.date-cell {
|
||||
font-weight: 600;
|
||||
color: var(--date-color);
|
||||
@@ -330,6 +366,15 @@ h1 {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.upcoming-date {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.upcoming-date::after {
|
||||
font-size: 9px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.leader-cell {
|
||||
width: 30%;
|
||||
font-size: 12px;
|
||||
@@ -378,6 +423,11 @@ h1 {
|
||||
.date-cell {
|
||||
width: 30%;
|
||||
font-size: 14px;
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
|
||||
.upcoming-date::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.topic-cell {
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in schedule %}
|
||||
<tr class="{% if not item.leaders %}special-event{% endif %}">
|
||||
<td class="date-cell">{{ item.date }}</td>
|
||||
<tr class="{% if not item.leaders %}special-event{% endif %} {% if upcoming_week_index is not none and loop.index0 == upcoming_week_index %}upcoming-week{% endif %}">
|
||||
<td class="date-cell{% if upcoming_week_index is not none and loop.index0 == upcoming_week_index %} upcoming-date{% endif %}">{{ item.date }}</td>
|
||||
<td class="leader-cell">{% if item.leaders %}{% if item.leaders|length > 1 %}{{ item.leaders[:-1]|join(', ') }} & {{ item.leaders[-1] }}{% else %}{{ item.leaders[0] }}{% endif %}{% endif %}</td>
|
||||
<td class="topic-cell" {% if item.leaders %}data-leaders="Leaders: {% if item.leaders|length > 1 %}{{ item.leaders[:-1]|join(', ') }} & {{ item.leaders[-1] }}{% else %}{{ item.leaders[0] }}{% endif %}"{% endif %}>{{ item.topic }}</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user