From 0a7896ac944032d85f6688f5fc14e0ed0f3b0b3c Mon Sep 17 00:00:00 2001 From: Sieciech Date: Tue, 27 Jul 2021 11:23:46 +0000 Subject: [PATCH] Create UI and demo homepage (#18) Co-authored-by: Sieciech Reviewed-on: http://git.fufle.net/Community/CureNet/pulls/18 Co-Authored-By: Sieciech Co-Committed-By: Sieciech --- docker/startup.sh | 14 +- src/frontend/angular.json | 12 +- src/frontend/package-lock.json | 81 +++- src/frontend/package.json | 8 +- src/frontend/shell | 4 +- src/frontend/src/app/app-routing.module.ts | 112 ++++- src/frontend/src/app/app.component.html | 75 +++- src/frontend/src/app/app.component.scss | 91 ++++ src/frontend/src/app/app.component.ts | 137 +++++- src/frontend/src/app/app.module.ts | 65 ++- .../app/modules/admin/admin-routing.module.ts | 20 + .../src/app/modules/admin/admin.module.ts | 16 + .../app/modules/material/material.module.ts | 27 ++ .../not-found/not-found.component.html | 3 + .../not-found/not-found.component.scss | 0 .../not-found/not-found.component.ts | 15 + .../shared/services/app/app.service.ts | 72 ++++ .../browser-storage.service.ts | 37 ++ .../shared/services/theme/theme.service.ts | 41 ++ .../src/app/modules/shared/shared.module.ts | 24 ++ src/frontend/src/app/styles/_base.scss | 6 + src/frontend/src/app/styles/_template.scss | 398 ++++++++++++++++++ src/frontend/src/app/styles/dark.scss | 35 ++ src/frontend/src/app/styles/light.scss | 35 ++ src/frontend/src/assets/lang/en.json | 28 ++ src/frontend/src/assets/lang/pl.json | 28 ++ src/frontend/src/index.html | 30 +- src/frontend/src/styles.scss | 44 ++ 28 files changed, 1399 insertions(+), 59 deletions(-) create mode 100644 src/frontend/src/app/modules/admin/admin-routing.module.ts create mode 100644 src/frontend/src/app/modules/admin/admin.module.ts create mode 100644 src/frontend/src/app/modules/material/material.module.ts create mode 100644 src/frontend/src/app/modules/shared/components/not-found/not-found.component.html create mode 100644 src/frontend/src/app/modules/shared/components/not-found/not-found.component.scss create mode 100644 src/frontend/src/app/modules/shared/components/not-found/not-found.component.ts create mode 100644 src/frontend/src/app/modules/shared/services/app/app.service.ts create mode 100644 src/frontend/src/app/modules/shared/services/browser-storage/browser-storage.service.ts create mode 100644 src/frontend/src/app/modules/shared/services/theme/theme.service.ts create mode 100644 src/frontend/src/app/modules/shared/shared.module.ts create mode 100644 src/frontend/src/app/styles/_base.scss create mode 100644 src/frontend/src/app/styles/_template.scss create mode 100644 src/frontend/src/app/styles/dark.scss create mode 100644 src/frontend/src/app/styles/light.scss create mode 100644 src/frontend/src/assets/lang/en.json create mode 100644 src/frontend/src/assets/lang/pl.json diff --git a/docker/startup.sh b/docker/startup.sh index 19336ff..5953e49 100644 --- a/docker/startup.sh +++ b/docker/startup.sh @@ -1,5 +1,15 @@ #!/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" mkdir -p /var/log/{apache2,nginx,pgadmin,postgresql} chown postgres:adm /var/log/postgresql -R @@ -39,7 +49,7 @@ echo "> Configure symfony" echo "> Configure angular" cd /web/frontend - npm ci + su developer -c 'time npm ci' 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' diff --git a/src/frontend/angular.json b/src/frontend/angular.json index 08083a6..732b756 100644 --- a/src/frontend/angular.json +++ b/src/frontend/angular.json @@ -48,7 +48,17 @@ "src/assets" ], "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": [], "vendorChunk": true, diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index f586e94..e77112f 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -291,6 +291,23 @@ "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": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-12.1.3.tgz", @@ -491,6 +508,14 @@ "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": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-12.1.3.tgz", @@ -1699,6 +1724,22 @@ "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": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2725,6 +2766,16 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "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": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -2819,6 +2870,11 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "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": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4978,6 +5034,13 @@ "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": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5075,6 +5138,11 @@ "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==", "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": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -7430,6 +7498,13 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "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": { "version": "3.1.23", "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", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "optional": true + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } }, "glob-parent": { "version": "3.1.0", diff --git a/src/frontend/package.json b/src/frontend/package.json index 80d28eb..b9be3ea 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -12,13 +12,19 @@ "private": true, "dependencies": { "@angular/animations": "~12.1.3", + "@angular/cdk": "^12.1.3", "@angular/common": "~12.1.3", "@angular/compiler": "~12.1.3", "@angular/core": "~12.1.3", "@angular/forms": "~12.1.3", + "@angular/material": "^12.1.3", "@angular/platform-browser": "~12.1.3", "@angular/platform-browser-dynamic": "~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", "tslib": "^2.0.0", "zone.js": "~0.11.4" @@ -27,9 +33,9 @@ "@angular-devkit/build-angular": "~12.1.3", "@angular/cli": "~12.1.3", "@angular/compiler-cli": "~12.1.3", - "@types/node": "^12.11.1", "@types/jasmine": "~3.6.0", "@types/jasminewd2": "~2.0.3", + "@types/node": "^12.11.1", "codelyzer": "^6.0.0", "jasmine-core": "~3.6.0", "jasmine-spec-reporter": "~5.0.0", diff --git a/src/frontend/shell b/src/frontend/shell index a2468e8..7ad2572 100644 --- a/src/frontend/shell +++ b/src/frontend/shell @@ -1 +1,3 @@ -docker.exe compose -p curenet exec app bash -c 'cd /web/frontend && bash' \ No newline at end of file +cd ../../docker +docker.exe compose -p curenet exec app bash -c 'cd /web/frontend && bash' +cd ../src/frontend \ No newline at end of file diff --git a/src/frontend/src/app/app-routing.module.ts b/src/frontend/src/app/app-routing.module.ts index d425c6f..8458c35 100644 --- a/src/frontend/src/app/app-routing.module.ts +++ b/src/frontend/src/app/app-routing.module.ts @@ -1,10 +1,102 @@ -import { NgModule } from '@angular/core'; -import { Routes, RouterModule } from '@angular/router'; - -const routes: Routes = []; - -@NgModule({ - imports: [RouterModule.forRoot(routes)], - exports: [RouterModule] -}) -export class AppRoutingModule { } +import { NgModule } from '@angular/core'; +import { Route, RouterModule } from '@angular/router'; +import { NotFoundComponent } from './modules/shared/components/not-found/not-found.component'; + +interface AppMenuEntry { + label: string; + icon: string; + path?: string; + matchExact?: boolean; + level?: number; +} + +interface AppRoute extends Route { + menuEntries?: AppMenuEntry[]; +} + +export const appRoutes: AppRoute[] = [ + { + path: '', + component: NotFoundComponent, + menuEntries: [ + { + label: 'MENU.HOME', + icon: 'fa fa-home', + matchExact: true, + }, + ], + }, + { + path: 'profile', + component: NotFoundComponent, + menuEntries: [ + { + label: 'MENU.PROFILE', + icon: 'fa fa-user', + }, + ], + }, + { + path: 'community', + component: NotFoundComponent, + menuEntries: [ + { + label: 'MENU.COMMUNITY', + icon: 'fa fa-users', + }, + ], + }, + { + path: 'messages', + component: NotFoundComponent, + menuEntries: [ + { + label: 'MENU.MESSAGES', + icon: 'fa fa-comments', + }, + ], + }, + { + path: 'tests', + component: NotFoundComponent, + menuEntries: [ + { + label: 'MENU.TESTS', + icon: 'fa fa-heartbeat', + }, + ], + }, + { + path: 'research', + component: NotFoundComponent, + menuEntries: [ + { + label: 'MENU.RESEARCH', + icon: 'fa fa-flask', + }, + ], + }, + { + path: 'admin', + loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule), + menuEntries: [ + { + label: 'MENU.ADMIN', + icon: 'fa fa-id-card', + matchExact: true, + }, + { + path: 'admin/users', + label: 'MENU.USERS', + icon: 'fa fa-users', + level: 1, + } + ], + }, +]; + +@NgModule({ + imports: [RouterModule.forRoot(appRoutes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/src/frontend/src/app/app.component.html b/src/frontend/src/app/app.component.html index d06582e..175f57e 100644 --- a/src/frontend/src/app/app.component.html +++ b/src/frontend/src/app/app.component.html @@ -1,2 +1,73 @@ - -It's works, you can start coding :) \ No newline at end of file + + + + + {{ 'APP.NAME' | translate }} + + + + + + + + + + + + + + + +
+ +
+
\ No newline at end of file diff --git a/src/frontend/src/app/app.component.scss b/src/frontend/src/app/app.component.scss index e69de29..844bf98 100644 --- a/src/frontend/src/app/app.component.scss +++ b/src/frontend/src/app/app.component.scss @@ -0,0 +1,91 @@ +$sidebar-width: 250px; +:host{ + position: fixed; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; +} +.menu{ + width: $sidebar-width; + flex-grow: 1; + display: flex; + flex-direction: column; + height: 100%; + > :first-child{ + flex-grow: 1; + } + > * { + width: $sidebar-width; + } +} +.avatar{ + width: 48px; + height: 48px; + border-radius: 10px; + background-color: rgba(0,0,0, 0.25); + background-position: center; + background-repeat: no-repeat; + background-size: cover; +} +.menu-item{ + display: flex; + position: relative; + cursor: pointer; + padding: 10px; + transition-duration: 400ms !important; + transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important; + transition-property: all !important; + &:after{ + display: block; + content: ""; + position: absolute; + top: 50%; + right: 0px; + width: 3px; + height: 0%; + background: var(--primary-color); + transition-duration: 400ms !important; + transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !important; + transition-property: all !important; + } + &.active{ + &:after{ + top: 0%; + height: 100%; + } + } + i { + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + margin-right: 10px; + transition: all 0.4s ease; + } + span{ + display: flex; + align-items: center; + flex-grow: 1; + opacity: 0.75; + } +} +.user-box{ + padding: 6px; +} +.user-menu-container{ + width: 46px; + .user-menu{ + position: absolute; + bottom: 6px; + right: 6px; + height: 48px; + width: 46px; + display: flex; + align-items: center; + justify-content: center; + } +} \ No newline at end of file diff --git a/src/frontend/src/app/app.component.ts b/src/frontend/src/app/app.component.ts index c6a5451..446080d 100644 --- a/src/frontend/src/app/app.component.ts +++ b/src/frontend/src/app/app.component.ts @@ -1,10 +1,127 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] -}) -export class AppComponent { - title = 'CureNet'; -} +import { Component } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { appRoutes } from './app-routing.module'; +import { AppService, WindowSize } from './modules/shared/services/app/app.service'; +import { BrowserStorageService } from './modules/shared/services/browser-storage/browser-storage.service'; +import { ThemeService } from './modules/shared/services/theme/theme.service'; +import { DomSanitizer, SafeStyle } from '@angular/platform-browser'; + +enum SidebarOpenEnum { + Default, + Open, + Closed, +} +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent { + isMobile = true; + 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; + appRoutes = appRoutes; + user = { + name: 'Name', + surname: 'Surname', + avatar: 'https://www.gravatar.com/avatar/81b206a89f89d5b1123b87606075c6a8?s=514&d=robohash', + }; + + 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, + private browserStorageService: BrowserStorageService, + private sanitizer: DomSanitizer, + ) { + this.themes = themeService.getThemes(); + this.langs = appService.getLangs(); + this.lang = appService.getLang(); + + this.themeControl.valueChanges.subscribe(theme => { + themeService.setTheme(theme); + }); + appService.changeLang(this.lang); + 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); + }); + + const sidebarUserPrefference = this.browserStorageService.getItem('sidebar.open'); + if (sidebarUserPrefference !== null) { + this.sidebarOpen = sidebarUserPrefference; + } + } + + 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 = !size.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; + this.browserStorageService.setItem('sidebar.open', this.sidebarOpen); + } + + onSidebarOpenedChange(opened: boolean) { + this.sidebarOpen = opened ? SidebarOpenEnum.Open : SidebarOpenEnum.Closed; + } + + url(url: string): SafeStyle { + return this.sanitizer.bypassSecurityTrustStyle(`url('${url}')`); + } +} \ No newline at end of file diff --git a/src/frontend/src/app/app.module.ts b/src/frontend/src/app/app.module.ts index 2c3ba29..6b83379 100644 --- a/src/frontend/src/app/app.module.ts +++ b/src/frontend/src/app/app.module.ts @@ -1,18 +1,47 @@ -import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; - -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; - -@NgModule({ - declarations: [ - AppComponent - ], - imports: [ - BrowserModule, - AppRoutingModule - ], - providers: [], - bootstrap: [AppComponent] -}) -export class AppModule { } +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { HttpClientModule, HttpClient } from '@angular/common/http'; +import { AppRoutingModule } from './app-routing.module'; +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({ + declarations: [ + AppComponent, + ], + imports: [ + BrowserModule, + AppRoutingModule, + BrowserAnimationsModule, + MaterialModule, + FormsModule, + ReactiveFormsModule, + HttpClientModule, + TranslateModule.forRoot({ + defaultLanguage: 'en', + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] + } + }), + ], + providers: [ + AppService, + ThemeService, + BrowserStorageService, + ], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/src/frontend/src/app/modules/admin/admin-routing.module.ts b/src/frontend/src/app/modules/admin/admin-routing.module.ts new file mode 100644 index 0000000..af0b82e --- /dev/null +++ b/src/frontend/src/app/modules/admin/admin-routing.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Route } from '@angular/router'; +import { NotFoundComponent } from '../shared/components/not-found/not-found.component'; + +const routes: Route[] = [ + { + path: '', + component: NotFoundComponent, + }, + { + path: 'users', + component: NotFoundComponent, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AdminRoutingModule { } diff --git a/src/frontend/src/app/modules/admin/admin.module.ts b/src/frontend/src/app/modules/admin/admin.module.ts new file mode 100644 index 0000000..6261d17 --- /dev/null +++ b/src/frontend/src/app/modules/admin/admin.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { AdminRoutingModule } from './admin-routing.module'; +import { SharedModule } from '../shared/shared.module'; + + +@NgModule({ + declarations: [], + imports: [ + CommonModule, + AdminRoutingModule, + SharedModule, + ] +}) +export class AdminModule { } diff --git a/src/frontend/src/app/modules/material/material.module.ts b/src/frontend/src/app/modules/material/material.module.ts new file mode 100644 index 0000000..99357e6 --- /dev/null +++ b/src/frontend/src/app/modules/material/material.module.ts @@ -0,0 +1,27 @@ +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'; +import {MatMenuModule} from '@angular/material/menu'; + +const itemsToExport = [ + MatToolbarModule, + MatButtonModule, + MatSidenavModule, + MatSelectModule, + MatMenuModule, +]; + +@NgModule({ + declarations: [], + imports: [ + CommonModule, + ...itemsToExport, + ], + exports: [ + ...itemsToExport, + ] +}) +export class MaterialModule { } diff --git a/src/frontend/src/app/modules/shared/components/not-found/not-found.component.html b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.html new file mode 100644 index 0000000..a8a991b --- /dev/null +++ b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.html @@ -0,0 +1,3 @@ +
+ {{ 'ERROR.PAGE_NOT_FOUND' | translate }} +
\ No newline at end of file diff --git a/src/frontend/src/app/modules/shared/components/not-found/not-found.component.scss b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/frontend/src/app/modules/shared/components/not-found/not-found.component.ts b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.ts new file mode 100644 index 0000000..7cb4124 --- /dev/null +++ b/src/frontend/src/app/modules/shared/components/not-found/not-found.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-not-found', + templateUrl: './not-found.component.html', + styleUrls: ['./not-found.component.scss'] +}) +export class NotFoundComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/frontend/src/app/modules/shared/services/app/app.service.ts b/src/frontend/src/app/modules/shared/services/app/app.service.ts new file mode 100644 index 0000000..40ae29e --- /dev/null +++ b/src/frontend/src/app/modules/shared/services/app/app.service.ts @@ -0,0 +1,72 @@ +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(); + size: WindowSize; + sizeChange = new Subject(); + + 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.translate.setDefaultLang(this.defaultLang); + this.changeLang(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', + ]; + } +} diff --git a/src/frontend/src/app/modules/shared/services/browser-storage/browser-storage.service.ts b/src/frontend/src/app/modules/shared/services/browser-storage/browser-storage.service.ts new file mode 100644 index 0000000..5ed4972 --- /dev/null +++ b/src/frontend/src/app/modules/shared/services/browser-storage/browser-storage.service.ts @@ -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; + } + +} diff --git a/src/frontend/src/app/modules/shared/services/theme/theme.service.ts b/src/frontend/src/app/modules/shared/services/theme/theme.service.ts new file mode 100644 index 0000000..080d21c --- /dev/null +++ b/src/frontend/src/app/modules/shared/services/theme/theme.service.ts @@ -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(); + + 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', + ]; + }; +} diff --git a/src/frontend/src/app/modules/shared/shared.module.ts b/src/frontend/src/app/modules/shared/shared.module.ts new file mode 100644 index 0000000..344df7e --- /dev/null +++ b/src/frontend/src/app/modules/shared/shared.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { NotFoundComponent } from './components/not-found/not-found.component'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { HttpLoaderFactory } from 'src/app/app.module'; +import { HttpClient } from '@angular/common/http'; + +@NgModule({ + declarations: [ + NotFoundComponent + ], + imports: [ + CommonModule, + TranslateModule.forRoot({ + defaultLanguage: 'en', + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] + } + }), + ], +}) +export class SharedModule { } diff --git a/src/frontend/src/app/styles/_base.scss b/src/frontend/src/app/styles/_base.scss new file mode 100644 index 0000000..300670b --- /dev/null +++ b/src/frontend/src/app/styles/_base.scss @@ -0,0 +1,6 @@ +@use 'sass:map'; + +$primary-color: map.get($theme, color, primary, 500); +body { + --primary-color: #{$primary-color}; +} \ No newline at end of file diff --git a/src/frontend/src/app/styles/_template.scss b/src/frontend/src/app/styles/_template.scss new file mode 100644 index 0000000..8d184f4 --- /dev/null +++ b/src/frontend/src/app/styles/_template.scss @@ -0,0 +1,398 @@ +$theme: ( + color: ( + primary: ( + 50: #e8eaf6, + 100: #c5cae9, + 200: #9fa8da, + 300: #7986cb, + 400: #5c6bc0, + 500: #3f51b5, + 600: #3949ab, + 700: #303f9f, + 800: #283593, + 900: #1a237e, + A100: #8c9eff, + A200: #536dfe, + A400: #3d5afe, + A700: #304ffe, + contrast: ( + 50: rgba(0, 0, 0, 0.87), + 100: rgba(0, 0, 0, 0.87), + 200: rgba(0, 0, 0, 0.87), + 300: white, + 400: white, + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(0, 0, 0, 0.87), + A200: white, + A400: white, + A700: white, + ), + default: #3f51b5, + lighter: #c5cae9, + darker: #303f9f, + text: #3f51b5, + default-contrast: white, + lighter-contrast: rgba(0, 0, 0, 0.87), + darker-contrast: white, + "50-contrast": rgba(0, 0, 0, 0.87), + "100-contrast": rgba(0, 0, 0, 0.87), + "200-contrast": rgba(0, 0, 0, 0.87), + "300-contrast": white, + "400-contrast": white, + "500-contrast": white, + "600-contrast": white, + "700-contrast": white, + "800-contrast": white, + "900-contrast": white, + "A100-contrast": rgba(0, 0, 0, 0.87), + "A200-contrast": white, + "A400-contrast": white, + "A700-contrast": white, + "contrast-contrast": null, + ), + accent: ( + 50: #fce4ec, + 100: #f8bbd0, + 200: #f48fb1, + 300: #f06292, + 400: #ec407a, + 500: #e91e63, + 600: #d81b60, + 700: #c2185b, + 800: #ad1457, + 900: #880e4f, + A100: #ff80ab, + A200: #ff4081, + A400: #f50057, + A700: #c51162, + contrast: ( + 50: rgba(0, 0, 0, 0.87), + 100: rgba(0, 0, 0, 0.87), + 200: rgba(0, 0, 0, 0.87), + 300: rgba(0, 0, 0, 0.87), + 400: rgba(0, 0, 0, 0.87), + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(0, 0, 0, 0.87), + A200: white, + A400: white, + A700: white, + ), + default: #ff4081, + lighter: #ff80ab, + darker: #f50057, + text: #ff4081, + default-contrast: white, + lighter-contrast: rgba(0, 0, 0, 0.87), + darker-contrast: white, + "50-contrast": rgba(0, 0, 0, 0.87), + "100-contrast": rgba(0, 0, 0, 0.87), + "200-contrast": rgba(0, 0, 0, 0.87), + "300-contrast": rgba(0, 0, 0, 0.87), + "400-contrast": rgba(0, 0, 0, 0.87), + "500-contrast": white, + "600-contrast": white, + "700-contrast": white, + "800-contrast": white, + "900-contrast": white, + "A100-contrast": rgba(0, 0, 0, 0.87), + "A200-contrast": white, + "A400-contrast": white, + "A700-contrast": white, + "contrast-contrast": null, + ), + warn: ( + 50: #ffebee, + 100: #ffcdd2, + 200: #ef9a9a, + 300: #e57373, + 400: #ef5350, + 500: #f44336, + 600: #e53935, + 700: #d32f2f, + 800: #c62828, + 900: #b71c1c, + A100: #ff8a80, + A200: #ff5252, + A400: #ff1744, + A700: #d50000, + contrast: ( + 50: rgba(0, 0, 0, 0.87), + 100: rgba(0, 0, 0, 0.87), + 200: rgba(0, 0, 0, 0.87), + 300: rgba(0, 0, 0, 0.87), + 400: rgba(0, 0, 0, 0.87), + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(0, 0, 0, 0.87), + A200: white, + A400: white, + A700: white, + ), + default: #f44336, + lighter: #ffcdd2, + darker: #d32f2f, + text: #f44336, + default-contrast: white, + lighter-contrast: rgba(0, 0, 0, 0.87), + darker-contrast: white, + "50-contrast": rgba(0, 0, 0, 0.87), + "100-contrast": rgba(0, 0, 0, 0.87), + "200-contrast": rgba(0, 0, 0, 0.87), + "300-contrast": rgba(0, 0, 0, 0.87), + "400-contrast": rgba(0, 0, 0, 0.87), + "500-contrast": white, + "600-contrast": white, + "700-contrast": white, + "800-contrast": white, + "900-contrast": white, + "A100-contrast": rgba(0, 0, 0, 0.87), + "A200-contrast": white, + "A400-contrast": white, + "A700-contrast": white, + "contrast-contrast": null, + ), + is-dark: true, + foreground: ( + base: white, + divider: rgba(255, 255, 255, 0.12), + dividers: rgba(255, 255, 255, 0.12), + disabled: rgba(255, 255, 255, 0.5), + disabled-button: rgba(255, 255, 255, 0.3), + disabled-text: rgba(255, 255, 255, 0.5), + elevation: black, + hint-text: rgba(255, 255, 255, 0.5), + secondary-text: rgba(255, 255, 255, 0.7), + icon: white, + icons: white, + text: white, + slider-min: white, + slider-off: rgba(255, 255, 255, 0.3), + slider-off-active: rgba(255, 255, 255, 0.3), + ), + background: ( + status-bar: black, + app-bar: #212121, + background: #303030, + hover: rgba(255, 255, 255, 0.04), + card: #424242, + dialog: #424242, + disabled-button: rgba(255, 255, 255, 0.12), + raised-button: #424242, + focused-button: rgba(255, 255, 255, 0.12), + selected-button: #212121, + selected-disabled-button: #424242, + disabled-button-toggle: black, + unselected-chip: #616161, + disabled-list-option: black, + tooltip: #616161, + ), + ), + primary: ( + 50: #e8eaf6, + 100: #c5cae9, + 200: #9fa8da, + 300: #7986cb, + 400: #5c6bc0, + 500: #3f51b5, + 600: #3949ab, + 700: #303f9f, + 800: #283593, + 900: #1a237e, + A100: #8c9eff, + A200: #536dfe, + A400: #3d5afe, + A700: #304ffe, + contrast: ( + 50: rgba(0, 0, 0, 0.87), + 100: rgba(0, 0, 0, 0.87), + 200: rgba(0, 0, 0, 0.87), + 300: white, + 400: white, + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(0, 0, 0, 0.87), + A200: white, + A400: white, + A700: white, + ), + default: #3f51b5, + lighter: #c5cae9, + darker: #303f9f, + text: #3f51b5, + default-contrast: white, + lighter-contrast: rgba(0, 0, 0, 0.87), + darker-contrast: white, + "50-contrast": rgba(0, 0, 0, 0.87), + "100-contrast": rgba(0, 0, 0, 0.87), + "200-contrast": rgba(0, 0, 0, 0.87), + "300-contrast": white, + "400-contrast": white, + "500-contrast": white, + "600-contrast": white, + "700-contrast": white, + "800-contrast": white, + "900-contrast": white, + "A100-contrast": rgba(0, 0, 0, 0.87), + "A200-contrast": white, + "A400-contrast": white, + "A700-contrast": white, + "contrast-contrast": null, + ), + accent: ( + 50: #fce4ec, + 100: #f8bbd0, + 200: #f48fb1, + 300: #f06292, + 400: #ec407a, + 500: #e91e63, + 600: #d81b60, + 700: #c2185b, + 800: #ad1457, + 900: #880e4f, + A100: #ff80ab, + A200: #ff4081, + A400: #f50057, + A700: #c51162, + contrast: ( + 50: rgba(0, 0, 0, 0.87), + 100: rgba(0, 0, 0, 0.87), + 200: rgba(0, 0, 0, 0.87), + 300: rgba(0, 0, 0, 0.87), + 400: rgba(0, 0, 0, 0.87), + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(0, 0, 0, 0.87), + A200: white, + A400: white, + A700: white, + ), + default: #ff4081, + lighter: #ff80ab, + darker: #f50057, + text: #ff4081, + default-contrast: white, + lighter-contrast: rgba(0, 0, 0, 0.87), + darker-contrast: white, + "50-contrast": rgba(0, 0, 0, 0.87), + "100-contrast": rgba(0, 0, 0, 0.87), + "200-contrast": rgba(0, 0, 0, 0.87), + "300-contrast": rgba(0, 0, 0, 0.87), + "400-contrast": rgba(0, 0, 0, 0.87), + "500-contrast": white, + "600-contrast": white, + "700-contrast": white, + "800-contrast": white, + "900-contrast": white, + "A100-contrast": rgba(0, 0, 0, 0.87), + "A200-contrast": white, + "A400-contrast": white, + "A700-contrast": white, + "contrast-contrast": null, + ), + warn: ( + 50: #ffebee, + 100: #ffcdd2, + 200: #ef9a9a, + 300: #e57373, + 400: #ef5350, + 500: #f44336, + 600: #e53935, + 700: #d32f2f, + 800: #c62828, + 900: #b71c1c, + A100: #ff8a80, + A200: #ff5252, + A400: #ff1744, + A700: #d50000, + contrast: ( + 50: rgba(0, 0, 0, 0.87), + 100: rgba(0, 0, 0, 0.87), + 200: rgba(0, 0, 0, 0.87), + 300: rgba(0, 0, 0, 0.87), + 400: rgba(0, 0, 0, 0.87), + 500: white, + 600: white, + 700: white, + 800: white, + 900: white, + A100: rgba(0, 0, 0, 0.87), + A200: white, + A400: white, + A700: white, + ), + default: #f44336, + lighter: #ffcdd2, + darker: #d32f2f, + text: #f44336, + default-contrast: white, + lighter-contrast: rgba(0, 0, 0, 0.87), + darker-contrast: white, + "50-contrast": rgba(0, 0, 0, 0.87), + "100-contrast": rgba(0, 0, 0, 0.87), + "200-contrast": rgba(0, 0, 0, 0.87), + "300-contrast": rgba(0, 0, 0, 0.87), + "400-contrast": rgba(0, 0, 0, 0.87), + "500-contrast": white, + "600-contrast": white, + "700-contrast": white, + "800-contrast": white, + "900-contrast": white, + "A100-contrast": rgba(0, 0, 0, 0.87), + "A200-contrast": white, + "A400-contrast": white, + "A700-contrast": white, + "contrast-contrast": null, + ), + is-dark: true, + foreground: ( + base: white, + divider: rgba(255, 255, 255, 0.12), + dividers: rgba(255, 255, 255, 0.12), + disabled: rgba(255, 255, 255, 0.5), + disabled-button: rgba(255, 255, 255, 0.3), + disabled-text: rgba(255, 255, 255, 0.5), + elevation: black, + hint-text: rgba(255, 255, 255, 0.5), + secondary-text: rgba(255, 255, 255, 0.7), + icon: white, + icons: white, + text: white, + slider-min: white, + slider-off: rgba(255, 255, 255, 0.3), + slider-off-active: rgba(255, 255, 255, 0.3), + ), + background: ( + status-bar: black, + app-bar: #212121, + background: #303030, + hover: rgba(255, 255, 255, 0.04), + card: #424242, + dialog: #424242, + disabled-button: rgba(255, 255, 255, 0.12), + raised-button: #424242, + focused-button: rgba(255, 255, 255, 0.12), + selected-button: #212121, + selected-disabled-button: #424242, + disabled-button-toggle: black, + unselected-chip: #616161, + disabled-list-option: black, + tooltip: #616161, + ), +); diff --git a/src/frontend/src/app/styles/dark.scss b/src/frontend/src/app/styles/dark.scss new file mode 100644 index 0000000..df3b111 --- /dev/null +++ b/src/frontend/src/app/styles/dark.scss @@ -0,0 +1,35 @@ +// 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/ +$theme-primary: mat.define-palette(mat.$blue-palette); +$theme-accent: mat.define-palette(mat.$green-palette, A200, A100, A400); + +// The warn palette is optional (defaults to red). +$theme-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". +$theme: mat.define-dark-theme(( + color: ( + primary: $theme-primary, + accent: $theme-accent, + warn: $theme-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($theme); + +@import "./base"; diff --git a/src/frontend/src/app/styles/light.scss b/src/frontend/src/app/styles/light.scss new file mode 100644 index 0000000..423617d --- /dev/null +++ b/src/frontend/src/app/styles/light.scss @@ -0,0 +1,35 @@ +// 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/ +$theme-primary: mat.define-palette(mat.$indigo-palette); +$theme-accent: mat.define-palette(mat.$light-blue-palette, A200, A100, A400); + +// The warn palette is optional (defaults to red). +$theme-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". +$theme: mat.define-light-theme(( + color: ( + primary: $theme-primary, + accent: $theme-accent, + warn: $theme-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($theme); + +@import "./base"; \ No newline at end of file diff --git a/src/frontend/src/assets/lang/en.json b/src/frontend/src/assets/lang/en.json new file mode 100644 index 0000000..58dc61a --- /dev/null +++ b/src/frontend/src/assets/lang/en.json @@ -0,0 +1,28 @@ +{ + "APP": { + "NAME": "CureNet", + "THEME": "Theme", + "LANGUAGE": "Language" + }, + "ERROR": { + "PAGE_NOT_FOUND": "Page not found or not implemented yet!" + }, + "THEME": { + "LIGHT": "Light", + "DARK": "Dark" + }, + "LANGUAGE": { + "PL": "Polish", + "EN": "English" + }, + "MENU": { + "HOME": "Dashboard", + "PROFILE": "Profile", + "COMMUNITY": "Community", + "MESSAGES": "Messages", + "TESTS": "Laboratory tests", + "RESEARCH": "Research", + "ADMIN": "Admin", + "USERS": "Users" + } +} \ No newline at end of file diff --git a/src/frontend/src/assets/lang/pl.json b/src/frontend/src/assets/lang/pl.json new file mode 100644 index 0000000..6855253 --- /dev/null +++ b/src/frontend/src/assets/lang/pl.json @@ -0,0 +1,28 @@ +{ + "APP": { + "NAME": "CureNet", + "THEME": "Motyw", + "LANGUAGE": "Język" + }, + "ERROR": { + "PAGE_NOT_FOUND": "Nie znaleziono strony lub nie została ona jeszcze zaimplementowana!" + }, + "THEME": { + "LIGHT": "Jasny", + "DARK": "Ciemny" + }, + "LANGUAGE": { + "PL": "Polski", + "EN": "Angielski" + }, + "MENU": { + "HOME": "Kokpit", + "PROFILE": "Profil", + "COMMUNITY": "Społeczność", + "MESSAGES": "Wiadomości", + "TESTS": "Wyniki badań", + "RESEARCH": "Badania naukowe", + "ADMIN": "Panel administratora", + "USERS": "Użytkownicy" + } +} \ No newline at end of file diff --git a/src/frontend/src/index.html b/src/frontend/src/index.html index 3af61ec..0b791e2 100644 --- a/src/frontend/src/index.html +++ b/src/frontend/src/index.html @@ -1,13 +1,17 @@ - - - - - Frontend - - - - - - - - + + + + + CureNet + + + + + + + + + + + + diff --git a/src/frontend/src/styles.scss b/src/frontend/src/styles.scss index 90d4ee0..ef52523 100644 --- a/src/frontend/src/styles.scss +++ b/src/frontend/src/styles.scss @@ -1 +1,45 @@ /* 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; + .menu-item{ + margin-left: 0px !important; + &:after{ + right: 190px; + } + & > i{ + width: 40px; + font-size: 120%; + } + } + .hide-on-side-opened{ + display: none; + } + & ~ .mat-drawer-content { + margin-left: 60px !important; + } + } +} +.w-220{ + width: 220px; +} \ No newline at end of file