This commit is contained in:
Sieciech 2021-07-26 16:43:18 +02:00
parent 7fabb5170a
commit 8b483ef021
20 changed files with 660 additions and 49 deletions

View File

@ -1,5 +1,15 @@
#!/bin/bash #!/bin/bash
echo "> Configure cache"
mkdir -p /tmp/app/{vendor/node_modules}
ln -s /tmp/app/node_modules /web/frontend/node_modules
ln -s /tmp/app/vendor /web/backend/vendor
echo "> Configure user"
useradd developer
chown developer:developer /web/frontend -R
chown developer:developer /web/backend -R
echo "> Configure logs" echo "> Configure logs"
mkdir -p /var/log/{apache2,nginx,pgadmin,postgresql} mkdir -p /var/log/{apache2,nginx,pgadmin,postgresql}
chown postgres:adm /var/log/postgresql -R chown postgres:adm /var/log/postgresql -R
@ -39,7 +49,7 @@ echo "> Configure symfony"
echo "> Configure angular" echo "> Configure angular"
cd /web/frontend cd /web/frontend
npm ci su developer -c 'time npm ci'
echo "> Starting angular" echo "> Starting angular"
ng serve --disable-host-check --host 0.0.0.0 --poll su developer -c 'ng serve --disable-host-check --host 0.0.0.0 --poll'

View File

@ -48,7 +48,17 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss",
{
"input": "src/app/styles/light.scss",
"bundleName": "light",
"inject": false
},
{
"input": "src/app/styles/dark.scss",
"bundleName": "dark",
"inject": false
}
], ],
"scripts": [], "scripts": [],
"vendorChunk": true, "vendorChunk": true,

View File

@ -291,6 +291,23 @@
"tslib": "^2.2.0" "tslib": "^2.2.0"
} }
}, },
"@angular/cdk": {
"version": "12.1.3",
"resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-12.1.3.tgz",
"integrity": "sha512-uCWHk/PjddNJsdrmexasphWGbf4kYtYyhUCSd4HEBrIDjYz166MTVSr3FHgn/s8/tlVou7uTnaEZM+ILWoe2iQ==",
"requires": {
"parse5": "^5.0.0",
"tslib": "^2.2.0"
},
"dependencies": {
"parse5": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
"optional": true
}
}
},
"@angular/cli": { "@angular/cli": {
"version": "12.1.3", "version": "12.1.3",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-12.1.3.tgz", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-12.1.3.tgz",
@ -491,6 +508,14 @@
"tslib": "^2.2.0" "tslib": "^2.2.0"
} }
}, },
"@angular/material": {
"version": "12.1.3",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-12.1.3.tgz",
"integrity": "sha512-ekkg3MDEN133NhcE0du7a69lFAIFyvK6Va+YRTxYQE0BCNVMTWXtGbOXZLovDMjgo1xdXwrEJrMRBeYo+FIttA==",
"requires": {
"tslib": "^2.2.0"
}
},
"@angular/platform-browser": { "@angular/platform-browser": {
"version": "12.1.3", "version": "12.1.3",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-12.1.3.tgz", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-12.1.3.tgz",
@ -1699,6 +1724,22 @@
"enhanced-resolve": "5.8.2" "enhanced-resolve": "5.8.2"
} }
}, },
"@ngx-translate/core": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-13.0.0.tgz",
"integrity": "sha512-+tzEp8wlqEnw0Gc7jtVRAJ6RteUjXw6JJR4O65KlnxOmJrCGPI0xjV/lKRnQeU0w4i96PQs/jtpL921Wrb7PWg==",
"requires": {
"tslib": "^2.0.0"
}
},
"@ngx-translate/http-loader": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-6.0.0.tgz",
"integrity": "sha512-LCekn6qCbeXWlhESCxU1rAbZz33WzDG0lI7Ig0pYC1o5YxJWrkU9y3Y4tNi+jakQ7R6YhTR2D3ox6APxDtA0wA==",
"requires": {
"tslib": "^2.0.0"
}
},
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -2725,6 +2766,16 @@
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true "dev": true
}, },
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true,
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bl": { "bl": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@ -2819,6 +2870,11 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true "dev": true
}, },
"bootstrap": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.2.tgz",
"integrity": "sha512-1Ge963tyEQWJJ+8qtXFU6wgmAVj9gweEjibUdbmcCEYsn38tVwRk8107rk2vzt6cfQcRr3SlZ8aQBqaD8aqf+Q=="
},
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -4978,6 +5034,13 @@
"escape-string-regexp": "^1.0.5" "escape-string-regexp": "^1.0.5"
} }
}, },
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true,
"optional": true
},
"fill-range": { "fill-range": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@ -5075,6 +5138,11 @@
"integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==",
"dev": true "dev": true
}, },
"font-awesome": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz",
"integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM="
},
"for-in": { "for-in": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@ -7430,6 +7498,13 @@
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
"dev": true "dev": true
}, },
"nan": {
"version": "2.14.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==",
"dev": true,
"optional": true
},
"nanoid": { "nanoid": {
"version": "3.1.23", "version": "3.1.23",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
@ -12599,7 +12674,11 @@
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
"integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
"dev": true, "dev": true,
"optional": true "optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1"
}
}, },
"glob-parent": { "glob-parent": {
"version": "3.1.0", "version": "3.1.0",

View File

@ -12,13 +12,19 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "~12.1.3", "@angular/animations": "~12.1.3",
"@angular/cdk": "^12.1.3",
"@angular/common": "~12.1.3", "@angular/common": "~12.1.3",
"@angular/compiler": "~12.1.3", "@angular/compiler": "~12.1.3",
"@angular/core": "~12.1.3", "@angular/core": "~12.1.3",
"@angular/forms": "~12.1.3", "@angular/forms": "~12.1.3",
"@angular/material": "^12.1.3",
"@angular/platform-browser": "~12.1.3", "@angular/platform-browser": "~12.1.3",
"@angular/platform-browser-dynamic": "~12.1.3", "@angular/platform-browser-dynamic": "~12.1.3",
"@angular/router": "~12.1.3", "@angular/router": "~12.1.3",
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"bootstrap": "^5.0.2",
"font-awesome": "^4.7.0",
"rxjs": "~6.5.5", "rxjs": "~6.5.5",
"tslib": "^2.0.0", "tslib": "^2.0.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
@ -27,9 +33,9 @@
"@angular-devkit/build-angular": "~12.1.3", "@angular-devkit/build-angular": "~12.1.3",
"@angular/cli": "~12.1.3", "@angular/cli": "~12.1.3",
"@angular/compiler-cli": "~12.1.3", "@angular/compiler-cli": "~12.1.3",
"@types/node": "^12.11.1",
"@types/jasmine": "~3.6.0", "@types/jasmine": "~3.6.0",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "^12.11.1",
"codelyzer": "^6.0.0", "codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0", "jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0", "jasmine-spec-reporter": "~5.0.0",

View File

@ -1 +1,3 @@
cd ../../docker
docker.exe compose -p curenet exec app bash -c 'cd /web/frontend && bash' docker.exe compose -p curenet exec app bash -c 'cd /web/frontend && bash'
cd ../src/frontend

View File

@ -1,2 +1,47 @@
<ng-template #toolbar>
<mat-toolbar [color]="isDark ? null : 'primary'">
<button mat-icon-button (click)="toggleSidebar()">
<i class="fa fa-bars"></i>
</button>
<span>My App</span>
<span class="flex-grow-1"></span>
<button mat-icon-button class="example-icon favorite-icon" aria-label="Example icon-button with heart icon">
<i class="fa fa-user"></i>
</button>
</mat-toolbar>
</ng-template>
<ng-container *ngIf="!isMobile">
<ng-container *ngTemplateOutlet="toolbar"></ng-container>
</ng-container>
<mat-drawer-container class="flex-grow-1">
<mat-drawer [mode]="sidebarMode" [opened]="isSidebarOpen" (openedChange)="onSidebarOpenedChange($event)">
<div class="menu">
<div>menu</div>
<div class="hide-on-side-opened">
<mat-form-field class="w-100 px-3">
<mat-label>{{ 'APP.LANGUAGE' | translate }}</mat-label>
<mat-select [formControl]="langControl">
<mat-option *ngFor="let lang of langs" [value]="lang">{{ 'LANGUAGE.'+lang.toUpperCase() | translate }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="w-100 px-3">
<mat-label>{{ 'APP.THEME' | translate }}</mat-label>
<mat-select [formControl]="themeControl">
<mat-option *ngFor="let theme of themes" [value]="theme">{{ 'THEME.'+theme.toUpperCase() | translate }}</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</mat-drawer>
<ng-container *ngIf="isMobile">
<ng-container *ngTemplateOutlet="toolbar"></ng-container>
</ng-container>
<div class="example-sidenav-content">
<router-outlet></router-outlet> <router-outlet></router-outlet>
It's works, you can start coding :) It's works, you can start coding :)
</div>
</mat-drawer-container>

View File

@ -0,0 +1,19 @@
:host{
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.menu{
width: 250px;
flex-grow: 1;
display: flex;
flex-direction: column;
height: 100%;
> :first-child{
flex-grow: 1;
}
}

View File

@ -1,10 +1,104 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { AppService, WindowSize } from './modules/shared/services/app/app.service';
import { ThemeService } from './modules/shared/services/theme/theme.service';
enum SidebarOpenEnum {
Default,
Open,
Closed,
}
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent { export class AppComponent {
isMobile = true;
title = 'CureNet'; title = 'CureNet';
sidebarOpen = SidebarOpenEnum.Default;
sidebarMode = 'over';
defaultSidebarOpen = false;
lang: string;
theme: string;
langs: string[] = [];
themes: string[] = [];
themeControl = new FormControl();
langControl = new FormControl();
isDark = true;
get isSidebarOpen() {
switch (this.sidebarOpen) {
case SidebarOpenEnum.Open:
return true;
break;
case SidebarOpenEnum.Closed:
return false;
break;
default:
return this.defaultSidebarOpen;
break;
}
}
constructor(
appService: AppService,
themeService: ThemeService,
) {
this.themes = themeService.getThemes();
this.langs = appService.getLangs();
this.lang = appService.getLang();
this.themeControl.valueChanges.subscribe(theme => {
themeService.setTheme(theme);
});
this.langControl.valueChanges.subscribe(lang => {
appService.changeLang(lang);
});
this.onThemeChanged(themeService.getTheme());
themeService.themeChange.subscribe(theme => {
this.onThemeChanged(theme);
});
this.onResize(appService.size);
appService.sizeChange.subscribe(size => {
this.onResize(size);
});
this.onLangChanged(appService.getLang());
appService.langChange.subscribe(lang => {
this.onLangChanged(lang);
});
}
onThemeChanged(theme: string) {
if (theme === undefined) {
return;
}
this.theme = theme;
this.themeControl.setValue(theme);
this.isDark = theme.indexOf('dark') !== -1;
}
onResize(size: WindowSize) {
if (size === undefined) {
return;
}
this.isMobile = size.isMobile;
this.defaultSidebarOpen = !this.isMobile;
this.sidebarMode = this.isMobile ? 'over' : 'side';
}
onLangChanged(lang: string) {
if (lang === undefined) {
return;
}
this.lang = lang;
this.langControl.setValue(lang);
}
toggleSidebar() {
this.sidebarOpen = this.isSidebarOpen ? SidebarOpenEnum.Closed : SidebarOpenEnum.Open;
}
onSidebarOpenedChange(opened: boolean) {
this.sidebarOpen = opened ? SidebarOpenEnum.Open : SidebarOpenEnum.Closed;
}
} }

View File

@ -1,18 +1,47 @@
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from './modules/material/material.module';
import { AppService } from './modules/shared/services/app/app.service';
import { ThemeService } from './modules/shared/services/theme/theme.service';
import { BrowserStorageService } from './modules/shared/services/browser-storage/browser-storage.service';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, '/assets/lang/', '.json');
}
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent AppComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
AppRoutingModule AppRoutingModule,
BrowserAnimationsModule,
MaterialModule,
FormsModule,
ReactiveFormsModule,
HttpClientModule,
TranslateModule.forRoot({
defaultLanguage: 'en',
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
],
providers: [
AppService,
ThemeService,
BrowserStorageService,
], ],
providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })
export class AppModule { } export class AppModule { }

View File

@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import {MatToolbarModule} from '@angular/material/toolbar';
import {MatButtonModule} from '@angular/material/button';
import {MatSidenavModule} from '@angular/material/sidenav';
import {MatSelectModule} from '@angular/material/select';
const itemsToExport = [
MatToolbarModule,
MatButtonModule,
MatSidenavModule,
MatSelectModule,
];
@NgModule({
declarations: [],
imports: [
CommonModule,
...itemsToExport,
],
exports: [
...itemsToExport,
]
})
export class MaterialModule { }

View File

@ -0,0 +1,73 @@
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { fromEvent, Subject } from 'rxjs';
import { BrowserStorageService } from '../browser-storage/browser-storage.service';
export class WindowSize {
isMobile: boolean;
constructor(
public width: number,
public height: number,
) {
this.isMobile = this.width <= 700;
}
update() {
this.width = window.innerWidth;
this.height = window.innerHeight;
}
static generate() {
return new WindowSize(window.innerWidth, window.innerHeight);
}
}
@Injectable()
export class AppService {
private lang = 'en';
private defaultLang = 'en';
langChange = new Subject<string>();
size: WindowSize;
sizeChange = new Subject<WindowSize>();
constructor(
browserStorageService: BrowserStorageService,
private translate: TranslateService,
) {
this.langChange.subscribe(lang => {
this.lang = lang;
browserStorageService.setItem('language', lang);
});
this.sizeChange.subscribe(size => this.size = size);
this.sizeChange.next(WindowSize.generate());
let lang = browserStorageService.getItem('language');
if (!lang) {
lang = this.defaultLang;
}
this.lang = lang;
this.translate.setDefaultLang(this.defaultLang);
this.changeLang(this.lang);
fromEvent(window, 'resize').subscribe(e => {
this.sizeChange.next(WindowSize.generate());
})
}
changeLang(lang: string) {
if (lang !== this.lang) {
this.translate.use(lang);
this.langChange.next(lang);
}
}
getLang() {
return this.lang;
}
getLangs() {
return [
'pl',
'en',
];
}
}

View File

@ -0,0 +1,37 @@
import { Injectable } from '@angular/core';
@Injectable()
export class BrowserStorageService {
private storage: Storage;
private namespace: string;
constructor() {
this.storage = localStorage;
this.namespace = 'default';
}
setNamespace(namespace: string) {
this.namespace = namespace;
}
getNamespace(namespace: string | null = null): string {
return namespace ?? this.namespace;
}
setItem(key: string, value: any, namespace: string | null = null) {
namespace = this.getNamespace(namespace);
const path = `${namespace}.${key}`;
this.storage.setItem(path, JSON.stringify(value));
}
getItem(key: string, namespace: string | null = null): any {
namespace = this.getNamespace(namespace);
const path = `${namespace}.${key}`;
return JSON.parse(this.storage.getItem(path) ?? 'null');
}
getItemOrDefault(key: string, defaultValue: any, namespace: string | null = null): any {
return this.getItem(key, namespace) ?? defaultValue;
}
}

View File

@ -0,0 +1,41 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { BrowserStorageService } from '../browser-storage/browser-storage.service';
@Injectable()
export class ThemeService {
private theme: string;
themeChange = new Subject<string>();
constructor(
browserStorageService: BrowserStorageService,
) {
this.themeChange.subscribe(theme => {
this.theme = theme;
browserStorageService.setItem('current-theme', theme);
});
let userTheme = browserStorageService.getItem('current-theme');
if (!userTheme) {
userTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
this.setTheme(userTheme);
}
getTheme() {
return this.theme;
}
setTheme(theme: string) {
if (theme !== this.theme) {
this.themeChange.next(theme);
document.getElementById('current-theme').setAttribute('href', `/${theme}.css`);
}
}
getThemes(): string[] {
return [
'light',
'dark',
];
};
}

View File

@ -0,0 +1,12 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [],
imports: [
CommonModule
]
})
export class SharedModule { }

View File

@ -0,0 +1,33 @@
// Custom Theming for Angular Material
// For more information: https://material.angular.io/guide/theming
@use '~@angular/material' as mat;
// Plus imports for other components in your app.
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat.core();
// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$frontend-primary: mat.define-palette(mat.$indigo-palette);
$frontend-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
// The warn palette is optional (defaults to red).
$frontend-warn: mat.define-palette(mat.$red-palette);
// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$frontend-theme: mat.define-dark-theme((
color: (
primary: $frontend-primary,
accent: $frontend-accent,
warn: $frontend-warn,
)
));
// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include mat.all-component-themes($frontend-theme);

View File

@ -0,0 +1,33 @@
// Custom Theming for Angular Material
// For more information: https://material.angular.io/guide/theming
@use '~@angular/material' as mat;
// Plus imports for other components in your app.
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat.core();
// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$frontend-primary: mat.define-palette(mat.$indigo-palette);
$frontend-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
// The warn palette is optional (defaults to red).
$frontend-warn: mat.define-palette(mat.$red-palette);
// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$frontend-theme: mat.define-light-theme((
color: (
primary: $frontend-primary,
accent: $frontend-accent,
warn: $frontend-warn,
)
));
// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include mat.all-component-themes($frontend-theme);

View File

@ -0,0 +1,14 @@
{
"THEME": {
"LIGHT": "Light",
"DARK": "Dark"
},
"LANGUAGE": {
"PL": "Polish",
"EN": "English"
},
"APP": {
"THEME": "Theme",
"LANGUAGE": "Language"
}
}

View File

@ -0,0 +1,14 @@
{
"THEME": {
"LIGHT": "Jasny",
"DARK": "Ciemny"
},
"LANGUAGE": {
"PL": "Polski",
"EN": "Angielski"
},
"APP": {
"THEME": "Motyw",
"LANGUAGE": "Język"
}
}

View File

@ -6,6 +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 rel="preconnect" href="https://fonts.gstatic.com">
<link rel="stylesheet" href="/light.css" id="current-theme">
<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>
<app-root></app-root> <app-root></app-root>

View File

@ -1 +1,32 @@
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
@import "~bootstrap/dist/css/bootstrap.css";
@import "~font-awesome/css/font-awesome.css";
body .mat-drawer.mat-drawer-side {
visibility: visible !important;
transform: none !important;
width: 250px;
&,
& .mat-drawer-inner-container{
transition-duration: 400ms !important;
transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important;
transition-property: transform, margin-left, margin-right, width !important;
overflow: hidden;
}
& ~ .mat-drawer-content{
margin-left: 250px !important;
}
&:not(.mat-drawer-opened) {
width: 60px;
.hide-on-side-opened{
display: none;
}
& ~ .mat-drawer-content {
margin-left: 60px !important;
}
}
}