mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
Merge pull request #2527 from alexandrevryghem/add-display-none-to-hidden-navbar-buttons_contribute-7.6
Minor header button improvements
This commit is contained in:
@@ -12,8 +12,7 @@ import { Router } from '@angular/router';
|
|||||||
* Represents a non-expandable section in the admin sidebar
|
* Represents a non-expandable section in the admin sidebar
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
selector: 'ds-admin-sidebar-section',
|
||||||
selector: 'li[ds-admin-sidebar-section]',
|
|
||||||
templateUrl: './admin-sidebar-section.component.html',
|
templateUrl: './admin-sidebar-section.component.html',
|
||||||
styleUrls: ['./admin-sidebar-section.component.scss'],
|
styleUrls: ['./admin-sidebar-section.component.scss'],
|
||||||
|
|
||||||
|
@@ -26,10 +26,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<ng-container *ngFor="let section of (sections | async)">
|
<li *ngFor="let section of (sections | async)">
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container>
|
*ngComponentOutlet="(sectionMap$ | async).get(section.id).component; injector: (sectionMap$ | async).get(section.id).injector;"></ng-container>
|
||||||
</ng-container>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-nav">
|
<div class="navbar-nav">
|
||||||
|
@@ -15,8 +15,7 @@ import { Router } from '@angular/router';
|
|||||||
* Represents a expandable section in the sidebar
|
* Represents a expandable section in the sidebar
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
selector: 'ds-expandable-admin-sidebar-section',
|
||||||
selector: 'li[ds-expandable-admin-sidebar-section]',
|
|
||||||
templateUrl: './expandable-admin-sidebar-section.component.html',
|
templateUrl: './expandable-admin-sidebar-section.component.html',
|
||||||
styleUrls: ['./expandable-admin-sidebar-section.component.scss'],
|
styleUrls: ['./expandable-admin-sidebar-section.component.scss'],
|
||||||
animations: [rotate, slide, bgColor]
|
animations: [rotate, slide, bgColor]
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, ElementRef } from '@angular/core';
|
||||||
import { ContextHelpService } from '../../shared/context-help.service';
|
import { ContextHelpService } from '../../shared/context-help.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,12 +15,23 @@ import { map } from 'rxjs/operators';
|
|||||||
export class ContextHelpToggleComponent implements OnInit {
|
export class ContextHelpToggleComponent implements OnInit {
|
||||||
buttonVisible$: Observable<boolean>;
|
buttonVisible$: Observable<boolean>;
|
||||||
|
|
||||||
|
subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private contextHelpService: ContextHelpService,
|
protected elRef: ElementRef,
|
||||||
) { }
|
protected contextHelpService: ContextHelpService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.buttonVisible$ = this.contextHelpService.tooltipCount$().pipe(map(x => x > 0));
|
this.buttonVisible$ = this.contextHelpService.tooltipCount$().pipe(map(x => x > 0));
|
||||||
|
this.subscriptions.push(this.buttonVisible$.subscribe((showContextHelpToggle: boolean) => {
|
||||||
|
if (showContextHelpToggle) {
|
||||||
|
this.elRef.nativeElement.classList.remove('d-none');
|
||||||
|
} else {
|
||||||
|
this.elRef.nativeElement.classList.add('d-none');
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick() {
|
onClick() {
|
||||||
|
@@ -7,12 +7,12 @@
|
|||||||
|
|
||||||
<nav role="navigation" [attr.aria-label]="'nav.user.description' | translate" class="navbar navbar-light navbar-expand-md flex-shrink-0 px-0">
|
<nav role="navigation" [attr.aria-label]="'nav.user.description' | translate" class="navbar navbar-light navbar-expand-md flex-shrink-0 px-0">
|
||||||
<ds-themed-search-navbar></ds-themed-search-navbar>
|
<ds-themed-search-navbar></ds-themed-search-navbar>
|
||||||
<ds-lang-switch></ds-lang-switch>
|
<ds-themed-lang-switch></ds-themed-lang-switch>
|
||||||
<ds-context-help-toggle></ds-context-help-toggle>
|
<ds-context-help-toggle></ds-context-help-toggle>
|
||||||
<ds-themed-auth-nav-menu></ds-themed-auth-nav-menu>
|
<ds-themed-auth-nav-menu></ds-themed-auth-nav-menu>
|
||||||
<ds-impersonate-navbar></ds-impersonate-navbar>
|
<ds-impersonate-navbar></ds-impersonate-navbar>
|
||||||
<div class="pl-2">
|
<div *ngIf="isXsOrSm$ | async" class="pl-2">
|
||||||
<button class="navbar-toggler" type="button" (click)="toggleNavbar()"
|
<button class="navbar-toggler px-0" type="button" (click)="toggleNavbar()"
|
||||||
aria-controls="collapsingNav"
|
aria-controls="collapsingNav"
|
||||||
aria-expanded="false" [attr.aria-label]="'nav.toggle' | translate">
|
aria-expanded="false" [attr.aria-label]="'nav.toggle' | translate">
|
||||||
<span class="navbar-toggler-icon fas fa-bars fa-fw" aria-hidden="true"></span>
|
<span class="navbar-toggler-icon fas fa-bars fa-fw" aria-hidden="true"></span>
|
||||||
|
@@ -20,3 +20,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
display: flex;
|
||||||
|
gap: calc(var(--bs-spacer) / 3);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
@@ -10,6 +10,8 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
|||||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { MenuService } from '../shared/menu/menu.service';
|
import { MenuService } from '../shared/menu/menu.service';
|
||||||
import { MenuServiceStub } from '../shared/testing/menu-service.stub';
|
import { MenuServiceStub } from '../shared/testing/menu-service.stub';
|
||||||
|
import { HostWindowService } from '../shared/host-window.service';
|
||||||
|
import { HostWindowServiceStub } from '../shared/testing/host-window-service.stub';
|
||||||
|
|
||||||
let comp: HeaderComponent;
|
let comp: HeaderComponent;
|
||||||
let fixture: ComponentFixture<HeaderComponent>;
|
let fixture: ComponentFixture<HeaderComponent>;
|
||||||
@@ -26,6 +28,7 @@ describe('HeaderComponent', () => {
|
|||||||
ReactiveFormsModule],
|
ReactiveFormsModule],
|
||||||
declarations: [HeaderComponent],
|
declarations: [HeaderComponent],
|
||||||
providers: [
|
providers: [
|
||||||
|
{ provide: HostWindowService, useValue: new HostWindowServiceStub(0) },
|
||||||
{ provide: MenuService, useValue: menuService }
|
{ provide: MenuService, useValue: menuService }
|
||||||
],
|
],
|
||||||
schemas: [NO_ERRORS_SCHEMA]
|
schemas: [NO_ERRORS_SCHEMA]
|
||||||
@@ -40,7 +43,7 @@ describe('HeaderComponent', () => {
|
|||||||
fixture = TestBed.createComponent(HeaderComponent);
|
fixture = TestBed.createComponent(HeaderComponent);
|
||||||
|
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the toggle button is clicked', () => {
|
describe('when the toggle button is clicked', () => {
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { MenuService } from '../shared/menu/menu.service';
|
import { MenuService } from '../shared/menu/menu.service';
|
||||||
import { MenuID } from '../shared/menu/menu-id.model';
|
import { MenuID } from '../shared/menu/menu-id.model';
|
||||||
|
import { HostWindowService } from '../shared/host-window.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the header with the logo and simple navigation
|
* Represents the header with the logo and simple navigation
|
||||||
@@ -11,20 +12,25 @@ import { MenuID } from '../shared/menu/menu-id.model';
|
|||||||
styleUrls: ['header.component.scss'],
|
styleUrls: ['header.component.scss'],
|
||||||
templateUrl: 'header.component.html',
|
templateUrl: 'header.component.html',
|
||||||
})
|
})
|
||||||
export class HeaderComponent {
|
export class HeaderComponent implements OnInit {
|
||||||
/**
|
/**
|
||||||
* Whether user is authenticated.
|
* Whether user is authenticated.
|
||||||
* @type {Observable<string>}
|
* @type {Observable<string>}
|
||||||
*/
|
*/
|
||||||
public isAuthenticated: Observable<boolean>;
|
public isAuthenticated: Observable<boolean>;
|
||||||
public showAuth = false;
|
public isXsOrSm$: Observable<boolean>;
|
||||||
menuID = MenuID.PUBLIC;
|
menuID = MenuID.PUBLIC;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private menuService: MenuService
|
protected menuService: MenuService,
|
||||||
|
protected windowService: HostWindowService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.isXsOrSm$ = this.windowService.isXsOrSm();
|
||||||
|
}
|
||||||
|
|
||||||
public toggleNavbar(): void {
|
public toggleNavbar(): void {
|
||||||
this.menuService.toggleMenu(this.menuID);
|
this.menuService.toggleMenu(this.menuID);
|
||||||
}
|
}
|
||||||
|
@@ -14,9 +14,9 @@
|
|||||||
</a>
|
</a>
|
||||||
<ul @slide *ngIf="(active | async)" (click)="deactivateSection($event)"
|
<ul @slide *ngIf="(active | async)" (click)="deactivateSection($event)"
|
||||||
class="m-0 shadow-none border-top-0 dropdown-menu show">
|
class="m-0 shadow-none border-top-0 dropdown-menu show">
|
||||||
<ng-container *ngFor="let subSection of (subSections$ | async)">
|
<li *ngFor="let subSection of (subSections$ | async)">
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngComponentOutlet="(sectionMap$ | async).get(subSection.id).component; injector: (sectionMap$ | async).get(subSection.id).injector;"></ng-container>
|
*ngComponentOutlet="(sectionMap$ | async).get(subSection.id).component; injector: (sectionMap$ | async).get(subSection.id).injector;"></ng-container>
|
||||||
</ng-container>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -4,7 +4,6 @@ import { MenuService } from '../../shared/menu/menu.service';
|
|||||||
import { slide } from '../../shared/animations/slide';
|
import { slide } from '../../shared/animations/slide';
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from 'rxjs/operators';
|
||||||
import { HostWindowService } from '../../shared/host-window.service';
|
import { HostWindowService } from '../../shared/host-window.service';
|
||||||
import { rendersSectionForMenu } from '../../shared/menu/menu-section.decorator';
|
|
||||||
import { MenuID } from '../../shared/menu/menu-id.model';
|
import { MenuID } from '../../shared/menu/menu-id.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,7 +15,6 @@ import { MenuID } from '../../shared/menu/menu-id.model';
|
|||||||
styleUrls: ['./expandable-navbar-section.component.scss'],
|
styleUrls: ['./expandable-navbar-section.component.scss'],
|
||||||
animations: [slide]
|
animations: [slide]
|
||||||
})
|
})
|
||||||
@rendersSectionForMenu(MenuID.PUBLIC, true)
|
|
||||||
export class ExpandableNavbarSectionComponent extends NavbarSectionComponent implements OnInit {
|
export class ExpandableNavbarSectionComponent extends NavbarSectionComponent implements OnInit {
|
||||||
/**
|
/**
|
||||||
* This section resides in the Public Navbar
|
* This section resides in the Public Navbar
|
||||||
|
@@ -8,8 +8,7 @@ import { MenuID } from '../../shared/menu/menu-id.model';
|
|||||||
* Themed wrapper for ExpandableNavbarSectionComponent
|
* Themed wrapper for ExpandableNavbarSectionComponent
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
selector: 'ds-themed-expandable-navbar-section',
|
||||||
selector: 'li[ds-themed-expandable-navbar-section]',
|
|
||||||
styleUrls: [],
|
styleUrls: [],
|
||||||
templateUrl: '../../shared/theme-support/themed.component.html',
|
templateUrl: '../../shared/theme-support/themed.component.html',
|
||||||
})
|
})
|
||||||
|
@@ -8,8 +8,7 @@ import { MenuID } from '../../shared/menu/menu-id.model';
|
|||||||
* Represents a non-expandable section in the navbar
|
* Represents a non-expandable section in the navbar
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
/* eslint-disable @angular-eslint/component-selector */
|
selector: 'ds-navbar-section',
|
||||||
selector: 'li[ds-navbar-section]',
|
|
||||||
templateUrl: './navbar-section.component.html',
|
templateUrl: './navbar-section.component.html',
|
||||||
styleUrls: ['./navbar-section.component.scss']
|
styleUrls: ['./navbar-section.component.scss']
|
||||||
})
|
})
|
||||||
|
@@ -8,9 +8,9 @@
|
|||||||
<li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)">
|
<li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)">
|
||||||
<ds-user-menu [inExpandableNavbar]="true"></ds-user-menu>
|
<ds-user-menu [inExpandableNavbar]="true"></ds-user-menu>
|
||||||
</li>
|
</li>
|
||||||
<ng-container *ngFor="let section of (sections | async)">
|
<li *ngFor="let section of (sections | async)">
|
||||||
<ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container>
|
<ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container>
|
||||||
</ng-container>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
<div id="search-navbar-container" [title]="'nav.search' | translate" (dsClickOutside)="collapse()">
|
<div id="search-navbar-container" [title]="'nav.search' | translate" (dsClickOutside)="collapse()">
|
||||||
<div class="d-inline-block position-relative">
|
<div class="d-inline-block position-relative">
|
||||||
<form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" autocomplete="on">
|
<form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" autocomplete="on" class="d-flex">
|
||||||
<input #searchInput [@toggleAnimation]="isExpanded" [attr.aria-label]="('nav.search' | translate)" name="query"
|
<input #searchInput [@toggleAnimation]="isExpanded" [attr.aria-label]="('nav.search' | translate)" name="query"
|
||||||
formControlName="query" type="text" placeholder="{{searchExpanded ? ('nav.search' | translate) : ''}}"
|
formControlName="query" type="text" placeholder="{{searchExpanded ? ('nav.search' | translate) : ''}}"
|
||||||
class="d-inline-block bg-transparent position-absolute form-control dropdown-menu-right p-1" [attr.data-test]="'header-search-box' | dsBrowserOnly">
|
class="bg-transparent position-absolute form-control dropdown-menu-right pl-1 pr-4"
|
||||||
|
[class.display]="searchExpanded ? 'inline-block' : 'none'"
|
||||||
|
[tabIndex]="searchExpanded ? 0 : -1"
|
||||||
|
[attr.data-test]="'header-search-box' | dsBrowserOnly">
|
||||||
<button class="submit-icon btn btn-link btn-link-inline" [attr.aria-label]="'nav.search.button' | translate" type="button" (click)="searchExpanded ? onSubmit(searchForm.value) : expand()" [attr.data-test]="'header-search-icon' | dsBrowserOnly">
|
<button class="submit-icon btn btn-link btn-link-inline" [attr.aria-label]="'nav.search.button' | translate" type="button" (click)="searchExpanded ? onSubmit(searchForm.value) : expand()" [attr.data-test]="'header-search-icon' | dsBrowserOnly">
|
||||||
<em class="fas fa-search fa-lg fa-fw"></em>
|
<em class="fas fa-search fa-lg fa-fw"></em>
|
||||||
</button>
|
</button>
|
||||||
|
@@ -12,6 +12,7 @@ input[type="text"] {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
border: 0 !important;
|
||||||
|
|
||||||
color: var(--ds-header-icon-color);
|
color: var(--ds-header-icon-color);
|
||||||
&:hover, &:focus {
|
&:hover, &:focus {
|
||||||
|
@@ -55,7 +55,7 @@ export const slideSidebarPadding = trigger('slideSidebarPadding', [
|
|||||||
|
|
||||||
export const expandSearchInput = trigger('toggleAnimation', [
|
export const expandSearchInput = trigger('toggleAnimation', [
|
||||||
state('collapsed', style({
|
state('collapsed', style({
|
||||||
width: '30px',
|
width: '0',
|
||||||
opacity: '0'
|
opacity: '0'
|
||||||
})),
|
})),
|
||||||
state('expanded', style({
|
state('expanded', style({
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item"
|
<li *ngIf="!(isAuthenticated | async) && !(isXsOrSm$ | async) && (showAuth | async)" class="nav-item"
|
||||||
(click)="$event.stopPropagation();">
|
(click)="$event.stopPropagation();">
|
||||||
<div ngbDropdown #loginDrop display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
|
<div ngbDropdown #loginDrop display="dynamic" placement="bottom-right" class="d-inline-block" @fadeInOut>
|
||||||
<a href="javascript:void(0);" class="dropdownLogin px-1" [attr.aria-label]="'nav.login' |translate"
|
<a href="javascript:void(0);" class="dropdownLogin px-0.5" [attr.aria-label]="'nav.login' |translate"
|
||||||
(click)="$event.preventDefault()" [attr.data-test]="'login-menu' | dsBrowserOnly"
|
(click)="$event.preventDefault()" [attr.data-test]="'login-menu' | dsBrowserOnly"
|
||||||
ngbDropdownToggle>{{ 'nav.login' | translate }}</a>
|
ngbDropdownToggle>{{ 'nav.login' | translate }}</a>
|
||||||
<div class="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu
|
<div class="loginDropdownMenu" [ngClass]="{'pl-3 pr-3': (loading | async)}" ngbDropdownMenu
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li *ngIf="!(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item">
|
<li *ngIf="!(isAuthenticated | async) && (isXsOrSm$ | async)" class="nav-item">
|
||||||
<a routerLink="/login" routerLinkActive="active" class="loginLink px-1">
|
<a routerLink="/login" routerLinkActive="active" class="loginLink px-0.5">
|
||||||
{{ 'nav.login' | translate }}<span class="sr-only">(current)</span>
|
{{ 'nav.login' | translate }}<span class="sr-only">(current)</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@@ -13,7 +13,6 @@ import { hasValue } from '../../../empty.util';
|
|||||||
* Represents an expandable section in the dso edit menus
|
* Represents an expandable section in the dso edit menus
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
/* tslint:disable:component-selector */
|
|
||||||
selector: 'ds-dso-edit-menu-expandable-section',
|
selector: 'ds-dso-edit-menu-expandable-section',
|
||||||
templateUrl: './dso-edit-menu-expandable-section.component.html',
|
templateUrl: './dso-edit-menu-expandable-section.component.html',
|
||||||
styleUrls: ['./dso-edit-menu-expandable-section.component.scss'],
|
styleUrls: ['./dso-edit-menu-expandable-section.component.scss'],
|
||||||
|
@@ -10,7 +10,6 @@ import { MenuSection } from '../../../menu/menu-section.model';
|
|||||||
* Represents a non-expandable section in the dso edit menus
|
* Represents a non-expandable section in the dso edit menus
|
||||||
*/
|
*/
|
||||||
@Component({
|
@Component({
|
||||||
/* tslint:disable:component-selector */
|
|
||||||
selector: 'ds-dso-edit-menu-section',
|
selector: 'ds-dso-edit-menu-section',
|
||||||
templateUrl: './dso-edit-menu-section.component.html',
|
templateUrl: './dso-edit-menu-section.component.html',
|
||||||
styleUrls: ['./dso-edit-menu-section.component.scss']
|
styleUrls: ['./dso-edit-menu-section.component.scss']
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<ul class="navbar-nav" *ngIf="(isAuthenticated$ | async) && isImpersonating">
|
<ul class="navbar-nav" *ngIf="isImpersonating$ | async">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<button class="btn btn-sm btn-dark" ngbTooltip="{{'nav.stop-impersonating' | translate}}" (click)="stopImpersonating()">
|
<button class="btn btn-sm btn-dark" ngbTooltip="{{'nav.stop-impersonating' | translate}}" (click)="stopImpersonating()">
|
||||||
<i class="fa fa-user-secret"></i>
|
<i class="fa fa-user-secret"></i>
|
||||||
|
@@ -14,6 +14,7 @@ import { authReducer } from '../../core/auth/auth.reducer';
|
|||||||
import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
|
import { AuthTokenInfo } from '../../core/auth/models/auth-token-info.model';
|
||||||
import { EPersonMock } from '../testing/eperson.mock';
|
import { EPersonMock } from '../testing/eperson.mock';
|
||||||
import { AppState, storeModuleConfig } from '../../app.reducer';
|
import { AppState, storeModuleConfig } from '../../app.reducer';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
|
||||||
describe('ImpersonateNavbarComponent', () => {
|
describe('ImpersonateNavbarComponent', () => {
|
||||||
let component: ImpersonateNavbarComponent;
|
let component: ImpersonateNavbarComponent;
|
||||||
@@ -65,7 +66,7 @@ describe('ImpersonateNavbarComponent', () => {
|
|||||||
|
|
||||||
describe('when the user is impersonating another user', () => {
|
describe('when the user is impersonating another user', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
component.isImpersonating = true;
|
component.isImpersonating$ = observableOf(true);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, ElementRef } from '@angular/core';
|
||||||
import { select, Store } from '@ngrx/store';
|
import { select, Store } from '@ngrx/store';
|
||||||
import { AppState } from '../../app.reducer';
|
import { AppState } from '../../app.reducer';
|
||||||
import { AuthService } from '../../core/auth/auth.service';
|
import { AuthService } from '../../core/auth/auth.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
import { isAuthenticated } from '../../core/auth/selectors';
|
import { isAuthenticated } from '../../core/auth/selectors';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -13,24 +14,32 @@ import { isAuthenticated } from '../../core/auth/selectors';
|
|||||||
* Navbar component for actions to take concerning impersonating users
|
* Navbar component for actions to take concerning impersonating users
|
||||||
*/
|
*/
|
||||||
export class ImpersonateNavbarComponent implements OnInit {
|
export class ImpersonateNavbarComponent implements OnInit {
|
||||||
/**
|
|
||||||
* Whether or not the user is authenticated.
|
|
||||||
* @type {Observable<string>}
|
|
||||||
*/
|
|
||||||
isAuthenticated$: Observable<boolean>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the user currently impersonating another user?
|
* Is the user currently impersonating another user?
|
||||||
*/
|
*/
|
||||||
isImpersonating: boolean;
|
isImpersonating$: Observable<boolean>;
|
||||||
|
|
||||||
constructor(private store: Store<AppState>,
|
subscriptions: Subscription[] = [];
|
||||||
private authService: AuthService) {
|
|
||||||
|
constructor(
|
||||||
|
protected elRef: ElementRef,
|
||||||
|
protected store: Store<AppState>,
|
||||||
|
protected authService: AuthService,
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.isAuthenticated$ = this.store.pipe(select(isAuthenticated));
|
this.isImpersonating$ = this.store.pipe(select(isAuthenticated)).pipe(
|
||||||
this.isImpersonating = this.authService.isImpersonating();
|
map((isUserAuthenticated: boolean) => isUserAuthenticated && this.authService.isImpersonating()),
|
||||||
|
);
|
||||||
|
this.subscriptions.push(this.isImpersonating$.subscribe((isImpersonating: boolean) => {
|
||||||
|
if (isImpersonating) {
|
||||||
|
this.elRef.nativeElement.classList.remove('d-none');
|
||||||
|
} else {
|
||||||
|
this.elRef.nativeElement.classList.add('d-none');
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<div ngbDropdown class="navbar-nav" *ngIf="moreThanOneLanguage" display="dynamic" placement="bottom-right">
|
<div ngbDropdown class="navbar-nav" *ngIf="moreThanOneLanguage" display="dynamic" placement="bottom-right">
|
||||||
<a href="javascript:void(0);" role="button"
|
<a href="javascript:void(0);" role="button"
|
||||||
[attr.aria-label]="'nav.language' |translate"
|
[attr.aria-label]="'nav.language' |translate"
|
||||||
[title]="'nav.language' | translate" class="px-1"
|
[title]="'nav.language' | translate"
|
||||||
(click)="$event.preventDefault()" data-toggle="dropdown" ngbDropdownToggle
|
(click)="$event.preventDefault()" data-toggle="dropdown" ngbDropdownToggle
|
||||||
tabindex="0">
|
tabindex="0">
|
||||||
<i class="fas fa-globe-asia fa-lg fa-fw"></i>
|
<i class="fas fa-globe-asia fa-lg fa-fw"></i>
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit, ElementRef } from '@angular/core';
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { LangConfig } from '../../../config/lang-config.interface';
|
import { LangConfig } from '../../../config/lang-config.interface';
|
||||||
import { environment } from '../../../environments/environment';
|
import { environment } from '../../../environments/environment';
|
||||||
import { LocaleService } from '../../core/locale/locale.service';
|
import { LocaleService } from '../../core/locale/locale.service';
|
||||||
@@ -25,6 +23,7 @@ export class LangSwitchComponent implements OnInit {
|
|||||||
moreThanOneLanguage: boolean;
|
moreThanOneLanguage: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
public el: ElementRef,
|
||||||
public translate: TranslateService,
|
public translate: TranslateService,
|
||||||
private localeService: LocaleService
|
private localeService: LocaleService
|
||||||
) {
|
) {
|
||||||
@@ -33,6 +32,9 @@ export class LangSwitchComponent implements OnInit {
|
|||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.activeLangs = environment.languages.filter((MyLangConfig) => MyLangConfig.active === true);
|
this.activeLangs = environment.languages.filter((MyLangConfig) => MyLangConfig.active === true);
|
||||||
this.moreThanOneLanguage = (this.activeLangs.length > 1);
|
this.moreThanOneLanguage = (this.activeLangs.length > 1);
|
||||||
|
if (!this.moreThanOneLanguage) {
|
||||||
|
this.el.nativeElement.parentElement.classList.add('d-none');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
27
src/app/shared/lang-switch/themed-lang-switch.component.ts
Normal file
27
src/app/shared/lang-switch/themed-lang-switch.component.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { ThemedComponent } from '../theme-support/themed.component';
|
||||||
|
import { LangSwitchComponent } from './lang-switch.component';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Themed wrapper for {@link LangSwitchComponent}
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-themed-lang-switch',
|
||||||
|
styleUrls: [],
|
||||||
|
templateUrl: '../theme-support/themed.component.html',
|
||||||
|
})
|
||||||
|
export class ThemedLangSwitchComponent extends ThemedComponent<LangSwitchComponent> {
|
||||||
|
|
||||||
|
protected getComponentName(): string {
|
||||||
|
return 'LangSwitchComponent';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected importThemedComponent(themeName: string): Promise<any> {
|
||||||
|
return import(`../../../themes/${themeName}/app/shared/lang-switch/lang-switch.component`);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected importUnthemedComponent(): Promise<any> {
|
||||||
|
return import(`./lang-switch.component`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -281,6 +281,7 @@ import {
|
|||||||
} from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component';
|
} from '../item-page/simple/field-components/specific-field/title/themed-item-page-field.component';
|
||||||
import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component';
|
import { BitstreamListItemComponent } from './object-list/bitstream-list-item/bitstream-list-item.component';
|
||||||
import { NgxPaginationModule } from 'ngx-pagination';
|
import { NgxPaginationModule } from 'ngx-pagination';
|
||||||
|
import { ThemedLangSwitchComponent } from './lang-switch/themed-lang-switch.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -332,6 +333,7 @@ const COMPONENTS = [
|
|||||||
DsSelectComponent,
|
DsSelectComponent,
|
||||||
ErrorComponent,
|
ErrorComponent,
|
||||||
LangSwitchComponent,
|
LangSwitchComponent,
|
||||||
|
ThemedLangSwitchComponent,
|
||||||
LoadingComponent,
|
LoadingComponent,
|
||||||
ThemedLoadingComponent,
|
ThemedLoadingComponent,
|
||||||
LogInComponent,
|
LogInComponent,
|
||||||
|
@@ -267,3 +267,29 @@ ul.dso-edit-menu-dropdown > li .nav-item.nav-link {
|
|||||||
.table td {
|
.table td {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pt-0\.5 {
|
||||||
|
padding-top: 0.125rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr-0\.5 {
|
||||||
|
padding-right: 0.125rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb-0\.5 {
|
||||||
|
padding-bottom: 0.125rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl-0\.5 {
|
||||||
|
padding-left: 0.125rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-0\.5 {
|
||||||
|
padding-left: 0.125rem !important;
|
||||||
|
padding-right: 0.125rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.py-0\.5 {
|
||||||
|
padding-top: 0.125rem !important;
|
||||||
|
padding-bottom: 0.125rem !important;
|
||||||
|
}
|
||||||
|
@@ -0,0 +1,12 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { LangSwitchComponent as BaseComponent } from '../../../../../app/shared/lang-switch/lang-switch.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-lang-switch',
|
||||||
|
// styleUrls: ['./lang-switch.component.scss'],
|
||||||
|
styleUrls: ['../../../../../app/shared/lang-switch/lang-switch.component.scss'],
|
||||||
|
// templateUrl: './lang-switch.component.html',
|
||||||
|
templateUrl: '../../../../../app/shared/lang-switch/lang-switch.component.html',
|
||||||
|
})
|
||||||
|
export class LangSwitchComponent extends BaseComponent {
|
||||||
|
}
|
@@ -54,6 +54,7 @@ import {
|
|||||||
ItemSearchResultListElementComponent
|
ItemSearchResultListElementComponent
|
||||||
} from './app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
|
} from './app/shared/object-list/search-result-list-element/item-search-result/item-types/item/item-search-result-list-element.component';
|
||||||
import { TopLevelCommunityListComponent } from './app/home-page/top-level-community-list/top-level-community-list.component';
|
import { TopLevelCommunityListComponent } from './app/home-page/top-level-community-list/top-level-community-list.component';
|
||||||
|
import { LangSwitchComponent } from './app/shared/lang-switch/lang-switch.component';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,6 +92,7 @@ const DECLARATIONS = [
|
|||||||
EditCollectionSelectorComponent,
|
EditCollectionSelectorComponent,
|
||||||
EditCommunitySelectorComponent,
|
EditCommunitySelectorComponent,
|
||||||
EditItemSelectorComponent,
|
EditItemSelectorComponent,
|
||||||
|
LangSwitchComponent,
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@@ -5,9 +5,9 @@
|
|||||||
<img src="assets/images/dspace-logo.svg" [attr.alt]="'menu.header.image.logo' | translate"/>
|
<img src="assets/images/dspace-logo.svg" [attr.alt]="'menu.header.image.logo' | translate"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-grow-1 ml-auto justify-content-end align-items-center">
|
<div class="navbar-buttons d-flex flex-grow-1 ml-auto justify-content-end align-items-center">
|
||||||
<ds-themed-search-navbar></ds-themed-search-navbar>
|
<ds-themed-search-navbar></ds-themed-search-navbar>
|
||||||
<ds-lang-switch></ds-lang-switch>
|
<ds-themed-lang-switch></ds-themed-lang-switch>
|
||||||
<ds-context-help-toggle></ds-context-help-toggle>
|
<ds-context-help-toggle></ds-context-help-toggle>
|
||||||
<ds-themed-auth-nav-menu></ds-themed-auth-nav-menu>
|
<ds-themed-auth-nav-menu></ds-themed-auth-nav-menu>
|
||||||
<ds-impersonate-navbar></ds-impersonate-navbar>
|
<ds-impersonate-navbar></ds-impersonate-navbar>
|
||||||
|
@@ -24,3 +24,9 @@
|
|||||||
color: var(--ds-header-icon-color-hover);
|
color: var(--ds-header-icon-color-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: calc(var(--bs-spacer) / 3);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
@@ -10,15 +10,17 @@
|
|||||||
<li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)">
|
<li *ngIf="(isXsOrSm$ | async) && (isAuthenticated$ | async)">
|
||||||
<ds-user-menu [inExpandableNavbar]="true"></ds-user-menu>
|
<ds-user-menu [inExpandableNavbar]="true"></ds-user-menu>
|
||||||
</li>
|
</li>
|
||||||
<ng-container *ngFor="let section of (sections | async)">
|
<li *ngFor="let section of (sections | async)">
|
||||||
<ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container>
|
<ng-container *ngComponentOutlet="(sectionMap$ | async).get(section.id)?.component; injector: (sectionMap$ | async).get(section.id)?.injector;"></ng-container>
|
||||||
</ng-container>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<ds-search-navbar class="navbar-collapsed"></ds-search-navbar>
|
<div class="navbar-buttons">
|
||||||
<ds-lang-switch class="navbar-collapsed"></ds-lang-switch>
|
<ds-themed-search-navbar class="navbar-collapsed"></ds-themed-search-navbar>
|
||||||
<ds-context-help-toggle class="navbar-collapsed"></ds-context-help-toggle>
|
<ds-themed-lang-switch class="navbar-collapsed"></ds-themed-lang-switch>
|
||||||
<ds-themed-auth-nav-menu class="navbar-collapsed"></ds-themed-auth-nav-menu>
|
<ds-context-help-toggle class="navbar-collapsed"></ds-context-help-toggle>
|
||||||
<ds-impersonate-navbar class="navbar-collapsed"></ds-impersonate-navbar>
|
<ds-themed-auth-nav-menu class="navbar-collapsed"></ds-themed-auth-nav-menu>
|
||||||
|
<ds-impersonate-navbar class="navbar-collapsed"></ds-impersonate-navbar>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
@@ -54,3 +54,9 @@ a.navbar-brand img {
|
|||||||
color: var(--ds-navbar-link-color-hover);
|
color: var(--ds-navbar-link-color-hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: calc(var(--bs-spacer) / 3);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user