From ff7d700bca441c842f0dc25a2820d95e27acefea Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Wed, 19 Jul 2023 17:49:56 +0200
Subject: [PATCH] feat: add spatial search badge when min tray closed feat:
 align jumbo chip icon to chip, not to line feat: introduce opacity to jumbo
 chip

---
 .../pureDumb/pureATPSelector.components.ts    | 69 ++++++++++++++-
 .../pureDumb/pureATPSelector.style.scss       | 14 +++
 .../pureDumb/pureATPSelector.template.html    | 23 +++--
 .../component/smartChip.component.ts          | 11 ++-
 .../smartChip/component/smartChip.style.scss  | 87 ++++++++++++-------
 .../component/smartChip.template.html         | 33 ++++---
 src/components/smartChip/module.ts            |  3 +
 .../smartChip/smartChip.action.directive.ts   |  9 ++
 src/features/guards.ts                        |  7 +-
 src/util/util.module.ts                       |  2 +-
 .../viewerCmp/viewerCmp.template.html         | 26 ++++--
 11 files changed, 217 insertions(+), 67 deletions(-)
 create mode 100644 src/components/smartChip/smartChip.action.directive.ts

diff --git a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts
index ef1976937..04b217ef5 100644
--- a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts
+++ b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.components.ts
@@ -1,6 +1,9 @@
-import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from "@angular/core";
+import { AfterViewInit, ChangeDetectionStrategy, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, Output, QueryList, SimpleChanges, ViewChildren } from "@angular/core";
+import { BehaviorSubject, Subscription, combineLatest, concat, merge, of } from "rxjs";
+import { map, switchMap } from "rxjs/operators";
 import { SxplrAtlas, SxplrParcellation, SxplrTemplate } from "src/atlasComponents/sapi/sxplrTypes";
 import { FilterGroupedParcellationPipe, GroupedParcellation } from "src/atlasComponents/sapiViews/core/parcellation";
+import { SmartChip } from "src/components/smartChip";
 
 export const darkThemePalette = [
   "#141414",
@@ -40,7 +43,9 @@ const pipe = new FilterGroupedParcellationPipe()
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
 
-export class PureATPSelector implements OnChanges{
+export class PureATPSelector implements OnChanges, AfterViewInit, OnDestroy{
+
+  #subscriptions: Subscription[] = []
 
   @Input('sxplr-pure-atp-selector-color-palette')
   colorPalette: string[] = darkThemePalette
@@ -67,6 +72,15 @@ export class PureATPSelector implements OnChanges{
   @Output('sxplr-pure-atp-selector-on-select')
   selectLeafEmitter = new EventEmitter<Partial<ATP>>()
 
+  @ViewChildren(SmartChip)
+  smartChips: QueryList<SmartChip<object>>
+
+  #menuOpen$ = new BehaviorSubject<{ some: boolean, all: boolean, none: boolean }>({ some: false, all: false, none: false })
+  menuOpen$ = this.#menuOpen$.asObservable()
+
+  @HostBinding('attr.data-menu-open')
+  menuOpen: 'some'|'all'|'none' = null
+
   getChildren(parc: GroupedParcellation|SxplrParcellation){
     return (parc as GroupedParcellation).parcellations || []
   }
@@ -98,4 +112,55 @@ export class PureATPSelector implements OnChanges{
       }
     }
   }
+
+  ngAfterViewInit(): void {
+    this.#subscriptions.push(
+      concat(
+        of(null),
+        this.smartChips.changes,
+      ).pipe(
+        switchMap(() =>
+          combineLatest(
+            Array.from(this.smartChips).map(chip =>
+              concat(
+                of(false),
+                merge(
+                  chip.menuOpened.pipe(
+                    map(() => true)
+                  ),
+                  chip.menuClosed.pipe(
+                    map(() => false)
+                  )
+                )
+              )
+            )
+          )
+        ),
+      ).subscribe(arr => {
+        const newVal = {
+          some: arr.some(val => val),
+          all: arr.every(val => val),
+          none: arr.every(val => !val),
+        }
+        this.#menuOpen$.next(newVal)
+
+        this.menuOpen = null
+        if (newVal.none) {
+          this.menuOpen = 'none'
+        }
+        if (newVal.all) {
+          this.menuOpen = 'all'
+        }
+        if (newVal.some) {
+          this.menuOpen = 'some'
+        }
+      })
+    )
+  }
+
+  ngOnDestroy(): void {
+    while (this.#subscriptions.length > 0) {
+      this.#subscriptions.pop().unsubscribe()
+    }
+  }
 }
diff --git a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.style.scss b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.style.scss
index cc3249fac..3bd40c266 100644
--- a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.style.scss
+++ b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.style.scss
@@ -1,3 +1,17 @@
+:host-context([experimental="true"]) :host
+{
+  opacity: 0.5;
+  transition: opacity ease-in-out 160ms;
+
+  &:hover,
+  &[data-menu-open="some"],
+  &[data-menu-open="all"]
+  {
+    opacity: 1;
+  }
+}
+
+
 :host
 {
   display: inline-flex;
diff --git a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html
index f8ed4de44..9aaf8f964 100644
--- a/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html
+++ b/src/atlasComponents/sapiViews/core/rich/ATPSelector/pureDumb/pureATPSelector.template.html
@@ -19,14 +19,9 @@
       </span>
     </ng-template>
 
-    <ng-template sxplrSmartChipContent>
-      <span class="chip-text">
-        {{ ATP.parcellation.shortName }}
-      </span>
-      <ng-content select="[parcellation-chip-suffix]">
-      </ng-content>
-
-      <button iav-stop="mousedown click"
+    <ng-template sxplrSmartChipAction>
+      <button
+        iav-stop="mousedown click"
         class="icons"
         mat-icon-button
         sxplr-dialog
@@ -39,6 +34,18 @@
         <i class="fas fa-info"></i>
       </button>
     </ng-template>
+    
+    <ng-template sxplrSmartChipAction>
+      <ng-content select="[parcellation-chip-suffix]">
+      </ng-content>
+    </ng-template>
+
+    <ng-template sxplrSmartChipContent>
+      <span class="chip-text">
+        {{ ATP.parcellation.shortName }}
+      </span>
+
+    </ng-template>
     <ng-template sxplrSmartChipMenu let-parc>
 
       <ng-container *ngTemplateOutlet="optionTmpl; context: {
diff --git a/src/components/smartChip/component/smartChip.component.ts b/src/components/smartChip/component/smartChip.component.ts
index 99eed1198..a6dac2d1a 100644
--- a/src/components/smartChip/component/smartChip.component.ts
+++ b/src/components/smartChip/component/smartChip.component.ts
@@ -1,8 +1,9 @@
-import { ChangeDetectionStrategy, Component, ContentChild, EventEmitter, HostBinding, Input, OnChanges, Output, SimpleChanges } from "@angular/core";
+import { ChangeDetectionStrategy, Component, ContentChild, ContentChildren, EventEmitter, HostBinding, Input, OnChanges, Output, QueryList, SimpleChanges } from "@angular/core";
 import { SmartChipContent } from "../smartChip.content.directive"
 import { SmartChipMenu } from "../smartChip.menu.directive";
 import { rgbToHsl, hexToRgb } from 'common/util'
 import { SmartChipHeader } from "../smartChip.header.directive";
+import { SmartChipAction } from "../smartChip.action.directive";
 
 const cssColorToHsl = (input: string) => {
   if (/rgb/i.test(input)) {
@@ -66,6 +67,14 @@ export class SmartChip<T extends object> implements OnChanges{
   @Output('itemClicked')
   itemClicked = new EventEmitter<T>()
 
+  @Output('menuOpened')
+  menuOpened = new EventEmitter()
+  @Output('menuClosed')
+  menuClosed = new EventEmitter()
+
+  @ContentChildren(SmartChipAction)
+  actionTmpls: QueryList<SmartChipAction>
+
   @ContentChild(SmartChipContent)
   contentTmpl: SmartChipContent
 
diff --git a/src/components/smartChip/component/smartChip.style.scss b/src/components/smartChip/component/smartChip.style.scss
index f6d54f007..df88b7eed 100644
--- a/src/components/smartChip/component/smartChip.style.scss
+++ b/src/components/smartChip/component/smartChip.style.scss
@@ -6,42 +6,65 @@
   position: relative;
 }
 
-:host-context([experimental=true]) :host
-{
-  min-height: 44px;
-}
 
-:host-context([experimental=true]) .smart-chip
+:host-context([experimental=true])
 {
-  display: inline-flex;
-  flex-direction: column!important;
-  border-radius: 22px;
-  align-items: center;
-  justify-content: start;
-}
+  :host
+  {
+    min-height: 44px;
+  }
 
-:host-context([experimental=true]) .header
-{
-  font-size: 80%;
-  margin-top:-0.5rem;
-  margin-bottom:0.3rem;
-  flex-basis: 1rem;
-}
+  .smart-chip
+  { 
+    display: inline-flex;
+    flex-direction: row;
+    border-radius: 22px;
+    justify-content: center;
 
-:host-context([experimental=true]) .body
-{
-  width: 100%;
-  flex: 1 1 0;
-  display: flex;
-  align-items: start;
-}
-:host-context([experimental=true]) .body>.body-content-wrapper
-{
-  height: 1px;
-  width: 100%;
-  overflow: visible;
-  display: flex;
-  align-items: center;
+    >.text
+    {
+      height: 0px;
+      overflow: visible;
+      display: inline-flex;
+      flex-direction: column;
+      justify-content: center;
+    }
+
+    >.icons
+    {
+      height: 0px;
+      overflow: visible;
+      display: inline-flex;
+      flex-direction: row;
+      align-items: center;
+    }
+  }
+
+  .header
+  {
+
+    font-size: 80%;
+    margin-top:-0.5rem;
+    margin-bottom:0.3rem;
+    flex-basis: 1rem;
+  }
+
+  .body
+  {
+    width: 100%;
+    flex: 1 1 0;
+    display: flex;
+    align-items: start;
+
+    >.body-content-wrapper
+    {
+      height: 1px;
+      width: 100%;
+      overflow: visible;
+      display: flex;
+      align-items: center;
+    }
+  }
 }
 
 .smart-chip
diff --git a/src/components/smartChip/component/smartChip.template.html b/src/components/smartChip/component/smartChip.template.html
index 659c02630..e057e1501 100644
--- a/src/components/smartChip/component/smartChip.template.html
+++ b/src/components/smartChip/component/smartChip.template.html
@@ -6,24 +6,35 @@
 
 <div [style.background-color]="color"
   [matMenuTriggerFor]="noMenuFlag ? null : mainMenu"
+  (menuOpened)="menuOpened.emit()"
+  (menuClosed)="menuClosed.emit()"
   matRipple
   [matRippleDisabled]="noMenuFlag"
   [ngClass]="smartChipClass"
-  class="mat-body smart-chip body sxplr-custom-cmp text">
+  class="mat-body smart-chip sxplr-custom-cmp text">
 
-  <!-- header component -->
+  <!-- text component -->
 
-  <ng-template [ngIf]="headerTmpl?.templateRef" let-tmpl>
-    <div class="mat-body sxplr-custom-cmp text header">
-      <ng-template [ngTemplateOutlet]="tmpl">
-      </ng-template>
+  <div class="text">
+    <ng-template [ngIf]="headerTmpl?.templateRef" let-tmpl>
+      <div class="mat-body sxplr-custom-cmp text header">
+        <ng-template [ngTemplateOutlet]="tmpl">
+        </ng-template>
+      </div>
+    </ng-template>
+    <div class="body">
+      <div class="body-content-wrapper">
+        <ng-template [ngTemplateOutlet]="contentTmpl?.templateRef || fallbackContentTmpl">
+        </ng-template>
+      </div>
     </div>
-  </ng-template>
-  <div class="body">
-    <div class="body-content-wrapper">
-      <ng-template [ngTemplateOutlet]="contentTmpl?.templateRef || fallbackContentTmpl">
+  </div>
+
+  <div class="icons">
+    <ng-template ngFor [ngForOf]="actionTmpls" let-actionTmpl>
+      <ng-template [ngTemplateOutlet]="actionTmpl.templateRef">
       </ng-template>
-    </div>
+    </ng-template>
   </div>
 </div>
 
diff --git a/src/components/smartChip/module.ts b/src/components/smartChip/module.ts
index e5c9616ad..58c8a2930 100644
--- a/src/components/smartChip/module.ts
+++ b/src/components/smartChip/module.ts
@@ -9,6 +9,7 @@ import { SmartChipContent } from "./smartChip.content.directive";
 import { SmartChipHeader } from "./smartChip.header.directive";
 import { SmartChipMenu } from "./smartChip.menu.directive";
 import { ExperimentalModule } from "src/experimental/experimental.module";
+import { SmartChipAction } from "./smartChip.action.directive";
 
 @NgModule({
   imports: [
@@ -22,6 +23,7 @@ import { ExperimentalModule } from "src/experimental/experimental.module";
     SmartChipMenu,
     SmartChipContent,
     SmartChipHeader,
+    SmartChipAction,
     SmartChip,
     HasSubMenuPipe,
   ],
@@ -29,6 +31,7 @@ import { ExperimentalModule } from "src/experimental/experimental.module";
     SmartChipMenu,
     SmartChipContent,
     SmartChipHeader,
+    SmartChipAction,
     SmartChip,
   ]
 })
diff --git a/src/components/smartChip/smartChip.action.directive.ts b/src/components/smartChip/smartChip.action.directive.ts
new file mode 100644
index 000000000..011965520
--- /dev/null
+++ b/src/components/smartChip/smartChip.action.directive.ts
@@ -0,0 +1,9 @@
+import { Directive, Inject, TemplateRef } from "@angular/core";
+
+@Directive({
+  selector: `ng-template[sxplrSmartChipAction]`
+})
+
+export class SmartChipAction {
+  constructor(@Inject(TemplateRef) public templateRef: TemplateRef<unknown>){}
+}
diff --git a/src/features/guards.ts b/src/features/guards.ts
index fefbc7a0b..eff1ea272 100644
--- a/src/features/guards.ts
+++ b/src/features/guards.ts
@@ -8,11 +8,6 @@ export function isVoiData(feature: unknown): feature is VoiFeature {
   return !!feature['bbox']
 }
 
-export function notQuiteRight(feature: unknown): string[] {
-  if (feature['name'].includes("Cellular level 3D reconstructed volumes at 1µm resolution")) {
-    return [
-      "This volume is currently not displayed correctly. We are working to restore the functionality."
-    ]
-  }
+export function notQuiteRight(_feature: unknown): string[] {
   return []
 }
diff --git a/src/util/util.module.ts b/src/util/util.module.ts
index d40b143f7..53355b1f5 100644
--- a/src/util/util.module.ts
+++ b/src/util/util.module.ts
@@ -77,7 +77,7 @@ import { PrettyPresentPipe } from './pretty-present.pipe';
     IncludesPipe,
     SidePanelComponent,
     DfToDsPipe,
-    PrettyPresentPipe
+    PrettyPresentPipe,
   ]
 })
 
diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html
index cd5c8600e..b39b4115c 100644
--- a/src/viewerModule/viewerCmp/viewerCmp.template.html
+++ b/src/viewerModule/viewerCmp/viewerCmp.template.html
@@ -293,14 +293,28 @@
     #minTray="sxplrExperimentalFlag"
     [ngIf]="minTray.show$ | async">
     <div class="tab-toggle-container">
+    
+      <div [ngClass]="(minTrayVisSwitch.switchState$ | async) ? '' : 'd-none'">
+
+        <ng-template [ngTemplateOutlet]="tabTmpl_defaultTmpl" [ngTemplateOutletContext]="{
+          fontIcon: 'fas fa-chevron-left',
+          matColor: null,
+          click: minTrayVisSwitch.toggle.bind(minTrayVisSwitch)
+        }">
+        </ng-template>
+      </div>
       
-    <ng-template [ngTemplateOutlet]="tabTmpl_defaultTmpl" [ngTemplateOutletContext]="{
-      fontIcon: (minTrayVisSwitch.switchState$ | async) ? 'fas fa-chevron-left' : 'fas fa-search',
-      matColor: (minTrayVisSwitch.switchState$ | async) ? null : 'primary',
-      click: minTrayVisSwitch.toggle.bind(minTrayVisSwitch)
-    }">
+      <div [ngClass]="(minTrayVisSwitch.switchState$ | async) ? 'd-none' : ''">
+
+        <ng-template [ngTemplateOutlet]="tabTmpl_defaultTmpl" [ngTemplateOutletContext]="{
+          fontIcon: 'fas fa-search',
+          matColor: 'primary',
+          click: minTrayVisSwitch.toggle.bind(minTrayVisSwitch),
+          badge: voiFeatureEntryCmp.totals$ | async
+        }">
+        </ng-template>
+      </div>
 
-    </ng-template>
     </div>
   </ng-template>
 
-- 
GitLab