WEB_DEV / templates /base.html
Binta26's picture
Upload 5 files
5b85ad6 verified
Raw
History Blame Contribute Delete
12.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{% block title %}IrisAI{% endblock %}</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Mono:wght@400;500&family=DM+Sans:wght@300;400;500;600&display=swap" rel="stylesheet" />
<style>
/* ── Reset & Variables ────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #0d0f14;
--surface: #13161e;
--surface2: #1a1e2a;
--border: #252836;
--accent: #7c6fff;
--accent2: #ff6f91;
--green: #4ade80;
--text: #e8eaf0;
--muted: #6b7280;
--radius: 12px;
--radius-lg: 20px;
}
html, body {
height: 100%;
background: var(--bg);
color: var(--text);
font-family: 'DM Sans', sans-serif;
font-size: 20px;
line-height: 1.6;
}
/* ── Noise texture overlay ────────────────────────────────── */
body::before {
content: '';
position: fixed; inset: 0; z-index: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
pointer-events: none;
}
/* ── Glowing blobs ────────────────────────────────────────── */
.blob {
position: fixed; border-radius: 50%;
filter: blur(80px); opacity: 0.12; pointer-events: none; z-index: 0;
}
.blob-1 { width: 500px; height: 500px; background: var(--accent); top: -150px; left: -150px; }
.blob-2 { width: 400px; height: 400px; background: var(--accent2); bottom: -100px; right: -100px; }
/* ── Nav ──────────────────────────────────────────────────── */
nav {
position: sticky; top: 0; z-index: 100;
display: flex; align-items: center; justify-content: space-between;
padding: 0 2rem;
height: 60px;
background: rgba(13,15,20,.85);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border);
}
.nav-logo {
font-family: 'DM Serif Display', serif;
font-size: 1.9rem;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
text-decoration: none;
}
.nav-links { display: flex; gap: 0.5rem; align-items: center; }
.nav-links a {
color: var(--muted); text-decoration: none; padding: 0.35rem 0.75rem;
border-radius: 8px; font-size: 0.875rem; font-weight: 500;
transition: color .2s, background .2s;
}
.nav-links a:hover { color: var(--text); background: var(--surface2); }
.nav-badge {
font-family: 'DM Mono', monospace; font-size: 0.9rem;
background: var(--surface2); border: 1px solid var(--border);
color: var(--muted); padding: 0.2rem 0.6rem; border-radius: 20px;
}
/* ── Page wrapper ─────────────────────────────────────────── */
.page {
position: relative; z-index: 1;
min-height: calc(100vh - 60px);
padding: 3rem 1.5rem;
}
.container { max-width: 860px; margin: 0 auto; }
.container-sm { max-width: 440px; margin: 0 auto; }
/* ── Flash messages ───────────────────────────────────────── */
.flashes { margin-bottom: 1.5rem; display: flex; flex-direction: column; gap: .5rem; }
.flash {
padding: .75rem 1rem; border-radius: var(--radius); font-size: .875rem;
border-left: 3px solid;
}
.flash.success { background: rgba(74,222,128,.08); border-color: var(--green); color: #86efac; }
.flash.danger { background: rgba(255,111,145,.08); border-color: var(--accent2); color: #fda4af; }
.flash.warning { background: rgba(250,204, 21,.08); border-color: #facc15; color: #fde68a; }
.flash.info { background: rgba(124,111,255,.08); border-color: var(--accent); color: #c4b5fd; }
/* ── Cards ────────────────────────────────────────────────── */
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 2rem;
}
.card + .card { margin-top: 1.5rem; }
/* ── Form elements ────────────────────────────────────────── */
.form-group { margin-bottom: 1.25rem; }
label {
display: block; margin-bottom: .4rem;
font-size: .9rem; font-weight: 600; letter-spacing: .05em;
text-transform: uppercase; color: var(--muted);
}
input[type="text"], input[type="password"], input[type="number"] {
width: 100%; padding: .75rem 1rem;
background: var(--surface2); border: 1px solid var(--border);
border-radius: var(--radius); color: var(--text);
font-family: inherit; font-size: .95rem;
transition: border-color .2s, box-shadow .2s;
outline: none;
}
input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(124,111,255,.15);
}
.input-hint { font-size: .9rem; color: var(--muted); margin-top: .3rem; }
/* ── Buttons ──────────────────────────────────────────────── */
.btn {
display: inline-flex; align-items: center; justify-content: center;
gap: .5rem; padding: .75rem 1.5rem;
border: none; border-radius: var(--radius); cursor: pointer;
font-family: inherit; font-size: .9rem; font-weight: 600;
text-decoration: none; transition: all .2s;
}
.btn-primary {
background: linear-gradient(135deg, var(--accent), #9d8fff);
color: #fff;
box-shadow: 0 4px 20px rgba(124,111,255,.3);
}
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 6px 24px rgba(124,111,255,.4); }
.btn-primary:active { transform: translateY(0); }
.btn-outline {
background: transparent; color: var(--muted);
border: 1px solid var(--border);
}
.btn-outline:hover { color: var(--text); border-color: var(--accent); background: rgba(124,111,255,.06); }
.btn-full { width: 100%; }
/* ── Grid ─────────────────────────────────────────────────── */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 540px) { .grid-2 { grid-template-columns: 1fr; } }
/* ── Divider ──────────────────────────────────────────────── */
.divider { border: none; border-top: 1px solid var(--border); margin: 1.5rem 0; }
/* ── Typography helpers ───────────────────────────────────── */
.serif { font-family: 'DM Serif Display', serif; }
.mono { font-family: 'DM Mono', monospace; }
.muted { color: var(--muted); }
.small { font-size: .9rem; }
/* ── Result card ──────────────────────────────────────────── */
.result-card {
border-radius: var(--radius-lg);
padding: 2rem;
border: 1px solid var(--border);
animation: slideUp .4s ease;
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
.result-name {
font-family: 'DM Serif Display', serif;
font-size: 2.5rem;
margin-bottom: .25rem;
}
.confidence-bar-wrap {
background: var(--surface2); border-radius: 100px;
height: 8px; margin: .75rem 0 .4rem;
overflow: hidden;
}
.confidence-bar {
height: 100%; border-radius: 100px;
background: linear-gradient(90deg, var(--accent), var(--accent2));
transition: width .8s ease;
}
/* ── Prob pills ───────────────────────────────────────────── */
.prob-grid { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1rem; }
.prob-pill {
font-family: 'DM Mono', monospace; font-size: .9rem;
padding: .3rem .75rem; border-radius: 100px;
border: 1px solid var(--border); background: var(--surface2);
color: var(--muted);
}
.prob-pill.active { border-color: var(--accent); color: var(--accent); background: rgba(124,111,255,.1); }
/* ── History table ────────────────────────────────────────── */
table { width: 100%; border-collapse: collapse; font-size: .85rem; }
th { color: var(--muted); font-weight: 600; font-size: .75rem;
text-transform: uppercase; letter-spacing: .05em;
padding: .5rem .75rem; text-align: left; border-bottom: 1px solid var(--border); }
td { padding: .6rem .75rem; border-bottom: 1px solid var(--border); color: var(--text); }
tr:last-child td { border-bottom: none; }
.badge {
display: inline-block; font-size: .72rem; font-weight: 600;
padding: .15rem .6rem; border-radius: 100px; font-family: 'DM Mono', monospace;
}
.badge-setosa { background: rgba(249,168,212,.15); color: #f9a8d4; }
.badge-versicolor { background: rgba(196,181,253,.15); color: #c4b5fd; }
.badge-virginica { background: rgba(110,231,183,.15); color: #6ee7b7; }
/* ── Page header ──────────────────────────────────────────── */
.page-header { margin-bottom: 2rem; }
.page-header h1 {
font-family: 'DM Serif Display', serif; font-size: 3rem;
background: linear-gradient(135deg, var(--text) 30%, var(--muted));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.page-header p { color: var(--muted); margin-top: .4rem; }
/* ── Auth page specifics ──────────────────────────────────── */
.auth-wrap {
display: flex; flex-direction: column; align-items: center;
justify-content: center; min-height: calc(100vh - 60px);
padding: 2rem 1.5rem;
}
.auth-logo {
font-family: 'DM Serif Display', serif; font-size: 2.8rem; text-align: center;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
margin-bottom: 2rem;
}
.auth-logo span { display: block; font-size: 3rem; opacity: .7;
font-family: 'DM Sans', sans-serif; font-weight: 400;
-webkit-text-fill-color: var(--muted); }
</style>
{% block head %}{% endblock %}
</head>
<body>
<div class="blob blob-1"></div>
<div class="blob blob-2"></div>
{% if session.username %}
<nav>
<a class="nav-logo" href="{{ url_for('predict') }}">🌸 IrisAI</a>
<div class="nav-links">
<span class="nav-badge">{{ session.username }}</span>
<a href="{{ url_for('predict') }}">Predict</a>
{% if session.username == 'admin' %}
<a href="{{ url_for('admin') }}" style="color:var(--accent)">βš™ Admin</a>
{% endif %}
<a href="{{ url_for('logout') }}">Logout</a>
</div>
</nav>
{% endif %}
{% block body %}{% endblock %}
</body>
</html>