Skip to content
Snippets Groups Projects
Commit 4746cfa3 authored by maeries's avatar maeries
Browse files

refactoring html code into its own files

parent 57d2fac8
No related branches found
No related tags found
No related merge requests found
......@@ -3,6 +3,9 @@
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/public/elo_website_combustion" />
<excludeFolder url="file://$MODULE_DIR$/public/elo_website_combustion/images" />
<excludeFolder url="file://$MODULE_DIR$/public/elo_website_electric" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (FSelo)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
......
import os
import csv
import math
import glob
from operator import truediv
import multiprocessing as mp
import os
from datetime import datetime
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.colors import LinearSegmentedColormap
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
import pandas as pd
from matplotlib.colors import LinearSegmentedColormap
import multiprocessing as mp
from team_page import get_team_page_html
from tools import *
from world_ranking_list import get_world_ranking_html
# Constants for Elo calculation
K_FACTOR = 10
......@@ -24,26 +24,6 @@ def expected_score(rating_a, rating_b):
return 1 / (1 + math.pow(10, (rating_b - rating_a) / 400))
def clean_filename(filename):
"""Clean a string to make it suitable for use as a filename"""
# Replace spaces and special characters
return ''.join(c if c.isalnum() else '_' for c in filename).lower()
def hex_to_normalized_rgb(hex_color):
# Remove the '#' symbol if present
hex_color = hex_color.lstrip('#')
# Convert the hex values to integers
red = int(hex_color[0:2], 16)
green = int(hex_color[2:4], 16)
blue = int(hex_color[4:6], 16)
# Normalize the values by dividing by 255
normalized_rgb = (red / 255, green / 255, blue / 255)
return normalized_rgb
class EloSystem:
def __init__(self, csv_directory, output_directory, competition_type):
self.competition_type = competition_type
......@@ -229,7 +209,7 @@ class EloSystem:
def generate_website(self):
"""Generate static HTML website with Elo ratings and visualizations"""
# Create main index page
self.create_index_page()
self.create_world_ranking()
# # Create team-specific pages
# for team_name in self.teams:
......@@ -248,248 +228,11 @@ class EloSystem:
print(f"Website generated in {self.output_directory}")
def create_index_page(self):
"""Create the main index.html page"""
def create_world_ranking(self):
"""Create the index.html page for the vehicle type"""
# Sort teams by Elo rating
sorted_teams = sorted(self.teams.items(), key=lambda x: x[1]['elo'], reverse=True)
html_content = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formula Student {self.competition_type} Elo Rankings</title>
{self.header_snippet}
<style>
body {{
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
min-height: 100vh;
margin: 0;
font-family: 'Helvetica Neue', sans-serif;
background: linear-gradient(135deg, #ebebeb, #c9c9c9);
animation: gradientAnimation 10s ease infinite;
background-size: 200% 200%;
padding: 20px;
}}
@keyframes gradientAnimation {{
0%, 100% {{
background-position: 0% 50%;
}}
50% {{
background-position: 100% 50%;
}}
}}
.content-container {{
max-width: 1200px;
width: 100%;
animation: fadeInUp 0.5s ease-out forwards;
}}
h1 {{
font-size: 40px;
text-transform: uppercase;
text-align: center;
color: #333;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
h2 {{
text-align: center;
color: #555;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
margin-top: 30px;
}}
p {{
text-align: center;
color: #777;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
table {{
border-collapse: collapse;
width: 100%;
margin-top: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
th, td {{
padding: 12px 15px;
text-align: left;
}}
th {{
background-color: #f2f2f2;
color: #333;
font-weight: bold;
text-transform: uppercase;
border-bottom: 2px solid {self.BORDER_COLOR};
}}
tr {{
background-color: white;
transition: background-color 0.3s ease;
}}
tr:nth-child(even) {{
background-color: #f9f9f9;
}}
tr:hover {{
background-color: #f5f5f5;
}}
.chart-container {{
margin: 30px 0;
display: flex;
justify-content: center;
width: 100%;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
background-color: white;
padding: 20px;
box-sizing: border-box;
}}
.chart-container img {{
max-width: 100%;
height: auto;
}}
a {{
color: {self.LINK_COLOR};
text-decoration: none;
transition: color 0.3s ease;
}}
a:hover {{
color: {self.LINK_COLOR_HOVER};
text-decoration: none;
}}
.timestamp {{
font-size: 12px;
color: #777;
text-align: center;
margin-top: 20px;
animation: fadeInUp 0.5s ease-out 0.7s forwards;
opacity: 0;
}}
.nav-button {{
margin-top: 30px;
padding: 1em 2em;
font-size: larger;
text-transform: uppercase;
width: 12em;
text-align: center;
border: none;
border-radius: 5px;
background: linear-gradient(135deg, #ffff1e, #ffc400);
color: black;
cursor: pointer;
box-shadow: 0 10px 20px rgba(255, 255, 30, 0.3);
animation: fadeInUp 0.5s ease-out 0.8s forwards;
opacity: 0;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
position: relative;
overflow: hidden;
}}
.nav-button:hover {{
box-shadow: 0 15px 30px rgba(255, 255, 30, 0.4);
transform: translateY(-2px);
}}
.nav-button::before {{
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.7s ease;
}}
.nav-button:hover::before {{
left: 100%;
}}
@keyframes fadeInUp {{
from {{
opacity: 0;
transform: translateY(20px);
}}
to {{
opacity: 1;
transform: translateY(0);
}}
}}
</style>
</head>
<body>
<div class="content-container">
<h1>Formula Student {self.competition_type} Elo Rankings</h1>
<p>Rankings based on {len(self.competition_history)} competitions.</p>
<div class="chart-container">
<img src="images/top_teams_elo.png" alt="Top Teams Elo Chart">
</div>
<h2>Current Rankings</h2>
<table>
<tr>
<th>Rank</th>
<th>Team</th>
<th>Elo Rating</th>
<th>Competitions</th>
</tr>
"""
# Add rows for each team
for rank, (team_name, team_data) in enumerate(sorted_teams, 1):
html_content += f"""
<tr>
<td>{rank}</td>
<td><a href="team_{clean_filename(team_name)}.html">{team_name}</a></td>
<td>{int(team_data['elo'])}</td>
<td>{team_data['competitions']}</td>
</tr>"""
html_content += """
</table>
<div class="chart-container">
<img src="images/elo_distribution.png" alt="Elo Distribution">
</div>
<div class="timestamp">
<p>Generated on {}</p>
</div>
<div style="display: flex; justify-content: center;">
<a href="index.html"><button class="nav-button">Back to Home</button></a>
</div>
</div>
</body>
</html>
""".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
html_content = get_world_ranking_html(self, sorted_teams)
# Write the HTML file
with open(os.path.join(self.output_directory, 'index.html'), 'w', encoding='utf-8') as f:
......@@ -507,208 +250,7 @@ class EloSystem:
# Filter history for this team's competitions
team_competitions = sorted(team_data['history'], key=lambda x: x['date'], reverse=True)
html_content = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{team_name} - Elo Profile</title>
{self.header_snippet}
<style>
body {{
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}}
h1, h2 {{
color: #333;
animation: fadeInUp 0.5s ease-out forwards;
}}
table {{
border-collapse: collapse;
width: 100%;
margin-top: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
th, td {{
padding: 12px 15px;
text-align: left;
}}
th {{
background-color: #f2f2f2;
color: #333;
font-weight: bold;
text-transform: uppercase;
border-bottom: 2px solid {self.BORDER_COLOR};
}}
tr {{
background-color: white;
transition: background-color 0.3s ease;
}}
tr:nth-child(even) {{
background-color: #f9f9f9;
}}
tr:hover {{
background-color: #f5f5f5;
}}
p {{
animation: fadeInUp 0.5s ease-out forwards;
}}
.chart-container {{
margin-top: 30px;
display: flex;
justify-content: center;
width: 100%;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
background-color: white;
padding: 20px;
box-sizing: border-box;
}}
.chart-container img {{
max-width: 100%;
height: auto;
}}
a {{
color: {self.LINK_COLOR};
text-decoration: none;
transition: color 0.3s ease;
}}
a:hover {{
color: {self.LINK_COLOR_HOVER};
text-decoration: none;
}}
.summary-stats {{
display: flex;
justify-content: space-around;
margin: 20px 0;
flex-wrap: wrap;
animation: fadeInUp 0.5s ease-out forwards;
}}
.stat-box {{
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
margin: 10px;
flex: 1;
min-width: 150px;
text-align: center;
background-color: #f9f9f9;
}}
.stat-value {{
font-size: 24px;
font-weight: bold;
color: #333;
}}
.stat-label {{
font-size: 14px;
color: #666;
}}
.positive {{
color: green;
}}
.negative {{
color: red;
}}
@keyframes fadeInUp {{
from {{
opacity: 0;
transform: translateY(20px);
}}
to {{
opacity: 1;
transform: translateY(0);
}}
}}
</style>
</head>
<body>
<h1>{team_name} - Elo Profile</h1>
<p><a href="index.html">← Back to Rankings</a></p>
<div class="summary-stats">
<div class="stat-box">
<div class="stat-value">{int(team_data['elo'])}</div>
<div class="stat-label">Current Elo</div>
</div>
<div class="stat-box">
<div class="stat-value">{team_data['competitions']}</div>
<div class="stat-label">Competitions</div>
</div>
"""
# Calculate average ranking if available
if team_competitions:
avg_rank = sum(comp['rank'] for comp in team_competitions) / len(team_competitions)
best_rank = min(comp['rank'] for comp in team_competitions)
html_content += f"""
<div class="stat-box">
<div class="stat-value">{avg_rank:.1f}</div>
<div class="stat-label">Avg. Placement</div>
</div>
<div class="stat-box">
<div class="stat-value">{best_rank}</div>
<div class="stat-label">Best Placement</div>
</div>
"""
html_content += """
</div>
<div class="chart-container">
<img src="images/{}_history.png" alt="{} Elo History">
</div>
<h2>Competition History</h2>
<table>
<tr>
<th>Date</th>
<th>Competition</th>
<th>Placement</th>
<th>Elo Before</th>
<th>Elo After</th>
<th>Elo Change</th>
</tr>
""".format(clean_filename(team_name), team_name)
# Add rows for each competition
for comp in team_competitions:
elo_change = comp['elo_change']
change_class = "positive" if elo_change > 0 else "negative" if elo_change < 0 else ""
html_content += f"""
<tr>
<td>{comp['date']}</td>
<td>{comp['competition']}</td>
<td>{comp['rank']} / {comp['participants']}</td>
<td>{int(comp['previous_elo'])}</td>
<td>{int(comp['new_elo'])}</td>
<td class="{change_class}">{'+' if elo_change > 0 else ''}{elo_change:.1f}</td>
</tr>"""
html_content += """
</table>
<p><small>Generated on {}</small></p>
</body>
</html>
""".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
html_content = get_team_page_html(self, team_name, team_data, team_competitions)
# Write the HTML file
with open(os.path.join(self.output_directory, f'team_{clean_filename(team_name)}.html'), 'w',
......@@ -906,7 +448,6 @@ class EloSystem:
def main():
"""Main function to run the Elo ranking system"""
import argparse
from time import time
parser = argparse.ArgumentParser(description='Process competition results and generate Elo rankings website')
parser.add_argument('--input', default='csv_files', help='Directory containing CSV result files')
......
......@@ -127,7 +127,7 @@
<div class="center">
<div class="by">
<div><h3>by</h3></div>
<div><img src="GET racing schwarz.svg" width="200em"></div>
<div><img src="GET_racing_schwarz.svg" width="200em"></div>
</div>
</div>
<div class="center">
......
from datetime import datetime
from tools import clean_filename
def get_team_page_html(self, team_name, team_data, team_competitions):
html_content = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{team_name} - Elo Profile</title>
{self.header_snippet}
<style>
body {{
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}}
h1, h2 {{
color: #333;
animation: fadeInUp 0.5s ease-out forwards;
}}
table {{
border-collapse: collapse;
width: 100%;
margin-top: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
th, td {{
padding: 12px 15px;
text-align: left;
}}
th {{
background-color: #f2f2f2;
color: #333;
font-weight: bold;
text-transform: uppercase;
border-bottom: 2px solid {self.BORDER_COLOR};
}}
tr {{
background-color: white;
transition: background-color 0.3s ease;
}}
tr:nth-child(even) {{
background-color: #f9f9f9;
}}
tr:hover {{
background-color: #f5f5f5;
}}
p {{
animation: fadeInUp 0.5s ease-out forwards;
}}
.chart-container {{
margin-top: 30px;
display: flex;
justify-content: center;
width: 100%;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
background-color: white;
padding: 20px;
box-sizing: border-box;
}}
.chart-container img {{
max-width: 100%;
height: auto;
}}
a {{
color: {self.LINK_COLOR};
text-decoration: none;
transition: color 0.3s ease;
}}
a:hover {{
color: {self.LINK_COLOR_HOVER};
text-decoration: none;
}}
.summary-stats {{
display: flex;
justify-content: space-around;
margin: 20px 0;
flex-wrap: wrap;
animation: fadeInUp 0.5s ease-out forwards;
}}
.stat-box {{
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
margin: 10px;
flex: 1;
min-width: 150px;
text-align: center;
background-color: #f9f9f9;
}}
.stat-value {{
font-size: 24px;
font-weight: bold;
color: #333;
}}
.stat-label {{
font-size: 14px;
color: #666;
}}
.positive {{
color: green;
}}
.negative {{
color: red;
}}
@keyframes fadeInUp {{
from {{
opacity: 0;
transform: translateY(20px);
}}
to {{
opacity: 1;
transform: translateY(0);
}}
}}
</style>
</head>
<body>
<h1>{team_name} - Elo Profile</h1>
<p><a href="index.html">← Back to Rankings</a></p>
<div class="summary-stats">
<div class="stat-box">
<div class="stat-value">{int(team_data['elo'])}</div>
<div class="stat-label">Current Elo</div>
</div>
<div class="stat-box">
<div class="stat-value">{team_data['competitions']}</div>
<div class="stat-label">Competitions</div>
</div>
"""
# Calculate average ranking if available
if team_competitions:
avg_rank = sum(comp['rank'] for comp in team_competitions) / len(team_competitions)
best_rank = min(comp['rank'] for comp in team_competitions)
html_content += f"""
<div class="stat-box">
<div class="stat-value">{avg_rank:.1f}</div>
<div class="stat-label">Avg. Placement</div>
</div>
<div class="stat-box">
<div class="stat-value">{best_rank}</div>
<div class="stat-label">Best Placement</div>
</div>
"""
html_content += """
</div>
<div class="chart-container">
<img src="images/{}_history.png" alt="{} Elo History">
</div>
<h2>Competition History</h2>
<table>
<tr>
<th>Date</th>
<th>Competition</th>
<th>Placement</th>
<th>Elo Before</th>
<th>Elo After</th>
<th>Elo Change</th>
</tr>
""".format(clean_filename(team_name), team_name)
# Add rows for each competition
for comp in team_competitions:
elo_change = comp['elo_change']
change_class = "positive" if elo_change > 0 else "negative" if elo_change < 0 else ""
html_content += f"""
<tr>
<td>{comp['date']}</td>
<td>{comp['competition']}</td>
<td>{comp['rank']} / {comp['participants']}</td>
<td>{int(comp['previous_elo'])}</td>
<td>{int(comp['new_elo'])}</td>
<td class="{change_class}">{'+' if elo_change > 0 else ''}{elo_change:.1f}</td>
</tr>"""
html_content += """
</table>
<p><small>Generated on {}</small></p>
</body>
</html>
""".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
return html_content
\ No newline at end of file
tools.py 0 → 100644
def clean_filename(filename):
"""Clean a string to make it suitable for use as a filename"""
# Replace spaces and special characters
return ''.join(c if c.isalnum() else '_' for c in filename).lower()
def hex_to_normalized_rgb(hex_color):
# Remove the '#' symbol if present
hex_color = hex_color.lstrip('#')
# Convert the hex values to integers
red = int(hex_color[0:2], 16)
green = int(hex_color[2:4], 16)
blue = int(hex_color[4:6], 16)
# Normalize the values by dividing by 255
normalized_rgb = (red / 255, green / 255, blue / 255)
return normalized_rgb
\ No newline at end of file
from datetime import datetime
from tools import clean_filename
def get_world_ranking_html(self, sorted_teams):
html_content = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Formula Student {self.competition_type} Elo Rankings</title>
{self.header_snippet}
<style>
body {{
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
min-height: 100vh;
margin: 0;
font-family: 'Helvetica Neue', sans-serif;
background: linear-gradient(135deg, #ebebeb, #c9c9c9);
animation: gradientAnimation 10s ease infinite;
background-size: 200% 200%;
padding: 20px;
}}
@keyframes gradientAnimation {{
0%, 100% {{
background-position: 0% 50%;
}}
50% {{
background-position: 100% 50%;
}}
}}
.content-container {{
max-width: 1200px;
width: 100%;
animation: fadeInUp 0.5s ease-out forwards;
}}
h1 {{
font-size: 40px;
text-transform: uppercase;
text-align: center;
color: #333;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
h2 {{
text-align: center;
color: #555;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
margin-top: 30px;
}}
p {{
text-align: center;
color: #777;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
table {{
border-collapse: collapse;
width: 100%;
margin-top: 20px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
}}
th, td {{
padding: 12px 15px;
text-align: left;
}}
th {{
background-color: #f2f2f2;
color: #333;
font-weight: bold;
text-transform: uppercase;
border-bottom: 2px solid {self.BORDER_COLOR};
}}
tr {{
background-color: white;
transition: background-color 0.3s ease;
}}
tr:nth-child(even) {{
background-color: #f9f9f9;
}}
tr:hover {{
background-color: #f5f5f5;
}}
.chart-container {{
margin: 30px 0;
display: flex;
justify-content: center;
width: 100%;
animation: fadeInUp 0.5s ease-out forwards;
opacity: 0;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
background-color: white;
padding: 20px;
box-sizing: border-box;
}}
.chart-container img {{
max-width: 100%;
height: auto;
}}
a {{
color: {self.LINK_COLOR};
text-decoration: none;
transition: color 0.3s ease;
}}
a:hover {{
color: {self.LINK_COLOR_HOVER};
text-decoration: none;
}}
.timestamp {{
font-size: 12px;
color: #777;
text-align: center;
margin-top: 20px;
animation: fadeInUp 0.5s ease-out 0.7s forwards;
opacity: 0;
}}
.nav-button {{
margin-top: 30px;
padding: 1em 2em;
font-size: larger;
text-transform: uppercase;
width: 12em;
text-align: center;
border: none;
border-radius: 5px;
background: linear-gradient(135deg, #ffff1e, #ffc400);
color: black;
cursor: pointer;
box-shadow: 0 10px 20px rgba(255, 255, 30, 0.3);
animation: fadeInUp 0.5s ease-out 0.8s forwards;
opacity: 0;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
position: relative;
overflow: hidden;
}}
.nav-button:hover {{
box-shadow: 0 15px 30px rgba(255, 255, 30, 0.4);
transform: translateY(-2px);
}}
.nav-button::before {{
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.7s ease;
}}
.nav-button:hover::before {{
left: 100%;
}}
@keyframes fadeInUp {{
from {{
opacity: 0;
transform: translateY(20px);
}}
to {{
opacity: 1;
transform: translateY(0);
}}
}}
</style>
</head>
<body>
<div class="content-container">
<h1>Formula Student {self.competition_type} Elo Rankings</h1>
<p>Rankings based on {len(self.competition_history)} competitions.</p>
<div class="chart-container">
<img src="images/top_teams_elo.png" alt="Top Teams Elo Chart">
</div>
<h2>Current Rankings</h2>
<table>
<tr>
<th>Rank</th>
<th>Team</th>
<th>Elo Rating</th>
<th>Competitions</th>
</tr>
"""
# Add rows for each team
for rank, (team_name, team_data) in enumerate(sorted_teams, 1):
html_content += f"""
<tr>
<td>{rank}</td>
<td><a href="team_{clean_filename(team_name)}.html">{team_name}</a></td>
<td>{int(team_data['elo'])}</td>
<td>{team_data['competitions']}</td>
</tr>"""
html_content += """
</table>
<div class="chart-container">
<img src="images/elo_distribution.png" alt="Elo Distribution">
</div>
<div class="timestamp">
<p>Generated on {}</p>
</div>
<div style="display: flex; justify-content: center;">
<a href="index.html"><button class="nav-button">Back to Home</button></a>
</div>
</div>
</body>
</html>
""".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
return html_content
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment