Pārlūkot izejas kodu

Angular: horizontal site layout; marked active nav item

Christian Kahlau 3 gadi atpakaļ
vecāks
revīzija
d2d4251728

+ 19 - 19
ng/src/app/app.component.html

@@ -1,41 +1,41 @@
 <app-header></app-header>
 
-<div class="container pt-5 d-flex flex-row">
-  <ul class="nav flex-column">
-    <li>
-      <div class="card" style="min-width: 200px">
+<div class="container pt-5">
+  <ul class="nav flex-row">
+    <li class="flex-fill">
+      <div class="card h-100">
         <div class="card-header btn btn-toolbar bg-primary text-light" routerLink="/">
           <fa-icon [icon]="fa.faChalkboard" class="pe-2"></fa-icon>
           <span class="flex-fill text-start">Dashboard</span>
-          <fa-icon [icon]="fa.faAngleRight"></fa-icon>
+          <fa-icon [class.hidden]="currentUrl !== '/'" [icon]="fa.faAngleDown" class="ps-2"></fa-icon>
         </div>
+        <div class="card-body p-1">- soon come -</div>
       </div>
     </li>
-    <li *ngFor="let server of serverConfigs">
-      <div class="card">
+    <li *ngFor="let server of serverConfigs" class="flex-fill">
+      <div class="card h-100">
         <div class="card-header btn btn-toolbar bg-primary text-light" [routerLink]="'/srv/' + server.id">
           <fa-icon [icon]="fa.faServer" class="pe-2"></fa-icon>
           <span class="flex-fill text-start">{{ server.title }}</span>
-          <fa-icon [icon]="fa.faAngleRight" class="caret-rotate"></fa-icon>
+          <fa-icon [class.hidden]="currentUrl !== '/srv/' + server.id" [icon]="fa.faAngleDown" class="ps-2"></fa-icon>
         </div>
-        <div class="card-body" aria-expanded="true">
-          <h5 class="border-bottom pb-2">Server metrics:</h5>
-          <ul class="nav flex-column">
-            <li *ngFor="let type of server.types" class="nav-item list-unstyled">
-              <fa-icon [icon]="type.type | faType" class="pe-2"></fa-icon>{{ type.type }}
-              <ul *ngIf="type.subtypes?.length" class="nav flex-column ps-4">
-                <li *ngFor="let sub of type.subtypes" class="nav-item list-unstyled">
-                  <fa-icon [icon]="type.type | faType" class="pe-2"></fa-icon>{{ sub.type }}
+        <div class="card-body p-1" aria-expanded="true">
+          <div *ngFor="let type of server.types" class="badge bg-primary me-1">
+            <div class="d-flex flex-column">
+              <div class="d-flex flex-row text-uppercase"><fa-icon [icon]="type.type | faType" class="pe-2 status-ok"></fa-icon>{{ type.type }}</div>
+              <ul *ngIf="type.subtypes" class="list-unstyled text-start subtypes-list">
+                <li *ngFor="let sub of type.subtypes" class="status-ok">
+                  {{ sub.type }}
                 </li>
               </ul>
-            </li>
-          </ul>
+            </div>
+          </div>
         </div>
       </div>
     </li>
   </ul>
 
-  <div class="flex-fill ps-3">
+  <div class="pt-3">
     <router-outlet></router-outlet>
   </div>
 </div>

+ 38 - 0
ng/src/app/app.component.scss

@@ -0,0 +1,38 @@
+ul.nav {
+  .hidden {
+    visibility: hidden;
+  }
+
+  fa-icon {
+    &.status-ok {
+      color: var(--bs-light);
+    }
+    &.status-warn {
+      color: var(--bs-warning);
+    }
+    &.status-error {
+      color: var(--bs-danger);
+    }
+  }
+
+  .list-unstyled.subtypes-list {
+    padding-left: 0;
+
+    li::before {
+      content: '\25cf'; // ●
+      font-size: larger;
+    }
+
+    li.status-ok::before {
+      color: var(--bs-light);
+    }
+
+    li.status-warn::before {
+      color: var(--bs-warning);
+    }
+
+    li.status-error::before {
+      color: var(--bs-danger);
+    }
+  }
+}

+ 15 - 5
ng/src/app/app.component.ts

@@ -1,8 +1,9 @@
 import { Component, OnInit } from '@angular/core';
-import { Subscription } from 'rxjs';
-import { ServerApiService } from './services/server-api.service';
-
+import { ActivationEnd, Router } from '@angular/router';
 import { faAngleDown, faAngleRight, faChalkboard, faServer } from '@fortawesome/free-solid-svg-icons';
+import { filter, Subscription } from 'rxjs';
+
+import { ServerApiService } from './services/server-api.service';
 
 @Component({
   selector: 'app-root',
@@ -15,8 +16,17 @@ export class AppComponent implements OnInit {
   public fa = { faAngleDown, faAngleRight, faChalkboard, faServer };
   public serverConfigs: ServerConfig[] = [];
 
-  constructor(private apiService: ServerApiService) {
-    this.subscriptions.push(this.apiService.serverConfigs$.subscribe({ next: this.onServerConfigs.bind(this) }));
+  public currentUrl: string = '/';
+
+  constructor(private apiService: ServerApiService, router: Router) {
+    this.subscriptions.push(
+      this.apiService.serverConfigs$.subscribe({ next: this.onServerConfigs.bind(this) }),
+      router.events.pipe(filter(e => e instanceof ActivationEnd)).subscribe({
+        next: e => {
+          this.currentUrl = '/' + (e as ActivationEnd).snapshot.url.map(seg => seg.path).join('/');
+        }
+      })
+    );
   }
 
   async ngOnInit() {

+ 8 - 1
ng/src/app/services/server-api.service.ts

@@ -4,6 +4,12 @@ import { firstValueFrom, map, ReplaySubject } from 'rxjs';
 import { environment } from 'src/environments/environment';
 import { IndexedReplaySubject } from '../lib/indexed-subject.class';
 
+const sortPriorities: { [k: string]: number } = {
+  cpu: 0,
+  ram: 1,
+  hdd: 2
+};
+
 @Injectable({
   providedIn: 'root'
 })
@@ -23,11 +29,12 @@ export class ServerApiService {
 
   public async getServerDataTypes(serverID: number) {
     const types = await firstValueFrom(this.http.get<ServerDataTypesConfig[]>(`${environment.apiBaseUrl}server/${serverID}/data/types`));
+    types.sort((a, b) => (sortPriorities[a.type] ?? 99) - (sortPriorities[b.type] ?? 99));
+
     const server = this.servers.find(s => s.id === serverID);
     if (server) server.types = types;
 
     this.serverDataTypes$.get(serverID).next(types);
-
     return types;
   }