add 404/403 pages
This commit is contained in:
1 parent
c645c722d5
commit
34f03860a6
5 files changed
+137
-2
No files matched your search
@@ -2,7 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from flask import Flask
|
from flask import Flask, render_template
|
||||||
|
|
||||||
from auth import current_user_id, is_logged_in
|
from auth import current_user_id, is_logged_in
|
||||||
from config import Config
|
from config import Config
|
||||||
@@ -42,6 +42,14 @@ def create_app(config_overrides: dict | None = None) -> Flask:
|
|||||||
app.register_blueprint(account_bp)
|
app.register_blueprint(account_bp)
|
||||||
app.register_blueprint(leagues_bp)
|
app.register_blueprint(leagues_bp)
|
||||||
|
|
||||||
|
@app.errorhandler(404)
|
||||||
|
def not_found(e):
|
||||||
|
return render_template("404.html"), 404
|
||||||
|
|
||||||
|
@app.errorhandler(403)
|
||||||
|
def forbidden(e):
|
||||||
|
return render_template("403.html"), 403
|
||||||
|
|
||||||
@app.cli.command("init-db")
|
@app.cli.command("init-db")
|
||||||
def init_db_command() -> None:
|
def init_db_command() -> None:
|
||||||
if not database_extensions_available() or db is None:
|
if not database_extensions_available() or db is None:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ DATA_PATH = BASE_DIR / "data" / "entries.csv"
|
|||||||
DEFAULT_DATABASE_URL = f"sqlite:///{BASE_DIR / 'data' / 'boker-dev.sqlite3'}"
|
DEFAULT_DATABASE_URL = f"sqlite:///{BASE_DIR / 'data' / 'boker-dev.sqlite3'}"
|
||||||
|
|
||||||
ELIGIBLE_MIN_SESSIONS = 3
|
ELIGIBLE_MIN_SESSIONS = 3
|
||||||
APP_VERSION = "2.5.10"
|
APP_VERSION = "2.5.11"
|
||||||
|
|
||||||
|
|
||||||
def load_local_env(env_path: Path) -> None:
|
def load_local_env(env_path: Path) -> None:
|
||||||
|
|||||||
@@ -5604,6 +5604,91 @@ select.control { cursor: pointer; }
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
ERROR PAGES (404, 403)
|
||||||
|
================================================================ */
|
||||||
|
.page--error {
|
||||||
|
padding: 0;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-pg {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: calc(100vh - 62px);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse 90% 70% at 50% 60%, #1c0e3e 0%, #100820 55%, var(--bg) 100%),
|
||||||
|
radial-gradient(ellipse 50% 40% at 80% 20%, rgba(155,140,240,.07) 0%, transparent 55%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* large suit watermark */
|
||||||
|
.error-pg__suit {
|
||||||
|
position: absolute;
|
||||||
|
font-size: clamp(320px, 46vw, 660px);
|
||||||
|
color: rgba(155,140,240,.065);
|
||||||
|
line-height: 1;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
.error-pg--403 .error-pg__suit {
|
||||||
|
color: rgba(155,140,240,.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-pg__body {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
gap: 0;
|
||||||
|
padding: clamp(32px, 5vw, 64px) clamp(24px, 5vw, 48px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-pg__code {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: clamp(80px, 13vw, 148px);
|
||||||
|
font-weight: 900;
|
||||||
|
letter-spacing: -.04em;
|
||||||
|
line-height: 1;
|
||||||
|
background: linear-gradient(135deg, var(--accent) 0%, rgba(155,140,240,.35) 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-pg__title {
|
||||||
|
font-size: clamp(28px, 4vw, 52px);
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--text);
|
||||||
|
letter-spacing: -.04em;
|
||||||
|
margin: 0 0 16px;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-pg__sub {
|
||||||
|
font-size: clamp(14px, 1.3vw, 16px);
|
||||||
|
color: rgba(255,255,255,.42);
|
||||||
|
max-width: 40ch;
|
||||||
|
line-height: 1.68;
|
||||||
|
margin: 0 0 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-pg__actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
LANDING — hero kicker (replaces pill eyebrow in hero only)
|
LANDING — hero kicker (replaces pill eyebrow in hero only)
|
||||||
================================================================ */
|
================================================================ */
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}403 · Access Denied · myboker.org{% endblock %}
|
||||||
|
{% block page_class %}page--error{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="error-pg error-pg--403">
|
||||||
|
<div class="error-pg__suit" aria-hidden="true">♣</div>
|
||||||
|
<div class="error-pg__body">
|
||||||
|
<span class="error-pg__code">403</span>
|
||||||
|
<h1 class="error-pg__title">Access denied.</h1>
|
||||||
|
<p class="error-pg__sub">You don't have permission to view this page. If you think this is a mistake, contact your league owner.</p>
|
||||||
|
<div class="error-pg__actions">
|
||||||
|
<a class="btn btn--primary btn--lg" href="{{ url_for('public.home') }}">Go home →</a>
|
||||||
|
{% if not is_logged_in %}
|
||||||
|
<a class="btn btn--ghost btn--lg" href="{{ url_for('account.login') }}">Sign in</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="btn btn--ghost btn--lg" href="javascript:history.back()">Go back</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}404 · Page Not Found · myboker.org{% endblock %}
|
||||||
|
{% block page_class %}page--error{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="error-pg">
|
||||||
|
<div class="error-pg__suit" aria-hidden="true">♠</div>
|
||||||
|
<div class="error-pg__body">
|
||||||
|
<span class="error-pg__code">404</span>
|
||||||
|
<h1 class="error-pg__title">Page not found.</h1>
|
||||||
|
<p class="error-pg__sub">That URL doesn't exist or the page has been moved. Double-check the address or head back to safety.</p>
|
||||||
|
<div class="error-pg__actions">
|
||||||
|
<a class="btn btn--primary btn--lg" href="{{ url_for('public.home') }}">Go home →</a>
|
||||||
|
<a class="btn btn--ghost btn--lg" href="javascript:history.back()">Go back</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
Reference in new issue
Block a user