Skip to content
Snippets Groups Projects
Commit 212f4e9d authored by mathias.chouet's avatar mathias.chouet
Browse files

angular-material

navbar et sidenav fixes
navbar: les onglets s'écroulent en un menu déroulant
sidenav: ajout d'icônes
sidenav: ajout sauvegarde de session
parent a429750e
No related branches found
No related tags found
1 merge request!29Resolve "Remplacer mdbootstrap par angular-material"
......@@ -11,21 +11,43 @@
<a class="navbar-brand"></a>
<!-- calculators list as a dropdown menu-->
<div [hidden]="tabsFitInNavbar">
ICI LE SUPER SELECT DE LA MORT
<button *ngIf="currentCalc" mat-button [matMenuTriggerFor]="menu" color="primary" class="calculators-menu-title">
<mat-icon class="dropdown-icon">arrow_drop_down</mat-icon>
<span class="calc-name">
{{ currentCalc.title }}
</span>
<span class="calc-type" [innerHTML]="'( ' + currentCalc ? currentCalc.type : '' + ' )'"></span>
</button>
<mat-menu #menu="matMenu" colo="accent">
<button mat-menu-item *ngFor="let c of calculators" class="calculator-menu-item"
[routerLink]="['/calculator/',c.uid]" [color]="c.active ? '' : 'primary'" [class.active]="c.active"
(click)="setActiveCalc(c.uid)">
<span class="calc-name">
{{ c.title }}
</span>
<span class="calc-type" [innerHTML]="'( ' + c.type + ' )'"></span>
</button>
</mat-menu>
</div>
<!-- calculators list as a tabs bar-->
<div id="tabs-container" [hidden]="! tabsFitInNavbar">
<button mat-raised-button color="primary" *ngFor="let c of calculators" class="calculator-button"
[routerLink]="['/calculator/',c.uid]" [color]="c.active ? '' : 'primary'" [class.active]="c.active"
(click)="setActiveCalc(c.uid)" [title]="'uid: ' + c.uid">
(click)="setActiveCalc(c.uid)">
<span class="calc-name">
{{ c.title }}
</span>
<span class="calc-type" [innerHTML]="'( ' + c.type + ' )'"></span>
</button>
<!-- <i id="new-calculator" class="fa fa-plus-square fa-2x" style='vertical-align: middle' routerLink="/list" (click)='sidenav.close()'></i> -->
</div>
<button mat-icon-button id="new-calculator" routerLink="/list" (click)="sidenav.close()">
<mat-icon>add_box</mat-icon>
</button>
......@@ -40,10 +62,27 @@
<mat-sidenav class="sidenav" #sidenav fxLayout="column" >
<div fxLayout="column">
<a id="close-side-nav" class="closebtn" (click)="sidenav.close()">×</a>
<a id="side-nav-list" routerLink="/list" (click)="sidenav.close()">{{ uitextSidenavNewCalc }}</a>
<a id="side-nav-load-session" (click)="loadSession()">{{ uitextSidenavLoadSession }}</a>
<a id="side-nav-setup" routerLink="/setup" (click)="sidenav.close()">{{ uitextSidenavParams }}</a>
<a id="side-nav-help" target="_blank" href="assets/docs-fr/" (click)="sidenav.close()">{{ uitextSidenavHelp }}</a>
<a id="side-nav-list" routerLink="/list" (click)="sidenav.close()">
<mat-icon>add</mat-icon>
{{ uitextSidenavNewCalc }}
</a>
<a id="side-nav-load-session" (click)="loadSession(); sidenav.close()">
<mat-icon>folder_open</mat-icon>
{{ uitextSidenavLoadSession }}
</a>
<a id="side-nav-save-session" (click)="saveForm(); sidenav.close()">
<mat-icon>save_alt</mat-icon>
{{ uitextSidenavSaveSession }}
</a>
<a id="side-nav-setup" routerLink="/setup" (click)="sidenav.close()">
<mat-icon>settings</mat-icon>
{{ uitextSidenavParams }}
</a>
<a id="side-nav-help" target="_blank" href="assets/docs-fr/" (click)="sidenav.close()">
<mat-icon>help</mat-icon>
{{ uitextSidenavHelp }}
</a>
<div class="hyd_version">
JaLHyd version: {{ getDateRevision()[0] }}<br/>
......@@ -52,7 +91,7 @@
</div>
</mat-sidenav>
<mat-sidenav-content fxFlexFill>
<mat-sidenav-content class="sidenav-content" fxFlexFill>
<!-- chargement des calculettes -->
<div appLoadCalcDialogAnchor></div>
......
// variables
$navbar_height: 54px;
// rules
.dropdown-menu > li > a:hover {
background-color: rgb(172, 172, 172);
background-image: none;
......@@ -8,7 +14,9 @@ button:focus {
}
#main-toolbar {
height: 54px;
position: fixed;
height: $navbar_height;
z-index: 200;
}
#open-menu mat-icon, #new-calculator mat-icon {
......@@ -30,28 +38,88 @@ button:focus {
}
.calculator-button {
width: 11%; /* 8 tabs */
/*width: 11%; // 8 tabs
@media screen and (max-width: 1200px) {
width: 14.5%; // 6 tabs
}*/
width: 15.8%; // 6 larger tabs
@media screen and (max-width: 1200px) {
width: 14%; /* 6 tabs */
width: 14.5%; // 6 tabs
}
@media screen and (max-width: 800px) {
width: 21%; /* 4 tabs */
width: 21%; // 4 tabs
}
@media screen and (max-width: 640px) {
width: 27%; /* 3 tabs */
width: 27%; // 3 larger tabs
}
@media screen and (max-width: 480px) {
width: 24%; /* 3 tabs */
width: 24%; // 3 tabs
}
@media screen and (max-width: 320px) {
width: 35%; /* 2 tabs */
}
/* tabs-looking buttons */
// tabs-looking buttons
margin-right: 3px;
margin-top: 11px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-bottom: solid #3F51B5 2px; /* @TODO */
border-bottom: solid #3F51B5 4px;
&.active {
border-bottom-color: white;
box-shadow: none;
.calc-type {
color: #777;
}
}
.calc-name {
display: block;
margin-top: -3px; // ark !
text-overflow: ellipsis;
overflow: hidden;
}
.calc-type {
display: block;
font-size: 0.7em;
color: #bbb;
line-height: 24px;
margin-top: -14px; // ark !
text-overflow: ellipsis;
overflow: hidden;
}
}
.calculators-menu-title {
background-color: white;
width: 360px; // minimal screen width supported: 480
margin-top: 8px;
.dropdown-icon {
float: right;
transform: scale(2);
margin-top: 8px;
margin-left: 10px;
}
.calc-name {
display: block;
margin-top: -3px; // ark !
text-overflow: ellipsis;
overflow: hidden;
}
.calc-type {
display: block;
font-size: 0.7em;
color: #777;
line-height: 24px;
margin-top: -14px; // ark !
text-overflow: ellipsis;
overflow: hidden;
}
}
.calculator-button {
&.active {
border-bottom-color: white;
......@@ -63,7 +131,9 @@ button:focus {
.calc-name {
display: block;
margin-top: -3px; /* ark ! */
margin-top: -3px; // ark !
text-overflow: ellipsis;
overflow: hidden;
}
.calc-type {
......@@ -71,7 +141,9 @@ button:focus {
font-size: 0.7em;
color: #bbb;
line-height: 24px;
margin-top: -14px; /* ark ! */
margin-top: -14px; // ark !
text-overflow: ellipsis;
overflow: hidden;
}
}
......@@ -79,19 +151,29 @@ button:focus {
// sidenav
.sidenav {
position:fixed;
height: 100%;
background-color: #111;
overflow-x: hidden;
padding-top: 60px;
padding-top: 60px + $navbar_height;
padding-right: 4em;
z-index: 100;
a, .div.hyd_version {
padding: 8px 8px 8px 32px;
padding: 8px 8px 8px 24px;
text-decoration: none;
font-size: 16px;
color: #aaaaaa;
display: block;
transition: 0.3s;
&:focus {
outline: 0;
}
&:hover {
color: #f1f1f1;
}
}
div.hyd_version {
......@@ -104,20 +186,23 @@ button:focus {
text-align: right;
}
a:hover {
color: #f1f1f1;
}
.closebtn {
position: absolute;
top: 0;
top: 54px;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
mat-icon {
color: #fff;
vertical-align: bottom;
margin-right: 6px;
}
}
/*@media screen and (max-height: 450px) {
.sidenav {padding-top: 15px;}
.sidenav a {font-size: 18px;}
}*/
// page contents
.sidenav-content {
margin-top: $navbar_height;
}
\ No newline at end of file
......@@ -35,6 +35,9 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
@ViewChild("navbar")
public navbar: MatToolbar;
/** current calculator, inferred from _currentFormId by setActiveCalc() (used for navbar menu) */
public currentCalc: any;
/**
* liste des calculettes. Forme des objets :
* "title": nom de la calculette
......@@ -44,11 +47,12 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
/**
* id du formulaire courant
* on utilise pas directement FormulaireService.currentFormId pour éviter l'erreur ExpressionChangedAfterItHasBeenCheckedError
* on utilise pas directement FormulaireService.currentFormId pour éviter l'erreur
* ExpressionChangedAfterItHasBeenCheckedError
*/
private _currentFormId: number;
private _currentFormId: string;
private _innerWidth;
private _innerWidth: number;
@ViewChild(LoadCalcDialogAnchorDirective)
private appLoadCalcDialogAnchor: LoadCalcDialogAnchorDirective;
......@@ -100,6 +104,7 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
@HostListener("window:resize", ["$event"])
onResize(event) {
// keep track of window size for navbar tabs arrangement
this._innerWidth = window.innerWidth;
}
......@@ -115,6 +120,10 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
return this.intlService.localizeText("INFO_MENU_LOAD_SESSION_TITLE");
}
public get uitextSidenavSaveSession() {
return this.intlService.localizeText("INFO_MENU_SAVE_SESSION_TITLE");
}
public get uitextSidenavHelp() {
return this.intlService.localizeText("INFO_MENU_HELP_TITLE");
}
......@@ -123,10 +132,17 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
return this._calculators;
}
public get currentFormId() {
return this._currentFormId;
}
public setActiveCalc(uid: string) {
this._calculators.forEach((calc) => {
calc.active = (calc.uid === uid);
});
// mark current calc for navbar menu
const index = this.getCalculatorIndexFromId(uid);
this.currentCalc = this._calculators[index];
}
/**
......@@ -136,10 +152,7 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
public get tabsFitInNavbar() {
// manual breakpoints
// @WARNING keep in sync with .calculator-buttons sizes in app.component.scss
let tabsLimit = 2;
if (this._innerWidth > 320) {
tabsLimit = 3;
}
let tabsLimit = 0;
if (this._innerWidth > 480) {
tabsLimit = 3;
}
......@@ -149,9 +162,9 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
if (this._innerWidth > 800) {
tabsLimit = 6;
}
if (this._innerWidth > 1200) {
/*if (this._innerWidth > 1200) {
tabsLimit = 8;
}
}*/
const fits = this._calculators.length <= tabsLimit;
return fits;
......@@ -202,7 +215,6 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
}
);
this.setActiveCalc(f.uid);
this._tabsChanged = true;
// abonnement en tant qu'observateur du nouveau formulaire
f.addObserver(this);
......@@ -213,13 +225,7 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
break;
case "currentFormChanged":
/*
utilisation de setTimeout() pour éviter le message console ExpressionChangedAfterItHasBeenCheckedError
relatif au getter getHighlightClass() (qui change de valeur quand le formulaire courant change)
*/
setTimeout(() => {
this._currentFormId = data["formId"];
}, 1);
this._currentFormId = data["formId"];
break;
case "saveForm":
......@@ -256,43 +262,6 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
private updateCalculatorTitle(f: FormulaireDefinition, title: string) {
const formIndex = this.getCalculatorIndexFromId(f.uid);
this._calculators[formIndex]["title"] = title;
this._tabsChanged = true; // recompute size !
}
/**
* sauvegarde du/des formulaires
* @param form formulaire à sélectionner par défaut dans la liste
*/
private saveForm(form: FormulaireDefinition) {
// création du dialogue de sélection des formulaires à sauver
const compRef: ComponentRef<SaveCalculatorComponent> = this.appSaveCalcDialogAnchor.createDialog();
// création de la liste des formulaires
const list = [];
for (const c of this._calculators) {
const uid = c["uid"];
list.push({
"selected": uid === form.uid,
"title": c["title"],
"uid": uid
});
}
// passage de la liste, récupération d'une Promise pour traiter le résultat
const prom: Promise<any[]> = compRef.instance.run(list);
prom.then(innerList => {
let name = compRef.instance.filename;
// ajout extension ".json"
const re = /.+\.json/;
const match = re.exec(name.toLowerCase());
if (match === null) {
name = name + ".json";
}
this.saveSession(innerList, name);
}).catch(err => { });
}
private saveSession(calcList: any[], filename) {
......@@ -342,7 +311,6 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
// MAJ affichage
this._tabsChanged = true;
if (newId === null) {
this.toList();
this._currentFormId = null;
......@@ -367,10 +335,6 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
this._routerCurrentComponent = a;
}
private getHighlightClass(uid: number) {
return uid === this._currentFormId ? "blue darken-2" : "";
}
// flag d'affichage des repères des colonnes Bootstrap : uniquement en mode dev
// cf. src/environments/*, ng build --env=<mode> (par ex : ng build --env=prod)
public get ruler(): boolean {
......@@ -394,6 +358,41 @@ export class AppComponent implements OnInit, OnDestroy, Observer {
return dr;
}
/**
* sauvegarde du/des formulaires
* @param form formulaire à sélectionner par défaut dans la liste
*/
public saveForm(form?: FormulaireDefinition) {
// création du dialogue de sélection des formulaires à sauver
const compRef: ComponentRef<SaveCalculatorComponent> = this.appSaveCalcDialogAnchor.createDialog();
// création de la liste des formulaires
const list = [];
for (const c of this._calculators) {
const uid = c["uid"];
list.push({
"selected": form ? (uid === form.uid) : true,
"title": c["title"],
"uid": uid
});
}
// passage de la liste, récupération d'une Promise pour traiter le résultat
const prom: Promise<any[]> = compRef.instance.run(list);
prom.then(innerList => {
let name = compRef.instance.filename;
// ajout extension ".json"
const re = /.+\.json/;
const match = re.exec(name.toLowerCase());
if (match === null) {
name = name + ".json";
}
this.saveSession(innerList, name);
}).catch(err => { });
}
/**
* détection de la fermeture de la page/navigateur et demande de confirmation
*/
......
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { MatButtonModule, MatCheckboxModule, MatIconModule, MatTabsModule, MatSidenavModule, MatToolbarModule } from "@angular/material";
import { MatButtonModule, MatCheckboxModule, MatIconModule, MatSelectModule, MatTabsModule, MatSidenavModule,
MatToolbarModule, MatMenuModule } from "@angular/material";
import { FlexLayoutModule } from "@angular/flex-layout";
import { MDBBootstrapModule } from "angular-bootstrap-md";
import { HttpClientModule } from "@angular/common/http";
......@@ -75,6 +76,8 @@ const appRoutes: Routes = [
MatButtonModule,
MatCheckboxModule,
MatIconModule,
MatMenuModule,
MatSelectModule,
MatSidenavModule,
MatTabsModule,
MatToolbarModule,
......
......@@ -160,7 +160,7 @@ export class FormulaireService extends Observable {
return f;
}).then(fi => {
if (jsonState === undefined) {
fi.calculatorName = decode(this.getLocalisedTitleFromCalculatorType(ct) + " (" + fi.uid + ")");
fi.calculatorName = decode(this.getLocalisedTitleFromCalculatorType(ct));
}
fi.initNub();
return fi;
......
......@@ -98,10 +98,11 @@
"INFO_LIB_ZDV": "Crest weir elevation or gate base",
"INFO_LIB_ZRAM": "Upstream apron elevation (m)",
"INFO_LIB_ZT": "Triangle top elevation (m)",
"INFO_MACRORUGO_TITRE": "Rock-ramp fishpasses",
"INFO_MENU_HELP_TITLE": "Help",
"INFO_MENU_LOAD_SESSION_TITLE": "Load session",
"INFO_MENU_NOUVELLE_CALC": "New calculation module",
"INFO_MACRORUGO_TITRE": "Rock-ramp fishpasses",
"INFO_MENU_SAVE_SESSION_TITLE": "Save session",
"INFO_OPTION_NO": "No",
"INFO_OPTION_YES": "Yes",
"INFO_OUVRAGE": "Structure",
......
......@@ -100,6 +100,7 @@
"INFO_LIB_ZT": "Cote haute du triangle (m)",
"INFO_MENU_HELP_TITLE": "Aide",
"INFO_MENU_LOAD_SESSION_TITLE": "Charger une session",
"INFO_MENU_SAVE_SESSION_TITLE": "Enregistrer la session",
"INFO_MENU_NOUVELLE_CALC": "Nouveau module de calcul",
"INFO_MACRORUGO_TITRE": "Passe à macro-rugosité",
"INFO_OPTION_NO": "Non",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment