Skip to content
Snippets Groups Projects
Commit c0a4fdc7 authored by lotte's avatar lotte
Browse files

57053: added menu preview

parent 38652b7a
Branches
Tags
No related merge requests found
Showing
with 177 additions and 78 deletions
<li class="sidebar-section">
<a class="nav-item nav-link shortcut-icon">
<a class="nav-item nav-link shortcut-icon" [routerLink]="section.model.link">
<i class="fas fa-{{section.icon}} fa-fw"></i>
</a>
<div class="sidebar-collapsible">
......
<nav @slideHorizontal class="navbar navbar-dark bg-dark p-0"
[ngClass]="{'active': sidebarOpen, 'inactive': sidebarClosed}"
[@slideSidebar]="{
value: ((menuCollapsed | async) ? 'collapsed' : 'expanded'),
value: (!(sidebarExpanded | async) ? 'collapsed' : 'expanded'),
params: {sidebarWidth: (sidebarWidth | async)}
}" (@slideSidebar.done)="finishSlide($event)" (@slideSidebar.start)="startSlide($event)" *ngIf="menuVisible | async">
}" (@slideSidebar.done)="finishSlide($event)" (@slideSidebar.start)="startSlide($event)" *ngIf="menuVisible | async" (mouseenter)="expandPreview($event)" (mouseleave)="collapsePreview($event)">
<div class="sidebar-top-level-items">
<ul class="navbar-nav">
<li class="admin-menu-header sidebar-section">
......@@ -30,8 +30,7 @@
<a class="nav-item nav-link shortcut-icon"
href="#"
(click)="toggle($event)">
<i class="fas fa-fw fa-angle-double-right"
[ngClass]="{'fa-angle-double-right': (menuCollapsed | async), 'fa-angle-double-left': !(menuCollapsed | async)}"></i>
<i class="fas fa-fw" [ngClass]="{'fa-angle-double-right': (menuCollapsed | async), 'fa-angle-double-left': !(menuCollapsed | async)}"></i>
</a>
<div class="sidebar-collapsible">
<a class="nav-item nav-link sidebar-section"
......
......@@ -20,7 +20,7 @@ $icon-z-index: 10;
}
&.inactive ::ng-deep .sidebar-collapsible {
margin-left: -#{$admin-sidebar-width};
margin-left: -#{$sidebar-items-width};
}
.navbar-nav {
......@@ -58,7 +58,7 @@ $icon-z-index: 10;
z-index: $icon-z-index;
}
.sidebar-collapsible {
width: $admin-sidebar-width;
width: $sidebar-items-width;
position: relative;
a {
padding-right: $spacer;
......@@ -69,10 +69,6 @@ $icon-z-index: 10;
color: $navbar-dark-active-color;
}
}
#sidebar-collapse-toggle {
border-top: 2px solid rgba(255, 255, 255, 0.1);
}
}
}
......
......@@ -8,7 +8,8 @@ import { MenuComponent } from '../../shared/menu/menu.component';
import { TextSectionTypeModel } from '../../shared/menu/models/section-types/text.model';
import { LinkSectionTypeModel } from '../../shared/menu/models/section-types/link.model';
import { AuthService } from '../../core/auth/auth.service';
import { first } from 'rxjs/operators';
import { first, map } from 'rxjs/operators';
import { combineLatest as combineLatestObservable } from 'rxjs';
@Component({
selector: 'ds-admin-sidebar',
......@@ -19,8 +20,9 @@ import { first } from 'rxjs/operators';
export class AdminSidebarComponent extends MenuComponent implements OnInit {
menuID = MenuID.ADMIN;
sidebarWidth: Observable<string>;
sidebarOpen = true;
sidebarClosed = !this.sidebarOpen;
sidebarOpen = true; // Open in UI, animation finished
sidebarClosed = !this.sidebarOpen; // Closed in UI, animation finished
sidebarExpanded: Observable<boolean>;
constructor(protected menuService: MenuService,
protected injector: Injector,
......@@ -33,7 +35,7 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
ngOnInit(): void {
this.createMenu();
super.ngOnInit();
this.sidebarWidth = this.variableService.getVariable('adminSidebarWidth');
this.sidebarWidth = this.variableService.getVariable('sidebarItemsWidth');
this.authService.isAuthenticated()
.subscribe((loggedIn: boolean) => {
if (loggedIn) {
......@@ -44,7 +46,11 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
.subscribe((collapsed: boolean) => {
this.sidebarOpen = !collapsed;
this.sidebarClosed = collapsed;
})
});
this.sidebarExpanded = combineLatestObservable(this.menuCollapsed, this.menuPreviewCollapsed)
.pipe(
map(([collapsed, previewCollapsed]) => (!collapsed || !previewCollapsed))
);
}
createMenu() {
......@@ -431,5 +437,4 @@ export class AdminSidebarComponent extends MenuComponent implements OnInit {
this.sidebarOpen = true;
}
}
}
<li class="sidebar-section" [ngClass]="{'active': (active | async)}"
<li class="sidebar-section" [ngClass]="{'expanded': (expanded | async)}"
[@bgColor]="{
value: ((active | async) ? 'endBackground' : 'startBackground'),
value: ((expanded | async) ? 'endBackground' : 'startBackground'),
params: {endColor: (sidebarActiveBg | async)}}">
<div class="icon-wrapper">
<a class="nav-item nav-link shortcut-icon" (click)="toggleSection($event)" href="#">
......@@ -15,9 +15,9 @@
*ngComponentOutlet="itemComponents.get(section.id); injector: itemInjectors.get(section.id);"></ng-container>
</span>
<i class="fas fa-chevron-right fa-pull-right"
[@rotate]="(active | async) ? 'expanded' : 'collapsed'"></i>
[@rotate]="(expanded | async) ? 'expanded' : 'collapsed'"></i>
</a>
<ul class="sidebar-sub-level-items list-unstyled" @slide *ngIf="(active | async)">
<ul class="sidebar-sub-level-items list-unstyled" @slide *ngIf="(expanded | async)">
<li *ngFor="let subSection of (subSections | async)">
<ng-container
*ngComponentOutlet="itemComponents.get(subSection.id); injector: itemInjectors.get(subSection.id);"></ng-container>
......
......@@ -9,6 +9,8 @@ import { rendersSectionForMenu } from '../../../shared/menu/menu.decorator';
import { MenuService } from '../../../shared/menu/menu.service';
import { MenuSection } from '../../../shared/menu/menu.reducer';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { combineLatest as combineLatestObservable } from 'rxjs';
@Component({
selector: 'ds-expandable-admin-sidebar-section',
......@@ -23,6 +25,8 @@ export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionC
menuID = MenuID.ADMIN;
sidebarActiveBg;
sidebarCollapsed: Observable<boolean>;
sidebarPreviewCollapsed: Observable<boolean>;
expanded: Observable<boolean>;
constructor(@Inject('sectionDataProvider') menuSection, protected menuService: MenuService,
private variableService: CSSVariableService, protected injector: Injector) {
......@@ -35,5 +39,10 @@ export class ExpandableAdminSidebarSectionComponent extends AdminSidebarSectionC
this.subSections = this.menuService.getSubSectionsByParentID(this.menuID, this.section.id);
this.sidebarActiveBg = this.variableService.getVariable('adminSidebarActiveBg');
this.sidebarCollapsed = this.menuService.isMenuCollapsed(this.menuID);
this.sidebarPreviewCollapsed = this.menuService.isMenuPreviewCollapsed(this.menuID);
this.expanded = combineLatestObservable(this.active, this.sidebarCollapsed, this.sidebarPreviewCollapsed)
.pipe(
map(([active, sidebarCollapsed, sidebarPreviewCollapsed]) => (active && (!sidebarCollapsed || !sidebarPreviewCollapsed)))
);
}
}
<div class="outer-wrapper">
<ds-admin-sidebar></ds-admin-sidebar>
<div class="inner-wrapper" [@slideSidebarMargin]="{
value: ((hasAdminSidebar | async) ? 'expanded' : 'collapsed'),
params: {collapsedSidebarWidth: (collapsedSidebarWidth | async)}
<div class="inner-wrapper" [@slideSidebarPadding]="{
value: (!(sidebarVisible | async) ? 'hidden' : (sidebarCollapsed | async) ? 'shown' : 'expanded'),
params: {collapsedSidebarWidth: (collapsedSidebarWidth | async), totalSidebarWidth: (totalSidebarWidth | async)}
}">
<ds-header-navbar-wrapper></ds-header-navbar-wrapper>
......
......@@ -25,6 +25,7 @@ body {
min-height: 100vh;
flex-direction: column;
width: 100%;
position: relative;
}
.main-content {
......@@ -39,7 +40,7 @@ ds-header-navbar-wrapper {
}
ds-admin-sidebar {
position: absolute;
position: fixed;
z-index: $sidebar-z-index;
}
......@@ -28,7 +28,7 @@ import { CSSVariableService } from './shared/sass-helper/sass-helper.service';
import { MenuService } from './shared/menu/menu.service';
import { MenuID } from './shared/menu/initial-menus-state';
import { Observable } from 'rxjs/internal/Observable';
import { slideSidebarMargin } from './shared/animations/slide';
import { slideSidebarPadding } from './shared/animations/slide';
@Component({
selector: 'ds-app',
......@@ -36,12 +36,14 @@ import { slideSidebarMargin } from './shared/animations/slide';
styleUrls: ['./app.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
animations: [slideSidebarMargin]
animations: [slideSidebarPadding]
})
export class AppComponent implements OnInit, AfterViewInit {
isLoading = true;
hasAdminSidebar: Observable<boolean>;
sidebarVisible: Observable<boolean>;
sidebarCollapsed: Observable<boolean>;
collapsedSidebarWidth: Observable<string>;
totalSidebarWidth: Observable<string>;
constructor(
@Inject(GLOBAL_CONFIG) public config: GlobalConfig,
......@@ -80,9 +82,11 @@ export class AppComponent implements OnInit, AfterViewInit {
first(),
filter((authenticated) => !authenticated)
).subscribe((authenticated) => this.authService.checkAuthenticationToken());
this.hasAdminSidebar = this.menuService.isMenuVisible(MenuID.ADMIN);
this.sidebarVisible = this.menuService.isMenuVisible(MenuID.ADMIN);
this.sidebarCollapsed = this.menuService.isMenuCollapsed(MenuID.ADMIN);
this.collapsedSidebarWidth = this.cssService.getVariable('collapsedSidebarWidth');
this.totalSidebarWidth = this.cssService.getVariable('totalSidebarWidth');
}
private storeCSSVariables() {
......
......@@ -9,7 +9,6 @@ nav.navbar {
@media screen and (max-width: map-get($grid-breakpoints, md)) {
.navbar {
width: 100%;
left: 0;
background-color: $white;
position: absolute;
overflow: hidden;
......@@ -37,7 +36,6 @@ nav.navbar {
padding-left: 0;
padding-right: 0;
}
}
<div class="page-not-found">
<div class="page-not-found container">
<h1>404</h1>
<h2><small>{{"404.page-not-found" | translate}}</small></h2>
<br/>
......
......@@ -59,8 +59,11 @@ export const slideSidebar = trigger('slideSidebar', [
))
]);
export const slideSidebarMargin = trigger('slideSidebarMargin', [
state('collapsed', style({ marginLeft: 0 })),
state('expanded', style({ marginLeft: '{{ collapsedSidebarWidth }}' }), { params: { collapsedSidebarWidth: '*' } }),
transition('collapsed <=> expanded', [animate('200ms')]),
export const slideSidebarPadding = trigger('slideSidebarPadding', [
state('hidden', style({ paddingLeft: 0 })),
state('shown', style({ paddingLeft: '{{ collapsedSidebarWidth }}' }), { params: { collapsedSidebarWidth: '*' } }),
state('expanded', style({ paddingLeft: '{{ totalSidebarWidth }}' }), { params: { totalSidebarWidth: '*' } }),
transition('hidden <=> shown', [animate('200ms')]),
transition('hidden <=> expanded', [animate('200ms')]),
transition('shown <=> expanded', [animate('200ms')]),
]);
\ No newline at end of file
......@@ -14,6 +14,7 @@ export const initialMenusState: MenusState = {
{
id: MenuID.ADMIN,
collapsed: true,
previewCollapsed: true,
visible: false,
sections: {},
sectionToSubsectionIndex: {}
......@@ -22,6 +23,7 @@ export const initialMenusState: MenusState = {
{
id: MenuID.PUBLIC,
collapsed: true,
previewCollapsed: true,
visible: true,
sections: {},
sectionToSubsectionIndex: {}
......
......@@ -9,6 +9,8 @@ export const MenuActionTypes = {
EXPAND_MENU: type('dspace/menu/EXPAND_MENU'),
SHOW_MENU: type('dspace/menu/SHOW_MENU'),
HIDE_MENU: type('dspace/menu/HIDE_MENU'),
COLLAPSE_MENU_PREVIEW: type('dspace/menu/COLLAPSE_MENU_PREVIEW'),
EXPAND_MENU_PREVIEW: type('dspace/menu/EXPAND_MENU_PREVIEW'),
ADD_SECTION: type('dspace/menu-section/ADD_SECTION'),
REMOVE_SECTION: type('dspace/menu-section/REMOVE_SECTION'),
SHOW_SECTION: type('dspace/menu-section/SHOW_SECTION'),
......@@ -66,6 +68,25 @@ export class HideMenuAction implements Action {
}
}
export class CollapseMenuPreviewAction implements Action {
type = MenuActionTypes.COLLAPSE_MENU_PREVIEW;
menuID: MenuID;
constructor(menuID: MenuID) {
this.menuID = menuID;
}
}
export class ExpandMenuPreviewAction implements Action {
type = MenuActionTypes.EXPAND_MENU_PREVIEW;
menuID: MenuID;
constructor(menuID: MenuID) {
this.menuID = menuID;
}
}
// MENU STRUCTURING ACTIONS
export abstract class MenuSectionAction implements Action {
type;
......
......@@ -15,6 +15,7 @@ import { MenuSectionComponent } from './menu-section/menu-section.component';
export class MenuComponent implements OnInit {
menuID: MenuID;
menuCollapsed: Observable<boolean>;
menuPreviewCollapsed: Observable<boolean>;
menuVisible: Observable<boolean>;
sections: Observable<MenuSection[]>;
sectionInjectors: Map<string, Injector> = new Map<string, Injector>();
......@@ -26,6 +27,7 @@ export class MenuComponent implements OnInit {
ngOnInit(): void {
this.menuCollapsed = this.menuService.isMenuCollapsed(this.menuID);
this.menuPreviewCollapsed = this.menuService.isMenuPreviewCollapsed(this.menuID);
this.menuVisible = this.menuService.isMenuVisible(this.menuID);
this.sections = this.menuService.getMenuTopSections(this.menuID).pipe(first());
this.sections.subscribe((sections: MenuSection[]) => {
......@@ -41,6 +43,27 @@ export class MenuComponent implements OnInit {
this.menuService.toggleMenu(this.menuID);
}
expand(event: Event) {
event.preventDefault();
this.menuService.expandMenu(this.menuID);
}
collapse(event: Event) {
event.preventDefault();
this.menuService.collapseMenu(this.menuID);
}
expandPreview(event: Event) {
console.log("HOI IK HOVER");
event.preventDefault();
this.menuService.expandMenuPreview(this.menuID);
}
collapsePreview(event: Event) {
event.preventDefault();
this.menuService.collapseMenuPreview(this.menuID);
}
getSectionComponent(section: MenuSection): Observable<GenericConstructor<MenuSectionComponent>> {
return this.menuService.hasSubSections(this.menuID, section.id).pipe(
map((expandable: boolean) => {
......
......@@ -17,45 +17,45 @@ import { MenuService } from './menu.service';
@Injectable()
export class MenuEffects {
//
// @Effect()
// public collapseSectionsOnCollapseMenu$: Observable<Action> = this.actions$.pipe(
// ofType(MenuActionTypes.COLLAPSE_MENU, MenuActionTypes.TOGGLE_MENU),
// switchMap((action: CollapseMenuAction | ToggleMenuAction) => {
// return this.menuService.getMenu(action.menuID).pipe(
// first(),
// switchMap((menu: MenuState) => {
// if (menu.collapsed) {
// const sections = menu.sections;
// return Object.keys(sections)
// .map((id) => {
// return new DeactivateMenuSectionAction(action.menuID, id);
// }
// )
// } else {
// return [{ type: 'NO_ACTION' }];
// }
// }
// )
// )
// })
// );
@Effect()
public collapseSectionsOnCollapseMenu$: Observable<Action> = this.actions$.pipe(
ofType(MenuActionTypes.COLLAPSE_MENU, MenuActionTypes.TOGGLE_MENU),
switchMap((action: CollapseMenuAction | ToggleMenuAction) => {
return this.menuService.getMenu(action.menuID).pipe(
first(),
switchMap((menu: MenuState) => {
if (menu.collapsed) {
const sections = menu.sections;
return Object.keys(sections)
.map((id) => {
return new DeactivateMenuSectionAction(action.menuID, id);
}
)
} else {
return [{ type: 'NO_ACTION' }];
}
}
)
)
})
);
@Effect()
public onExpandSectionMenuExpandMenu: Observable<Action> = this.actions$.pipe(
ofType(MenuActionTypes.ACTIVATE_SECTION, MenuActionTypes.TOGGLE_ACTIVE_SECTION),
switchMap((action: ActivateMenuSectionAction | ToggleActiveMenuSectionAction) => {
return this.menuService.getMenu(action.menuID).pipe(
first(),
map((menu: MenuState) => {
if (menu.collapsed) {
return new ExpandMenuAction(menu.id)
} else {
return { type: 'NO_ACTION' };
}
}));
})
);
// @Effect()
// public onExpandSectionMenuExpandMenu: Observable<Action> = this.actions$.pipe(
// ofType(MenuActionTypes.ACTIVATE_SECTION, MenuActionTypes.TOGGLE_ACTIVE_SECTION),
// switchMap((action: ActivateMenuSectionAction | ToggleActiveMenuSectionAction) => {
// return this.menuService.getMenu(action.menuID).pipe(
// first(),
// map((menu: MenuState) => {
// if (menu.collapsed) {
// return new ExpandMenuAction(menu.id)
// } else {
// return { type: 'NO_ACTION' };
// }
// }));
// })
// );
constructor(private actions$: Actions,
private menuService: MenuService) {
......
......@@ -18,7 +18,8 @@ export type MenusState = {
export interface MenuState {
id: MenuID;
collapsed: boolean;
collapsed: boolean
previewCollapsed: boolean;
visible: boolean;
sections: MenuSections
sectionToSubsectionIndex: MenuSectionIndex;
......@@ -53,6 +54,14 @@ export function menusReducer(state: MenusState = initialMenusState, action: Menu
const newMenuState = Object.assign({}, menuState, { collapsed: false });
return Object.assign({}, state, { [action.menuID]: newMenuState });
}
case MenuActionTypes.COLLAPSE_MENU_PREVIEW: {
const newMenuState = Object.assign({}, menuState, { previewCollapsed: true });
return Object.assign({}, state, { [action.menuID]: newMenuState });
}
case MenuActionTypes.EXPAND_MENU_PREVIEW: {
const newMenuState = Object.assign({}, menuState, { previewCollapsed: false });
return Object.assign({}, state, { [action.menuID]: newMenuState });
}
case MenuActionTypes.TOGGLE_MENU: {
const newMenuState = Object.assign({}, menuState, { collapsed: !menuState.collapsed });
return Object.assign({}, state, { [action.menuID]: newMenuState });
......
......@@ -7,8 +7,13 @@ import { Observable } from 'rxjs/internal/Observable';
import { map, switchMap } from 'rxjs/operators';
import {
ActivateMenuSectionAction,
AddMenuSectionAction, DeactivateMenuSectionAction, HideMenuAction,
RemoveMenuSectionAction, ShowMenuAction,
AddMenuSectionAction,
CollapseMenuAction, CollapseMenuPreviewAction,
DeactivateMenuSectionAction,
ExpandMenuAction, ExpandMenuPreviewAction,
HideMenuAction,
RemoveMenuSectionAction,
ShowMenuAction,
ToggleActiveMenuSectionAction,
ToggleMenuAction,
} from './menu.actions';
......@@ -97,12 +102,34 @@ export class MenuService {
);
}
isMenuPreviewCollapsed(menuID: MenuID): Observable<boolean> {
return this.getMenu(menuID).pipe(
map((state: MenuState) => state.previewCollapsed)
);
}
isMenuVisible(menuID: MenuID): Observable<boolean> {
return this.getMenu(menuID).pipe(
map((state: MenuState) => state.visible)
);
}
expandMenu(menuID: MenuID): void {
this.store.dispatch(new ExpandMenuAction(menuID));
}
collapseMenu(menuID: MenuID): void {
this.store.dispatch(new CollapseMenuAction(menuID));
}
expandMenuPreview(menuID: MenuID): void {
this.store.dispatch(new ExpandMenuPreviewAction(menuID));
}
collapseMenuPreview(menuID: MenuID): void {
this.store.dispatch(new CollapseMenuPreviewAction(menuID));
}
toggleMenu(menuID: MenuID): void {
this.store.dispatch(new ToggleMenuAction(menuID));
}
......
......@@ -2,6 +2,9 @@
$fa-fixed-width: 1.25rem;
$icon-padding: 1rem;
$collapsed-sidebar-width: calculatePx($fa-fixed-width + (2 * $icon-padding));
$sidebar-items-width: 250px;
$total-sidebar-width: $collapsed-sidebar-width + $sidebar-items-width;
/* Fonts */
$fa-font-path: "../assets/fonts";
/* Images */
......
......@@ -18,7 +18,6 @@ $header-logo-height: 80px;
$admin-sidebar-bg: $dark;
$admin-sidebar-active-bg: darken($dark, 3%);
$admin-sidebar-header-bg: darken($dark, 7%);
$admin-sidebar-width: 250px;
$dark-scrollbar-background: $admin-sidebar-active-bg;
$dark-scrollbar-foreground: #47495d;
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment