diff --git a/.gitignore b/.gitignore index 4a28d67aecc150bc9b509a5abf305128d1784839..05ba580503a02c6b0557b29836fa8bc2a42b4295 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ site *.log cachedKgDataset.json +tmp diff --git a/deploy/app.js b/deploy/app.js index 0a9aaa02df174ea5d934dddc6c7d998bd647f220..3fa93a530fe2ea7076fe7978d00654afc0ab7bc4 100644 --- a/deploy/app.js +++ b/deploy/app.js @@ -197,9 +197,6 @@ app.get('/', (req, res, next) => { } }) - -app.use('/logo', require('./logo')) - app.get('/ready', async (req, res) => { const authIsReady = authReady ? await authReady() : false diff --git a/deploy/logo/index.js b/deploy/logo/index.js deleted file mode 100644 index d4750d225f9d0a09510db3fa40175544670c2969..0000000000000000000000000000000000000000 --- a/deploy/logo/index.js +++ /dev/null @@ -1,40 +0,0 @@ -const fs = require('fs') -const path = require('path') -const { getHandleErrorFn } = require('../util/streamHandleError') -const router = require('express').Router() - -const map = new Map([ - ['hbp', { - mimetype: 'image/png', - light: 'HBP_Primary_RGB_BlackText.png', - dark: 'HBP_Primary_RGB_WhiteText.png' - }], - ['ebrains', { - mimetype: 'image/svg+xml', - light: 'ebrains-logo-dark.svg', - dark: 'ebrains-logo-light.svg' - }], - ['fzj', { - mimetype: 'image/svg+xml', - light: 'fzj_black_transparent_svg.svg', - dark: 'fzj_white_transparent_svg.svg' - }] -]) - -router.get('/', (req, res) => { - - const USE_LOGO = process.env.USE_LOGO || 'hbp' - const { mimetype, light, dark } = map.get(USE_LOGO) || map.get('hbp') - const darktheme = !!req.query.darktheme - try { - res.setHeader('Content-type', mimetype) - fs.createReadStream( - path.join(__dirname, `assets/${darktheme ? dark : light}`) - ).pipe(res).on('error', getHandleErrorFn(req, res)) - } catch (e) { - console.error(`Fetching logo error ${e.toString()}`) - res.status(500).end() - } -}) - -module.exports = router \ No newline at end of file diff --git a/docs/releases/v2.6.0.md b/docs/releases/v2.6.0.md new file mode 100644 index 0000000000000000000000000000000000000000..853734ec7ae2d1d333e9792ca2e549fcfb2bd87d --- /dev/null +++ b/docs/releases/v2.6.0.md @@ -0,0 +1,6 @@ +# v2.5.0 + +## Under the hood stuff + +- refactor: simplify DOM, remove unused functions +- reworked logo path diff --git a/mkdocs.yml b/mkdocs.yml index 476dfab49e8293f4cb00942adf79868386926570..9fab0d68ff6d30462e2cb384f1d68b188da7f267 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,6 +40,7 @@ pages: - Fetching datasets: 'advanced/datasets.md' - Display non-atlas volumes: 'advanced/otherVolumes.md' - Release notes: + - v2.6.0: 'releases/v2.6.0.md' - v2.5.4: 'releases/v2.5.4.md' - v2.5.3: 'releases/v2.5.3.md' - v2.5.2: 'releases/v2.5.2.md' diff --git a/package.json b/package.json index 0f3aae01c1446f0e95a11d8265e25f925317d8d3..7bf07fa3c9d273e95eb25397e684856e01424490 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "interactive-viewer", - "version": "2.5.4", + "version": "2.6.0", "description": "HBP interactive atlas viewer. Integrating KG query, dataset previews & more. Based on humanbrainproject/nehuba & google/neuroglancer. Built with angular", "scripts": { "build-aot": "VERSION=`node -e 'console.log(require(\"./package.json\").version)'` ng build && node ./third_party/matomo/processMatomo.js", diff --git a/deploy/logo/assets/HBP_Primary_RGB_BlackText.png b/src/assets/logo/HBP_Primary_RGB_BlackText.png similarity index 100% rename from deploy/logo/assets/HBP_Primary_RGB_BlackText.png rename to src/assets/logo/HBP_Primary_RGB_BlackText.png diff --git a/deploy/logo/assets/HBP_Primary_RGB_WhiteText.png b/src/assets/logo/HBP_Primary_RGB_WhiteText.png similarity index 100% rename from deploy/logo/assets/HBP_Primary_RGB_WhiteText.png rename to src/assets/logo/HBP_Primary_RGB_WhiteText.png diff --git a/deploy/logo/assets/ebrains-logo-dark.svg b/src/assets/logo/ebrains-logo-dark.svg similarity index 100% rename from deploy/logo/assets/ebrains-logo-dark.svg rename to src/assets/logo/ebrains-logo-dark.svg diff --git a/deploy/logo/assets/ebrains-logo-light.svg b/src/assets/logo/ebrains-logo-light.svg similarity index 100% rename from deploy/logo/assets/ebrains-logo-light.svg rename to src/assets/logo/ebrains-logo-light.svg diff --git a/deploy/logo/assets/fzj_black_transparent_svg.svg b/src/assets/logo/fzj_black_transparent_svg.svg similarity index 100% rename from deploy/logo/assets/fzj_black_transparent_svg.svg rename to src/assets/logo/fzj_black_transparent_svg.svg diff --git a/deploy/logo/assets/fzj_white_transparent_svg.svg b/src/assets/logo/fzj_white_transparent_svg.svg similarity index 100% rename from deploy/logo/assets/fzj_white_transparent_svg.svg rename to src/assets/logo/fzj_white_transparent_svg.svg diff --git a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.template.html b/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.template.html index e7b687d28f0262123213da9f38d0aaf77e36a2f6..ad5c5c2ff1b6ce6c8ecdac226f2d350933355f9a 100644 --- a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.template.html +++ b/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.template.html @@ -112,7 +112,7 @@ <ng-template #tileContent> <div class="d-flex flex-column justify-content-start w-100 mb-1 mt-1 overflow-hidden cursor-pointer singleLayerImageContainer" - [matTooltip]="getTooltipText(tileSrc)" + [matTooltip]="tileSrc | atlasLayerTooltip" matTooltipPosition="above" (click)="onClick && onClick()" [ngStyle]="{opacity: disabled ? '0.2': '1' }"> diff --git a/src/atlasComponents/uiSelectors/atlasLayerTooltip.pipe.ts b/src/atlasComponents/uiSelectors/atlasLayerTooltip.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..285f134543afa5151de4627fe2f507515e5f81de --- /dev/null +++ b/src/atlasComponents/uiSelectors/atlasLayerTooltip.pipe.ts @@ -0,0 +1,12 @@ +import { Pipe, PipeTransform } from "@angular/core"; + +@Pipe({ + name: 'atlasLayerTooltip', + pure: true +}) + +export class AtlaslayerTooltipPipe implements PipeTransform{ + public transform(layer: any){ + return layer.name + } +} diff --git a/src/atlasComponents/uiSelectors/module.ts b/src/atlasComponents/uiSelectors/module.ts index d655e9887d960671c3c02ceb798647d7691d67ef..1236e0c0c7e179302b980f216c10cf21fa782a63 100644 --- a/src/atlasComponents/uiSelectors/module.ts +++ b/src/atlasComponents/uiSelectors/module.ts @@ -6,6 +6,7 @@ import { AtlasDropdownSelector } from "./atlasDropdown/atlasDropdown.component"; import { AtlasLayerSelector, GetPreviewUrlPipe } from "./atlasLayerSelector/atlasLayerSelector.component"; import {QuickTourModule} from "src/ui/quickTour/module"; import { KgDatasetModule } from "../regionalFeatures/bsFeatures/kgDataset"; +import { AtlaslayerTooltipPipe } from "./atlasLayerTooltip.pipe"; @NgModule({ imports: [ @@ -19,6 +20,7 @@ import { KgDatasetModule } from "../regionalFeatures/bsFeatures/kgDataset"; AtlasDropdownSelector, AtlasLayerSelector, GetPreviewUrlPipe, + AtlaslayerTooltipPipe, ], exports: [ AtlasDropdownSelector, diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index f866c771f21c42422f72bc7c32a9c9938146d7de..f407f68944dad36fb049901fcc59e9e91fc77f47 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -8,10 +8,11 @@ import { TemplateRef, ViewChild, ElementRef, + Inject, } from "@angular/core"; -import { Store, select, ActionsSubject } from "@ngrx/store"; -import { Observable, Subscription, interval, merge, of, timer, fromEvent } from "rxjs"; -import { map, filter, distinctUntilChanged, delay, withLatestFrom, switchMapTo, take, startWith } from "rxjs/operators"; +import { Store, select } from "@ngrx/store"; +import { Observable, Subscription, merge, timer, fromEvent } from "rxjs"; +import { map, filter, distinctUntilChanged, delay, switchMapTo, take, startWith } from "rxjs/operators"; import { IavRootStoreInterface, @@ -21,8 +22,7 @@ import { import { WidgetServices } from "src/widget"; import { LocalFileService } from "src/services/localFile.service"; -import { AGREE_COOKIE, AGREE_KG_TOS } from "src/services/state/uiState.store"; -import { SHOW_KG_TOS } from 'src/services/state/uiState.store.helper' +import { AGREE_COOKIE } from "src/services/state/uiState.store"; import { isSame } from "src/util/fn"; import { colorAnimation } from "./atlasViewer.animation" import { MouseHoverDirective } from "src/mouseoverModule"; @@ -34,6 +34,7 @@ import { SlServiceService } from "src/spotlight/sl-service.service"; import { PureContantService } from "src/util"; import { ClickInterceptorService } from "src/glue"; import { environment } from 'src/environments/environment' +import { DOCUMENT } from "@angular/common"; /** * TODO @@ -61,8 +62,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { @ViewChild('cookieAgreementComponent', {read: TemplateRef}) public cookieAgreementComponent: TemplateRef<any> - @ViewChild('kgToS', {read: TemplateRef}) public kgTosComponent: TemplateRef<any> - @ViewChild(MouseHoverDirective) private mouseOverNehuba: MouseHoverDirective @ViewChild('idleOverlay', {read: TemplateRef}) idelTmpl: TemplateRef<any> @@ -85,20 +84,19 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { public selectedParcellation: any private cookieDialogRef: MatDialogRef<any> - private kgTosDialogRef: MatDialogRef<any> constructor( private store: Store<IavRootStoreInterface>, private widgetServices: WidgetServices, private pureConstantService: PureContantService, private matDialog: MatDialog, - private dispatcher$: ActionsSubject, private rd: Renderer2, public localFileService: LocalFileService, private snackbar: MatSnackBar, private el: ElementRef, private slService: SlServiceService, - private clickIntService: ClickInterceptorService + private clickIntService: ClickInterceptorService, + @Inject(DOCUMENT) private document, ) { this.snackbarMessage$ = this.store.pipe( @@ -147,7 +145,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { this.subscriptions.push( merge( - fromEvent(window.document, 'mouseup'), + fromEvent(this.document, 'mouseup'), this.slService.onClick ).pipe( startWith(true), @@ -196,7 +194,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { this.subscriptions.push( this.pureConstantService.darktheme$.subscribe(flag => { - this.rd.setAttribute(document.body, 'darktheme', this.meetsRequirement && flag.toString()) + this.rd.setAttribute(this.document.body, 'darktheme', this.meetsRequirement && flag.toString()) }), ) } @@ -212,13 +210,9 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { prefecthMainBundle.rel = 'preload' prefecthMainBundle.as = 'script' prefecthMainBundle.href = 'main.bundle.js' - this.rd.appendChild(document.head, prefecthMainBundle) + this.rd.appendChild(this.document.head, prefecthMainBundle) } - // this.onhoverLandmark$ = this.mouseOverNehuba.currentOnHoverObs$.pipe( - // select('landmark') - // ) - /** * Show Cookie disclaimer if not yet agreed */ @@ -234,18 +228,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { this.cookieDialogRef = this.matDialog.open(this.cookieAgreementComponent) }) - this.dispatcher$.pipe( - filter(({type}) => type === SHOW_KG_TOS), - withLatestFrom(this.store.pipe( - select('uiState'), - select('agreedKgTos'), - )), - map(([_, agreed]) => agreed), - filter(flag => !flag), - delay(0), - ).subscribe(() => { - this.kgTosDialogRef = this.matDialog.open(this.kgTosComponent) - }) } /** @@ -264,7 +246,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { */ public meetsRequirements(): boolean { - const canvas = document.createElement('canvas') + const canvas = this.document.createElement('canvas') const gl = canvas.getContext('webgl2') as WebGLRenderingContext if (!gl) { @@ -280,13 +262,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { return true } - public kgTosClickedOk() { - if (this.kgTosDialogRef) { this.kgTosDialogRef.close() } - this.store.dispatch({ - type: AGREE_KG_TOS, - }) - } - public cookieClickedOk() { if (this.cookieDialogRef) { this.cookieDialogRef.close() } this.store.dispatch({ diff --git a/src/atlasViewer/atlasViewer.style.css b/src/atlasViewer/atlasViewer.style.css index c6c87ac87da646244f55ce6654b404763ee369c8..0f938ac6632a634a35ee793318a408c0e70248fd 100644 --- a/src/atlasViewer/atlasViewer.style.css +++ b/src/atlasViewer/atlasViewer.style.css @@ -34,17 +34,13 @@ layout-floating-container > * top: 0; } -[signinWrapper] -{ - margin: 0.8em 0.4em; -} - -[contextualBlock] +mat-list[dense].contextual-block { + display: inline-block; background-color:rgba(200,200,200,0.8); } -:host-context([darktheme="true"]) [contextualBlock] +:host-context([darktheme="true"]) mat-list[dense].contextual-block { background-color : rgba(30,30,30,0.8); } diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html index fbaa8bf4c5dee3f37516c8d928c4c1a008897130..a342026d3dd8218ac46b665b76511152629a5226 100644 --- a/src/atlasViewer/atlasViewer.template.html +++ b/src/atlasViewer/atlasViewer.template.html @@ -1,26 +1,14 @@ + +<!-- required for manufacturing plugin templates --> +<div pluginFactoryDirective> +</div> + <ng-container *ngIf="meetsRequirement; else doesNotMeetReqTemplate"> <ng-container *ngTemplateOutlet="viewerBody"> </ng-container> </ng-container> -<!-- kg tos --> -<ng-template #kgToS> - <h2 mat-dialog-title>Knowledge Graph ToS</h2> - <mat-dialog-content> - <small> - <kgtos-component> - </kgtos-component> - </small> - </mat-dialog-content> - - <mat-dialog-actions class="justify-content-end"> - <button color="primary" mat-raised-button (click)="kgTosClickedOk()" cdkFocusInitial> - Ok - </button> - </mat-dialog-actions> -</ng-template> - <!-- cookie --> <ng-template #cookieAgreementComponent> <h2 mat-dialog-title>Privacy Policy</h2> @@ -40,7 +28,7 @@ <!-- atlas template --> <ng-template #viewerBody> - <div class="atlas-container w-100 h-100" + <div class="w-100 h-100" iav-media-query quick-tour [quick-tour-position]="quickTourFinale.position" @@ -65,41 +53,33 @@ <div floatingContainerDirective> </div> - <div - *ngIf="(media.mediaBreakPoint$ | async) < 3" + <div *ngIf="(media.mediaBreakPoint$ | async) < 3" class="fixed-bottom pe-none mb-2 d-flex justify-content-center"> <ng-container *ngTemplateOutlet="logoTmpl"> </ng-container> </div> - <div floatingMouseContextualContainerDirective> + <div *ngIf="!ismobile" floatingMouseContextualContainerDirective> - <div *ngIf="!ismobile" - class="d-inline-block" + <div class="h-0" iav-mouse-hover - #iavMouseHoverContextualBlock="iavMouseHover" - contextualBlock> - - <ng-container - *ngFor="let labelText of iavMouseHoverContextualBlock.currentOnHoverObs$ | async | mouseOverTextPipe"> - - <mat-list dense> - - <mat-list-item class="h-auto"> + #iavMouseHoverContextualBlock="iavMouseHover"> + </div> + <mat-list dense class="contextual-block"> - <mat-icon - [fontSet]="(labelText.label | mouseOverIconPipe).fontSet" - [fontIcon]="(labelText.label | mouseOverIconPipe).fontIcon" - mat-list-icon> + <mat-list-item *ngFor="let labelText of iavMouseHoverContextualBlock.currentOnHoverObs$ | async | mouseOverTextPipe" + class="h-auto"> - </mat-icon> + <mat-icon + [fontSet]="(labelText.label | mouseOverIconPipe).fontSet" + [fontIcon]="(labelText.label | mouseOverIconPipe).fontIcon" + mat-list-icon> + </mat-icon> - <div matLine *ngFor="let text of labelText.text" [innerHTML]="text"></div> + <div matLine *ngFor="let text of labelText.text" [innerHTML]="text"></div> - </mat-list-item> - </mat-list> - </ng-container> - </div> + </mat-list-item> + </mat-list> <!-- TODO Potentially implementing plugin contextual info --> </div> @@ -113,10 +93,6 @@ </div> </layout-floating-container> - - <!-- required for manufacturing plugin templates --> - <div pluginFactoryDirective> - </div> </div> </ng-template> diff --git a/src/components/markdown/markdown.component.ts b/src/components/markdown/markdown.component.ts index e48f409c0cbd604c5be32c424a491552cedaa0a5..bd5ea00320923c15e4517232021822b91fd8e630 100644 --- a/src/components/markdown/markdown.component.ts +++ b/src/components/markdown/markdown.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild, ChangeDetectorRef, AfterViewChecked } from '@angular/core' +import { ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild, ChangeDetectorRef, AfterViewChecked, OnChanges } from '@angular/core' import * as showdown from 'showdown' @Component({ @@ -10,7 +10,7 @@ import * as showdown from 'showdown' changeDetection : ChangeDetectionStrategy.OnPush, }) -export class MarkdownDom implements AfterViewChecked { +export class MarkdownDom implements OnChanges { @Input() public markdown: string = `` public innerHtml: string = `` @@ -21,6 +21,7 @@ export class MarkdownDom implements AfterViewChecked { constructor( private cdr: ChangeDetectorRef ) { + this.cdr.detach() this.converter.setFlavor('github') } @@ -30,7 +31,7 @@ export class MarkdownDom implements AfterViewChecked { return '' } - public ngAfterViewChecked(){ + ngOnChanges(){ this.innerHtml = this.converter.makeHtml( this.getMarkdown() ) diff --git a/src/extra_styles.css b/src/extra_styles.css index ae2f870b0e9158e1b3032959d203fca162c9c4bd..99d5560ccf6da747eed7c3641c97b620aadd29fc 100644 --- a/src/extra_styles.css +++ b/src/extra_styles.css @@ -758,6 +758,16 @@ kg-dataset-previewer > img opacity: 1.0; } +.m-15 +{ + margin: 15px; +} + +.m-1px +{ + margin:1px; +} + .ml-15px-n { margin-left: -15px!important; @@ -805,6 +815,10 @@ kg-dataset-previewer > img { margin-top: -1rem!important; } +.mt-1-n +{ + margin-top: -0.5rem!important; +} .mb-6 { @@ -886,3 +900,8 @@ mat-list.sm mat-list-item margin-top: auto; margin-bottom: auto; } + +.v-align-top +{ + vertical-align: top; +} \ No newline at end of file diff --git a/src/layouts/fourCorners/fourCorners.style.css b/src/layouts/fourCorners/fourCorners.style.css index 352b490b2acf42d4d92344bdc0be28d4f8cf80da..553d5ecec474e79bfcae4533a5ab01373c185557 100644 --- a/src/layouts/fourCorners/fourCorners.style.css +++ b/src/layouts/fourCorners/fourCorners.style.css @@ -10,4 +10,28 @@ .corner-container { z-index: 5; -} \ No newline at end of file +} + +.grid-container +{ + height: 50%; + display: grid; + grid-template-columns: auto auto; +} + +.top-left +{ + place-self: start start; +} +.top-right +{ + place-self: start end; +} +.bottom-left +{ + place-self: end start; +} +.bottom-right +{ + place-self: end end; +} diff --git a/src/layouts/fourCorners/fourCorners.template.html b/src/layouts/fourCorners/fourCorners.template.html index 96cfe86cdb46e296f4b44fa92adfb377dec010fd..c0e98df279d32db83b96227fa439642ff79175cc 100644 --- a/src/layouts/fourCorners/fourCorners.template.html +++ b/src/layouts/fourCorners/fourCorners.template.html @@ -2,19 +2,24 @@ <ng-content select="[iavLayoutFourCornersContent]"></ng-content> </div> -<div [ngClass]="cornerContainerClasses" - class="corner-container position-absolute top-0 left-0"> - <ng-content select="[iavLayoutFourCornersTopLeft]"></ng-content> +<div class="grid-container"> + <div [ngClass]="cornerContainerClasses" + class="corner-container top-left"> + <ng-content select="[iavLayoutFourCornersTopLeft]"></ng-content> + </div> + <div [ngClass]="cornerContainerClasses" + class="corner-container top-right"> + <ng-content select="[iavLayoutFourCornersTopRight]"></ng-content> + </div> </div> -<div [ngClass]="cornerContainerClasses" - class="corner-container position-absolute top-0 right-0"> - <ng-content select="[iavLayoutFourCornersTopRight]"></ng-content> -</div> -<div [ngClass]="cornerContainerClasses" - class="corner-container position-absolute bottom-0 left-0"> - <ng-content select="[iavLayoutFourCornersBottomLeft]"></ng-content> + +<div class="grid-container"> + <div [ngClass]="cornerContainerClasses" + class="corner-container bottom-left"> + <ng-content select="[iavLayoutFourCornersBottomLeft]"></ng-content> + </div> + <div [ngClass]="cornerContainerClasses" + class="corner-container bottom-right"> + <ng-content select="[iavLayoutFourCornersBottomRight]"></ng-content> + </div> </div> -<div [ngClass]="cornerContainerClasses" - class="corner-container position-absolute bottom-0 right-0"> - <ng-content select="[iavLayoutFourCornersBottomRight]"></ng-content> -</div> \ No newline at end of file diff --git a/src/overwrite.scss b/src/overwrite.scss index 9aa3141ed73802f6b6b75ecc85cade85afdbcbae..c8e7e12e46e899f162b3085f1cd523be12835d24 100644 --- a/src/overwrite.scss +++ b/src/overwrite.scss @@ -1,3 +1,5 @@ +@use 'sass:math'; + iav-cmp-viewer-container { @@ -33,4 +35,39 @@ kg-ds-prv-regional-feature-view { min-height: 20em; } -} \ No newline at end of file +} + +// no prefix +@for $i from 1 through 12 { + $vw: math.div(100vw * $i, 12); + .vw-col-#{$i} { + width: $vw; + } + .vw-col-#{$i}-nm { + margin-left: -1 * $vw; + } +} + +$medias: "-sm","-md","-lg","-xl","-xxl"; +$media-map: ( + "-sm": 576px, + "-md": 768px, + "-lg": 992px, + "-xl": 1200px, + "-xxl": 2000px, +); + +@each $media in $medias { + $size: map-get($media-map, $media); + @media (min-width: $size) { + @for $i from 1 through 12 { + $vw: math.div(100vw * $i, 12); + .vw-col#{$media}-#{$i} { + width: $vw; + } + .vw-col#{$media}-#{$i}-nm { + margin-left: -1 * $vw; + } + } + } +} diff --git a/src/ui/logoContainer/logoContainer.component.ts b/src/ui/logoContainer/logoContainer.component.ts index b7a85fda32a4147929b64e02be4f72c8481066b4..3ae73afe9c647971c928716477b7b69723719f2e 100644 --- a/src/ui/logoContainer/logoContainer.component.ts +++ b/src/ui/logoContainer/logoContainer.component.ts @@ -2,6 +2,9 @@ import { Component } from "@angular/core"; import { PureContantService } from "src/util"; import { Subscription } from "rxjs"; +const imageDark = 'assets/logo/ebrains-logo-dark.svg' +const imageLight = 'assets/logo/ebrains-logo-light.svg' + @Component({ selector : 'logo-container', templateUrl : './logoContainer.template.html', @@ -12,10 +15,10 @@ import { Subscription } from "rxjs"; export class LogoContainer { // only used to define size - public imgSrc = `${this.pureConstantService.backendUrl}logo` + public imgSrc = imageDark public containerStyle = { - backgroundImage: `url('${this.pureConstantService.backendUrl}logo')` + backgroundImage: `url('${this.imgSrc}')` } private subscriptions: Subscription[] = [] @@ -25,7 +28,7 @@ export class LogoContainer { this.subscriptions.push( pureConstantService.darktheme$.subscribe(flag => { this.containerStyle = { - backgroundImage: `url('${this.pureConstantService.backendUrl}logo${!!flag ? '?darktheme=true' : ''}')` + backgroundImage: `url('${flag ? imageLight : imageDark}')` } }) ) diff --git a/src/util/directives/switch.directive.ts b/src/util/directives/switch.directive.ts index eb582253a951b061958c69ff19dd1317c97ab30f..89dd445186afe7d49e2ee8c7b7d50a27429edff7 100644 --- a/src/util/directives/switch.directive.ts +++ b/src/util/directives/switch.directive.ts @@ -1,16 +1,28 @@ import { Directive, Input, Output, EventEmitter } from "@angular/core"; +import { BehaviorSubject } from "rxjs"; @Directive({ selector: '[iav-switch]', exportAs: 'iavSwitch' }) export class SwitchDirective{ - @Input('iav-switch-initstate') switchState: boolean = false + + switchState: boolean = false + @Input('iav-switch-delay') delay: number = 0 @Output('iav-switch-event') eventemitter: EventEmitter<boolean> = new EventEmitter() - emit(flag){ + @Input('iav-switch-state') + set setSwitchState(val: boolean) { + this.switchState = val + this.emit() + } + + public switchState$ = new BehaviorSubject(this.switchState) + + emit(){ this.eventemitter.emit(this.switchState) + this.switchState$.next(this.switchState) } toggle(){ diff --git a/src/viewerModule/nehuba/statusCard/statusCard.component.ts b/src/viewerModule/nehuba/statusCard/statusCard.component.ts index 76dfa6bbbdb0288b6755984fa651d71b3e50c5df..7e129dd484746f49bc7a73fdc9e5fff307a7e446 100644 --- a/src/viewerModule/nehuba/statusCard/statusCard.component.ts +++ b/src/viewerModule/nehuba/statusCard/statusCard.component.ts @@ -50,7 +50,6 @@ export class StatusCardComponent implements OnInit, OnChanges{ public navVal$: Observable<string> public mouseVal$: Observable<string> - public useTouchInterface$: Observable<boolean> public quickTourData: IQuickTourData = { description: QUICKTOUR_DESC.STATUS_CARD, @@ -72,7 +71,6 @@ export class StatusCardComponent implements OnInit, OnChanges{ private dialog: MatDialog, @Optional() @Inject(NEHUBA_INSTANCE_INJTKN) nehubaViewer$: Observable<NehubaViewerUnit> ) { - this.useTouchInterface$ = of(true) //this.pureConstantService.useTouchUI$ if (nehubaViewer$) { this.subscriptions.push( diff --git a/src/viewerModule/nehuba/statusCard/statusCard.template.html b/src/viewerModule/nehuba/statusCard/statusCard.template.html index 5f57d9719055a265dbfb005c5c4d7d3cc46ab1ea..10542f7c52238767a0c069f9ca916751154f1f55 100644 --- a/src/viewerModule/nehuba/statusCard/statusCard.template.html +++ b/src/viewerModule/nehuba/statusCard/statusCard.template.html @@ -89,7 +89,7 @@ </div> <!-- cursor pos --> - <mat-form-field *ngIf="!(useTouchInterface$ | async)" + <mat-form-field class="w-100"> <mat-label> Cursor Position @@ -115,17 +115,6 @@ {{ navVal$ | async }} </span> - <!-- only show cursor if touch interface is not on --> - <span *ngIf="false && !(useTouchInterface$ | async)"> - <!-- padding --> - <span class="pl-4"></span> - - <i aria-label="cursor location" class="fas fa-mouse-pointer"></i> - <span class="pl2"> - {{ mouseVal$ | async }} - </span> - </span> - <mat-divider [vertical]="true"></mat-divider> <button mat-icon-button diff --git a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html index a1a1507eedbdcf739c18c24f77642fb397d6df84..783d582fd907bba374635025e2f6f8afe8cf1550 100644 --- a/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html +++ b/src/viewerModule/nehuba/viewerCtrl/viewerCtrlCmp/viewerCtrlCmp.template.html @@ -8,8 +8,8 @@ (iav-key-event)="delinToggle.toggle()" name="toggle-delineation"> - <markdown-dom class="d-inline-block iv-custom-comp text"> - Show delineations `[q]` + <markdown-dom class="d-inline-block iv-custom-comp text" + markdown="Show delineations `[q]`"> </markdown-dom> </mat-slide-toggle> diff --git a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html index c1981ce4f144361f24e86026bf15de4d063f89fc..31f59c7293be5be213c6634d42722f4cb852bf45 100644 --- a/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html +++ b/src/viewerModule/threeSurfer/threeSurferGlue/threeSurfer.template.html @@ -42,8 +42,8 @@ {{ mode.name }} </span> <markdown-dom *ngIf="mode.name === selectedMode" - class="d-inline-block"> - `[q]` + class="d-inline-block" + markdown="`[q]`"> </markdown-dom> </button> </mat-menu> diff --git a/src/viewerModule/viewerCmp/viewerCmp.component.ts b/src/viewerModule/viewerCmp/viewerCmp.component.ts index bb0c20a548bf82504019a4fe307c180d6d498d4b..3134f6e035c31ed7e96f5b063e531e4b9aa41e84 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.component.ts +++ b/src/viewerModule/viewerCmp/viewerCmp.component.ts @@ -1,7 +1,7 @@ -import { Component, ComponentFactory, ComponentFactoryResolver, ElementRef, Inject, Injector, Input, OnDestroy, Optional, TemplateRef, ViewChild, ViewContainerRef } from "@angular/core"; +import { ChangeDetectionStrategy, Component, ComponentFactory, ComponentFactoryResolver, Inject, Injector, Input, OnDestroy, Optional, TemplateRef, ViewChild, ViewContainerRef } from "@angular/core"; import { select, Store } from "@ngrx/store"; -import {combineLatest, merge, NEVER, Observable, of, Subject, Subscription} from "rxjs"; -import {catchError, distinctUntilChanged, filter, map, shareReplay, startWith, switchMap } from "rxjs/operators"; +import { combineLatest, merge, NEVER, Observable, of, Subscription } from "rxjs"; +import {catchError, distinctUntilChanged, map, shareReplay, startWith, switchMap } from "rxjs/operators"; import { viewerStateSetSelectedRegions } from "src/services/state/viewerState/actions"; import { viewerStateContextedSelectedRegionsSelector, @@ -13,9 +13,7 @@ import { import { CONST, ARIA_LABELS, QUICKTOUR_DESC } from 'common/constants' import { OVERWRITE_SHOW_DATASET_DIALOG_TOKEN, REGION_OF_INTEREST } from "src/util/interfaces"; import { animate, state, style, transition, trigger } from "@angular/animations"; -import { SwitchDirective } from "src/util/directives/switch.directive"; -import { QuickTourThis, IQuickTourData } from "src/ui/quickTour"; -import { MatDrawer } from "@angular/material/sidenav"; +import { IQuickTourData } from "src/ui/quickTour"; import { PureContantService } from "src/util"; import { EnumViewerEvt, TContextArg, TSupportedViewers, TViewerEvent } from "../viewer.interface"; import { getGetRegionFromLabelIndexId, switchMapWaitFor } from "src/util/fn"; @@ -25,6 +23,7 @@ import { MAT_DIALOG_DATA } from "@angular/material/dialog"; import { GenericInfoCmp } from "src/atlasComponents/regionalFeatures/bsFeatures/genericInfo"; import { _PLI_VOLUME_INJ_TOKEN, _TPLIVal } from "src/glue"; import { uiActionSetPreviewingDatasetFiles } from "src/services/state/uiState.store.helper"; +import { viewerStateSetViewerMode } from "src/services/state/viewerState.store.helper"; type TCStoreViewerCmp = { overlaySideNav: any @@ -113,7 +112,8 @@ export function ROIFactory(store: Store<any>, svc: PureContantService){ deps: [ ComponentStore ] }, ComponentStore - ] + ], + changeDetection: ChangeDetectionStrategy.OnPush }) export class ViewerCmp implements OnDestroy { @@ -124,12 +124,6 @@ export class ViewerCmp implements OnDestroy { public CONST = CONST public ARIA_LABELS = ARIA_LABELS - @ViewChild('sideNavTopSwitch', { static: true }) - private sidenavTopSwitch: SwitchDirective - - @ViewChild('sideNavFullLeftSwitch', { static: true }) - private sidenavLeftSwitch: SwitchDirective - @ViewChild('genericInfoVCR', { read: ViewContainerRef }) genericInfoVCR: ViewContainerRef @@ -169,6 +163,7 @@ export class ViewerCmp implements OnDestroy { public viewerMode$: Observable<string> = this.store$.pipe( select(viewerStateViewerModeSelector), + shareReplay(1), ) public overlaySidenav$ = this.cStore.select(s => s.overlaySideNav).pipe( @@ -187,12 +182,8 @@ export class ViewerCmp implements OnDestroy { return 'notsupported' }) ) - - /** - * TODO may need to be deprecated - * in favour of regional feature/data feature - */ - public iavAdditionalLayers$ = new Subject<any[]>() + + public pliVol$ = this._pliVol$ || NEVER /** * if no regions are selected, nor any additional layers (being deprecated) @@ -200,9 +191,9 @@ export class ViewerCmp implements OnDestroy { * and the full left side bar should not be expandable * if it is already expanded, it should collapse */ - public alwaysHideMinorPanel$: Observable<boolean> = combineLatest([ + public onlyShowMiniTray$: Observable<boolean> = combineLatest([ this.selectedRegions$, - this.iavAdditionalLayers$.pipe( + this.pliVol$.pipe( startWith([]) ) ]).pipe( @@ -221,7 +212,6 @@ export class ViewerCmp implements OnDestroy { private genericInfoCF: ComponentFactory<GenericInfoCmp> - public pliVol$ = this._pliVol$ || NEVER public clearVoi(){ this.store$.dispatch( uiActionSetPreviewingDatasetFiles({ @@ -241,24 +231,9 @@ export class ViewerCmp implements OnDestroy { this.genericInfoCF = cfr.resolveComponentFactory(GenericInfoCmp) this.subscriptions.push( - this.pliVol$.subscribe(val => { - if (val.length > 0) { - this.sidenavTopSwitch && this.sidenavTopSwitch.open() - this.sidenavLeftSwitch && this.sidenavLeftSwitch.open() - } else { - this.sidenavTopSwitch && this.sidenavTopSwitch.close() - this.sidenavLeftSwitch && this.sidenavLeftSwitch.close() - } - }), this.selectedRegions$.subscribe(() => { this.clearPreviewingDataset() }), - this.alwaysHideMinorPanel$.pipe( - distinctUntilChanged(), - filter(flag => !flag), - ).subscribe(() => { - this.openSideNavs() - }), this.viewerModuleSvc.context$.subscribe( (ctx: any) => this.context = ctx ), @@ -373,13 +348,12 @@ export class ViewerCmp implements OnDestroy { ) } - public handleChipClick(){ - this.openSideNavs() - } - - private openSideNavs() { - this.sidenavLeftSwitch && this.sidenavLeftSwitch.open() - this.sidenavTopSwitch && this.sidenavTopSwitch.open() + public exitSpecialViewMode(){ + this.store$.dispatch( + viewerStateSetViewerMode({ + payload: null + }) + ) } public clearPreviewingDataset(){ @@ -391,21 +365,6 @@ export class ViewerCmp implements OnDestroy { }) } - @ViewChild('regionSelRef', { read: ElementRef }) - regionSelRef: ElementRef<any> - - @ViewChild('regionSearchQuickTour', { read: QuickTourThis }) - regionSearchQuickTour: QuickTourThis - - @ViewChild('matDrawerLeft', { read: MatDrawer }) - matDrawerLeft: MatDrawer - - handleSideNavAnimationDone(sideNavExpanded: boolean) { - this.regionSearchQuickTour?.attachTo( - !sideNavExpanded ? null : this.regionSelRef - ) - } - public handleViewerEvent(event: TViewerEvent<'nehuba' | 'threeSurfer'>){ switch(event.type) { case EnumViewerEvt.VIEWERLOADED: diff --git a/src/viewerModule/viewerCmp/viewerCmp.style.css b/src/viewerModule/viewerCmp/viewerCmp.style.css index 19b64d6b88116e5954dd0fb2226e6fc79b3dcc01..6633b28f8ec233a078953ba66fbb6c73877b2274 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.style.css +++ b/src/viewerModule/viewerCmp/viewerCmp.style.css @@ -49,3 +49,13 @@ mat-drawer { overflow-x: hidden; } + +.transition-margin-left +{ + transition: margin-left 200ms cubic-bezier(0.35, 0, 0.25, 1); +} + +._pli-container +{ + padding-top: 5rem; +} diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html index b77622c13103c80c4ccc5e2c938ccd1bca2a97d1..27b7140344ac2b3b5b60c0b5deda2d87f2c8b66c 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.template.html +++ b/src/viewerModule/viewerCmp/viewerCmp.template.html @@ -3,133 +3,221 @@ </ng-container> </div> -<layout-floating-container [zIndex]="10"> - - <!-- Annotation mode --> - <mat-drawer-container *ngIf="viewerMode$ | async as viewerMode" - class="mat-drawer-content-overflow-visible w-100 h-100 position-absolute invisible" - [hasBackdrop]="false"> - - <mat-drawer #viewerModeDrawer="matDrawer" - mode="side" - (annotation-event-directive)="viewerModeDrawer.open()" - [annotation-event-directive-filter]="['showList']" - [autoFocus]="false" - [disableClose]="true" - class="p-0 pe-all col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2"> - - <!-- annotation --> - <ng-template [ngIf]="viewerMode === ARIA_LABELS.VIEWER_MODE_ANNOTATING"> - <annotation-list></annotation-list> - </ng-template> - <ng-template [ngIf]="viewerMode === ARIA_LABELS.VIEWER_MODE_KEYFRAME"> - <key-frame-controller></key-frame-controller> +<!-- master draw container --> +<mat-drawer-container + *ngIf="viewerLoaded" + iav-switch + [iav-switch-state]="!(onlyShowMiniTray$ | async)" + #showFullSidenavSwitch="iavSwitch" + class="position-absolute w-100 h-100 mat-drawer-content-overflow-visible invisible" + [hasBackdrop]="false"> + + <!-- master drawer --> + <mat-drawer + mode="side" + #drawer="matDrawer" + [opened]="!(onlyShowMiniTray$ | async)" + [@openClose]="showFullSidenavSwitch && (showFullSidenavSwitch.switchState$ | async) ? 'open' : 'closed'" + (@openClose.start)="$event.toState === 'open' && drawer.open()" + (@openClose.done)="$event.toState === 'closed' && drawer.close()" + [autoFocus]="false" + [disableClose]="true" + class="iv-custom-comp darker-bg p-0 pe-all col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2 z-index-10"> + + <!-- entry template --> + <ng-template [ngIf]="viewerMode$ | async" let-mode [ngIfElse]="regularTmpl"> + <ng-template [ngTemplateOutlet]="alternateModeDrawerTmpl" + [ngTemplateOutletContext]="{ + mode: mode + }"></ng-template> + </ng-template> + + <!-- regular mode --> + <ng-template #regularTmpl> + <ng-template + [ngTemplateOutlet]="regularModeDrawerTmpl" + [ngTemplateOutletContext]="{ + drawer: drawer, + showFullSidenavSwitch: showFullSidenavSwitch + }"> + </ng-template> + </ng-template> + </mat-drawer> + + <!-- master content --> + <mat-drawer-content class="visible pe-none position-relative"> + <iav-layout-fourcorners> + + <!-- top left --> + <div iavLayoutFourCornersTopLeft class="ws-no-wrap"> + + <!-- special mode --> + <ng-template [ngIf]="viewerMode$ | async" let-mode [ngIfElse]="defaultTopLeftTmpl"> + <ng-template [ngTemplateOutlet]="specialModeTopLeftTmpl" + [ngTemplateOutletContext]="{ + mode: mode, + toggleMatDrawer: drawer.toggle.bind(drawer) + }"> + </ng-template> </ng-template> - </mat-drawer> - <mat-drawer-content class="visible position-relative pe-none"> + <!-- default mode top left tmpl --> + <ng-template #defaultTopLeftTmpl> + <ng-template [ngTemplateOutlet]="defaultMainContentTopLeft" + [ngTemplateOutletContext]="{ + isOpen: drawer.opened, + drawer: drawer, + showFullSidenavSwitch: showFullSidenavSwitch + }"> + </ng-template> + </ng-template> + </div> - <!-- annotation specific --> - <iav-layout-fourcorners *ngIf="viewerMode === ARIA_LABELS.VIEWER_MODE_ANNOTATING"> - <!-- pullable tab top right corner --> - <div iavLayoutFourCornersTopLeft class="tab-toggle-container"> + <!-- top right --> + <div iavLayoutFourCornersTopRight class="ws-no-wrap"> - <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { - matColor: 'primary', - fontIcon: 'fa-list', - tooltip: 'Annotation list', - click: viewerModeDrawer.toggle.bind(viewerModeDrawer), - badge: toolPanel?.annBadges$ | async + <!-- exit special mode --> + <ng-template [ngIf]="viewerMode$ | async" let-mode [ngIfElse]="defaultTopRightTmpl"> + <ng-template [ngTemplateOutlet]="specialTopRightTmpl" + [ngTemplateOutletContext]="{ + mode: mode }"> - </ng-container> - - <annotating-tools-panel class="z-index-10" - #toolPanel="annoToolsPanel"> - </annotating-tools-panel> - </div> - - <div iavLayoutFourCornersTopRight> - <mat-card class="mat-card-sm pe-all m-4"> - <span> - Annotating - </span> - <button mat-icon-button - [matTooltip]="ARIA_LABELS.EXIT_ANNOTATION_MODE" - color="warn" - annotation-switch - annotation-switch-mode="off"> - <i class="fas fa-times"></i> - </button> - </mat-card> - </div> - - </iav-layout-fourcorners> - - - <!-- key frame specific --> - <iav-layout-fourcorners *ngIf="viewerMode === ARIA_LABELS.VIEWER_MODE_KEYFRAME"> - <!-- pullable tab top right corner --> - <div iavLayoutFourCornersTopLeft class="tab-toggle-container"> - - <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { - matColor: 'primary', - fontIcon: 'fa-play', - tooltip: 'Annotation list', - click: viewerModeDrawer.toggle.bind(viewerModeDrawer) + </ng-template> + </ng-template> + + <!-- default mode top right tmpl --> + <ng-template #defaultTopRightTmpl> + <ng-template [ngTemplateOutlet]="minDefaultMainContentTopRight"> + </ng-template> + </ng-template> + </div> + + + <!-- bottom left --> + <div iavLayoutFourCornersBottomLeft class="ws-no-wrap"> + + <!-- special bottom left --> + <ng-template [ngIf]="viewerMode$ | async" let-mode [ngIfElse]="localBottomLeftTmpl"></ng-template> + + <!-- default mode bottom left tmpl --> + <ng-template #localBottomLeftTmpl> + + <!-- not the most elegant, but it's a hard problem to solve --> + <!-- on the one hand, showFullSidenavSwitch can be of two states --> + <!-- and drawer.opened can be of two states --> + <ng-template [ngTemplateOutlet]="bottomLeftTmpl" + [ngTemplateOutletContext]="{ + showFullSideNav: (showFullSidenavSwitch.switchState$ | async) + ? drawer.open.bind(drawer) + : showFullSidenavSwitch.open.bind(showFullSidenavSwitch) }"> - </ng-container> - </div> - - <div iavLayoutFourCornersTopRight> - <mat-card class="mat-card-sm pe-all m-4"> - <span> - Key Frame - </span> - <button mat-icon-button - color="warn" - key-frame-play-now="off"> - <i class="fas fa-times"></i> - </button> - </mat-card> - </div> - - </iav-layout-fourcorners> - </mat-drawer-content> - - </mat-drawer-container> - - <!-- top drawer --> - <mat-drawer-container - [hidden]="viewerMode$ | async" - [iav-switch-initstate]="false" - iav-switch - #sideNavTopSwitch="iavSwitch" - class="mat-drawer-content-overflow-visible w-100 h-100 position-absolute invisible" - [hasBackdrop]="false"> - - <!-- sidenav-content --> - - <!-- (closedStart)="sideNavwFullLeftSwitch.switchState && matDrawerLeft.close()" - (openedStart)="sideNavFullLeftSwitch.switchState && matDrawerLeft.open()" --> - <mat-drawer class="box-shadow-none border-0 pe-none bg-none col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2" - mode="side" - [attr.data-mat-drawer-top-open]="matDrawerTop.opened" - [opened]="sideNavTopSwitch.switchState" - [autoFocus]="false" - [disableClose]="true" - (openedChange)="handleSideNavAnimationDone($event)" - #matDrawerTop="matDrawer"> - - <div class="h-0 w-100 region-text-search-autocomplete-position"> - <ng-container *ngTemplateOutlet="autocompleteTmpl; context: { showTour: true }"> - </ng-container> + </ng-template> + </ng-template> + </div> + </iav-layout-fourcorners> + </mat-drawer-content> +</mat-drawer-container> + +<!-- alternate mode drawer tmpl --> +<ng-template #alternateModeDrawerTmpl let-mode="mode"> + <ng-container [ngSwitch]="mode"> + <annotation-list *ngSwitchCase="ARIA_LABELS.VIEWER_MODE_ANNOTATING"> + </annotation-list> + <key-frame-controller *ngSwitchCase="ARIA_LABELS.VIEWER_MODE_KEYFRAME"> + </key-frame-controller> + <span *ngSwitchDefault>View mode {{ mode }} does not have side nav registered.</span> + </ng-container> +</ng-template> + + +<!-- regular mode drawer tmpl --> +<ng-template #regularModeDrawerTmpl + let-drawer="drawer" + let-showFullSidenavSwitch="showFullSidenavSwitch"> + + <!-- check if preview volume --> + <ng-template [ngIf]="overlaySidenav$ | async" let-overlaySideNav> + + <!-- back btn --> + <button mat-button + (click)="clearPreviewingDataset()" + [attr.aria-label]="ARIA_LABELS.CLOSE" + class="position-absolute z-index-10 m-2"> + <i class="fas fa-chevron-left"></i> + <span class="ml-1"> + Back + </span> + </button> + + <ng-template #genericInfoVCR> + </ng-template> + </ng-template> + + <div [ngClass]="{ + 'invisible overflow-hidden h-0': overlaySidenav$ | async, + 'h-100': !(overlaySidenav$ | async) + }" class="pe-all position-relative d-flex flex-column"> + + + <!-- if pli voi is visible, show pli template + otherwise show region tmpl --> + <ng-template + [ngTemplateOutlet]="(pliVol$ | async)?.[0] + ? voiTmpl + : sidenavRegionTmpl" + [ngTemplateOutletContext]="{ + drawer: drawer, + showFullSidenavSwitch: showFullSidenavSwitch + }"> + </ng-template> + + <!-- <ng-template let-pliVol [ngIf]="pliVol$ | async" [ngIfElse]="sidenavRegionTmpl"> + <ng-template [ngIf]="pliVol.length > 0" [ngIfElse]="sidenavRegionTmpl"> + <ng-template [ngTemplateOutlet]="voiTmpl"> + + </ng-template> + </ng-template> + </ng-template> --> + + <!-- TODO dataset preview will become deprecated in the future. + Regional feature/data feature will replace it --> + <!-- <div class="hidden" + iav-shown-dataset + #iavShownDataset="iavShownDataset"> + </div> --> + </div> +</ng-template> + + +<!-- minimal default drawer content --> +<ng-template #minSearchTray + let-showFullSidenav="showFullSidenav" + let-drawer="drawer"> + + <div class="mt-2 d-inline-block vw-col-10 vw-col-sm-10 vw-col-md-5 vw-col-lg-4 vw-col-xl-3 vw-col-xxl-2" + iav-switch + [iav-switch-state]="true" + #minTrayVisSwitch="iavSwitch" + [ngClass]="{ + 'vw-col-10-nm vw-col-sm-10-nm vw-col-md-5-nm vw-col-lg-4-nm vw-col-xl-3-nm vw-col-xxl-2-nm': !(minTrayVisSwitch.switchState$ | async), + 'transition-margin-left': !drawer.opened + }"> + + <div class="h-0 w-100 region-text-search-autocomplete-position"> + <ng-container *ngTemplateOutlet="autocompleteTmpl; context: { showTour: true }"> + </ng-container> + </div> + + <!-- such a gross implementation --> + <!-- TODO fix this --> + <div class="mt-1-n w-100 pl-2 pr-2 m-1px"> <button mat-raised-button - *ngIf="!(alwaysHideMinorPanel$ | async)" + *ngIf="!(onlyShowMiniTray$ | async)" [attr.aria-label]="ARIA_LABELS.EXPAND" - (click)="sideNavFullLeftSwitch && sideNavFullLeftSwitch.open()" + (click)="showFullSidenav()" class="explore-btn pe-all w-100" [ngClass]="{ 'darktheme': iavRegion.rgbDarkmode === true, @@ -145,215 +233,190 @@ [region]="(selectedRegions$ | async) && (selectedRegions$ | async)[0]" #iavRegion="iavRegion"> </div> - </button> - </mat-drawer> - - <mat-drawer-content class="visible position-relative pe-none"> - - <iav-layout-fourcorners [iav-layout-fourcorners-cnr-cntr-ngclass]="{'w-100': true}"> - - <!-- pullable tab top left corner --> - <div iavLayoutFourCornersTopLeft class="d-flex flex-nowrap w-100"> - - <!-- top left --> - <div class="flex-grow-1 d-flex flex-nowrap align-items-start"> - - <div *ngIf="viewerLoaded" - class="pe-all tab-toggle-container" - (click)="sideNavTopSwitch && sideNavTopSwitch.toggle()" - quick-tour - [quick-tour-description]="quickTourRegionSearch.description" - [quick-tour-order]="quickTourRegionSearch.order" - #regionSearchQuickTour="quickTour"> - <ng-container *ngTemplateOutlet="tabTmpl; context: { - isOpen: sideNavTopSwitch.switchState, - regionSelected: selectedRegions$ | async, - iavAdditionallayers: iavAdditionalLayers$ | async - }"> - </ng-container> - </div> - - <iav-cmp-viewer-nehuba-status *ngIf="(useViewer$ | async) === 'nehuba'" - class="pe-all mt-2 muted-7"> - </iav-cmp-viewer-nehuba-status> - </div> - - <!-- top right --> - <div class="flex-grow-0 d-inline-flex align-items-start"> - - <!-- signin banner at top right corner --> - - - <top-menu-cmp class="mt-3 mr-2 d-inline-block" - [ismobile]="ismobile" - [viewerLoaded]="viewerLoaded"> - </top-menu-cmp> - - <div *ngIf="viewerLoaded" - class="iv-custom-comp bg card m-2 mat-elevation-z2" - quick-tour - [quick-tour-description]="quickTourAtlasSelector.description" - [quick-tour-order]="quickTourAtlasSelector.order"> - <atlas-dropdown-selector class="pe-all mt-2"> - </atlas-dropdown-selector> - </div> - </div> - </div> + </div> + + </div> - </iav-layout-fourcorners> + <!-- tab toggling hide/show of min search tray --> + <div class="tab-toggle-container d-inline-block v-align-top"> + <ng-container *ngTemplateOutlet="tabTmpl; context: { + isOpen: minTrayVisSwitch.switchState$ | async, + regionSelected: selectedRegions$ | async, + click: minTrayVisSwitch.toggle.bind(minTrayVisSwitch) + }"> + </ng-container> + </div> - </mat-drawer-content> - </mat-drawer-container> +</ng-template> - <!-- full left drawer --> - <mat-drawer-container - [hidden]="viewerMode$ | async" - [iav-switch-initstate]="!(alwaysHideMinorPanel$ | async)" - iav-switch - #sideNavFullLeftSwitch="iavSwitch" - class="mat-drawer-content-overflow-visible w-100 h-100 position-absolute invisible" - [hasBackdrop]="false"> - - <!-- sidenav-content --> - <mat-drawer class="darker-bg iv-custom-comp visible col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2 d-flex flex-column pe-all" - mode="push" - [opened]="sideNavTopSwitch.switchState && sideNavFullLeftSwitch.switchState" - [attr.data-mat-drawer-fullleft-open]="matDrawerLeft.opened" - [autoFocus]="false" - #matDrawerLeft="matDrawer" - (openedChange)="$event && sideNavFullLeftSwitch.open()" - [@openClose]="sideNavTopSwitch.switchState && sideNavFullLeftSwitch.switchState ? 'open' : 'closed'" - (@openClose.done)="$event.toState === 'closed' && matDrawerLeft.close()" - [disableClose]="true"> - - <!-- check if preview volume --> - <div *ngIf="overlaySidenav$ | async as overlaySideNav" class="position-relative d-flex flex-column h-100"> - <div class="position-relative ml-15px-n mr-15px-n"> - - <!-- back btn --> - <button mat-button - (click)="clearPreviewingDataset()" - [attr.aria-label]="ARIA_LABELS.CLOSE" - class="position-absolute z-index-10 m-2"> - <i class="fas fa-chevron-left"></i> - <span class="ml-1"> - Back - </span> - </button> - <ng-template #genericInfoVCR> - </ng-template> - </div> - </div> +<!-- top left --> +<!-- default top left --> +<ng-template #defaultMainContentTopLeft + let-isOpen="isOpen" + let-drawer="drawer" + let-showFullSidenavSwitch="showFullSidenavSwitch"> + + <!-- min search tray --> + <ng-template [ngIf]="!(showFullSidenavSwitch.switchState$ | async)"> + <ng-template + [ngTemplateOutlet]="minSearchTray" + [ngTemplateOutletContext]="{ + showFullSidenav: showFullSidenavSwitch.open.bind(showFullSidenavSwitch), + drawer: drawer + }"> + </ng-template> + </ng-template> - <div [ngClass]="{ - 'invisible overflow-hidden h-0': overlaySidenav$ | async, - 'h-100': !(overlaySidenav$ | async) - }" class="position-relative d-flex flex-column"> - - <ng-template let-pliVol [ngIf]="pliVol$ | async" [ngIfElse]="sidenavRegionTmpl"> - <ng-template [ngIf]="pliVol.length > 0" [ngIfElse]="sidenavRegionTmpl"> - <ng-template [ngTemplateOutlet]="voiTmpl"> + <!-- pullable tab top left corner --> + <div *ngIf="showFullSidenavSwitch.switchState$ | async" + class="v-align-top pe-all tab-toggle-container d-inline-block" + (click)="drawer.toggle()" + quick-tour + [quick-tour-description]="quickTourRegionSearch.description" + [quick-tour-order]="quickTourRegionSearch.order"> + <ng-container *ngTemplateOutlet="tabTmpl; context: { + isOpen: isOpen, + regionSelected: selectedRegions$ | async + }"> + </ng-container> + </div> - </ng-template> - </ng-template> - </ng-template> + <!-- status panel for (for nehuba viewer) --> + <iav-cmp-viewer-nehuba-status *ngIf="(useViewer$ | async) === 'nehuba'" + class="pe-all mt-2 muted-7 d-inline-block v-align-top"> + </iav-cmp-viewer-nehuba-status> +</ng-template> - <!-- TODO dataset preview will become deprecated in the future. - Regional feature/data feature will replace it --> - <!-- <div class="hidden" - iav-shown-dataset - #iavShownDataset="iavShownDataset"> - </div> --> - </div> - </mat-drawer> +<!-- special mode top left --> +<ng-template #specialModeTopLeftTmpl + let-mode="mode" + let-toggleMatDrawer="toggleMatDrawer"> - <!-- main-content --> - <mat-drawer-content class="visible position-relative" [hidden]="viewerMode$ | async"> + <div class="tab-toggle-container"> - <iav-layout-fourcorners [iav-layout-fourcorners-cnr-cntr-ngclass]="{'w-100': true}"> + <ng-container [ngSwitch]="mode"> + <!-- annotating top left --> + <ng-template [ngSwitchCase]="ARIA_LABELS.VIEWER_MODE_ANNOTATING"> + <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { + matColor: 'primary', + fontIcon: 'fa-list', + tooltip: 'Annotation list', + click: toggleMatDrawer, + badge: toolPanel?.annBadges$ | async + }"> + </ng-container> + + <annotating-tools-panel class="z-index-10 d-block" + #toolPanel="annoToolsPanel"> + </annotating-tools-panel> + </ng-template> + </ng-container> + </div> +</ng-template> - <!-- bottom left corner (atlas selector and currently selected) --> - <div iavLayoutFourCornersBottomLeft class="d-inline-flex align-items-center mb-4 ml-2 w-100"> - <!-- atlas selector --> - <atlas-layer-selector *ngIf="viewerLoaded && !(isStandaloneVolumes$ | async)" - #alSelector="atlasLayerSelector" - (iav-outsideClick)="alSelector.selectorExpanded = false"> - </atlas-layer-selector> +<!-- top right --> +<!-- default top right --> +<ng-template #minDefaultMainContentTopRight> - <!-- chips --> - <div *ngIf="parcellationSelected$ | async" class="flex-grow-0 p-1 pr-2 flex-shrink-1 overflow-y-hidden overflow-x-auto pe-all"> + <!-- signin banner at top right corner --> + <top-menu-cmp class="mt-3 mr-2 d-inline-block" + [ismobile]="ismobile" + [viewerLoaded]="viewerLoaded"> + </top-menu-cmp> - <viewer-state-breadcrumb - (on-item-click)="handleChipClick()"> - </viewer-state-breadcrumb> - </div> - </div> + <atlas-dropdown-selector + class="v-align-top pt-2 pe-all mt-2 iv-custom-comp bg card m-2 mat-elevation-z2 d-inline-block" + quick-tour + [quick-tour-description]="quickTourAtlasSelector.description" + [quick-tour-order]="quickTourAtlasSelector.order"> + </atlas-dropdown-selector> - </iav-layout-fourcorners> +</ng-template> + +<ng-template #specialTopRightTmpl let-mode="mode"> + <mat-card class="mat-card-sm pe-all m-4"> + <span> + {{ mode }} + </span> + <button mat-icon-button + color="warn" + (click)="exitSpecialViewMode()"> + <i class="fas fa-times"></i> + </button> + </mat-card> +</ng-template> - </mat-drawer-content> - </mat-drawer-container> +<!-- bottom left --> +<ng-template #bottomLeftTmpl let-showFullSideNav="showFullSideNav"> + + <!-- atlas selector --> + <atlas-layer-selector *ngIf="viewerLoaded && !(isStandaloneVolumes$ | async)" + #alSelector="atlasLayerSelector" + class="d-inline-block" + (iav-outsideClick)="alSelector.selectorExpanded = false"> + </atlas-layer-selector> + + <!-- chips --> + <viewer-state-breadcrumb + *ngIf="parcellationSelected$ | async" + class="d-inline-block" + (on-item-click)="showFullSideNav()"> + </viewer-state-breadcrumb> +</ng-template> -</layout-floating-container> <!-- viewer tmpl --> <ng-template #viewerTmpl> - - <iav-layout-fourcorners> - <div iavLayoutFourCornersContent - class="w-100 h-100 position-absolute"> - <div class="h-100 w-100 overflow-hidden position-relative" - ctx-menu-host - [ctx-menu-host-tmpl]="viewerCtxMenuTmpl"> - - <ng-container [ngSwitch]="useViewer$ | async"> - - <!-- nehuba viewer --> - <iav-cmp-viewer-nehuba-glue class="d-block w-100 h-100 position-absolute left-0 top-0" - *ngSwitchCase="'nehuba'" - (viewerEvent)="handleViewerEvent($event)" - [selectedTemplate]="templateSelected$ | async" - [selectedParcellation]="parcellationSelected$ | async" - #iavCmpViewerNehubaGlue="iavCmpViewerNehubaGlue"> - </iav-cmp-viewer-nehuba-glue> - - <!-- three surfer (free surfer viewer) --> - <three-surfer-glue-cmp class="d-block w-100 h-100 position-absolute left-0 top-0" - *ngSwitchCase="'threeSurfer'" - (viewerEvent)="handleViewerEvent($event)" - [selectedTemplate]="templateSelected$ | async" - [selectedParcellation]="parcellationSelected$ | async"> - </three-surfer-glue-cmp> - - <!-- if not supported, show not supported message --> - <div *ngSwitchCase="'notsupported'">Template not supported by any of the viewers</div> - - <!-- by default, show splash screen --> - <div *ngSwitchDefault> - <ui-splashscreen class="position-absolute left-0 top-0"> - </ui-splashscreen> - </div> - </ng-container> - + <div class="position-absolute w-100 h-100 z-index-1"> + + <ng-container [ngSwitch]="useViewer$ | async"> + + <!-- nehuba viewer --> + <iav-cmp-viewer-nehuba-glue class="d-block w-100 h-100 position-absolute left-0 top-0" + *ngSwitchCase="'nehuba'" + (viewerEvent)="handleViewerEvent($event)" + [selectedTemplate]="templateSelected$ | async" + [selectedParcellation]="parcellationSelected$ | async" + #iavCmpViewerNehubaGlue="iavCmpViewerNehubaGlue"> + </iav-cmp-viewer-nehuba-glue> + + <!-- three surfer (free surfer viewer) --> + <three-surfer-glue-cmp class="d-block w-100 h-100 position-absolute left-0 top-0" + *ngSwitchCase="'threeSurfer'" + (viewerEvent)="handleViewerEvent($event)" + [selectedTemplate]="templateSelected$ | async" + [selectedParcellation]="parcellationSelected$ | async"> + </three-surfer-glue-cmp> + + <!-- if not supported, show not supported message --> + <div *ngSwitchCase="'notsupported'">Template not supported by any of the viewers</div> + + <!-- by default, show splash screen --> + <div *ngSwitchDefault> + <ui-splashscreen class="position-absolute left-0 top-0"> + </ui-splashscreen> </div> - </div> - </iav-layout-fourcorners> + </ng-container> + + <!-- <div class="h-100 w-100 overflow-hidden position-relative" + ctx-menu-host + [ctx-menu-host-tmpl]="viewerCtxMenuTmpl"> + </div> --> + </div> </ng-template> -<!-- auto complete search box --> +<!-- auto complete search box --> <ng-template #autocompleteTmpl let-showTour="showTour"> - <div class="iv-custom-comp bg card w-100 mat-elevation-z8 pe-all"> + <div class="iv-custom-comp bg card ml-2 mr-2 mat-elevation-z8 pe-all"> <region-text-search-autocomplete class="w-100 pt-2 flex-shrink-0 flex-grow-0"> </region-text-search-autocomplete> - <div class="w-100 h-100 position-absolute pe-none" - *ngIf="showTour" - #regionSelRef> + <div class="w-100 h-100 position-absolute pe-none" *ngIf="showTour"> </div> </div> </ng-template> @@ -362,15 +425,18 @@ <ng-template #tabTmpl let-isOpen="isOpen" let-regionSelected="regionSelected" - let-iavAdditionallayers="iavAdditionallayers"> + let-iavAdditionallayers="iavAdditionallayers" + let-click="click"> <!-- if mat drawer is open --> <ng-template [ngIf]="isOpen" [ngIfElse]="tabTmpl_closedTmpl"> - <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { - matColor: 'basic', - fontIcon: 'fa-chevron-left' - }"> - </ng-container> + <ng-template [ngTemplateOutlet]="tabTmpl_defaultTmpl" + [ngTemplateOutletContext]="{ + matColor: 'basic', + fontIcon: 'fa-chevron-left', + click: click + }"> + </ng-template> </ng-template> <!-- if matdrawer is closed --> @@ -381,7 +447,8 @@ <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { matColor: 'accent', fontIcon: 'fa-database', - tooltip: 'Explore dataset preview' + tooltip: 'Explore dataset preview', + click: click }"> </ng-container> </ng-template> @@ -402,7 +469,8 @@ customColor: tabTmpl_iavRegion.rgbString, customColorDarkmode: tabTmpl_iavRegion.rgbDarkmode, fontIcon: 'fa-brain', - tooltip: 'Explore ' + tabTmpl_iavRegion.region.name + tooltip: 'Explore ' + tabTmpl_iavRegion.region.name, + click: click }"> </ng-container> @@ -413,7 +481,8 @@ <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { matColor: 'primary', fontIcon: 'fa-sitemap', - tooltip: 'Explore regions' + tooltip: 'Explore regions', + click: click }"> </ng-container> </ng-template> @@ -422,6 +491,7 @@ </ng-template> + <ng-template #tabTmpl_defaultTmpl let-matColor="matColor" let-fontIcon="fontIcon" @@ -466,31 +536,29 @@ </span> </button> - <mat-card class="sidenav-cover-header-container"> - <div class="sidenav-cover-header-container"> - <mat-card-title> - {{ _pliTitle }} - </mat-card-title> + <mat-card class="_pli-container"> + <mat-card-title> + {{ _pliTitle }} + </mat-card-title> - <mat-card-subtitle class="d-inline-flex align-items-center flex-wrap"> - <mat-icon fontSet="fas" fontIcon="fa-database"></mat-icon> - <span> - Dataset preview - </span> + <mat-card-subtitle class="d-inline-flex align-items-center flex-wrap"> + <mat-icon fontSet="fas" fontIcon="fa-database"></mat-icon> + <span> + Dataset preview + </span> - <mat-divider vertical="true" class="ml-2 h-2rem"></mat-divider> + <mat-divider vertical="true" class="ml-2 h-2rem"></mat-divider> - <a [href]="_pliLink" - mat-icon-button - matTooltip="Explore in EBRAINS Knowledge Graph" - target="_blank"> - <i class="fas fa-external-link-alt"></i> - </a> + <a [href]="_pliLink" + mat-icon-button + matTooltip="Explore in EBRAINS Knowledge Graph" + target="_blank"> + <i class="fas fa-external-link-alt"></i> + </a> - </mat-card-subtitle> - </div> + </mat-card-subtitle> - <small class="text-muted iv-custom-comp darker-bg"> + <small class="d-block text-muted iv-custom-comp darker-bg"> {{ _pliDesc }} </small> @@ -506,7 +574,9 @@ </ng-template> <!-- region sidenav tmpl --> -<ng-template #sidenavRegionTmpl> +<ng-template #sidenavRegionTmpl + let-drawer="drawer" + let-showFullSidenavSwitch="showFullSidenavSwitch"> <!-- region search autocomplete --> <!-- [@openCloseAnchor]="sideNavFullLeftSwitch.switchState ? 'open' : 'closed'" --> @@ -549,8 +619,11 @@ </div> <!-- collapse btn --> - <ng-container *ngTemplateOutlet="collapseBtn"> - </ng-container> + <ng-template [ngTemplateOutlet]="collapseBtn" + [ngTemplateOutletContext]="{ + collapse: showFullSidenavSwitch.close.bind(showFullSidenavSwitch) + }"> + </ng-template> </ng-template> @@ -559,7 +632,7 @@ <!-- region detail --> <region-menu [region]="region" - class="flex-grow-1 bs-border-box ml-15px-n mr-15px-n mat-elevation-z4"> + class="flex-grow-1 bs-border-box mat-elevation-z4"> </region-menu> </ng-template> @@ -666,13 +739,13 @@ </ng-template> <!-- collapse btn --> -<ng-template #collapseBtn> +<ng-template #collapseBtn let-collapse="collapse"> <div class="h-0 w-100 collapse-position d-flex flex-column justify-content-end align-items-center"> <button mat-raised-button class="mat-elevation-z8" [attr.aria-label]="ARIA_LABELS.COLLAPSE" - (click)="sideNavFullLeftSwitch.close()" + (click)="collapse()" color="basic"> <i class="fas fa-chevron-up"></i> <span>