commit bedb9995d7f77ae2da68545809b30b2f395b6f58
Author: Ondřej Váně <onry.vane@gmail.com>
Date:   Sun Apr 12 15:41:17 2020 +0200

    Re #7817: Responzivní navigační lišta
    
    - přidána responzivního chování pro navigační lištu
    - přidán boční navigační panel

diff --git a/fe/fulltextsearch/src/app/app.component.html b/fe/fulltextsearch/src/app/app.component.html
index ef92397..9593ca7 100644
--- a/fe/fulltextsearch/src/app/app.component.html
+++ b/fe/fulltextsearch/src/app/app.component.html
@@ -1,4 +1,4 @@
 <div>
-  <app-header></app-header>
+  <app-main-nav></app-main-nav>
   <router-outlet></router-outlet>
 </div>
diff --git a/fe/fulltextsearch/src/app/app.module.ts b/fe/fulltextsearch/src/app/app.module.ts
index 1cf1bea..47ab504 100644
--- a/fe/fulltextsearch/src/app/app.module.ts
+++ b/fe/fulltextsearch/src/app/app.module.ts
@@ -6,7 +6,6 @@ import { AppRoutingModule } from './app-routing.module';
 import { AppComponent } from './app.component';
 import { FormsModule } from '@angular/forms';
 import { HomeComponent } from './components/pages/home/home.component';
-import { HeaderComponent } from './components/layout/header/header.component';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { MatToolbarModule } from '@angular/material/toolbar';
 import { MatButtonModule } from '@angular/material/button';
@@ -22,15 +21,18 @@ import { TableComponent } from './components/pages/browse/table/table.component'
 import { MatTableModule } from '@angular/material/table';
 import { MatPaginatorModule } from '@angular/material/paginator';
 import { MatSortModule } from '@angular/material/sort';
-import {MatDialogModule} from '@angular/material/dialog';
+import { MatDialogModule } from '@angular/material/dialog';
 import { AboutDialogComponent } from './components/shared-components/about-dialog/about-dialog.component';
 import { SearchPaginatorComponent } from './components/pages/search/search-paginator/search-paginator.component';
+import { MainNavComponent } from './components/layout/main-nav/main-nav.component';
+import { LayoutModule } from '@angular/cdk/layout';
+import { MatSidenavModule } from '@angular/material/sidenav';
+import { MatListModule } from '@angular/material/list';
 
 @NgModule({
   declarations: [
     AppComponent,
     HomeComponent,
-    HeaderComponent,
     SearchComponent,
     BrowseComponent,
     UploadComponent,
@@ -38,7 +40,8 @@ import { SearchPaginatorComponent } from './components/pages/search/search-pagin
     SearchBoxComponent,
     TableComponent,
     AboutDialogComponent,
-    SearchPaginatorComponent
+    SearchPaginatorComponent,
+    MainNavComponent,
   ],
   imports: [
     BrowserModule,
@@ -54,7 +57,10 @@ import { SearchPaginatorComponent } from './components/pages/search/search-pagin
     MatTableModule,
     MatPaginatorModule,
     MatSortModule,
-    MatDialogModule
+    MatDialogModule,
+    LayoutModule,
+    MatSidenavModule,
+    MatListModule
   ],
   providers: [],
   bootstrap: [AppComponent]
diff --git a/fe/fulltextsearch/src/app/components/layout/header/header.component.css b/fe/fulltextsearch/src/app/components/layout/header/header.component.css
deleted file mode 100644
index 218f5ec..0000000
--- a/fe/fulltextsearch/src/app/components/layout/header/header.component.css
+++ /dev/null
@@ -1,46 +0,0 @@
-.space {
-  flex: 1 1 auto;
-}
-
-a:hover {
-  color: var(--navbar-text-color);
-  background-color: var(--primary-color-dark);
-}
-
-a {
-  font-weight: bold;
-  font-size: large;
-  color: var(--navbar-text-color);
-}
-
-.app-header {
-  position: sticky;
-  position: -webkit-sticky;
-  top: 0;
-  z-index: 1000;
-  background-color: var(--primary-color);
-}
-
-.app-logo {
-  color: var(--navbar-text-color);
-  margin-right: 10pt;
-  padding: 5pt 8pt 5pt 5pt;
-}
-
-.app-logo:hover {
-  cursor: pointer;
-  background-color: var(--primary-color-dark);
-}
-
-.app-logo div {
-  margin-left: 15pt;
-  margin-top: 5pt;
-  text-align: center;
-  font-size: medium;
-  font-weight: bold;
-  line-height: normal;
-}
-
-mat-icon {
-  font-size: 40pt;
-}
diff --git a/fe/fulltextsearch/src/app/components/layout/header/header.component.html b/fe/fulltextsearch/src/app/components/layout/header/header.component.html
deleted file mode 100644
index 6375f44..0000000
--- a/fe/fulltextsearch/src/app/components/layout/header/header.component.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<mat-toolbar class="mat-elevation-z8 app-header">
-  <!-- app logo -->
-  <div class="app-logo" routerLink="" style="outline: none">
-    <span style="display: flex;">
-      <mat-icon>search</mat-icon>
-      <div>FULL TEXT SEARCH<br> APPLICATION</div>
-      </span>
-  </div>
-  <!-- left navigation items -->
-  <a mat-button class="noHover active" routerLink="search">Search</a>
-  <a mat-button routerLink="browse">Browse</a>
-  <a mat-button routerLink="upload">Upload</a>
-  <!-- navigation items space -->
-  <div class="space"></div>
-  <!-- right navigation items -->
-  <a mat-button (click)="openAboutDialog()">About</a>
-  <a mat-button routerLink="help">Help</a>
-  <a mat-button>EN</a>
-</mat-toolbar>
diff --git a/fe/fulltextsearch/src/app/components/layout/header/header.component.spec.ts b/fe/fulltextsearch/src/app/components/layout/header/header.component.spec.ts
deleted file mode 100644
index 2d0479d..0000000
--- a/fe/fulltextsearch/src/app/components/layout/header/header.component.spec.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { HeaderComponent } from './header.component';
-
-describe('HeaderComponent', () => {
-  let component: HeaderComponent;
-  let fixture: ComponentFixture<HeaderComponent>;
-
-  beforeEach(async(() => {
-    TestBed.configureTestingModule({
-      declarations: [ HeaderComponent ]
-    })
-    .compileComponents();
-  }));
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(HeaderComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/fe/fulltextsearch/src/app/components/layout/header/header.component.ts b/fe/fulltextsearch/src/app/components/layout/header/header.component.ts
deleted file mode 100644
index 4303f20..0000000
--- a/fe/fulltextsearch/src/app/components/layout/header/header.component.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { MatDialog } from '@angular/material/dialog';
-import { AboutDialogComponent } from '../../shared-components/about-dialog/about-dialog.component';
-
-@Component({
-  selector: 'app-header',
-  templateUrl: './header.component.html',
-  styleUrls: ['./header.component.css']
-})
-export class HeaderComponent implements OnInit {
-
-  constructor( public dialog: MatDialog ) { }
-
-  ngOnInit() {
-  }
-
-  openAboutDialog() {
-    this.dialog.open(AboutDialogComponent, { panelClass: 'custom-dialog-container' });
-  }
-
-}
diff --git a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.css b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.css
new file mode 100644
index 0000000..25a3859
--- /dev/null
+++ b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.css
@@ -0,0 +1,97 @@
+.sidenav-container {
+  height: 100%;
+}
+
+.sidenav {
+  width: 200px;
+}
+
+.sidenav .mat-toolbar {
+  background: var(--primary-color);
+  color: var(--navbar-text-color);
+
+}
+
+.mat-toolbar.mat-primary {
+  position: sticky;
+  top: 0;
+  z-index: 10;
+}
+
+.hidden {
+  display: none;
+}
+
+.space {
+  flex: 1 1 auto;
+}
+
+a:hover {
+  color: var(--navbar-text-color);
+  background-color: var(--primary-color-dark);
+}
+
+a {
+  font-weight: bold;
+  font-size: large;
+  color: var(--navbar-text-color);
+}
+
+.app-header {
+  position: sticky;
+  position: -webkit-sticky;
+  top: 0;
+}
+
+.app-logo {
+  color: var(--navbar-text-color);
+  margin-right: 10pt;
+  padding: 5pt 8pt 5pt 5pt;
+}
+
+.app-logo:hover {
+  cursor: pointer;
+  background-color: var(--primary-color-dark);
+}
+
+.app-logo div {
+  margin-left: 15pt;
+  margin-top: 5pt;
+  text-align: center;
+  font-size: medium;
+  font-weight: bold;
+  line-height: normal;
+}
+
+.app-logo mat-icon {
+  font-size: 40pt;
+}
+
+mat-nav-list mat-icon {
+  margin-right: 10px;
+}
+
+mat-nav-list a:hover {
+  color: #932523;
+}
+
+.position-fixed {
+  position: fixed
+}
+
+mat-sidenav-content {
+  margin-top: 64px;
+}
+
+
+mat-toolbar.mat-primary {
+  background-color: var(--primary-color);
+}
+
+.mat-drawer-backdrop {
+  height: 100%;
+}
+
+mat-sidenav-content {
+  margin-top: 56px;
+}
diff --git a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.html b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.html
new file mode 100644
index 0000000..71a729b
--- /dev/null
+++ b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.html
@@ -0,0 +1,62 @@
+<mat-sidenav-container class="sidenav-container">
+  <mat-sidenav #drawer class="sidenav position-fixed" fixedInViewport
+               [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
+               [mode]="(isHandset$ | async) ? 'over' : 'side'"
+               [opened]="(isHandset$ | async) === false"
+               [ngClass]="{hidden: !(isHandset$ | async)}">
+    <mat-toolbar>Menu</mat-toolbar>
+    <mat-nav-list (click)="drawer.close()">
+      <a mat-list-item routerLink="">
+        <mat-icon>home</mat-icon>
+        Home</a>
+      <a mat-list-item routerLink="search">
+        <mat-icon>search</mat-icon>
+        Search</a>
+      <a mat-list-item routerLink="browse">
+        <mat-icon>list</mat-icon>
+        Browse</a>
+      <a mat-list-item routerLink="upload">
+        <mat-icon>backup</mat-icon>
+        Upload</a>
+      <a mat-list-item (click)="openAboutDialog()">
+        <mat-icon>info</mat-icon>
+        About</a>
+      <a mat-list-item routerLink="help">
+        <mat-icon>help</mat-icon>
+        Help</a>
+      <a mat-list-item>
+        <mat-icon>translate</mat-icon>
+        EN</a>
+    </mat-nav-list>
+  </mat-sidenav>
+  <mat-sidenav-content>
+    <mat-toolbar color="primary" class="position-fixed">
+      <button
+        type="button"
+        aria-label="Toggle sidenav"
+        mat-icon-button
+        (click)="drawer.toggle()"
+        *ngIf="isHandset$ | async">
+        <mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
+      </button>
+      <!-- app logo -->
+      <div class="app-logo" routerLink="" style="outline: none">
+        <span style="display: flex;">
+        <mat-icon>search</mat-icon>
+        <div>FULL TEXT SEARCH<br> APPLICATION</div>
+      </span>
+      </div>
+      <!-- left navigation items -->
+      <a mat-button class="noHover active" routerLink="search" *ngIf="!(isHandset$ | async)">Search</a>
+      <a mat-button routerLink="browse" *ngIf="!(isHandset$ | async)">Browse</a>
+      <a mat-button routerLink="upload" *ngIf="!(isHandset$ | async)">Upload</a>
+      <!-- navigation items space -->
+      <div class="space" *ngIf="!(isHandset$ | async)"></div>
+      <!-- right navigation items -->
+      <a mat-button (click)="openAboutDialog()" *ngIf="!(isHandset$ | async)">About</a>
+      <a mat-button routerLink="help" *ngIf="!(isHandset$ | async)">Help</a>
+      <a mat-button *ngIf="!(isHandset$ | async)">EN</a>
+    </mat-toolbar>
+    <ng-content></ng-content>
+  </mat-sidenav-content>
+</mat-sidenav-container>
diff --git a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.spec.ts b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.spec.ts
new file mode 100644
index 0000000..0e4aa5b
--- /dev/null
+++ b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.spec.ts
@@ -0,0 +1,40 @@
+import { LayoutModule } from '@angular/cdk/layout';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { MatButtonModule } from '@angular/material/button';
+import { MatIconModule } from '@angular/material/icon';
+import { MatListModule } from '@angular/material/list';
+import { MatSidenavModule } from '@angular/material/sidenav';
+import { MatToolbarModule } from '@angular/material/toolbar';
+
+import { MainNavComponent } from './main-nav.component';
+
+describe('MainNavComponent', () => {
+  let component: MainNavComponent;
+  let fixture: ComponentFixture<MainNavComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [MainNavComponent],
+      imports: [
+        NoopAnimationsModule,
+        LayoutModule,
+        MatButtonModule,
+        MatIconModule,
+        MatListModule,
+        MatSidenavModule,
+        MatToolbarModule,
+      ]
+    }).compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MainNavComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should compile', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.ts b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.ts
new file mode 100644
index 0000000..2e0cdcc
--- /dev/null
+++ b/fe/fulltextsearch/src/app/components/layout/main-nav/main-nav.component.ts
@@ -0,0 +1,27 @@
+import { Component } from '@angular/core';
+import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
+import { Observable } from 'rxjs';
+import { map, shareReplay } from 'rxjs/operators';
+import { AboutDialogComponent } from '../../shared-components/about-dialog/about-dialog.component';
+import {MatDialog} from '@angular/material/dialog';
+
+@Component({
+  selector: 'app-main-nav',
+  templateUrl: './main-nav.component.html',
+  styleUrls: ['./main-nav.component.css']
+})
+export class MainNavComponent {
+
+  isHandset$: Observable<boolean> = this.breakpointObserver.observe(Breakpoints.Handset)
+    .pipe(
+      map(result => result.matches),
+      shareReplay()
+    );
+
+  constructor(private breakpointObserver: BreakpointObserver, public dialog: MatDialog) {}
+
+  openAboutDialog() {
+    this.dialog.open(AboutDialogComponent, { panelClass: 'custom-dialog-container' });
+  }
+
+}
diff --git a/fe/fulltextsearch/src/styles.css b/fe/fulltextsearch/src/styles.css
index 5c668a0..73d01c9 100644
--- a/fe/fulltextsearch/src/styles.css
+++ b/fe/fulltextsearch/src/styles.css
@@ -1,3 +1,12 @@
+
+body {
+  height: 100% !important;
+}
+
+.mat-drawer-backdrop {
+  position: fixed !important;
+}
+
 /* styles for our custom dialog */
 .custom-dialog-container .mat-dialog-container {
   padding: 0;
