aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md34
-rw-r--r--app/__init__.py30
-rw-r--r--app/static/custom.css41
-rw-r--r--app/static/file.js11
-rw-r--r--app/static/timer.js (renamed from app/static/custom.js)188
-rw-r--r--app/templates/controls.j283
-rw-r--r--app/templates/games.j242
-rw-r--r--app/templates/index.j211
-rw-r--r--app/templates/login.html8
-rw-r--r--app/templates/macros.j278
-rw-r--r--app/templates/players.j234
11 files changed, 282 insertions, 278 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..9c15148
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,34 @@
+# Contributing
+
+To contribute you need to have [git](https://git-scm.com/) and [UV](https://docs.astral.sh/uv/) setup.
+
+## Setup
+
+Set up the repository via a git clone and setup a new branch using the following commands:
+
+```bash
+git clone git@gitlab.com:KaranJayachandra/match_up.git
+cd match_up
+git checkout develop
+git branch <branch-name>
+git checkout <branch-name>
+```
+
+Now we can install the dependencies using:
+
+```bash
+uv sync
+```
+
+A database URI needs to be added to let the application know where to create a test database by creating a `.flaskenv` file in the root directory containing the variable `SQLALCHEMY_DATABASE_URI=sqlite:///app.db`. Now, we need to initialize a database for testing via the following commands:
+
+```bash
+uv run flask init
+uv run flask migrate
+```
+
+We are now ready to run the flask application using:
+
+```bash
+uv run flask run
+```
diff --git a/app/__init__.py b/app/__init__.py
index 3d3b498..0e0ea09 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -31,7 +31,7 @@ g = Session()
@app.route("/", methods=["GET"])
def home():
- return render_template("index.j2", url_for=url_for)
+ return render_template("index.j2", url_for=url_for, login_status=is_logged_in())
@app.route("/control", methods=["GET"])
@@ -46,6 +46,7 @@ def get_list_of_players():
regulars=g.players.regulars(),
guests=g.players.guests(),
url_for=url_for,
+ login_status=is_logged_in(),
)
@@ -54,19 +55,29 @@ def get_list_of_courts():
return render_template("courts.j2", courts=g.courts.all())
+def login_required(f):
+ @wraps(f)
+ def decorated_function(*args, **kwargs):
+ if not is_logged_in():
+ response = Response("User isn't logged in!")
+ response.headers["HX-Redirect"] = url_for("simplelogin.login")
+ return response
+ return f(*args, **kwargs)
+
+ return decorated_function
+
+
@app.route("/propose", methods=["POST"])
+@login_required
def get_random_games():
- if not is_logged_in():
- return redirect(url_for("login"))
g.levels = int(request.form["levels"].split()[0])
g.teams = request.form["team"] == "Teams"
return render_template("games.j2", games=g.propose(), title="Proposal")
@app.route("/confirm", methods=["POST"])
+@login_required
def confirm_games():
- if not is_logged_in():
- return redirect(url_for("simplelogin.login"))
return render_template("games.j2", games=g.confirm(), title=f"Round: {g.round()}")
@@ -76,15 +87,6 @@ def clear_games():
"games.j2", games=g.current_round(), title=f"Round: {g.round()}"
)
-def login_required(f):
- @wraps(f)
- def decorated_function(*args, **kwargs):
- if not is_logged_in():
- response = Response("User isn't logged in!")
- response.headers["HX-Redirect"] = url_for("simplelogin.login")
- return response
- return f(*args, **kwargs)
- return decorated_function
@app.route("/reset", methods=["POST"])
@login_required
diff --git a/app/static/custom.css b/app/static/custom.css
index fafc51a..a5ca36f 100644
--- a/app/static/custom.css
+++ b/app/static/custom.css
@@ -1,19 +1,34 @@
-button, input, .select, .select select {
+button, input, select {
width: 100%;
-}
-table {
- font-size: 17.5px;
+ height: 100%;
}
td {
width: 20%;
}
-img {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%,-50%);
+.grid {
+ margin-top: 20px;
+ margin-bottom: 20px;
+}
+footer {
+ text-align: center;
+}
+.parent, .timer {
+ display: grid;
+ grid-column-gap: 20px;
+ grid-row-gap: 20px;
+ margin-top: 20px;
+ margin-bottom: 20px;
+ grid-auto-columns: 1fr;
+ grid-auto-rows: 1fr;
+}
+@media (min-width: 900px) {
+ table {
+ font-size: xx-large;
+ }
+ .parent {
+ grid-template-columns: repeat(4, 1fr);
+ }
+ .timer {
+ grid-template-columns: 4fr repeat(2, 1fr);
+ }
}
-.center {
- margin: auto;
- width: 50%;
-} \ No newline at end of file
diff --git a/app/static/file.js b/app/static/file.js
new file mode 100644
index 0000000..403ddf6
--- /dev/null
+++ b/app/static/file.js
@@ -0,0 +1,11 @@
+window.onload = function() {
+ const fileInput = document.querySelector("#file-js input[type=file]");
+ if (fileInput !== null) {
+ fileInput.onchange = () => {
+ if (fileInput.files.length > 0) {
+ const fileName = document.querySelector("#file-js .file-name");
+ fileName.textContent = fileInput.files[0].name;
+ }
+ }
+ };
+} \ No newline at end of file
diff --git a/app/static/custom.js b/app/static/timer.js
index 1d36493..e8e7854 100644
--- a/app/static/custom.js
+++ b/app/static/timer.js
@@ -1,97 +1,91 @@
-let minsPerRound = Number(sessionStorage.getItem("minsPerRound")) || 12;
-let timerRunningFlag = Number(sessionStorage.getItem("timerRunningFlag")) || 0;
-let deadline = Number(sessionStorage.getItem("deadline")) || new Date().getTime();
-let clock = 0;
-
-function setTimer(m, s) {
- let timer = document.getElementById("timer-display");
- m = m < 10 ? ("0" + m) : m;
- s = s < 10 ? ("0" + s) : s;
- timer.value = `${m}:${s}`;
-}
-
-function setSessionData() {
- sessionStorage.setItem("deadline", deadline);
- sessionStorage.setItem("minsPerRound", minsPerRound);
- sessionStorage.setItem("timerRunningFlag", timerRunningFlag);
-}
-
-function resetTimer() {
- clearInterval(clock);
- setTimer(minsPerRound, 0);
- timerRunningFlag = 0;
- setSessionData();
-}
-
-function updateTimer(milliseconds) {
- const m = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60));
- const s = Math.floor((milliseconds % (1000 * 60)) / 1000);
- setTimer(m, s);
-}
-
-function refreshTimer() {
- const now = new Date().getTime();
- const millisecondsToDeadline = deadline - now;
- if (millisecondsToDeadline > 0) {
- updateTimer(millisecondsToDeadline);
- return;
- }
- resetTimer();
- const notification = new Notyf({
- duration: 30 * 1000,
- position: {x: 'center', y: 'top'},
- types: [{
- type: 'success',
- background: 'indianred',
- duration: 1000 * 1000,
- dismissible: true
- }]
- });
- notification.success("Round completed");
-}
-
-function startTimer(fresh) {
- if (fresh) {
- now = new Date().getTime();
- const millisecondsToDeadline = minsPerRound * 60 * 1000;
- deadline = now + millisecondsToDeadline;
- }
- timerRunningFlag = 1;
- setSessionData();
- clock = setInterval(refreshTimer, 1000);
-}
-
-if (timerRunningFlag) startTimer(0); else resetTimer();
-
-document.getElementById("timer-start").addEventListener('click', ()=> {
- if (timerRunningFlag != 0) return;
- startTimer(1);
-});
-
-document.getElementById("timer-stop").addEventListener('click', ()=>{
- resetTimer();
-});
-
-document.getElementById("timer-inc").addEventListener('click', ()=> {
- if (timerRunningFlag == 0) {
- minsPerRound += 1;
- resetTimer();
- }
-});
-
-document.getElementById("timer-dec").addEventListener('click', ()=> {
- if (timerRunningFlag == 0 && minsPerRound != 0) {
- minsPerRound -= 1;
- resetTimer();
- }
-});
-
-const fileInput = document.querySelector("#file-js input[type=file]");
- if (fileInput !== null) {
- fileInput.onchange = () => {
- if (fileInput.files.length > 0) {
- const fileName = document.querySelector("#file-js .file-name");
- fileName.textContent = fileInput.files[0].name;
- }
- }
-}; \ No newline at end of file
+let minsPerRound = Number(sessionStorage.getItem("minsPerRound")) || 12;
+let timerRunningFlag = Number(sessionStorage.getItem("timerRunningFlag")) || 0;
+let deadline = Number(sessionStorage.getItem("deadline")) || new Date().getTime();
+let clock = 0;
+
+function setTimer(m, s) {
+ let timer = document.getElementById("timer-display");
+ m = m < 10 ? ("0" + m) : m;
+ s = s < 10 ? ("0" + s) : s;
+ timer.value = `${m}:${s}`;
+}
+
+function setSessionData() {
+ sessionStorage.setItem("deadline", deadline);
+ sessionStorage.setItem("minsPerRound", minsPerRound);
+ sessionStorage.setItem("timerRunningFlag", timerRunningFlag);
+}
+
+function resetTimer() {
+ clearInterval(clock);
+ setTimer(minsPerRound, 0);
+ timerRunningFlag = 0;
+ setSessionData();
+}
+
+function updateTimer(milliseconds) {
+ const m = Math.floor((milliseconds % (1000 * 60 * 60)) / (1000 * 60));
+ const s = Math.floor((milliseconds % (1000 * 60)) / 1000);
+ setTimer(m, s);
+}
+
+function refreshTimer() {
+ const now = new Date().getTime();
+ const millisecondsToDeadline = deadline - now;
+ if (millisecondsToDeadline > 0) {
+ updateTimer(millisecondsToDeadline);
+ return;
+ }
+ resetTimer();
+ const notification = new Notyf({
+ duration: 30 * 1000,
+ position: {x: 'center', y: 'top'},
+ types: [{
+ type: 'success',
+ background: 'indianred',
+ duration: 1000 * 1000,
+ dismissible: true
+ }]
+ });
+ notification.success("Round completed");
+}
+
+function startTimer(fresh) {
+ if (fresh) {
+ now = new Date().getTime();
+ const millisecondsToDeadline = minsPerRound * 60 * 1000;
+ deadline = now + millisecondsToDeadline;
+ }
+ timerRunningFlag = 1;
+ setSessionData();
+ clock = setInterval(refreshTimer, 1000);
+}
+
+window.onload = function () {
+ if (timerRunningFlag)
+ startTimer(0);
+ else resetTimer();
+
+ document.getElementById("timer-start").addEventListener('click', ()=> {
+ if (timerRunningFlag != 0) return;
+ startTimer(1);
+ });
+
+ document.getElementById("timer-stop").addEventListener('click', ()=>{
+ resetTimer();
+ });
+
+ document.getElementById("timer-inc").addEventListener('click', ()=> {
+ if (timerRunningFlag == 0) {
+ minsPerRound += 1;
+ resetTimer();
+ }
+ });
+
+ document.getElementById("timer-dec").addEventListener('click', ()=> {
+ if (timerRunningFlag == 0 && minsPerRound != 0) {
+ minsPerRound -= 1;
+ resetTimer();
+ }
+ });
+} \ No newline at end of file
diff --git a/app/templates/controls.j2 b/app/templates/controls.j2
index 0acf5a6..97351bf 100644
--- a/app/templates/controls.j2
+++ b/app/templates/controls.j2
@@ -1,47 +1,48 @@
{% from "macros.j2" import court_button %}
-<div class="fixed-grid has-6-cols">
- <div class="grid">
- {% for court in courts %}
- {{ court_button(court) }}
- {% endfor %}
+<h3>Timer</h3>
+<div class="timer">
+ <div role="group" style="height: 100%">
+ <button id="timer-dec"><i class="fas fa-light fa-minus"></i></button>
+ <input id="timer-display" type="text" style="text-align:center; height: 100%" readonly></input>
+ <button id="timer-inc"><i class="fas fa-light fa-plus"></i></button>
</div>
+ <button id="timer-start"><i class="fas fa-light fa-play"></i></button>
+ <button id="timer-stop"><i class="fas fa-light fa-stop"></i></button>
</div>
-<div class="columns">
- <div class="column">
- <div class="select is-responsive">
- <select name="levels">
- <option>10 Levels</option>
- <option>8 Levels</option>
- <option>6 Levels</option>
- <option>4 Levels</option>
- <option>2 Levels</option>
- <option>0 Levels</option>
- </select>
- </div>
- </div>
- <div class="column">
- <div class="select is-responsive">
- <select name="team">
- <option>Random</option>
- <option>Teams</option>
- </select>
- </div>
- </div>
- <div class="column">
- <button class="button is-dark is-responsive"
- hx-post="/propose"
- hx-target="#games"
- hx-include="[name='levels'], [name='team']">Generate</button>
- </div>
- <div class="column"></div>
- <div class="column">
- <button class="button is-dark is-responsive"
- hx-post="/confirm"
- hx-target="#games">Confirm</button>
+<h3>Generation</h3>
+<div class="grid">
+ <button class="button is-dark is-responsive"
+ hx-post="/propose"
+ hx-target="#games"
+ hx-include="[name='levels'], [name='team']">Generate</button>
+ <button class="button is-dark is-responsive"
+ hx-post="/confirm"
+ hx-target="#games">Confirm</button>
+ <button class="button is-dark is-responsive"
+ hx-post="/reset"
+ hx-target="#games">RESET!</button>
+</div>
+<div class="grid">
+ <div class="select is-responsive">
+ <select name="levels">
+ <option>10 Levels</option>
+ <option>8 Levels</option>
+ <option>6 Levels</option>
+ <option>4 Levels</option>
+ <option>2 Levels</option>
+ <option>0 Levels</option>
+ </select>
</div>
- <div class="column">
- <button class="button is-dark is-responsive"
- hx-post="/reset"
- hx-target="#games">RESET!</button>
+ <div class="select is-responsive">
+ <select name="team">
+ <option>Random</option>
+ <option>Teams</option>
+ </select>
</div>
+</div>
+<h3>Courts</h3>
+<div class="parent">
+{% for court in courts %}
+ {{ court_button(court) }}
+{% endfor %}
</div> \ No newline at end of file
diff --git a/app/templates/games.j2 b/app/templates/games.j2
index dff1e0f..00ffb71 100644
--- a/app/templates/games.j2
+++ b/app/templates/games.j2
@@ -1,21 +1,21 @@
-<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth" id="games">
-<thead>
- <th colspan="5" align="center"> {{ title }} </th>
-</thead>
-<thead>
- <th align="center"> Court </th>
- <th colspan="2" align="center"> Team 1 </th>
- <th colspan="2" align="center"> Team 2 </th>
-</thead>
-<tbody>
-{% for game in games %}
- <tr {% if game.team_1[0].first_name == 'RESERVED' %} class="is-danger" {% endif %}>
- <th align="center" style="width: 8%;">{{ game.court.id }}</th>
- <td style="width: 23%;"><strong>{{ game.team_1[0].first_name }}</strong>{{ " " + game.team_1[0].last_name }}</th>
- <td style="width: 23%;"><strong>{{ game.team_1[1].first_name }}</strong>{{ " " + game.team_1[1].last_name }}</th>
- <td style="width: 23%;"><strong>{{ game.team_2[0].first_name }}</strong>{{ " " + game.team_2[0].last_name }}</th>
- <td style="width: 23%;"><strong>{{ game.team_2[1].first_name }}</strong>{{ " " + game.team_2[1].last_name }}</th>
- </tr>
-{% endfor %}
-</tbody>
-</table> \ No newline at end of file
+<div id="games" class="overflow-auto">
+ <h3> {{ title }} </h3>
+ <table>
+ <thead>
+ <th align="center"> Court </th>
+ <th colspan="2" align="center"> Team 1 </th>
+ <th colspan="2" align="center"> Team 2 </th>
+ </thead>
+ <tbody>
+ {% for game in games %}
+ <tr {% if game.team_1[0].first_name == 'RESERVED' %} data-theme="dark" {% endif %}>
+ <td align="center" style="width: 8%;">{{ game.court.id }}</th>
+ <td style="width: 23%;"><strong>{{ game.team_1[0].first_name }}</strong>{{ " " + game.team_1[0].last_name }}</th>
+ <td style="width: 23%;"><strong>{{ game.team_1[1].first_name }}</strong>{{ " " + game.team_1[1].last_name }}</th>
+ <td style="width: 23%;"><strong>{{ game.team_2[0].first_name }}</strong>{{ " " + game.team_2[0].last_name }}</th>
+ <td style="width: 23%;"><strong>{{ game.team_2[1].first_name }}</strong>{{ " " + game.team_2[1].last_name }}</th>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+<div> \ No newline at end of file
diff --git a/app/templates/index.j2 b/app/templates/index.j2
index ce0d531..af6ca4c 100644
--- a/app/templates/index.j2
+++ b/app/templates/index.j2
@@ -3,11 +3,14 @@
<html lang="en">
{{ header(url_for) }}
<body>
- <section class="section">
- {{ navbar(url_for) }}
+ <header class="container">{{ navbar(url_for, login_status) }}</header>
+ <main class="container">
+ <h2>Games</h2>
<div hx-post="/clear" hx-swap="outerHTML" hx-trigger="load"></div>
+ <h2>Controls</h2>
<div hx-get="/control" hx-swap="outerHTML" hx-trigger="load"></div>
- {{ footer() }}
- </section>
+ </main>
+ <footer class="container">{{ footer() }}</footer>
+ <script src="{{ url_for('static', filename='timer.js') }}"></script>
</body>
</html>
diff --git a/app/templates/login.html b/app/templates/login.html
index a42f2c5..e3109b6 100644
--- a/app/templates/login.html
+++ b/app/templates/login.html
@@ -3,8 +3,8 @@
<html lang="en">
{{ header(url_for) }}
<body>
- <section class="section">
- {{ navbar(url_for) }}
+ <header class="container">{{ navbar(url_for) }}</header>
+ <main class="container">
<form action="{{ url_for('simplelogin.login') }}" method="post">
<div class="form-group">
{{ form.csrf_token }}
@@ -16,8 +16,8 @@
</form>
<input class="button is-dark" type="submit" value="Login">
</form>
- {{ footer() }}
- </section>
+ </main>
+ <footer class="container">{{ footer() }}</footer>
</body>
</html> \ No newline at end of file
diff --git a/app/templates/macros.j2 b/app/templates/macros.j2
index e08bfe1..e82b910 100644
--- a/app/templates/macros.j2
+++ b/app/templates/macros.j2
@@ -1,93 +1,45 @@
{% macro court_button(court) -%}
-<button class= "button is-responsive {% if court.status %}is-success{% else %}is-danger{% endif %}"
+<button class= "{% if court.status %}{% else %}contrast{% endif %}"
hx-post="{{ "/court-toggle/" ~ court.id}}"
hx-swap="outerHTML"> Court {{ court.id }}</button>
{%- endmacro %}
{% macro player_button(player) -%}
-<button class="button is-responsive {% if player.status %}is-success{% else %}is-danger {% endif %}"
+<button class="{% if player.status %}{% else %}contrast{% endif %}"
hx-post="{{ "/player-toggle/" ~ player.id}}"
hx-swap="outerHTML"> {{ player.first_name + " " + player.last_name}} </button>
{%- endmacro %}
-{% macro guest_control(level, value) -%}
-<div class="field center has-addons is-centered" id="guests_{{level}}">
- <div class="control">
- <button class="button is-responsive is-dark"
- hx-post="/decrement_guest"
- hx-swap="outerHTML"
- hx-vals='{"level": "{{ level }}"}'
- hx-target="#guests_{{ level }}"><span class="icon"><i class="fas fa-light fa-minus"></i></span></button>
- </div>
- <div class="control">
- <input class="input is-responsive" type="text" style="text-align:center" value="{{ value }}" disabled>
- </div>
- <div class="control">
- <button class="button is-responsive is-dark"
- hx-post="/increment_guest"
- hx-swap="outerHTML"
- hx-vals='{"level": "{{ level }}"}'
- hx-target="#guests_{{ level }}"><span class="icon"><i class="fas fa-light fa-plus"></i></span></button>
- </div>
-</div>
-{%- endmacro %}
-
{% macro header(url_for) -%}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Match Up!</title>
<link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}">
-<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.4/css/bulma.min.css">
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='custom.css') }}">
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.6/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/js/fontawesome.min.js"></script>
-<script defer src="{{ url_for('static', filename='custom.js') }}"></script>
</head>
{%- endmacro %}
{% macro footer() -%}
-<div class="content has-text-centered">Made by <a href="https://karanjayachandra.com/">Karan</a> using <a href="https://flask.palletsprojects.com">Flask</a>, <a href="https://htmx.org/">HTMX</a>, <a href="https://carlosroso.com/notyf/">Notyf</a> and <a href="https://bulma.io">Bulma</a></div>
+<div class="container">Made by <a href="https://karanjayachandra.com/">Karan</a> with <i class="fas fa-heart"></i></div>
{%- endmacro %}
-{% macro navbar(url_for) -%}
-<nav class="level">
- <p class="level-item has-text-centered">
- <button class="button is-link" onclick="location.href = '/';">Games</button>
- </p>
- <p class="level-item has-text-centered">
- <button class="button is-link" onclick="location.href = '/players';">Players</button>
- </p>
- <div class="level-item has-text-centered"></div>
- <div class="level-left"></div>
- <div class="level-item has-text-centered">
- <p class="title">Match Up!</p>
- </div>
- <div class="level-item has-text-centered"></div>
- <div class="level-right">
- <div class="field has-addons has-addons-centered">
- <div class="control"><button class="button is-dark" id="timer-dec">
- <span class="icon"><i class="fas fa-light fa-minus"></i></span>
- </button></div>
- <p class="control has-icons-left has-icons-right">
- <input class="input is-responsive" id="timer-display" type="text" style="text-align:center; " readonly>
- <span class="icon is-small is-left">
- <i class="fas fa-light fa-clock"></i>
- </span>
- </p>
- <div class="control"><button class="button is-dark" id="timer-inc">
- <span class="icon"><i class="fas fa-light fa-plus"></i></span>
- </button></div>
- <div class="control"><button class="button is-dark" id="timer-start">
- <span class="icon"><i class="fas fa-light fa-play"></i></span>
- </button></div>
- <div class="control"><button class="button is-dark" id="timer-stop">
- <span class="icon"><i class="fas fa-light fa-stop"></i></span>
- </button></div>
- </div>
- </div>
+
+{% macro navbar(url_for, login_status) -%}
+<nav>
+ <ul>
+ <li><strong>Match Up!</strong></li>
+ </ul>
+ <ul>
+ <li><a href="/">Games</a></li>
+ <li><a href="/players">Players</a></li>
+ {% if login_status %}<li><a href="/logout/">Logout</a></li>{% else %}<li><a href="/login/">Login</a></li>{% endif %}
+ </ul>
</nav>
{%- endmacro %} \ No newline at end of file
diff --git a/app/templates/players.j2 b/app/templates/players.j2
index 16e3878..bacb215 100644
--- a/app/templates/players.j2
+++ b/app/templates/players.j2
@@ -3,46 +3,38 @@
<html lang="en">
{{ header(url_for) }}
<body>
- <section class="section">
- {{ navbar(url_for) }}
- <h4 class="title is-4">Members</h4>
- <div class="fixed-grid has-4-cols">
- <div class="grid">
+ <header class="container">{{ navbar(url_for, login_status) }}</header>
+ <main class="container">
+ <h3 >Members</h3>
+ <div class="parent">
{% for regular in regulars %}
<div class="cell"> {{ player_button(regular) }} </div>
{% endfor %}
</div>
- <h4 class="title is-4">Guests</h4>
- <div class="fixed-grid has-4-cols">
- <div class="grid">
+ <h3>Guests</h3>
+ <div class="parent">
{% for guest in guests %}
<div class="cell"> {{ player_button(guest) }} </div>
{% endfor %}
</div>
- </section>
- <section class="section">
- <div class="column">
+ <h3>Controls</h3>
+ <div class="grid">
<button class="button is-dark is-responsive"
hx-post="/reset_players">RESET!</button>
</div>
- <div class="column">
+ <h3>Player Update</h3>
+ <div class="grid">
<form method="POST" enctype="multipart/form-data" hx-post="/update_players">
<div id="file-js" class="file has-name is-fullwidth">
<label class="file-label">
<input class="file-input" type="file" name="players" />
- <span class="file-cta">
- <span class="file-icon">
- <i class="fas fa-upload"></i>
- </span>
- <span class="file-label"> Choose a file… </span>
- </span>
- <span class="file-name"> No file uploaded </span>
</label>
<button class="button is-dark is-responsive">UPDATE!</button>
</div>
</form>
</div>
- {{ footer() }}
- </section>
+ <footer class="container">{{ footer() }}</footer>
+ <script src="{{ url_for('static', filename='file.js') }}"></script>
+ </main>
</body>
</html> \ No newline at end of file