From 0e3266c50ae40e2644ccfbbf4ce9f34da061741f Mon Sep 17 00:00:00 2001 From: Kim Rutherford Date: Tue, 10 Dec 2024 14:14:34 +1300 Subject: [PATCH] Highlight visible sections in menu on gene pages Refs pombase/website#2271 Refs pombase/website#1940 --- package.json | 1 + .../annotation-table-intersection-event.ts | 4 +++ .../annotation-table.component.html | 8 +++-- .../annotation-table.component.ts | 8 ++++- src/app/app.module.ts | 12 ++++++- .../gene-details/gene-details.component.html | 33 ++++++++++++++++++- .../gene-details/gene-details.component.ts | 15 +++++++++ .../details-page-menu.component.css | 5 +++ .../details-page-menu.component.html | 4 +++ .../details-page-menu.component.ts | 31 ++++++++++++++++- yarn.lock | 7 ++++ 11 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 src/app/annotation-table-intersection-event.ts diff --git a/package.json b/package.json index 7b2e6d49a..b2beacee3 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "bootstrap": "^4", "file-saver": "^2.0.2", "ngx-bootstrap": "^18", + "ngx-intersection-observer": "^1.0.13", "ngx-page-scroll": "^13", "ngx-page-scroll-core": "^13", "ngx-toastr": "^19", diff --git a/src/app/annotation-table-intersection-event.ts b/src/app/annotation-table-intersection-event.ts new file mode 100644 index 000000000..a678500d2 --- /dev/null +++ b/src/app/annotation-table-intersection-event.ts @@ -0,0 +1,4 @@ +export class AnnotationTableIntersection { + constructor(public annotationTypeName: string, + public isIntersecting: boolean) {} +} diff --git a/src/app/annotation-table/annotation-table.component.html b/src/app/annotation-table/annotation-table.component.html index 3374a5c33..be4fa8cf5 100644 --- a/src/app/annotation-table/annotation-table.component.html +++ b/src/app/annotation-table/annotation-table.component.html @@ -41,7 +41,9 @@ -
+
-
+
{{capitalize(conf.display_name)}}
; @Input() geneDetails?: GeneDetails; @Input() scope: string; // "gene", "term", "reference" ... + @Output() annotationTableIntersection = new EventEmitter(); config: AnnotationTableConfig = getAnnotationTableConfig(); typeConfig: AnnotationType; @@ -89,6 +91,10 @@ export class AnnotationTableComponent implements OnInit, OnChanges { ngOnInit() { } + intersectHandler(subTableName: string, isIntersecting: boolean) { + this.annotationTableIntersection.emit(new AnnotationTableIntersection(subTableName, isIntersecting)); + } + ngOnChanges() { this.typeConfig = this.config.getAnnotationType(this.annotationTypeName); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5db4b0954..c2c952fe7 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -164,6 +164,9 @@ import { GeneticInteractionTableTypeFilterComponent } from './genetic-interactio import { RnaStructureComponent } from './rna-structure/rna-structure.component'; import { ProteinFeatureTableComponent } from './protein-feature-table/protein-feature-table.component'; +import { IntersectionObserverModule } from 'ngx-intersection-observer'; +import { IntersectionObserverConfig } from 'ngx-intersection-observer/lib/intersection-observer-config.model'; + @Pipe({ name: 'safeUrl', standalone: false @@ -319,7 +322,14 @@ export class PomBaseUrlSerializer extends DefaultUrlSerializer { ProteinFeatureTableComponent, ], bootstrap: [AppComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA], imports: [BrowserModule, + schemas: [CUSTOM_ELEMENTS_SCHEMA], + imports: [ + IntersectionObserverModule.forRoot({ + debounce: 50, + threshold: 1, + autoRemove: true + } as IntersectionObserverConfig), + BrowserModule, CommonModule, BrowserAnimationsModule, FormsModule, diff --git a/src/app/gene-details/gene-details.component.html b/src/app/gene-details/gene-details.component.html index 16dc0d4c6..037fc84ca 100644 --- a/src/app/gene-details/gene-details.component.html +++ b/src/app/gene-details/gene-details.component.html @@ -103,6 +103,7 @@
@@ -133,7 +134,10 @@
- @@ -167,6 +180,8 @@ @@ -174,33 +189,49 @@
diff --git a/src/app/gene-details/gene-details.component.ts b/src/app/gene-details/gene-details.component.ts index 75ceba400..9e40bab03 100644 --- a/src/app/gene-details/gene-details.component.ts +++ b/src/app/gene-details/gene-details.component.ts @@ -17,6 +17,8 @@ import { DeployConfigService } from '../deploy-config.service'; import { Util } from '../shared/util'; import { MenuItem } from '../types'; +import { AnnotationTableIntersection } from '../annotation-table-intersection-event'; + @Component({ selector: 'app-gene-details', templateUrl: './gene-details.component.html', @@ -32,6 +34,7 @@ export class GeneDetailsComponent implements OnInit { annotationTypeOrder: Array = []; annotationTypeOrderNames: Array = []; menuItems: Array = []; + onScreenItems: Set = new Set(); config: AnnotationTableConfig = getAnnotationTableConfig(); appConfig: AppConfig = getAppConfig(); noGeneNameRoute = this.appConfig.no_gene_name_route; @@ -423,6 +426,18 @@ export class GeneDetailsComponent implements OnInit { !!this.geneDetails.characterisation_status; } + intersect(annotationTypeName: string, isIntersecting: boolean): void { + if (isIntersecting) { + this.onScreenItems.add(annotationTypeName); + } else { + this.onScreenItems.delete(annotationTypeName); + } + } + + subTableIntersect(event: AnnotationTableIntersection) { + this.intersect(event.annotationTypeName, event.isIntersecting); + } + ngOnInit(): void { this.route.params.forEach((params: Params) => { if (params['uniquename'] !== undefined) { diff --git a/src/app/shared/details-page-menu/details-page-menu.component.css b/src/app/shared/details-page-menu/details-page-menu.component.css index a09420d35..f9ca77e67 100644 --- a/src/app/shared/details-page-menu/details-page-menu.component.css +++ b/src/app/shared/details-page-menu/details-page-menu.component.css @@ -11,3 +11,8 @@ opacity: 1; transition: opacity 0.2s; } + +.is-on-screen { + border-right: 3px solid #667; + background-color: #e8e8dfdd; +} \ No newline at end of file diff --git a/src/app/shared/details-page-menu/details-page-menu.component.html b/src/app/shared/details-page-menu/details-page-menu.component.html index d9c922dbd..669d7555d 100644 --- a/src/app/shared/details-page-menu/details-page-menu.component.html +++ b/src/app/shared/details-page-menu/details-page-menu.component.html @@ -10,12 +10,16 @@ diff --git a/src/app/shared/details-page-menu/details-page-menu.component.ts b/src/app/shared/details-page-menu/details-page-menu.component.ts index bdc3ca771..9eb006aeb 100644 --- a/src/app/shared/details-page-menu/details-page-menu.component.ts +++ b/src/app/shared/details-page-menu/details-page-menu.component.ts @@ -18,6 +18,7 @@ interface DisplayMenuItem extends MenuItem { export class DetailsPageMenuComponent implements OnInit, OnChanges { @Input() title: string; @Input() menuItems: Array = []; + @Input() onScreenItems = new Set(); displayMenuItems: Array = []; @@ -52,6 +53,10 @@ export class DetailsPageMenuComponent implements OnInit, OnChanges { } clicked(menuItem: DisplayMenuItem): void { + if (!menuItem.subItems) { + menuItem.subItemsVisible = false; + return; + } const currentItemValue = menuItem.subItemsVisible; this.displayMenuItems.map(item => { item.subItemsVisible = false; @@ -59,6 +64,28 @@ export class DetailsPageMenuComponent implements OnInit, OnChanges { menuItem.subItemsVisible = !currentItemValue; } + isOnScreen(menuItem: MenuItem, subItemsVisible: boolean): boolean { + if (!this.menuPositionFixed) { + // don't highlight menu item before we've scrolled + return false; + } + if (subItemsVisible) { + return false; + } + if (this.onScreenItems.has(menuItem.id)) { + return true; + } + if (menuItem.subItems) { + for (const subMenuItem of menuItem.subItems) { + if (this.onScreenItems.has(subMenuItem.id)) { + return true; + } + } + } + + return false; + } + ngOnInit() { } @@ -66,7 +93,9 @@ export class DetailsPageMenuComponent implements OnInit, OnChanges { this.displayMenuItems = this.menuItems.map(item => { let displayItem = { ...item, subItemsVisible: false }; - + if (displayItem.subItems && displayItem.subItems.length == 0) { + displayItem.subItems = undefined; + } return displayItem; }); } diff --git a/yarn.lock b/yarn.lock index 9d63ec0c6..5d72c7006 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5245,6 +5245,13 @@ ngx-bootstrap@^18: dependencies: tslib "^2.3.0" +ngx-intersection-observer@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/ngx-intersection-observer/-/ngx-intersection-observer-1.0.13.tgz#da40026f79a5883d9845f19d3af5b54e40f7feef" + integrity sha512-QQsJInaH6OM/ANxiMBmKm9GJo8UfCo6VNf+5D1XTKV3x7ETwKIoQB+K11AV2LD/5GYPjoigl7TrtJKkR/GAkdg== + dependencies: + tslib "^2.3.0" + ngx-page-scroll-core@^13: version "13.0.0" resolved "https://registry.yarnpkg.com/ngx-page-scroll-core/-/ngx-page-scroll-core-13.0.0.tgz#d898bdbf4d0620998e04aa30c612a6a588b37064"