frontend: redesign error page with enhanced layout, responsive design, and improved error handling
This commit is contained in:
parent
3ca68dae80
commit
0e4cfa5bb5
@ -1,10 +1,31 @@
|
||||
<div class="container">
|
||||
<mat-card class="card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ errorName }}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<p>{{ message }}</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<div class="error-page">
|
||||
<div class="error-container fade-in">
|
||||
<div class="error-content">
|
||||
<div class="error-icon-section">
|
||||
<mat-icon class="error-main-icon">error_outline</mat-icon>
|
||||
</div>
|
||||
|
||||
<div class="error-details">
|
||||
<h1 class="error-title">{{ errorName }}</h1>
|
||||
<p class="error-message">{{ message }}</p>
|
||||
</div>
|
||||
|
||||
<div class="error-actions">
|
||||
<button mat-flat-button color="primary" (click)="goBack()" class="action-button">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
Go Back
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="error-illustration">
|
||||
<div class="illustration-container">
|
||||
<mat-icon class="illustration-icon">cloud_off</mat-icon>
|
||||
<div class="illustration-text">
|
||||
<span class="illustration-title">Oops!</span>
|
||||
<span class="illustration-subtitle">Something went wrong</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,33 +1,220 @@
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
background-color: var(--ov-background-color);
|
||||
@import '../../../../../../src/assets/styles/design-tokens';
|
||||
|
||||
.error-page {
|
||||
@include ov-theme-transition;
|
||||
@include ov-flex-center;
|
||||
min-height: 100vh;
|
||||
background: var(--ov-meet-background-color);
|
||||
padding: var(--ov-meet-spacing-lg);
|
||||
|
||||
.error-container {
|
||||
@include ov-theme-transition;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: var(--ov-meet-spacing-xxl);
|
||||
max-width: 800px;
|
||||
width: 100%;
|
||||
|
||||
@include ov-tablet-down {
|
||||
flex-direction: column;
|
||||
gap: var(--ov-meet-spacing-xl);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ov-meet-spacing-lg);
|
||||
|
||||
.error-icon-section {
|
||||
@include ov-flex-center;
|
||||
justify-content: flex-start;
|
||||
|
||||
@include ov-tablet-down {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.error-main-icon {
|
||||
@include ov-icon(xl);
|
||||
color: var(--ov-meet-color-error);
|
||||
background: rgba(var(--ov-meet-color-error), 0.1);
|
||||
border-radius: var(--ov-meet-radius-circle);
|
||||
padding: var(--ov-meet-spacing-md);
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.error-details {
|
||||
.error-title {
|
||||
margin: 0 0 var(--ov-meet-spacing-sm) 0;
|
||||
font-size: var(--ov-meet-font-size-xxl);
|
||||
font-weight: var(--ov-meet-font-weight-semibold);
|
||||
color: var(--ov-meet-text-primary);
|
||||
line-height: var(--ov-meet-line-height-tight);
|
||||
|
||||
@include ov-mobile-down {
|
||||
font-size: var(--ov-meet-font-size-xl);
|
||||
}
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin: 0;
|
||||
font-size: var(--ov-meet-font-size-md);
|
||||
color: var(--ov-meet-text-secondary);
|
||||
line-height: var(--ov-meet-line-height-normal);
|
||||
max-width: 400px;
|
||||
|
||||
@include ov-tablet-down {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
@include ov-mobile-down {
|
||||
font-size: var(--ov-meet-font-size-sm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-actions {
|
||||
display: flex;
|
||||
gap: var(--ov-meet-spacing-md);
|
||||
margin-top: var(--ov-meet-spacing-md);
|
||||
|
||||
@include ov-tablet-down {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@include ov-mobile-down {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
@include ov-button-base;
|
||||
@include ov-flex-center;
|
||||
gap: var(--ov-meet-spacing-xs);
|
||||
min-width: 120px;
|
||||
|
||||
&.secondary {
|
||||
color: var(--ov-meet-text-secondary);
|
||||
border-color: var(--ov-meet-border-color);
|
||||
|
||||
&:hover {
|
||||
color: var(--ov-meet-text-primary);
|
||||
border-color: var(--ov-meet-text-primary);
|
||||
background: var(--ov-meet-surface-hover);
|
||||
}
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
@include ov-icon(sm);
|
||||
}
|
||||
|
||||
@include ov-mobile-down {
|
||||
min-width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-illustration {
|
||||
flex: 1;
|
||||
@include ov-flex-center;
|
||||
|
||||
@include ov-tablet-down {
|
||||
order: -1;
|
||||
}
|
||||
|
||||
.illustration-container {
|
||||
@include ov-flex-center;
|
||||
flex-direction: column;
|
||||
gap: var(--ov-meet-spacing-lg);
|
||||
opacity: 0.6;
|
||||
|
||||
.illustration-icon {
|
||||
font-size: 120px;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
color: var(--ov-meet-text-hint);
|
||||
|
||||
@include ov-mobile-down {
|
||||
font-size: 80px;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.illustration-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ov-meet-spacing-xs);
|
||||
text-align: center;
|
||||
|
||||
.illustration-title {
|
||||
font-size: var(--ov-meet-font-size-xl);
|
||||
font-weight: var(--ov-meet-font-weight-bold);
|
||||
color: var(--ov-meet-text-secondary);
|
||||
|
||||
@include ov-mobile-down {
|
||||
font-size: var(--ov-meet-font-size-lg);
|
||||
}
|
||||
}
|
||||
|
||||
.illustration-subtitle {
|
||||
font-size: var(--ov-meet-font-size-sm);
|
||||
color: var(--ov-meet-text-hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 400px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
background-color: var(--ov-surface-color);
|
||||
border-radius: var(--ov-surface-radius);
|
||||
// Animation states
|
||||
.fade-in {
|
||||
animation: fadeIn 0.6s ease-out forwards;
|
||||
}
|
||||
|
||||
mat-card-header {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// Enhanced responsive design
|
||||
@include ov-mobile-down {
|
||||
.error-page {
|
||||
padding: var(--ov-meet-spacing-md);
|
||||
|
||||
.error-container {
|
||||
.error-content {
|
||||
.error-details {
|
||||
.error-title {
|
||||
margin-bottom: var(--ov-meet-spacing-md);
|
||||
}
|
||||
}
|
||||
|
||||
.error-actions {
|
||||
margin-top: var(--ov-meet-spacing-lg);
|
||||
|
||||
.action-button {
|
||||
padding: var(--ov-meet-spacing-md) var(--ov-meet-spacing-lg);
|
||||
font-size: var(--ov-meet-font-size-md);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat-card-title {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
mat-card-content p {
|
||||
font-size: 1em;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
mat-card-actions {
|
||||
margin-top: 20px;
|
||||
// Dark theme enhancements
|
||||
[data-theme='dark'] {
|
||||
.error-page {
|
||||
.error-container {
|
||||
.error-content {
|
||||
.error-icon-section {
|
||||
.error-main-icon {
|
||||
background: rgba(var(--ov-meet-color-error), 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Location } from '@angular/common';
|
||||
import { ErrorReason } from '@lib/models';
|
||||
|
||||
@Component({
|
||||
selector: 'ov-error',
|
||||
standalone: true,
|
||||
imports: [MatCardModule],
|
||||
imports: [MatCardModule, MatIconModule, MatButtonModule],
|
||||
templateUrl: './error.component.html',
|
||||
styleUrl: './error.component.scss'
|
||||
})
|
||||
@ -14,7 +17,10 @@ export class ErrorComponent implements OnInit {
|
||||
errorName = 'Error';
|
||||
message = '';
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private location: Location
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams.subscribe((params) => {
|
||||
@ -64,4 +70,8 @@ export class ErrorComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
goBack(): void {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user