restyled the login page

This commit is contained in:
Fabio Formosa
2026-05-13 22:48:56 +02:00
parent 93990a5994
commit 699e661d81
2 changed files with 287 additions and 51 deletions

View File

@@ -1,36 +1,63 @@
<div
class="content flex flex-row justify-center"
style="padding-bottom: 160px">
<mat-card elevation="5" class="flex-1">
<mat-card-subtitle>
<h2>Quartz Manager</h2>
</mat-card-subtitle>
<section class="login-shell">
<div class="login-hero" aria-hidden="true">
<div class="brand">
<span class="brand-mark">QM</span>
<div>
<h1>Quartz Manager</h1>
<p>Scheduler operations console</p>
</div>
</div>
<mat-card-title>
<h2>{{ title }}</h2>
</mat-card-title>
<div class="hero-card">
<span class="card-title">Operational View</span>
<div class="status-row">
<span class="pulse"></span>
<span>Jobs, triggers, logs and live execution state</span>
</div>
<div class="metric-grid">
<div>
<strong>01</strong>
<span>Secure entry</span>
</div>
<div>
<strong>24/7</strong>
<span>Runtime visibility</span>
</div>
</div>
</div>
</div>
<mat-card class="login-card">
<mat-card-content>
<div class="form-header">
<span class="eyebrow">Welcome back</span>
<h2>{{ title }}</h2>
<p>Sign in to manage scheduler activity and inspect runtime signals.</p>
</div>
@if (notification) {
<p [class]="notification.msgType">{{ notification.msgBody }}</p>
<p class="notification {{ notification.msgType }}">{{ notification.msgBody }}</p>
} @if (!submitted) {
<form [formGroup]="form" (ngSubmit)="onSubmit()" #loginForm="ngForm">
<mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Username</mat-label>
<input
matInput
formControlName="username"
required
placeholder="user" />
autocomplete="username" />
</mat-form-field>
<mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Password</mat-label>
<input
matInput
formControlName="password"
required
type="password"
placeholder="password" />
autocomplete="current-password" />
</mat-form-field>
<button
class="login-button"
type="submit"
[disabled]="!loginForm.form.valid"
mat-raised-button
@@ -39,8 +66,11 @@
</button>
</form>
} @if (submitted) {
<mat-spinner mode="indeterminate"></mat-spinner>
<div class="loading-state">
<mat-spinner mode="indeterminate"></mat-spinner>
<span>Checking credentials...</span>
</div>
}
</mat-card-content>
</mat-card>
</div>
</section>

View File

@@ -1,62 +1,268 @@
:host {
--bg: oklch(98% 0.005 250);
--surface: oklch(100% 0 0);
--fg: oklch(22% 0.02 240);
--muted: oklch(50% 0.018 240);
--border: oklch(90% 0.008 240);
--accent: oklch(56% 0.19 302);
--success: oklch(58% 0.16 145);
--danger: oklch(58% 0.19 28);
--radius: 8px;
display: block;
flex: 1;
color: var(--fg);
font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', system-ui, sans-serif;
}
.content {
* {
box-sizing: border-box;
}
.login-shell {
width: 100%;
min-height: min(680px, calc(100vh - 170px));
display: grid;
grid-template-columns: minmax(280px, 0.9fr) minmax(320px, 430px);
gap: 20px;
align-items: stretch;
padding: 18px;
border: 1px solid var(--border);
border-radius: 14px;
background:
radial-gradient(circle at top left, oklch(56% 0.19 302 / 0.16), transparent 34%),
var(--bg);
animation: fadein 1s;
-o-animation: fadein 1s;
-moz-animation: fadein 1s;
-webkit-animation: fadein 1s;
}
.login-hero {
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 430px;
padding: 24px;
border: 1px solid var(--border);
border-radius: 12px;
background:
linear-gradient(145deg, oklch(99% 0.003 250 / 0.92), oklch(95% 0.018 285 / 0.92)),
var(--surface);
}
.login-hero::after {
content: "";
position: absolute;
inset: auto -80px -95px auto;
width: 260px;
height: 260px;
border-radius: 999px;
background: oklch(56% 0.19 302 / 0.13);
}
.brand {
position: relative;
z-index: 1;
display: flex;
align-items: center;
gap: 12px;
}
.brand-mark {
width: 42px;
height: 42px;
display: grid;
place-items: center;
border-radius: 9px;
background: var(--accent);
color: white;
font-family: 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, Menlo, monospace;
font-size: 13px;
font-weight: 800;
}
h1,
h2,
p {
margin: 0;
}
h1 {
font-size: 21px;
line-height: 1.1;
}
.brand p,
.form-header p,
.status-row,
.metric-grid span,
.loading-state span {
color: var(--muted);
}
.hero-card {
position: relative;
z-index: 1;
display: grid;
gap: 18px;
max-width: 440px;
padding: 18px;
border: 1px solid var(--border);
border-radius: var(--radius);
background: oklch(100% 0 0 / 0.78);
box-shadow: 0 22px 60px oklch(22% 0.02 240 / 0.10);
backdrop-filter: blur(12px);
}
.card-title,
.eyebrow,
.metric-grid strong {
font-family: 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, Menlo, monospace;
}
.card-title,
.eyebrow {
font-size: 12px;
font-weight: 800;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--muted);
}
.status-row {
display: flex;
align-items: center;
gap: 9px;
line-height: 1.45;
}
.pulse {
width: 10px;
height: 10px;
flex: 0 0 auto;
border-radius: 999px;
background: var(--success);
box-shadow: 0 0 0 6px oklch(58% 0.16 145 / 0.12);
}
.metric-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.metric-grid div {
display: grid;
gap: 5px;
padding: 12px;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--surface);
}
.metric-grid strong {
font-size: 24px;
line-height: 1;
}
.login-card {
align-self: center;
width: 100%;
border: 1px solid var(--border);
border-radius: 12px;
background: var(--surface);
box-shadow: 0 24px 70px oklch(22% 0.02 240 / 0.14);
}
.login-card mat-card-content {
display: grid;
gap: 22px;
padding: 30px;
}
.form-header {
display: grid;
gap: 8px;
}
.form-header h2 {
font-size: 28px;
line-height: 1.05;
}
.form-header p {
line-height: 1.45;
}
form {
display: grid;
gap: 12px;
}
mat-form-field,
.login-button {
width: 100%;
}
mat-card {
max-width: 350px;
text-align: center;
animation: fadein 1s;
-o-animation: fadein 1s; /* Opera */
-moz-animation: fadein 1s; /* Firefox */
-webkit-animation: fadein 1s; /* Safari and Chrome */
}
mat-form-field {
display: block;
.login-button {
min-height: 44px;
border-radius: 7px;
font-weight: 700;
}
mat-spinner {
width: 25px;
height: 25px;
margin: 20px auto 0 auto;
}
button {
display: block;
width: 100%;
.loading-state {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
min-height: 128px;
font-size: 13px;
}
.notification {
margin: 0;
padding: 12px 14px;
border-radius: var(--radius);
line-height: 1.4;
}
.error {
color: #D50000;
border: 1px solid oklch(58% 0.19 28 / 0.30);
background: oklch(98% 0.02 28);
color: var(--danger);
}
.success {
color: #8BC34A;
border: 1px solid oklch(58% 0.16 145 / 0.30);
background: oklch(98% 0.02 145);
color: var(--success);
}
@media screen and (max-width: 599px) {
.content {
/* https://github.com/angular/flex-layout/issues/295 */
display: block !important;
@media screen and (max-width: 760px) {
.login-shell {
grid-template-columns: 1fr;
min-height: auto;
padding: 12px;
}
mat-card {
/* https://github.com/angular/flex-layout/issues/295 */
display: block !important;
max-width: 999px;
.login-hero {
min-height: auto;
gap: 24px;
padding: 18px;
}
}
.login-card mat-card-content {
padding: 24px 20px;
}
a {
text-decoration: none;
cursor: auto;
color: #FFFFFF;
.form-header h2 {
font-size: 25px;
}
}