diff --git a/webapp/.angular-cli.json b/webapp/.angular-cli.json index 862071be9ffc02a136894ecaed8fe4050f4c44fe..8310aa96c05fa2afd99b235933f74649a667ee41 100644 --- a/webapp/.angular-cli.json +++ b/webapp/.angular-cli.json @@ -19,7 +19,8 @@ "testTsconfig": "tsconfig.spec.json", "prefix": "app", "styles": [ - "styles.scss" + "styles.scss", + "theme.scss" ], "scripts": [], "environmentSource": "environments/environment.ts", diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 9ba900984a9e075ac4bf541806e54c3f1e1a29dd..090f6bcac4ad711bad57fa74369b6848f681d9e1 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -9167,6 +9167,12 @@ "pify": "3.0.0" } }, + "sass-recursive-map-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sass-recursive-map-merge/-/sass-recursive-map-merge-1.0.1.tgz", + "integrity": "sha512-OuDTGVGx2o2sPeaSgGob5s2Qf6LxoMU4LG7n6vCzNgfXyBz/y8tKzcEYdmvgyhjvGQVcGA1g2UJnP7WMmahuVg==", + "dev": true + }, "saucelabs": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", diff --git a/webapp/package.json b/webapp/package.json index 20789ef7cb18019d6c09e0ff6f44ecc8c75d6f64..01a565070f427b258d33759fe79a2b959f4ed199 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -45,6 +45,7 @@ "protractor": "~5.1.2", "ts-node": "~4.1.0", "tslint": "~5.9.1", + "sass-recursive-map-merge": "^1.0.1", "typescript": "~2.5.3" } } diff --git a/webapp/src/app/app-routing.module.ts b/webapp/src/app/app-routing.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c38405b0235287c98d52810c8165c4cf5052902 --- /dev/null +++ b/webapp/src/app/app-routing.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [ + { path: '', redirectTo: 'app', pathMatch: 'full' } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/webapp/src/app/app.component.html b/webapp/src/app/app.component.html index fa2706a406ba65e05f8e23003ce6e9df291fa146..6a164d6971c1e767eae999e03e288a6325ba9ed9 100644 --- a/webapp/src/app/app.component.html +++ b/webapp/src/app/app.component.html @@ -1,20 +1,2 @@ -<!--The content below is only a placeholder and can be replaced.--> -<div style="text-align:center"> - <h1> - Welcome to {{ title }}! - </h1> - <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="> -</div> -<h2>Here are some links to help you start: </h2> -<ul> - <li> - <h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2> - </li> - <li> - <h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2> - </li> - <li> - <h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2> - </li> -</ul> +<router-outlet></router-outlet> diff --git a/webapp/src/app/app.module.ts b/webapp/src/app/app.module.ts index f4b848b8835c0e14215239eab4444bcca16d2493..2d9e72fbd4c9f4672bcaa7c9a0c8be27abbd72a3 100644 --- a/webapp/src/app/app.module.ts +++ b/webapp/src/app/app.module.ts @@ -4,8 +4,9 @@ import { NgModule } from '@angular/core'; import { AppMaterialModule } from './app.material.module'; - import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; +import { CoreModule } from './core/core.module'; @NgModule({ @@ -15,7 +16,9 @@ import { AppComponent } from './app.component'; imports: [ BrowserModule, BrowserAnimationsModule, - AppMaterialModule + AppMaterialModule, + CoreModule, + AppRoutingModule ], providers: [], bootstrap: [AppComponent] diff --git a/webapp/src/app/core/components/footer/footer.component.html b/webapp/src/app/core/components/footer/footer.component.html new file mode 100644 index 0000000000000000000000000000000000000000..6800e0eb1bdd02470a1e7a55dab3a9ed7d615d50 --- /dev/null +++ b/webapp/src/app/core/components/footer/footer.component.html @@ -0,0 +1,3 @@ +<p> + footer works! +</p> diff --git a/webapp/src/app/core/components/footer/footer.component.scss b/webapp/src/app/core/components/footer/footer.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/webapp/src/app/core/components/footer/footer.component.spec.ts b/webapp/src/app/core/components/footer/footer.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ca6c45431d529bbf993d17231e1c7604bb6a480 --- /dev/null +++ b/webapp/src/app/core/components/footer/footer.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FooterComponent } from './footer.component'; + +describe('FooterComponent', () => { + let component: FooterComponent; + let fixture: ComponentFixture<FooterComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FooterComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FooterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/webapp/src/app/core/components/footer/footer.component.ts b/webapp/src/app/core/components/footer/footer.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..da17d824231ebb84b3dd5872e8ad33b5ef659771 --- /dev/null +++ b/webapp/src/app/core/components/footer/footer.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'] +}) +export class FooterComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/webapp/src/app/core/components/header/header.component.html b/webapp/src/app/core/components/header/header.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c3dba65821136f45183b547d8cc500d8b27f793a --- /dev/null +++ b/webapp/src/app/core/components/header/header.component.html @@ -0,0 +1,3 @@ +<mat-toolbar color="primary"> + <span>OpenData</span> +</mat-toolbar> \ No newline at end of file diff --git a/webapp/src/app/core/components/header/header.component.scss b/webapp/src/app/core/components/header/header.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/webapp/src/app/core/components/header/header.component.spec.ts b/webapp/src/app/core/components/header/header.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d0479d7d071a5e6d19a74d195ff34b2edeb5616 --- /dev/null +++ b/webapp/src/app/core/components/header/header.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeaderComponent } from './header.component'; + +describe('HeaderComponent', () => { + let component: HeaderComponent; + let fixture: ComponentFixture<HeaderComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeaderComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/webapp/src/app/core/components/header/header.component.ts b/webapp/src/app/core/components/header/header.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..591e148a7dc2965fb26c07394dd0ae005930bca8 --- /dev/null +++ b/webapp/src/app/core/components/header/header.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.scss'] +}) +export class HeaderComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/webapp/src/app/core/components/main/main.component.html b/webapp/src/app/core/components/main/main.component.html new file mode 100644 index 0000000000000000000000000000000000000000..bfa5088f191e9dc19dae414a23c66f29c10a30fa --- /dev/null +++ b/webapp/src/app/core/components/main/main.component.html @@ -0,0 +1,9 @@ +<app-header></app-header> + +<div class="container-fluid"> + <p> + main works! + </p> +</div> + +<app-footer></app-footer> diff --git a/webapp/src/app/core/components/main/main.component.scss b/webapp/src/app/core/components/main/main.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/webapp/src/app/core/components/main/main.component.spec.ts b/webapp/src/app/core/components/main/main.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0878044ab32aff4c5da064c511d97805bf305c08 --- /dev/null +++ b/webapp/src/app/core/components/main/main.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MainComponent } from './main.component'; + +describe('MainComponent', () => { + let component: MainComponent; + let fixture: ComponentFixture<MainComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MainComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MainComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/webapp/src/app/core/components/main/main.component.ts b/webapp/src/app/core/components/main/main.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..8b899ba8f85ff4b77f58fe4b40e901e358650a85 --- /dev/null +++ b/webapp/src/app/core/components/main/main.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-main', + templateUrl: './main.component.html', + styleUrls: ['./main.component.scss'] +}) +export class MainComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/webapp/src/app/core/core-routing.module.ts b/webapp/src/app/core/core-routing.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..90928dee8fee6426218ddb728ebd039c707db39e --- /dev/null +++ b/webapp/src/app/core/core-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { MainComponent } from './components/main/main.component'; + +const routes: Routes = [ + { path: 'app', component: MainComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class CoreRoutingModule { } diff --git a/webapp/src/app/core/core.module.ts b/webapp/src/app/core/core.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7e457442d22a2eb7963e5ac31f083260f1817aa --- /dev/null +++ b/webapp/src/app/core/core.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { CoreRoutingModule } from './core-routing.module'; +import { HeaderComponent } from './components/header/header.component'; +import { MainComponent } from './components/main/main.component'; +import { FooterComponent } from './components/footer/footer.component'; +import { AppMaterialModule } from '../app.material.module'; + +@NgModule({ + imports: [ + CommonModule, + CoreRoutingModule, + AppMaterialModule + ], + declarations: [HeaderComponent, MainComponent, FooterComponent] +}) +export class CoreModule { } diff --git a/webapp/src/assets/img/android-chrome-192x192.png b/webapp/src/assets/img/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..27c7e19579c49567b1de0625ddf670927b0718e7 Binary files /dev/null and b/webapp/src/assets/img/android-chrome-192x192.png differ diff --git a/webapp/src/assets/img/android-chrome-512x512.png b/webapp/src/assets/img/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..70d2e5c65b6f2d949814afaefbf7dfa0521687ea Binary files /dev/null and b/webapp/src/assets/img/android-chrome-512x512.png differ diff --git a/webapp/src/assets/img/apple-touch-icon.png b/webapp/src/assets/img/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f6a9f6786a18ae9941594b9731ad679fe919be15 Binary files /dev/null and b/webapp/src/assets/img/apple-touch-icon.png differ diff --git a/webapp/src/assets/img/favicon-16x16.png b/webapp/src/assets/img/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..1870e1d32ea23a1106918dc041f86739f2589f61 Binary files /dev/null and b/webapp/src/assets/img/favicon-16x16.png differ diff --git a/webapp/src/assets/img/favicon-32x32.png b/webapp/src/assets/img/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..f6297745e4fddbc6d05d33642f5fbd858f1cbef6 Binary files /dev/null and b/webapp/src/assets/img/favicon-32x32.png differ diff --git a/webapp/src/assets/img/favicon.ico b/webapp/src/assets/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5619a8f1cf3db720725e00d80636e23de406e8de Binary files /dev/null and b/webapp/src/assets/img/favicon.ico differ diff --git a/webapp/src/assets/img/logo.svg b/webapp/src/assets/img/logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..2bb541a68f8595a52f51e4c22fe9f69e65b6b97a --- /dev/null +++ b/webapp/src/assets/img/logo.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="185.6" height="37.9" viewBox="0 0 185.6 37.9"> + <path d="M14.4 21.3C12.8 23 10.5 24 8.1 24c-2.2 0-4.4-.9-5.9-2.4C0 19.5 0 17.4 0 12c0-5.3 0-7.4 2.2-9.6C3.8.9 5.9 0 8.1 0c4.2 0 7.4 2.7 8.1 6.9h-1.8c-.7-3.3-3.1-5.3-6.3-5.3-1.7 0-3.3.6-4.5 1.8C1.9 5.1 1.8 6.9 1.8 12s.1 6.9 1.8 8.6c1.2 1.2 2.8 1.8 4.5 1.8 1.9 0 3.7-.8 4.9-2.3 1-1.3 1.4-2.7 1.4-4.7v-2.1H8.1v-1.6h8.2v3.8c0 2.6-.5 4.3-1.9 5.8zm22.2 2.5l-5.7-10.9h-6.5v10.9h-1.8V.2h9c3.9 0 6.8 2.2 6.8 6.3 0 3.5-2.1 5.8-5.5 6.4l5.7 10.9h-2zm-5.2-22h-7v9.6h7c3 0 5.2-1.5 5.2-4.8s-2.2-4.8-5.2-4.8m27 22l-2.1-5.7h-11l-2.1 5.7h-1.9L50 .2h1.6l8.7 23.6h-1.9zM50.8 2.6l-5 13.9h9.9L50.8 2.6zM80 23.8L66.3 3.3v20.5h-1.8V.2h1.8L80 20.7V.2h1.8v23.6H80zm23-2.1c-1.4 1.4-3.5 2.1-5.9 2.1h-8V.2h8c2.5 0 4.5.8 5.9 2.2 2.4 2.4 2.3 6.1 2.3 9.3 0 3.2.1 7.6-2.3 10m-1.2-18.1c-1.4-1.4-3.2-1.8-5.1-1.8H91v20.4h5.7c1.9 0 3.7-.4 5.1-1.8 1.9-1.9 1.8-6.1 1.8-8.7-.1-2.6.1-6.2-1.8-8.1z" fill="#ed1c24"/> + <path d="M110.8 23.8V.2h4.6v19.5h10.8v4.1h-15.4zm25.6-9.7v9.7h-4.6v-9.7L124.7.2h5l4.4 9.5 4.4-9.5h5l-7.1 13.9zm24 7.3c-1.7 1.7-3.7 2.6-6.4 2.6s-4.8-.9-6.4-2.6c-2.4-2.4-2.3-5.3-2.3-9.4 0-4.1-.1-7 2.3-9.4C149.3.9 151.3 0 154 0s4.7.9 6.4 2.6c2.4 2.4 2.4 5.3 2.4 9.4-.1 4.1 0 7.1-2.4 9.4m-3.5-16c-.7-.8-1.7-1.3-3-1.3s-2.3.5-3 1.3c-.9 1-1.1 2.1-1.1 6.6s.2 5.6 1.1 6.6c.7.8 1.7 1.3 3 1.3s2.3-.5 3-1.3c.9-1 1.2-2.1 1.2-6.6s-.3-5.6-1.2-6.6zm24.6 18.4l-9.4-14.5v14.5h-4.6V.2h4.1l9.4 14.5V.2h4.6v23.6h-4.1z" fill="#050607"/> + <path d="M159.4 33.2c0-.8 0-2-1.1-2s-1 1.5-1 2.3c0 .7.1 1.8 1 1.8 1 0 1.1-.7 1.1-2.1m-2-1.9c.3-.5.7-.7 1.2-.7.9 0 1.7.3 1.7 2.6 0 1.3 0 2.8-1.7 2.8-.5 0-.9-.2-1.2-.6v2.5h-.9v-7.3h.9v.7zm-61.1 3.1c0 .5.2 1 .8 1 .5 0 1.2-.3 1.1-2-.8-.1-1.9-.1-1.9 1m1.9.8c-.3.6-.7.9-1.3.9-1.1 0-1.4-.7-1.4-1.7 0-1.6 1.6-1.7 2.8-1.6 0-.7 0-1.5-.9-1.5-.6 0-.9.4-.8.9h-.9c0-1.2.7-1.6 1.8-1.6 1.4 0 1.7.7 1.7 1.6v2.5c0 .4 0 .8.1 1.3h-.9l-.2-.8zm15.4.7v-3.7c0-.5-.2-1-.8-1-.3 0-.6.2-.7.4-.2.3-.2.6-.2.8V36h-.9v-4.2c0-.4 0-.7-.1-1.1h.9v.7c.2-.6.7-.8 1.3-.8.5 0 1 .2 1.2.7.3-.6.8-.7 1.3-.7.6 0 1.4.1 1.4 1.4v4h-.9v-3.7c0-.5-.2-1-.8-1-.3 0-.4 0-.7.2-.2.2-.3.7-.3.9V36c.2-.1-.7-.1-.7-.1zm12.1-7.5l-1.4 1.5h-.7l.9-1.5h1.2zm-.2 4.5c0-1.5-.4-1.7-1.1-1.7-.6 0-1 .3-1 1.7h2.1zm-2.1.7c0 1.5.4 1.8 1.1 1.8.6 0 .9-.5.9-1h.9c0 1.2-.7 1.7-1.8 1.7s-2-.3-2-2.7c0-1.5.2-2.8 2-2.8 1.5 0 1.9.8 1.9 2.6v.4h-3zm8.8-2.9v-1l.9-.4v1.4h1.1v.6H133v3.2c0 .3 0 .8.8.8h.4v.7c-.3 0-.6.1-.9.1-.8 0-1.2-.3-1.2-.9v-3.7h-.9v-.6l1-.2zm8.4.8c.4-.8.8-.9 1.7-.9v.9h-.4c-.9 0-1.2.7-1.2 1.4V36h-.9v-5.3h.9l-.1.8zm9.7 1.5c0-1.4-.4-1.8-1.1-1.8-.7 0-1.1.3-1.1 1.8 0 1.7.2 2.3 1.1 2.3.8 0 1.1-.6 1.1-2.3m-3.1.4c0-1.5.2-2.8 2-2.8s2 1.3 2 2.8c0 2.3-.9 2.7-2 2.7-1.2-.1-2-.4-2-2.7zm21.5-.4c0-1.4-.4-1.8-1.1-1.8s-1.1.3-1.1 1.8c0 1.7.2 2.3 1.1 2.3.8 0 1.1-.6 1.1-2.3m-3.1.4c0-1.5.2-2.8 2-2.8s2 1.3 2 2.8c0 2.3-.9 2.7-2 2.7-1.2-.1-2-.4-2-2.7zm10.4 2.5h-.9v-7.5h.9v7.5zm8.4-3c0-1.5-.4-1.7-1.1-1.7-.5 0-1 .3-1 1.7h2.1zm-2.1.7c0 1.5.4 1.8 1.1 1.8.6 0 .9-.5.9-1h.9c0 1.2-.7 1.7-1.8 1.7s-2-.3-2-2.7c0-1.5.2-2.8 2-2.8 1.5 0 1.9.8 1.9 2.6v.4h-3zm-91.8 2.3h-.9v-7.5h.9v7.5z" fill="#231f20"/> +</svg> diff --git a/webapp/src/scss/_functions.scss b/webapp/src/scss/_functions.scss new file mode 100644 index 0000000000000000000000000000000000000000..1266d34bd9029922e92809b52827b479c7d9e8f9 --- /dev/null +++ b/webapp/src/scss/_functions.scss @@ -0,0 +1,86 @@ +// Bootstrap functions +// +// Utility mixins and functions for evalutating source code across our variables, maps, and mixins. + +// Ascending +// Used to evaluate Sass maps like our grid breakpoints. +@mixin _assert-ascending($map, $map-name) { + $prev-key: null; + $prev-num: null; + @each $key, $num in $map { + @if $prev-num == null { + // Do nothing + } @else if not comparable($prev-num, $num) { + @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } @else if $prev-num >= $num { + @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } + $prev-key: $key; + $prev-num: $num; + } +} + +// Starts at zero +// Another grid mixin that ensures the min-width of the lowest breakpoint starts at 0. +@mixin _assert-starts-at-zero($map) { + $values: map-values($map); + $first-value: nth($values, 1); + @if $first-value != 0 { + @warn "First breakpoint in `$grid-breakpoints` must start at 0, but starts at #{$first-value}."; + } +} + +// Replace `$search` with `$replace` in `$string` +// Used on our SVG icon backgrounds for custom forms. +// +// @author Hugo Giraudel +// @param {String} $string - Initial string +// @param {String} $search - Substring to replace +// @param {String} $replace ('') - New value +// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} + +// Color contrast +@function color-yiq($color) { + $r: red($color); + $g: green($color); + $b: blue($color); + + $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000; + + @if ($yiq >= $yiq-contrasted-threshold) { + @return $yiq-text-dark; + } @else { + @return $yiq-text-light; + } +} + +// Retrieve color Sass maps +@function color($key: "blue") { + @return map-get($colors, $key); +} + +@function theme-color($key: "primary") { + @return map-get($theme-colors, $key); +} + +@function gray($key: "100") { + @return map-get($grays, $key); +} + +// Request a theme color level +@function theme-color-level($color-name: "primary", $level: 0) { + $color: theme-color($color-name); + $color-base: if($level > 0, #000, #fff); + $level: abs($level); + + @return mix($color-base, $color, $level * $theme-color-interval); +} diff --git a/webapp/src/scss/_grid.scss b/webapp/src/scss/_grid.scss new file mode 100644 index 0000000000000000000000000000000000000000..a227515379c4bd9979039bc0e86ca3626123b96b --- /dev/null +++ b/webapp/src/scss/_grid.scss @@ -0,0 +1,52 @@ +// Container widths +// +// Set the container width, and override it for fixed navbars in media queries. + +@if $enable-grid-classes { + .container { + @include make-container(); + @include make-container-max-widths(); + } +} + +// Fluid container +// +// Utilizes the mixin meant for fixed width containers, but with 100% width for +// fluid, full width layouts. + +@if $enable-grid-classes { + .container-fluid { + @include make-container(); + } +} + +// Row +// +// Rows contain and clear the floats of your columns. + +@if $enable-grid-classes { + .row { + @include make-row(); + } + + // Remove the negative margin from default .row, then the horizontal padding + // from all immediate children columns (to prevent runaway style inheritance). + .no-gutters { + margin-right: 0; + margin-left: 0; + + > .col, + > [class*="col-"] { + padding-right: 0; + padding-left: 0; + } + } +} + +// Columns +// +// Common styles for small and large grid columns + +@if $enable-grid-classes { + @include make-grid-columns(); +} diff --git a/webapp/src/scss/_variables.scss b/webapp/src/scss/_variables.scss new file mode 100644 index 0000000000000000000000000000000000000000..be580deb334db623fe68d885df0823f6df945b87 --- /dev/null +++ b/webapp/src/scss/_variables.scss @@ -0,0 +1,894 @@ +// Variables +// +// Variables should follow the `$component-state-property-size` formula for +// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. + + +// +// Color system +// + +// stylelint-disable +$white: #fff !default; +$gray-100: #f8f9fa !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #adb5bd !default; +$gray-600: #6c757d !default; +$gray-700: #495057 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$black: #000 !default; + +$grays: () !default; +$grays: map-merge(( + "100": $gray-100, + "200": $gray-200, + "300": $gray-300, + "400": $gray-400, + "500": $gray-500, + "600": $gray-600, + "700": $gray-700, + "800": $gray-800, + "900": $gray-900 +), $grays); + +$blue: #007bff !default; +$indigo: #6610f2 !default; +$purple: #6f42c1 !default; +$pink: #e83e8c !default; +$red: #dc3545 !default; +$orange: #fd7e14 !default; +$yellow: #ffc107 !default; +$green: #28a745 !default; +$teal: #20c997 !default; +$cyan: #17a2b8 !default; + +$colors: () !default; +$colors: map-merge(( + "blue": $blue, + "indigo": $indigo, + "purple": $purple, + "pink": $pink, + "red": $red, + "orange": $orange, + "yellow": $yellow, + "green": $green, + "teal": $teal, + "cyan": $cyan, + "white": $white, + "gray": $gray-600, + "gray-dark": $gray-800 +), $colors); + +$primary: $blue !default; +$secondary: $gray-600 !default; +$success: $green !default; +$info: $cyan !default; +$warning: $yellow !default; +$danger: $red !default; +$light: $gray-100 !default; +$dark: $gray-800 !default; + +$theme-colors: () !default; +$theme-colors: map-merge(( + "primary": $primary, + "secondary": $secondary, + "success": $success, + "info": $info, + "warning": $warning, + "danger": $danger, + "light": $light, + "dark": $dark +), $theme-colors); +// stylelint-enable + +// Set a specific jump point for requesting color jumps +$theme-color-interval: 8% !default; + +// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. +$yiq-contrasted-threshold: 150 !default; + +// Customize the light and dark text colors for use in our YIQ color contrast function. +$yiq-text-dark: $gray-900 !default; +$yiq-text-light: $white !default; + +// Options +// +// Quickly modify global styling by enabling or disabling optional features. + +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS +$enable-grid-classes: true !default; +$enable-print-styles: true !default; + + +// Spacing +// +// Control the default styling of most Bootstrap elements by modifying these +// variables. Mostly focused on spacing. +// You can add more entries to the $spacers map, should you need more variation. + +// stylelint-disable +$spacer: 1rem !default; +$spacers: () !default; +$spacers: map-merge(( + 0: 0, + 1: ($spacer * .25), + 2: ($spacer * .5), + 3: $spacer, + 4: ($spacer * 1.5), + 5: ($spacer * 3) +), $spacers); + +// This variable affects the `.h-*` and `.w-*` classes. +$sizes: () !default; +$sizes: map-merge(( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100% +), $sizes); +// stylelint-enable + +// Body +// +// Settings for the `<body>` element. + +$body-bg: $white !default; +$body-color: $gray-900 !default; + +// Links +// +// Style anchor elements. + +$link-color: theme-color("primary") !default; +$link-decoration: none !default; +$link-hover-color: darken($link-color, 15%) !default; +$link-hover-decoration: underline !default; + +// Paragraphs +// +// Style p element. + +$paragraph-margin-bottom: 1rem !default; + + +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. + +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px +) !default; + +@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +@include _assert-starts-at-zero($grid-breakpoints); + + +// Grid containers +// +// Define the maximum width of `.container` for different screen sizes. + +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px +) !default; + +@include _assert-ascending($container-max-widths, "$container-max-widths"); + + +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +$grid-columns: 12 !default; +$grid-gutter-width: 30px !default; + +// Components +// +// Define common padding and border radius sizes and more. + +$line-height-lg: 1.5 !default; +$line-height-sm: 1.5 !default; + +$border-width: 1px !default; +$border-color: $gray-300 !default; + +$border-radius: .25rem !default; +$border-radius-lg: .3rem !default; +$border-radius-sm: .2rem !default; + +$component-active-color: $white !default; +$component-active-bg: theme-color("primary") !default; + +$caret-width: .3em !default; + +$transition-base: all .2s ease-in-out !default; +$transition-fade: opacity .15s linear !default; +$transition-collapse: height .35s ease !default; + + +// Fonts +// +// Font, line-height, and color for body text, headings, and more. + +// stylelint-disable value-keyword-case +$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default; +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; +$font-family-base: $font-family-sans-serif !default; +// stylelint-enable value-keyword-case + +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-lg: ($font-size-base * 1.25) !default; +$font-size-sm: ($font-size-base * .875) !default; + +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-bold: 700 !default; + +$font-weight-base: $font-weight-normal !default; +$line-height-base: 1.5 !default; + +$h1-font-size: $font-size-base * 2.5 !default; +$h2-font-size: $font-size-base * 2 !default; +$h3-font-size: $font-size-base * 1.75 !default; +$h4-font-size: $font-size-base * 1.5 !default; +$h5-font-size: $font-size-base * 1.25 !default; +$h6-font-size: $font-size-base !default; + +$headings-margin-bottom: ($spacer / 2) !default; +$headings-font-family: inherit !default; +$headings-font-weight: 500 !default; +$headings-line-height: 1.2 !default; +$headings-color: inherit !default; + +$display1-size: 6rem !default; +$display2-size: 5.5rem !default; +$display3-size: 4.5rem !default; +$display4-size: 3.5rem !default; + +$display1-weight: 300 !default; +$display2-weight: 300 !default; +$display3-weight: 300 !default; +$display4-weight: 300 !default; +$display-line-height: $headings-line-height !default; + +$lead-font-size: ($font-size-base * 1.25) !default; +$lead-font-weight: 300 !default; + +$small-font-size: 80% !default; + +$text-muted: $gray-600 !default; + +$blockquote-small-color: $gray-600 !default; +$blockquote-font-size: ($font-size-base * 1.25) !default; + +$hr-border-color: rgba($black, .1) !default; +$hr-border-width: $border-width !default; + +$mark-padding: .2em !default; + +$dt-font-weight: $font-weight-bold !default; + +$kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; +$nested-kbd-font-weight: $font-weight-bold !default; + +$list-inline-padding: .5rem !default; + +$mark-bg: #fcf8e3 !default; + +$hr-margin-y: $spacer !default; + + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +$table-cell-padding: .75rem !default; +$table-cell-padding-sm: .3rem !default; + +$table-bg: transparent !default; +$table-accent-bg: rgba($black, .05) !default; +$table-hover-bg: rgba($black, .075) !default; +$table-active-bg: $table-hover-bg !default; + +$table-border-width: $border-width !default; +$table-border-color: $gray-300 !default; + +$table-head-bg: $gray-200 !default; +$table-head-color: $gray-700 !default; + +$table-dark-bg: $gray-900 !default; +$table-dark-accent-bg: rgba($white, .05) !default; +$table-dark-hover-bg: rgba($white, .075) !default; +$table-dark-border-color: lighten($gray-900, 7.5%) !default; +$table-dark-color: $body-bg !default; + + +// Buttons + Forms +// +// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. + +$input-btn-padding-y: .375rem !default; +$input-btn-padding-x: .75rem !default; +$input-btn-line-height: $line-height-base !default; + +$input-btn-focus-width: .2rem !default; +$input-btn-focus-color: rgba($component-active-bg, .25) !default; +$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; + +$input-btn-padding-y-sm: .25rem !default; +$input-btn-padding-x-sm: .5rem !default; +$input-btn-line-height-sm: $line-height-sm !default; + +$input-btn-padding-y-lg: .5rem !default; +$input-btn-padding-x-lg: 1rem !default; +$input-btn-line-height-lg: $line-height-lg !default; + +$input-btn-border-width: $border-width !default; + + +// Buttons +// +// For each of Bootstrap's buttons, define text, background, and border color. + +$btn-padding-y: $input-btn-padding-y !default; +$btn-padding-x: $input-btn-padding-x !default; +$btn-line-height: $input-btn-line-height !default; + +$btn-padding-y-sm: $input-btn-padding-y-sm !default; +$btn-padding-x-sm: $input-btn-padding-x-sm !default; +$btn-line-height-sm: $input-btn-line-height-sm !default; + +$btn-padding-y-lg: $input-btn-padding-y-lg !default; +$btn-padding-x-lg: $input-btn-padding-x-lg !default; +$btn-line-height-lg: $input-btn-line-height-lg !default; + +$btn-border-width: $input-btn-border-width !default; + +$btn-font-weight: $font-weight-normal !default; +$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; +$btn-focus-width: $input-btn-focus-width !default; +$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; +$btn-disabled-opacity: .65 !default; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; + +$btn-link-disabled-color: $gray-600 !default; + +$btn-block-spacing-y: .5rem !default; + +// Allows for customizing button radius independently from global border radius +$btn-border-radius: $border-radius !default; +$btn-border-radius-lg: $border-radius-lg !default; +$btn-border-radius-sm: $border-radius-sm !default; + +$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + + +// Forms + +$input-padding-y: $input-btn-padding-y !default; +$input-padding-x: $input-btn-padding-x !default; +$input-line-height: $input-btn-line-height !default; + +$input-padding-y-sm: $input-btn-padding-y-sm !default; +$input-padding-x-sm: $input-btn-padding-x-sm !default; +$input-line-height-sm: $input-btn-line-height-sm !default; + +$input-padding-y-lg: $input-btn-padding-y-lg !default; +$input-padding-x-lg: $input-btn-padding-x-lg !default; +$input-line-height-lg: $input-btn-line-height-lg !default; + +$input-bg: $white !default; +$input-disabled-bg: $gray-200 !default; + +$input-color: $gray-700 !default; +$input-border-color: $gray-400 !default; +$input-border-width: $input-btn-border-width !default; +$input-box-shadow: inset 0 1px 1px rgba($black, .075) !default; + +$input-border-radius: $border-radius !default; +$input-border-radius-lg: $border-radius-lg !default; +$input-border-radius-sm: $border-radius-sm !default; + +$input-focus-bg: $input-bg !default; +$input-focus-border-color: lighten($component-active-bg, 25%) !default; +$input-focus-color: $input-color !default; +$input-focus-width: $input-btn-focus-width !default; +$input-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$input-placeholder-color: $gray-600 !default; + +$input-height-border: $input-border-width * 2 !default; + +$input-height-inner: ($font-size-base * $input-btn-line-height) + ($input-btn-padding-y * 2) !default; +$input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; + +$input-height-inner-sm: ($font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default; +$input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; + +$input-height-inner-lg: ($font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2) !default; +$input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; + +$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$form-text-margin-top: .25rem !default; + +$form-check-input-gutter: 1.25rem !default; +$form-check-input-margin-y: .3rem !default; +$form-check-input-margin-x: .25rem !default; + +$form-check-inline-margin-x: .75rem !default; +$form-check-inline-input-margin-x: .3125rem !default; + +$form-group-margin-bottom: 1rem !default; + +$input-group-addon-color: $input-color !default; +$input-group-addon-bg: $gray-200 !default; +$input-group-addon-border-color: $input-border-color !default; + +$custom-control-gutter: 1.5rem !default; +$custom-control-spacer-x: 1rem !default; + +$custom-control-indicator-size: 1rem !default; +$custom-control-indicator-bg: $gray-300 !default; +$custom-control-indicator-bg-size: 50% 50% !default; +$custom-control-indicator-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; + +$custom-control-indicator-disabled-bg: $gray-200 !default; +$custom-control-label-disabled-color: $gray-600 !default; + +$custom-control-indicator-checked-color: $component-active-color !default; +$custom-control-indicator-checked-bg: $component-active-bg !default; +$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; +$custom-control-indicator-checked-box-shadow: none !default; + +$custom-control-indicator-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow !default; + +$custom-control-indicator-active-color: $component-active-color !default; +$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; +$custom-control-indicator-active-box-shadow: none !default; + +$custom-checkbox-indicator-border-radius: $border-radius !default; +$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E"), "#", "%23") !default; + +$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; +$custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; +$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3E%3C/svg%3E"), "#", "%23") !default; +$custom-checkbox-indicator-indeterminate-box-shadow: none !default; + +$custom-radio-indicator-border-radius: 50% !default; +$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3E%3C/svg%3E"), "#", "%23") !default; + +$custom-select-padding-y: .375rem !default; +$custom-select-padding-x: .75rem !default; +$custom-select-height: $input-height !default; +$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator +$custom-select-line-height: $input-btn-line-height !default; +$custom-select-color: $input-color !default; +$custom-select-disabled-color: $gray-600 !default; +$custom-select-bg: $white !default; +$custom-select-disabled-bg: $gray-200 !default; +$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions +$custom-select-indicator-color: $gray-800 !default; +$custom-select-indicator: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E"), "#", "%23") !default; +$custom-select-border-width: $input-btn-border-width !default; +$custom-select-border-color: $input-border-color !default; +$custom-select-border-radius: $border-radius !default; + +$custom-select-focus-border-color: $input-focus-border-color !default; +$custom-select-focus-box-shadow: inset 0 1px 2px rgba($black, .075), 0 0 5px rgba($custom-select-focus-border-color, .5) !default; + +$custom-select-font-size-sm: 75% !default; +$custom-select-height-sm: $input-height-sm !default; + +$custom-select-font-size-lg: 125% !default; +$custom-select-height-lg: $input-height-lg !default; + +$custom-file-height: $input-height !default; +$custom-file-focus-border-color: $input-focus-border-color !default; +$custom-file-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$custom-file-padding-y: $input-btn-padding-y !default; +$custom-file-padding-x: $input-btn-padding-x !default; +$custom-file-line-height: $input-btn-line-height !default; +$custom-file-color: $input-color !default; +$custom-file-bg: $input-bg !default; +$custom-file-border-width: $input-btn-border-width !default; +$custom-file-border-color: $input-border-color !default; +$custom-file-border-radius: $input-border-radius !default; +$custom-file-box-shadow: $input-box-shadow !default; +$custom-file-button-color: $custom-file-color !default; +$custom-file-button-bg: $input-group-addon-bg !default; +$custom-file-text: ( + en: "Browse" +) !default; + + +// Form validation +$form-feedback-margin-top: $form-text-margin-top !default; +$form-feedback-font-size: $small-font-size !default; +$form-feedback-valid-color: theme-color("success") !default; +$form-feedback-invalid-color: theme-color("danger") !default; + + +// Dropdowns +// +// Dropdown menu container and contents. + +$dropdown-min-width: 10rem !default; +$dropdown-padding-y: .5rem !default; +$dropdown-spacer: .125rem !default; +$dropdown-bg: $white !default; +$dropdown-border-color: rgba($black, .15) !default; +$dropdown-border-radius: $border-radius !default; +$dropdown-border-width: $border-width !default; +$dropdown-divider-bg: $gray-200 !default; +$dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; + +$dropdown-link-color: $gray-900 !default; +$dropdown-link-hover-color: darken($gray-900, 5%) !default; +$dropdown-link-hover-bg: $gray-100 !default; + +$dropdown-link-active-color: $component-active-color !default; +$dropdown-link-active-bg: $component-active-bg !default; + +$dropdown-link-disabled-color: $gray-600 !default; + +$dropdown-item-padding-y: .25rem !default; +$dropdown-item-padding-x: 1.5rem !default; + +$dropdown-header-color: $gray-600 !default; + + +// Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. + +$zindex-dropdown: 1000 !default; +$zindex-sticky: 1020 !default; +$zindex-fixed: 1030 !default; +$zindex-modal-backdrop: 1040 !default; +$zindex-modal: 1050 !default; +$zindex-popover: 1060 !default; +$zindex-tooltip: 1070 !default; + +// Navs + +$nav-link-padding-y: .5rem !default; +$nav-link-padding-x: 1rem !default; +$nav-link-disabled-color: $gray-600 !default; + +$nav-tabs-border-color: $gray-300 !default; +$nav-tabs-border-width: $border-width !default; +$nav-tabs-border-radius: $border-radius !default; +$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; +$nav-tabs-link-active-color: $gray-700 !default; +$nav-tabs-link-active-bg: $body-bg !default; +$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default; + +$nav-pills-border-radius: $border-radius !default; +$nav-pills-link-active-color: $component-active-color !default; +$nav-pills-link-active-bg: $component-active-bg !default; + +// Navbar + +$navbar-padding-y: ($spacer / 2) !default; +$navbar-padding-x: $spacer !default; + +$navbar-nav-link-padding-x: .5rem !default; + +$navbar-brand-font-size: $font-size-lg !default; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +$nav-link-height: ($font-size-base * $line-height-base + $nav-link-padding-y * 2) !default; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default; + +$navbar-toggler-padding-y: .25rem !default; +$navbar-toggler-padding-x: .75rem !default; +$navbar-toggler-font-size: $font-size-lg !default; +$navbar-toggler-border-radius: $btn-border-radius !default; + +$navbar-dark-color: rgba($white, .5) !default; +$navbar-dark-hover-color: rgba($white, .75) !default; +$navbar-dark-active-color: $white !default; +$navbar-dark-disabled-color: rgba($white, .25) !default; +$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; +$navbar-dark-toggler-border-color: rgba($white, .1) !default; + +$navbar-light-color: rgba($black, .5) !default; +$navbar-light-hover-color: rgba($black, .7) !default; +$navbar-light-active-color: rgba($black, .9) !default; +$navbar-light-disabled-color: rgba($black, .3) !default; +$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default; +$navbar-light-toggler-border-color: rgba($black, .1) !default; + +// Pagination + +$pagination-padding-y: .5rem !default; +$pagination-padding-x: .75rem !default; +$pagination-padding-y-sm: .25rem !default; +$pagination-padding-x-sm: .5rem !default; +$pagination-padding-y-lg: .75rem !default; +$pagination-padding-x-lg: 1.5rem !default; +$pagination-line-height: 1.25 !default; + +$pagination-color: $link-color !default; +$pagination-bg: $white !default; +$pagination-border-width: $border-width !default; +$pagination-border-color: $gray-300 !default; + +$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$pagination-hover-color: $link-hover-color !default; +$pagination-hover-bg: $gray-200 !default; +$pagination-hover-border-color: $gray-300 !default; + +$pagination-active-color: $component-active-color !default; +$pagination-active-bg: $component-active-bg !default; +$pagination-active-border-color: $pagination-active-bg !default; + +$pagination-disabled-color: $gray-600 !default; +$pagination-disabled-bg: $white !default; +$pagination-disabled-border-color: $gray-300 !default; + + +// Jumbotron + +$jumbotron-padding: 2rem !default; +$jumbotron-bg: $gray-200 !default; + + +// Cards + +$card-spacer-y: .75rem !default; +$card-spacer-x: 1.25rem !default; +$card-border-width: $border-width !default; +$card-border-radius: $border-radius !default; +$card-border-color: rgba($black, .125) !default; +$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default; +$card-cap-bg: rgba($black, .03) !default; +$card-bg: $white !default; + +$card-img-overlay-padding: 1.25rem !default; + +$card-group-margin: ($grid-gutter-width / 2) !default; +$card-deck-margin: $card-group-margin !default; + +$card-columns-count: 3 !default; +$card-columns-gap: 1.25rem !default; +$card-columns-margin: $card-spacer-y !default; + + +// Tooltips + +$tooltip-font-size: $font-size-sm !default; +$tooltip-max-width: 200px !default; +$tooltip-color: $white !default; +$tooltip-bg: $black !default; +$tooltip-border-radius: $border-radius !default; +$tooltip-opacity: .9 !default; +$tooltip-padding-y: .25rem !default; +$tooltip-padding-x: .5rem !default; +$tooltip-margin: 0 !default; + +$tooltip-arrow-width: .8rem !default; +$tooltip-arrow-height: .4rem !default; +$tooltip-arrow-color: $tooltip-bg !default; + + +// Popovers + +$popover-font-size: $font-size-sm !default; +$popover-bg: $white !default; +$popover-max-width: 276px !default; +$popover-border-width: $border-width !default; +$popover-border-color: rgba($black, .2) !default; +$popover-border-radius: $border-radius-lg !default; +$popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; + +$popover-header-bg: darken($popover-bg, 3%) !default; +$popover-header-color: $headings-color !default; +$popover-header-padding-y: .5rem !default; +$popover-header-padding-x: .75rem !default; + +$popover-body-color: $body-color !default; +$popover-body-padding-y: $popover-header-padding-y !default; +$popover-body-padding-x: $popover-header-padding-x !default; + +$popover-arrow-width: 1rem !default; +$popover-arrow-height: .5rem !default; +$popover-arrow-color: $popover-bg !default; + +$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; + + +// Badges + +$badge-font-size: 75% !default; +$badge-font-weight: $font-weight-bold !default; +$badge-padding-y: .25em !default; +$badge-padding-x: .4em !default; +$badge-border-radius: $border-radius !default; + +$badge-pill-padding-x: .6em !default; +// Use a higher than normal value to ensure completely rounded edges when +// customizing padding or font-size on labels. +$badge-pill-border-radius: 10rem !default; + + +// Modals + +// Padding applied to the modal body +$modal-inner-padding: 1rem !default; + +$modal-dialog-margin: .5rem !default; +$modal-dialog-margin-y-sm-up: 1.75rem !default; + +$modal-title-line-height: $line-height-base !default; + +$modal-content-bg: $white !default; +$modal-content-border-color: rgba($black, .2) !default; +$modal-content-border-width: $border-width !default; +$modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; +$modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5) !default; + +$modal-backdrop-bg: $black !default; +$modal-backdrop-opacity: .5 !default; +$modal-header-border-color: $gray-200 !default; +$modal-footer-border-color: $modal-header-border-color !default; +$modal-header-border-width: $modal-content-border-width !default; +$modal-footer-border-width: $modal-header-border-width !default; +$modal-header-padding: 1rem !default; + +$modal-lg: 800px !default; +$modal-md: 500px !default; +$modal-sm: 300px !default; + +$modal-transition: transform .3s ease-out !default; + + +// Alerts +// +// Define alert colors, border radius, and padding. + +$alert-padding-y: .75rem !default; +$alert-padding-x: 1.25rem !default; +$alert-margin-bottom: 1rem !default; +$alert-border-radius: $border-radius !default; +$alert-link-font-weight: $font-weight-bold !default; +$alert-border-width: $border-width !default; + +$alert-bg-level: -10 !default; +$alert-border-level: -9 !default; +$alert-color-level: 6 !default; + + +// Progress bars + +$progress-height: 1rem !default; +$progress-font-size: ($font-size-base * .75) !default; +$progress-bg: $gray-200 !default; +$progress-border-radius: $border-radius !default; +$progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; +$progress-bar-color: $white !default; +$progress-bar-bg: theme-color("primary") !default; +$progress-bar-animation-timing: 1s linear infinite !default; +$progress-bar-transition: width .6s ease !default; + +// List group + +$list-group-bg: $white !default; +$list-group-border-color: rgba($black, .125) !default; +$list-group-border-width: $border-width !default; +$list-group-border-radius: $border-radius !default; + +$list-group-item-padding-y: .75rem !default; +$list-group-item-padding-x: 1.25rem !default; + +$list-group-hover-bg: $gray-100 !default; +$list-group-active-color: $component-active-color !default; +$list-group-active-bg: $component-active-bg !default; +$list-group-active-border-color: $list-group-active-bg !default; + +$list-group-disabled-color: $gray-600 !default; +$list-group-disabled-bg: $list-group-bg !default; + +$list-group-action-color: $gray-700 !default; +$list-group-action-hover-color: $list-group-action-color !default; + +$list-group-action-active-color: $body-color !default; +$list-group-action-active-bg: $gray-200 !default; + + +// Image thumbnails + +$thumbnail-padding: .25rem !default; +$thumbnail-bg: $body-bg !default; +$thumbnail-border-width: $border-width !default; +$thumbnail-border-color: $gray-300 !default; +$thumbnail-border-radius: $border-radius !default; +$thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; + + +// Figures + +$figure-caption-font-size: 90% !default; +$figure-caption-color: $gray-600 !default; + + +// Breadcrumbs + +$breadcrumb-padding-y: .75rem !default; +$breadcrumb-padding-x: 1rem !default; +$breadcrumb-item-padding: .5rem !default; + +$breadcrumb-margin-bottom: 1rem !default; + +$breadcrumb-bg: $gray-200 !default; +$breadcrumb-divider-color: $gray-600 !default; +$breadcrumb-active-color: $gray-600 !default; +$breadcrumb-divider: "/" !default; + + +// Carousel + +$carousel-control-color: $white !default; +$carousel-control-width: 15% !default; +$carousel-control-opacity: .5 !default; + +$carousel-indicator-width: 30px !default; +$carousel-indicator-height: 3px !default; +$carousel-indicator-spacer: 3px !default; +$carousel-indicator-active-bg: $white !default; + +$carousel-caption-width: 70% !default; +$carousel-caption-color: $white !default; + +$carousel-control-icon-width: 20px !default; + +$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E"), "#", "%23") !default; +$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E"), "#", "%23") !default; + +$carousel-transition: transform .6s ease !default; + + +// Close + +$close-font-size: $font-size-base * 1.5 !default; +$close-font-weight: $font-weight-bold !default; +$close-color: $black !default; +$close-text-shadow: 0 1px 0 $white !default; + +// Code + +$code-font-size: 87.5% !default; +$code-color: $pink !default; + +$kbd-padding-y: .2rem !default; +$kbd-padding-x: .4rem !default; +$kbd-font-size: $code-font-size !default; +$kbd-color: $white !default; +$kbd-bg: $gray-900 !default; + +$pre-color: $gray-900 !default; +$pre-scrollable-max-height: 340px !default; + + +// Printing +$print-page-size: a3 !default; +$print-body-min-width: map-get($grid-breakpoints, "lg") !default; diff --git a/webapp/src/scss/bootstrap-grid.scss b/webapp/src/scss/bootstrap-grid.scss new file mode 100644 index 0000000000000000000000000000000000000000..26c0dc89c284609ece9e6f9f14a53ba3d708107e --- /dev/null +++ b/webapp/src/scss/bootstrap-grid.scss @@ -0,0 +1,32 @@ +/*! + * Bootstrap Grid v4.0.0 (https://getbootstrap.com) + * Copyright 2011-2018 The Bootstrap Authors + * Copyright 2011-2018 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +@at-root { + @-ms-viewport { width: device-width; } // stylelint-disable-line at-rule-no-vendor-prefix +} + +html { + box-sizing: border-box; + -ms-overflow-style: scrollbar; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} + +@import "functions"; +@import "variables"; + +@import "mixins/breakpoints"; +@import "mixins/grid-framework"; +@import "mixins/grid"; + +@import "grid"; +@import "utilities/display"; +@import "utilities/flex"; diff --git a/webapp/src/scss/mixins/_breakpoints.scss b/webapp/src/scss/mixins/_breakpoints.scss new file mode 100644 index 0000000000000000000000000000000000000000..d1ad684cc76e58d07333a38e0d6e0451b8f47de8 --- /dev/null +++ b/webapp/src/scss/mixins/_breakpoints.scss @@ -0,0 +1,123 @@ +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px) +// +// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// 576px +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. Null for the largest (last) breakpoint. +// The maximum value is calculated as the minimum of the next one less 0.02px +// to work around the limitations of `min-` and `max-` prefixes and viewports with fractional widths. +// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max +// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari. +// See https://bugs.webkit.org/show_bug.cgi?id=178261 +// +// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// 767.98px +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $next: breakpoint-next($name, $breakpoints); + @return if($next, breakpoint-min($next, $breakpoints) - .02px, null); +} + +// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront. +// Useful for making responsive utilities. +// +// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// "" (Returns a blank string) +// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// "-sm" +@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { + @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}"); +} + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +// Makes the @content apply to the given breakpoint and wider. +@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +// Makes the @content apply to the given breakpoint and narrower. +@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} + +// Media that spans multiple breakpoint widths. +// Makes the @content apply between the min and max breakpoints +@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($lower, $breakpoints); + $max: breakpoint-max($upper, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($lower, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($upper, $breakpoints) { + @content; + } + } +} + +// Media between the breakpoint's minimum and maximum widths. +// No minimum for the smallest breakpoint, and no maximum for the largest one. +// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. +@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + $max: breakpoint-max($name, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($name, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($name, $breakpoints) { + @content; + } + } +} diff --git a/webapp/src/scss/mixins/_grid-framework.scss b/webapp/src/scss/mixins/_grid-framework.scss new file mode 100644 index 0000000000000000000000000000000000000000..7b37f868f198be0b678dda85a84bc058c247efeb --- /dev/null +++ b/webapp/src/scss/mixins/_grid-framework.scss @@ -0,0 +1,67 @@ +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `$grid-columns`. + +@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { + // Common properties for all breakpoints + %grid-column { + position: relative; + width: 100%; + min-height: 1px; // Prevent columns from collapsing when empty + padding-right: ($gutter / 2); + padding-left: ($gutter / 2); + } + + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + // Allow columns to stretch full width below their breakpoints + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @extend %grid-column; + } + } + .col#{$infix}, + .col#{$infix}-auto { + @extend %grid-column; + } + + @include media-breakpoint-up($breakpoint, $breakpoints) { + // Provide basic `.col-{bp}` classes for equal-width flexbox columns + .col#{$infix} { + flex-basis: 0; + flex-grow: 1; + max-width: 100%; + } + .col#{$infix}-auto { + flex: 0 0 auto; + width: auto; + max-width: none; // Reset earlier grid tiers + } + + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @include make-col($i, $columns); + } + } + + .order#{$infix}-first { order: -1; } + + .order#{$infix}-last { order: $columns + 1; } + + @for $i from 0 through $columns { + .order#{$infix}-#{$i} { order: $i; } + } + + // `$columns - 1` because offsetting by the width of an entire row isn't possible + @for $i from 0 through ($columns - 1) { + @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0 + .offset#{$infix}-#{$i} { + @include make-col-offset($i, $columns); + } + } + } + } + } +} diff --git a/webapp/src/scss/mixins/_grid.scss b/webapp/src/scss/mixins/_grid.scss new file mode 100644 index 0000000000000000000000000000000000000000..b75ebcbca0ceec5d315ec319b7cd1a5907c49f19 --- /dev/null +++ b/webapp/src/scss/mixins/_grid.scss @@ -0,0 +1,52 @@ +/// Grid system +// +// Generate semantic grid columns with these mixins. + +@mixin make-container() { + width: 100%; + padding-right: ($grid-gutter-width / 2); + padding-left: ($grid-gutter-width / 2); + margin-right: auto; + margin-left: auto; +} + + +// For each breakpoint, define the maximum width of the container in a media query +@mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) { + @each $breakpoint, $container-max-width in $max-widths { + @include media-breakpoint-up($breakpoint, $breakpoints) { + max-width: $container-max-width; + } + } +} + +@mixin make-row() { + display: flex; + flex-wrap: wrap; + margin-right: ($grid-gutter-width / -2); + margin-left: ($grid-gutter-width / -2); +} + +@mixin make-col-ready() { + position: relative; + // Prevent columns from becoming too narrow when at smaller grid tiers by + // always setting `width: 100%;`. This works because we use `flex` values + // later on to override this initial width. + width: 100%; + min-height: 1px; // Prevent collapsing + padding-right: ($grid-gutter-width / 2); + padding-left: ($grid-gutter-width / 2); +} + +@mixin make-col($size, $columns: $grid-columns) { + flex: 0 0 percentage($size / $columns); + // Add a `max-width` to ensure content within each column does not blow out + // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari + // do not appear to require this. + max-width: percentage($size / $columns); +} + +@mixin make-col-offset($size, $columns: $grid-columns) { + $num: $size / $columns; + margin-left: if($num == 0, 0, percentage($num)); +} diff --git a/webapp/src/scss/utilities/_display.scss b/webapp/src/scss/utilities/_display.scss new file mode 100644 index 0000000000000000000000000000000000000000..20aeeb5f3e7586bba0fe69bff02057b15b2309f3 --- /dev/null +++ b/webapp/src/scss/utilities/_display.scss @@ -0,0 +1,38 @@ +// stylelint-disable declaration-no-important + +// +// Utilities for common `display` values +// + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .d#{$infix}-none { display: none !important; } + .d#{$infix}-inline { display: inline !important; } + .d#{$infix}-inline-block { display: inline-block !important; } + .d#{$infix}-block { display: block !important; } + .d#{$infix}-table { display: table !important; } + .d#{$infix}-table-row { display: table-row !important; } + .d#{$infix}-table-cell { display: table-cell !important; } + .d#{$infix}-flex { display: flex !important; } + .d#{$infix}-inline-flex { display: inline-flex !important; } + } +} + + +// +// Utilities for toggling `display` in print +// + +@media print { + .d-print-none { display: none !important; } + .d-print-inline { display: inline !important; } + .d-print-inline-block { display: inline-block !important; } + .d-print-block { display: block !important; } + .d-print-table { display: table !important; } + .d-print-table-row { display: table-row !important; } + .d-print-table-cell { display: table-cell !important; } + .d-print-flex { display: flex !important; } + .d-print-inline-flex { display: inline-flex !important; } +} diff --git a/webapp/src/scss/utilities/_flex.scss b/webapp/src/scss/utilities/_flex.scss new file mode 100644 index 0000000000000000000000000000000000000000..8e470384362f4d46c1b27e743f03e4eaed80324f --- /dev/null +++ b/webapp/src/scss/utilities/_flex.scss @@ -0,0 +1,46 @@ +// stylelint-disable declaration-no-important + +// Flex variation +// +// Custom styles for additional flex alignment options. + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .flex#{$infix}-row { flex-direction: row !important; } + .flex#{$infix}-column { flex-direction: column !important; } + .flex#{$infix}-row-reverse { flex-direction: row-reverse !important; } + .flex#{$infix}-column-reverse { flex-direction: column-reverse !important; } + + .flex#{$infix}-wrap { flex-wrap: wrap !important; } + .flex#{$infix}-nowrap { flex-wrap: nowrap !important; } + .flex#{$infix}-wrap-reverse { flex-wrap: wrap-reverse !important; } + + .justify-content#{$infix}-start { justify-content: flex-start !important; } + .justify-content#{$infix}-end { justify-content: flex-end !important; } + .justify-content#{$infix}-center { justify-content: center !important; } + .justify-content#{$infix}-between { justify-content: space-between !important; } + .justify-content#{$infix}-around { justify-content: space-around !important; } + + .align-items#{$infix}-start { align-items: flex-start !important; } + .align-items#{$infix}-end { align-items: flex-end !important; } + .align-items#{$infix}-center { align-items: center !important; } + .align-items#{$infix}-baseline { align-items: baseline !important; } + .align-items#{$infix}-stretch { align-items: stretch !important; } + + .align-content#{$infix}-start { align-content: flex-start !important; } + .align-content#{$infix}-end { align-content: flex-end !important; } + .align-content#{$infix}-center { align-content: center !important; } + .align-content#{$infix}-between { align-content: space-between !important; } + .align-content#{$infix}-around { align-content: space-around !important; } + .align-content#{$infix}-stretch { align-content: stretch !important; } + + .align-self#{$infix}-auto { align-self: auto !important; } + .align-self#{$infix}-start { align-self: flex-start !important; } + .align-self#{$infix}-end { align-self: flex-end !important; } + .align-self#{$infix}-center { align-self: center !important; } + .align-self#{$infix}-baseline { align-self: baseline !important; } + .align-self#{$infix}-stretch { align-self: stretch !important; } + } +} diff --git a/webapp/src/styles.scss b/webapp/src/styles.scss index 90d4ee0072ce3fc41812f8af910219f9eea3c3de..df64f3c452e1de8a5b7dad7bfe21e7db81cc51c6 100644 --- a/webapp/src/styles.scss +++ b/webapp/src/styles.scss @@ -1 +1,19 @@ /* You can add global styles to this file, and also import other style files */ + +@import '~scss/bootstrap-grid.scss'; + +html, +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 0; + padding: 0; + height: 100%; +} + +h1, h2, h3 { + font-size: 2em; + font-weight: 700; + padding-left: 0.5em; + margin: 0; + flex: 1; +} \ No newline at end of file diff --git a/webapp/src/theme.scss b/webapp/src/theme.scss new file mode 100644 index 0000000000000000000000000000000000000000..9feaf1a174397fd34508d3b221d7d46e1239cba6 --- /dev/null +++ b/webapp/src/theme.scss @@ -0,0 +1,17 @@ +// Charger les outils Material Design +@import '~@angular/material/theming'; + +// Charger les mixins de theming des composants +@import 'theming/all-theme'; + +// Charger le thème principal +@import 'theming/grandlyon/grandlyon'; + +// Le mixin `mat-core()` ne doit être appélé qu'une seule fois puisqu'il génère +// des styles CSS. +// TODO: passer en argument la configuration typographique. +@include mat-core(); + +@include angular-material-theme($gl-theme); +@include app-theme($gl-theme); + diff --git a/webapp/src/theming/_all-theme.scss b/webapp/src/theming/_all-theme.scss new file mode 100644 index 0000000000000000000000000000000000000000..50310d0330dc28b2fbba8590f60ac6e6e5396e86 --- /dev/null +++ b/webapp/src/theming/_all-theme.scss @@ -0,0 +1,29 @@ +@mixin app-theme($theme) { + // @include app-shared-theme($theme); + // @include app-components-theme($theme); +} + +// Theming des éléments transverses + +// @import "shared/form-theme"; +// @import "shared/loader-theme"; +// @import "shared/table-theme"; + +// @mixin app-shared-theme($theme) { +// @include app-shared-form-theme($theme); +// @include app-shared-loader-theme($theme); +// @include app-shared-table-theme($theme); +// } + +// // Theming des composants Angular + +// @import "~app/app-theme.component"; +// @import "~app/components/menu/menu-theme.component"; +// @import "~app/components/federal/welcome/welcome-theme.component"; + +// @mixin app-components-theme($theme) { +// @include app-app-theme($theme); +// @include app-menu-theme($theme); +// @include app-welcome-theme($theme); +// } + diff --git a/webapp/src/theming/_theming.scss b/webapp/src/theming/_theming.scss new file mode 100644 index 0000000000000000000000000000000000000000..b09f09c57fa6a1b565890b3d74517a6d3bde9097 --- /dev/null +++ b/webapp/src/theming/_theming.scss @@ -0,0 +1,11 @@ +@import "~sass-recursive-map-merge/recursive-map-merge"; + +@function app-override-theme($mat-theme, $foreground: null, $background: null) { + $theme: ( + foreground: $foreground, + background: $background, + ); + + @return recursive-map-merge($mat-theme, $theme); +} + diff --git a/webapp/src/theming/grandlyon/config/_palette.scss b/webapp/src/theming/grandlyon/config/_palette.scss new file mode 100644 index 0000000000000000000000000000000000000000..eb2416e0684178388d861e60dbcacc20f322bdcc --- /dev/null +++ b/webapp/src/theming/grandlyon/config/_palette.scss @@ -0,0 +1,89 @@ +// Color palettes for Grand Lyon, la Métropole +// +// Generator: +// http://mcg.mbitson.com/#!?vermilion=%23e10000&woodsmoke=%23050707&themename=grandlyon + +$gl-dark-primary-text: black; +$gl-light-primary-text: white; + +$gl-vermilion: ( + 50: #ffebeb, + 100: #ff9f9f, + 200: #ff6767, + 300: #ff1f1f, + 400: #ff0101, + 500: #e10000, + 600: #c20000, + 700: #a40000, + 800: #850000, + 900: #670000, + A100: #ffe1e1, + A200: #ff7b7b, + A400: #ff1515, + A700: #fa0000, + contrast: ( + 50: $gl-dark-primary-text, + 100: $gl-dark-primary-text, + 200: $gl-dark-primary-text, + 300: $gl-light-primary-text, + 400: $gl-light-primary-text, + 500: $gl-light-primary-text, + 600: $gl-light-primary-text, + 700: $gl-light-primary-text, + 800: $gl-light-primary-text, + 900: $gl-light-primary-text, + A100: $gl-dark-primary-text, + A200: $gl-dark-primary-text, + A400: $gl-light-primary-text, + A700: $gl-light-primary-text, + ) +); + +$gl-woodsmoke: ( + 50: #e1e1e1, + 100: #b4b5b5, + 200: #828383, + 300: #505151, + 400: #2b2c2c, + 500: #050707, + 600: #040606, + 700: #040505, + 800: #030404, + 900: #010202, + A100: #a6a6a6, + A200: #8c8c8c, + A400: #737373, + A700: #666666, + contrast: ( + 50: $gl-dark-primary-text, + 100: $gl-dark-primary-text, + 200: $gl-dark-primary-text, + 300: $gl-light-primary-text, + 400: $gl-light-primary-text, + 500: $gl-light-primary-text, + 600: $gl-light-primary-text, + 700: $gl-light-primary-text, + 800: $gl-light-primary-text, + 900: $gl-light-primary-text, + A100: $gl-dark-primary-text, + A200: $gl-dark-primary-text, + A400: $gl-light-primary-text, + A700: $gl-light-primary-text, + ) +); + +// Palette des couleurs d'arrière plan spécifique au thème clair. +$gl-light-theme-background: ( + // spécifiques + actived-navigation: #f0f0f0, + form: rgba(220, 220, 220, 0.4), + table-header: #d3d3d3, +); + +// Palette des couleurs de premier plan spécifique au thème clair. +$gl-light-theme-foreground: ( + // spécifiques + valid: #4caf50, + invalid: #d32f2f, +); + diff --git a/webapp/src/theming/grandlyon/config/_variables.scss b/webapp/src/theming/grandlyon/config/_variables.scss new file mode 100644 index 0000000000000000000000000000000000000000..2ac14af97461419e2f758924aeddaf66f16d1341 --- /dev/null +++ b/webapp/src/theming/grandlyon/config/_variables.scss @@ -0,0 +1,9 @@ +@import "palette"; + +// Palettes +// -------- + +$gl-theme-primary: mat-palette($gl-vermilion); +$gl-theme-accent: mat-palette($gl-woodsmoke); +$gl-theme-warn: mat-palette($gl-woodsmoke); + diff --git a/webapp/src/theming/grandlyon/grandlyon.scss b/webapp/src/theming/grandlyon/grandlyon.scss new file mode 100644 index 0000000000000000000000000000000000000000..73837988d9dfb56153cfb79fe56e02f8e0ca8f0b --- /dev/null +++ b/webapp/src/theming/grandlyon/grandlyon.scss @@ -0,0 +1,10 @@ +@import '../theming'; + +@import "config/variables"; + +$gl-theme: app-override-theme( + mat-light-theme($gl-theme-primary, $gl-theme-accent, $gl-theme-warn), + $foreground: $gl-light-theme-foreground, + $background: $gl-light-theme-background +); +