improved dashboard

This commit is contained in:
Bojan Kucera 2025-06-02 20:31:22 -04:00
parent 114c280734
commit 90168ba619
8 changed files with 781 additions and 47 deletions

View file

@ -1,18 +1,67 @@
<!-- Trading Dashboard App -->
<div class="min-h-screen bg-gray-50">
<app-sidebar></app-sidebar>
<main class="main-content">
<router-outlet></router-outlet>
</main>
<div class="app-layout">
<!-- Sidebar -->
<app-sidebar [opened]="sidenavOpened()" (navigationItemClick)="onNavigationClick($event)"></app-sidebar>
<!-- Main Content Area -->
<div class="main-content" [class.main-content-closed]="!sidenavOpened()">
<!-- Top Navigation Bar -->
<mat-toolbar class="top-toolbar">
<button mat-icon-button (click)="toggleSidenav()" class="mr-2">
<mat-icon>menu</mat-icon>
</button>
<span class="text-lg font-semibold text-gray-800">{{ title }}</span>
<span class="spacer"></span>
<button mat-icon-button>
<mat-icon>notifications</mat-icon>
</button>
<button mat-icon-button>
<mat-icon>account_circle</mat-icon>
</button>
</mat-toolbar>
<!-- Page Content -->
<div class="page-content">
<router-outlet></router-outlet>
</div>
</div>
</div>
<style>
.app-layout {
display: flex;
height: 100vh;
background-color: #f9fafb;
}
.main-content {
margin-left: 256px; /* Width of sidebar (w-64 = 16rem = 256px) */
min-height: 100vh;
flex: 1;
display: flex;
flex-direction: column;
margin-left: 256px; /* Width of sidebar */
transition: margin-left 0.3s ease;
}
.main-content-closed {
margin-left: 0;
}
.top-toolbar {
background-color: white;
border-bottom: 1px solid #e5e7eb;
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
}
.spacer {
flex: 1;
}
.page-content {
flex: 1;
padding: 1.5rem;
overflow-y: auto;
}
@media (max-width: 768px) {
.main-content {
margin-left: 0;

View file

@ -1,4 +1,22 @@
/* Sidebar specific styles */
.sidebar {
position: fixed;
top: 0;
left: 0;
width: 16rem; /* 256px */
height: 100vh;
background-color: white;
border-right: 1px solid #e5e7eb;
transform: translateX(0);
transition: transform 0.3s ease-in-out;
z-index: 1000;
overflow-y: auto;
}
.sidebar-closed {
transform: translateX(-100%);
}
.nav-button {
width: 100%;
text-align: left;

View file

@ -1,8 +1,5 @@
<mat-sidenav
[opened]="opened()"
mode="side"
class="w-64 bg-white border-r border-gray-200">
<!-- Sidebar Navigation -->
<aside class="sidebar" [class.sidebar-closed]="!opened()">
<!-- Logo/Brand -->
<div class="p-6 border-b border-gray-200">
<h2 class="text-xl font-bold text-gray-900">
@ -30,4 +27,4 @@
}
</div>
</nav>
</mat-sidenav>
</aside>

View file

@ -3,7 +3,8 @@ import { CommonModule } from '@angular/common';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { Router } from '@angular/router';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
export interface NavigationItem {
label: string;
@ -37,15 +38,24 @@ export class SidebarComponent {
{ label: 'Settings', icon: 'settings', route: '/settings' }
];
constructor(private router: Router) {}
constructor(private router: Router) {
// Listen to route changes to update active state
this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
this.updateActiveRoute(event.urlAfterRedirects);
});
}
onNavigationClick(route: string) {
this.navigationItemClick.emit(route);
this.router.navigate([route]);
// Update active state
this.updateActiveRoute(route);
}
private updateActiveRoute(currentRoute: string) {
this.navigationItems.forEach(item => {
item.active = item.route === route;
item.active = item.route === currentRoute;
});
}
}

View file

@ -34,10 +34,9 @@
</mat-card>
<mat-card class="p-6">
<div class="flex items-center justify-between">
<div>
<div class="flex items-center justify-between"> <div>
<p class="text-sm text-gray-600">Last Update</p>
<p class="text-lg font-semibold text-gray-900">{{ new Date().toLocaleTimeString() }}</p>
<p class="text-lg font-semibold text-gray-900">{{ currentTime() }}</p>
</div>
<mat-icon class="text-purple-600 text-3xl">access_time</mat-icon>
</div>

View file

@ -45,45 +45,52 @@ export class MarketDataComponent {
},
{
symbol: 'GOOGL',
price: 138.21,
change: -1.82,
changePercent: -1.30,
volume: 23450000,
marketCap: '1.75T',
high52Week: 152.10,
low52Week: 125.45
price: 2847.56,
change: -12.34,
changePercent: -0.43,
volume: 12450000,
marketCap: '1.78T',
high52Week: 3030.93,
low52Week: 2193.62
},
{
symbol: 'MSFT',
price: 378.85,
change: 4.12,
changePercent: 1.10,
volume: 34560000,
marketCap: '2.82T',
high52Week: 384.30,
price: 415.26,
change: 8.73,
changePercent: 2.15,
volume: 23180000,
marketCap: '3.08T',
high52Week: 468.35,
low52Week: 309.45
},
{
symbol: 'TSLA',
price: 248.42,
change: -3.21,
changePercent: -1.28,
volume: 67890000,
marketCap: '789B',
price: 248.50,
change: -5.21,
changePercent: -2.05,
volume: 89760000,
marketCap: '789.2B',
high52Week: 299.29,
low52Week: 138.80
low52Week: 152.37
},
{
symbol: 'AMZN',
price: 145.67,
change: 1.89,
changePercent: 1.31,
volume: 29340000,
marketCap: '1.52T',
high52Week: 155.20,
price: 152.74,
change: 3.18,
changePercent: 2.12,
volume: 34520000,
marketCap: '1.59T',
high52Week: 170.17,
low52Week: 118.35
}
]);
protected displayedColumns: string[] = ['symbol', 'price', 'change', 'changePercent', 'volume', 'marketCap'];
protected currentTime = signal<string>(new Date().toLocaleTimeString()); constructor() {
// Update time every second
setInterval(() => {
this.currentTime.set(new Date().toLocaleTimeString());
}, 1000);
}
}