Using angular-mat in toolbar

This commit is contained in:
Artur 2024-11-27 20:54:25 +01:00
parent 8312bfb121
commit 34ed2b4bd0
10 changed files with 2673 additions and 591 deletions

View File

@ -28,6 +28,7 @@
} }
], ],
"styles": [ "styles": [
"@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css", "src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.css" "node_modules/bootstrap/dist/css/bootstrap.css"
], ],
@ -106,6 +107,7 @@
} }
], ],
"styles": [ "styles": [
"@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css" "src/styles.css"
], ],
"scripts": [] "scripts": []

3044
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,12 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^18.2.0", "@angular/animations": "^18.2.0",
"@angular/cdk": "^17.0.0",
"@angular/common": "^18.2.0", "@angular/common": "^18.2.0",
"@angular/compiler": "^18.2.0", "@angular/compiler": "^18.2.0",
"@angular/core": "^18.2.0", "@angular/core": "^18.2.0",
"@angular/forms": "^18.2.0", "@angular/forms": "^18.2.0",
"@angular/material": "^17.0.0",
"@angular/platform-browser": "^18.2.0", "@angular/platform-browser": "^18.2.0",
"@angular/platform-browser-dynamic": "^18.2.0", "@angular/platform-browser-dynamic": "^18.2.0",
"@angular/router": "^18.2.0", "@angular/router": "^18.2.0",
@ -28,9 +30,10 @@
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^18.2.4", "@angular-devkit/build-angular": "^18.2.4",
"@angular/cli": "^18.2.4", "@angular/cli": "^19.0.0",
"@angular/compiler-cli": "^18.2.0", "@angular/compiler-cli": "^18.2.0",
"@angular/localize": "^18.2.4", "@angular/localize": "^18.2.4",
"@schematics/angular": "^19.0.0",
"@types/jasmine": "~5.1.0", "@types/jasmine": "~5.1.0",
"angular-eslint": "18.4.0", "angular-eslint": "18.4.0",
"eslint": "^9.13.0", "eslint": "^9.13.0",

View File

@ -0,0 +1,40 @@
.mat-toolbar {
display: flex;
align-items: center;
justify-content: space-between; /* Równe rozmieszczenie elementów */
padding: 0 16px; /* Marginesy wewnętrzne */
}
.col-left {
display: flex;
align-items: center;
justify-content: flex-start; /* Wyrównanie flagi do lewej */
}
.flag {
height: 25px; /* Powiększenie flagi */
width: auto;
margin-right: 16px; /* Odstęp od sąsiednich elementów */
border: none; /* Brak ramki */
}
.toolbar-item {
font-size: 22px; /* Większy rozmiar tekstu */
font-weight: 500;
text-transform: none; /* Bez uppercase */
color: white; /* Kolor tekstu */
}
button.mat-icon-button {
padding: 0; /* Brak dodatkowych marginesów */
}
.mat-toolbar-row {
display: flex;
width: 100%;
}
.col {
text-align: center; /* Wyśrodkowanie tekstu w kolumnach */
flex: 1; /* Równe rozciąganie kolumn */
}

View File

@ -1,30 +1,31 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark sticky-top"> <mat-toolbar color="primary" class="sticky-top mat-toolbar">
<div class="me-auto col-auto"> <mat-toolbar-row>
<a class="navbar-brand ms-2"> <div class="col-left">
<a <button mat-icon-button class="flag-button" (click)="switchLanguage(translate.currentLang === 'pl' ? 'en' : 'pl')">
class="navbar-brand ms-2" <img loading="lazy" class="flag"
role="button" src="/flag-icons-main/flags/4x3/{{ translate.currentLang === 'pl' ? 'us' : 'pl' }}.svg"
tabindex="0" alt="Switch language">
(click)="switchLanguage( translate.currentLang === 'pl' ? 'en' : 'pl' )" </button>
(keydown)="handleKeyDown($event)"> </div>
<img <div class="col">
loading="lazy" <button mat-button class="toolbar-item" [routerLink]="'/about-me'">{{ 'topBar.aboutMe' | translate }}</button>
class="border border-dark" </div>
height="25" <div class="col">
src= "/flag-icons-main/flags/4x3/{{ translate.currentLang === 'pl' ? 'us' : 'pl' }}.svg" <button mat-button class="toolbar-item" [routerLink]="'/asset-calculator'">{{ 'topBar.depreciationCalculator' | translate }}</button>
alt="Switch language" </div>
> <div class="col">
</a> <button mat-button class="toolbar-item" [routerLink]="'/quotes'">{{ 'topBar.courses' | translate }}</button>
</div>
<div class="col">
<button mat-button class="toolbar-item" [routerLink]="'/friendly-pages'">{{ 'topBar.friendlyPages' | translate }}</button>
</div>
</mat-toolbar-row>
</mat-toolbar>
<router-outlet></router-outlet>
</a>
</div>
<div class="container d-flex justify-content-between align-items-center">
<!-- Navbar links -->
<a class="navbar-brand" [routerLink]="'/about-me'">{{ 'topBar.aboutMe' | translate }}</a>
<a class="navbar-brand" [routerLink]="'/asset-calculator'">{{ 'topBar.depreciationCalculator' | translate }}</a>
<a class="navbar-brand" [routerLink]="'/quotes'">{{ 'topBar.courses' | translate }}</a>
<a class="navbar-brand" [routerLink]="'/friendly-pages'">{{ 'topBar.friendlyPages' | translate }}</a>
</div>
</nav>
<router-outlet /> <router-outlet />

View File

@ -2,11 +2,14 @@ import { Component, HostListener, OnDestroy } from '@angular/core';
import { RouterOutlet, RouterModule } from '@angular/router'; import { RouterOutlet, RouterModule } from '@angular/router';
import { TranslateService, TranslateModule } from '@ngx-translate/core'; import { TranslateService, TranslateModule } from '@ngx-translate/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
standalone: true, standalone: true,
imports: [RouterOutlet, TranslateModule, RouterModule], imports: [RouterOutlet, TranslateModule, RouterModule, MatToolbarModule, MatButtonModule, MatIconModule, MatMenuModule],
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.css'], // Fixed typo styleUrls: ['./app.component.css'], // Fixed typo
}) })

View File

@ -7,6 +7,7 @@ import { HttpClient, provideHttpClient} from '@angular/common/http';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
const httpLoaderFactory: (http: HttpClient) => TranslateHttpLoader = (http: HttpClient) => const httpLoaderFactory: (http: HttpClient) => TranslateHttpLoader = (http: HttpClient) =>
new TranslateHttpLoader(http, './i18n/', '.json'); new TranslateHttpLoader(http, './i18n/', '.json');
@ -24,7 +25,7 @@ export const appConfig: ApplicationConfig = {
useFactory: httpLoaderFactory, useFactory: httpLoaderFactory,
deps: [ HttpClient ], deps: [ HttpClient ],
}, },
})]) })]), provideAnimationsAsync()
], ],
}; };

View File

@ -17,20 +17,24 @@ class AssetLifeChangeWrapper{
when = signal<string> ( YearMonth.todayTxt()); when = signal<string> ( YearMonth.todayTxt());
initial = signal<number>( 0 ); initial = signal<number>( 0 );
constructor( assetLifeChange : AssetLifeChange ){
this.set(assetLifeChange);
}
get(): AssetLifeChange { get(): AssetLifeChange {
const ym = this.when(); const ym = this.when();
const when = YearMonth.from( ym ); const when = YearMonth.from( ym );
return new AssetLifeChange( when, this.initial() , 0, 0 ); return new AssetLifeChange( when, this.initial() , 0, 0 );
} }
set(assetLifeChange: AssetLifeChange) {
constructor( assetLifeChange : AssetLifeChange ){ this.when.set(YearMonth.toTxt(assetLifeChange.when));
this.initial.set(assetLifeChange.initial);
this.when.set( YearMonth.toTxt( assetLifeChange.when ) );
this.initial.set( assetLifeChange.initial );
} }
} }
const NAME_IN_STORAGE = 'assetForCalculator'; const NAME_IN_STORAGE = 'assetForCalculator';
@Component({ @Component({
selector: 'app-asset-calculator', selector: 'app-asset-calculator',
standalone: true, standalone: true,
@ -70,6 +74,24 @@ export class AssetCalculatorComponent {
effect( () => this.reCalculate( ) ) effect( () => this.reCalculate( ) )
} }
private storage = {
load: (key: string) => {
try {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
} catch {
console.error(`Failed to load ${key} from localStorage`);
return null;
}
},
save: (key: string, data: any) => {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch {
console.error(`Failed to save ${key} to localStorage`);
}
}
};
ngOnInit(): void{ ngOnInit(): void{
this.restoreState(); this.restoreState();
@ -84,28 +106,12 @@ export class AssetCalculatorComponent {
} }
private restoreState() { private restoreState() {
const savedAsset = localStorage.getItem(NAME_IN_STORAGE); const savedAsset = this.storage.load(NAME_IN_STORAGE);
if( savedAsset ) { if (savedAsset) this.assetToControls(savedAsset);
try {
const parsedAsset : Asset = JSON.parse(savedAsset);
this.assetToControls( parsedAsset );
} catch (error) {
console.error('Failed to parse saved asset:', error);
localStorage.removeItem(NAME_IN_STORAGE);
}
}
} }
private saveState(asset:Asset) { private saveState(asset: Asset) {
this.storage.save(NAME_IN_STORAGE, asset);
// Zapisywanie danych przed zniszczeniem komponentu
try {
// Serialize the asset to a JSON string
localStorage.setItem(NAME_IN_STORAGE, JSON.stringify(asset) );
} catch (error) {
console.error('Failed to save asset:', error);
}
} }
@ -115,24 +121,22 @@ export class AssetCalculatorComponent {
} }
} }
private updateBatch(asset: Asset) { private updateBatch(asset: Asset) {
const life0 = asset.life[0]; const [firstLife, ...restLives] = asset.life;
const method0 = asset.depreciationMethods[0]; const method0 = asset.depreciationMethods[0];
this.initialValueAsset.set(life0.initial);
const ymText =YearMonth.toTxt( life0.when ); this.initialValueAsset.set(firstLife.initial);
this.startDepreciation.set(ymText); this.startDepreciation.set(YearMonth.toTxt(firstLife.when));
this.rate.set(method0.rate); this.rate.set(method0.rate);
this.typeDepreciation.set(method0.type); this.typeDepreciation.set(method0.type);
this.factor.set(method0.rate); this.factor.set(method0.factor);
const lifeChanges = restLives.map((lifeChange) =>
new AssetLifeChangeWrapper(lifeChange)
);
this.lifeChangesSignal.set(lifeChanges);
}
console.log( asset.life );
for( let i = 1; i < asset.life.length ; i++ ){
const assetLifeChange = asset.life[i];
const lifeChangeWrapper = this.addLifeChange2(assetLifeChange);
lifeChangeWrapper.initial.set( assetLifeChange.initial );
lifeChangeWrapper.when.set(YearMonth.toTxt( assetLifeChange.when ));
};
}
private controlsToAsset(): Asset { private controlsToAsset(): Asset {

View File

@ -6,8 +6,10 @@
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head> </head>
<body> <body class="mat-typography">
<app-root></app-root> <app-root></app-root>
</body> </body>
</html> </html>

View File

@ -16,3 +16,15 @@ main {
padding: 20px; /* Odstęp wewnętrzny */ padding: 20px; /* Odstęp wewnętrzny */
background-color: #f8f9fa; /* Tło formularza */ background-color: #f8f9fa; /* Tło formularza */
} }
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
.spacer {
flex: 1 1 auto;
}
mat-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
}