mirror of
https://github.com/akveo/ngx-admin.git
synced 2026-01-28 12:16:10 +01:00
project structure update for more accurate import
This commit is contained in:
parent
36288562e6
commit
945cdb7e4f
43 changed files with 47 additions and 42 deletions
12
src/app/theme/components/baCard/baCard.component.ts
Normal file
12
src/app/theme/components/baCard/baCard.component.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import {Component, ViewEncapsulation, Input} from 'angular2/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ba-card',
|
||||
styles: [require('./baCard.scss')],
|
||||
template: require('./baCard.html'),
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class BaCard {
|
||||
@Input() title:String;
|
||||
@Input() baCardClass:String;
|
||||
}
|
||||
8
src/app/theme/components/baCard/baCard.html
Normal file
8
src/app/theme/components/baCard/baCard.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<div class="card {{cardType}} {{baCardClass || ''}}" zoom-in ba-panel-blur>
|
||||
<div *ngIf="title" class="card-header clearfix">
|
||||
<h3 class="card-title">{{title}}</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
0
src/app/theme/components/baCard/baCard.scss
Normal file
0
src/app/theme/components/baCard/baCard.scss
Normal file
1
src/app/theme/components/baCard/index.ts
Normal file
1
src/app/theme/components/baCard/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './baCard.component.ts';
|
||||
25
src/app/theme/components/contentTop/contentTop.component.ts
Normal file
25
src/app/theme/components/contentTop/contentTop.component.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import {Component} from 'angular2/core';
|
||||
import {Subscription} from "rxjs/Subscription";
|
||||
|
||||
import {ThemeGlobal} from "../../../theme";
|
||||
|
||||
@Component({
|
||||
selector: 'content-top',
|
||||
styles: [require('./contentTop.scss')],
|
||||
template: require('./contentTop.html'),
|
||||
})
|
||||
export class ContentTop {
|
||||
activePageTitle = '';
|
||||
private _themeGlobalSubscription:Subscription;
|
||||
|
||||
constructor(private _themeGlobal:ThemeGlobal) {
|
||||
this._themeGlobalSubscription = this._themeGlobal.getDataStream().subscribe((data) => {
|
||||
this.activePageTitle = data['menu.activeLink'] != null ? data['menu.activeLink'].title : this.activePageTitle;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
// prevent memory leak when component destroyed
|
||||
this._themeGlobalSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
9
src/app/theme/components/contentTop/contentTop.html
Normal file
9
src/app/theme/components/contentTop/contentTop.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<div class="content-top clearfix">
|
||||
<h1 class="al-title">{{ activePageTitle }}</h1>
|
||||
|
||||
<ul class="breadcrumb al-breadcrumb">
|
||||
<li>
|
||||
<a href="#/dashboard">Home</a></li>
|
||||
<li>{{ activePageTitle }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
40
src/app/theme/components/contentTop/contentTop.scss
Normal file
40
src/app/theme/components/contentTop/contentTop.scss
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
@import '../../sass/conf/conf';
|
||||
|
||||
.content-top {
|
||||
padding-top: 13px;
|
||||
padding-bottom: 27px;
|
||||
}
|
||||
|
||||
h1.al-title {
|
||||
font-weight: $font-bold;
|
||||
color: #ffffff;
|
||||
float: left;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 24px;
|
||||
text-transform: uppercase;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.al-breadcrumb {
|
||||
background: none;
|
||||
color: #ffffff;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
float: right;
|
||||
padding-top: 11px;
|
||||
li {
|
||||
font-size: 18px;
|
||||
font-weight: $font-light;
|
||||
}
|
||||
}
|
||||
|
||||
.al-look {
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
padding-top: 10px;
|
||||
> a {
|
||||
font-size: 19px;
|
||||
}
|
||||
}
|
||||
1
src/app/theme/components/contentTop/index.ts
Normal file
1
src/app/theme/components/contentTop/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './contentTop.component.ts';
|
||||
5
src/app/theme/components/index.ts
Normal file
5
src/app/theme/components/index.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
export * from './pageTop';
|
||||
export * from './msgCenter';
|
||||
export * from './sidebar';
|
||||
export * from './contentTop';
|
||||
export * from './baCard';
|
||||
1
src/app/theme/components/msgCenter/index.ts
Normal file
1
src/app/theme/components/msgCenter/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './msgCenter.component.ts';
|
||||
88
src/app/theme/components/msgCenter/msgCenter.component.ts
Normal file
88
src/app/theme/components/msgCenter/msgCenter.component.ts
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
import {Component} from 'angular2/core';
|
||||
|
||||
import {ProfilePicturePipe} from '../../pipes';
|
||||
|
||||
@Component({
|
||||
selector: 'msg-center',
|
||||
styles: [require('./msgCenter.scss')],
|
||||
template: require('./msgCenter.html'),
|
||||
pipes: [ProfilePicturePipe]
|
||||
})
|
||||
export class MsgCenter {
|
||||
|
||||
notifications = [
|
||||
{
|
||||
name: 'Vlad',
|
||||
text: 'Vlad posted a new article.',
|
||||
time: '1 min ago'
|
||||
},
|
||||
{
|
||||
name: 'Kostya',
|
||||
text: 'Kostya changed his contact information.',
|
||||
time: '2 hrs ago'
|
||||
},
|
||||
{
|
||||
image: 'assets/img/shopping-cart.svg',
|
||||
text: 'New orders received.',
|
||||
time: '5 hrs ago'
|
||||
},
|
||||
{
|
||||
name: 'Andrey',
|
||||
text: 'Andrey replied to your comment.',
|
||||
time: '1 day ago'
|
||||
},
|
||||
{
|
||||
name: 'Nasta',
|
||||
text: 'Today is Nasta\'s birthday.',
|
||||
time: '2 days ago'
|
||||
},
|
||||
{
|
||||
image: 'assets/img/comments.svg',
|
||||
text: 'New comments on your post.',
|
||||
time: '3 days ago'
|
||||
},
|
||||
{
|
||||
name: 'Kostya',
|
||||
text: 'Kostya invited you to join the event.',
|
||||
time: '1 week ago'
|
||||
}
|
||||
];
|
||||
|
||||
messages = [
|
||||
{
|
||||
name: 'Nasta',
|
||||
text: 'After you get up and running, you can place Font Awesome icons just about...',
|
||||
time: '1 min ago'
|
||||
},
|
||||
{
|
||||
name: 'Vlad',
|
||||
text: 'You asked, Font Awesome delivers with 40 shiny new icons in version 4.2.',
|
||||
time: '2 hrs ago'
|
||||
},
|
||||
{
|
||||
name: 'Kostya',
|
||||
text: 'Want to request new icons? Here\'s how. Need vectors or want to use on the...',
|
||||
time: '10 hrs ago'
|
||||
},
|
||||
{
|
||||
name: 'Andrey',
|
||||
text: 'Explore your passions and discover new ones by getting involved. Stretch your...',
|
||||
time: '1 day ago'
|
||||
},
|
||||
{
|
||||
name: 'Nasta',
|
||||
text: 'Get to know who we are - from the inside out. From our history and culture, to the...',
|
||||
time: '1 day ago'
|
||||
},
|
||||
{
|
||||
name: 'Kostya',
|
||||
text: 'Need some support to reach your goals? Apply for scholarships across a variety of...',
|
||||
time: '2 days ago'
|
||||
},
|
||||
{
|
||||
name: 'Vlad',
|
||||
text: 'Wrap the dropdown\'s trigger and the dropdown menu within .dropdown, or...',
|
||||
time: '1 week ago'
|
||||
}
|
||||
];
|
||||
}
|
||||
55
src/app/theme/components/msgCenter/msgCenter.html
Normal file
55
src/app/theme/components/msgCenter/msgCenter.html
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<ul class="al-msg-center clearfix">
|
||||
<li class="dropdown">
|
||||
<a href class="dropdown-toggle" id="msg-dd1" data-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa fa-bell-o"></i><span>5</span>
|
||||
|
||||
<div class="notification-ring"></div>
|
||||
</a>
|
||||
|
||||
<div class="top-dropdown-menu dropdown-menu" aria-labelledby="msg-dd1">
|
||||
<i class="dropdown-arr"></i>
|
||||
|
||||
<div class="header clearfix">
|
||||
<strong>Notifications</strong>
|
||||
<a href>Mark All as Read</a>
|
||||
<a href>Settings</a>
|
||||
</div>
|
||||
<div class="msg-list">
|
||||
<a *ngFor="#msg of notifications" href class="clearfix">
|
||||
<div class="img-area"><img [ngClass]="{'photo-msg-item': !msg.image}"
|
||||
src="{{ ( msg.image || (msg.name | profilePicture)) }}"></div>
|
||||
<div class="msg-area">
|
||||
<div>{{ msg.text }}</div>
|
||||
<span>{{ msg.time }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<a href>See all notifications</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href class="msg dropdown-toggle" id="msg-dd2" data-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa fa-envelope-o"></i><span>5</span>
|
||||
<div class="notification-ring"></div>
|
||||
</a>
|
||||
<div class="top-dropdown-menu dropdown-menu" aria-labelledby="msg-dd2">
|
||||
<i class="dropdown-arr"></i>
|
||||
<div class="header clearfix">
|
||||
<strong>Messages</strong>
|
||||
<a href>Mark All as Read</a>
|
||||
<a href>Settings</a>
|
||||
</div>
|
||||
<div class="msg-list">
|
||||
<a *ngFor="#msg of messages" href class="clearfix">
|
||||
<div class="img-area"><img [ngClass]="{'photo-msg-item': !msg.image}"
|
||||
src="{{ ( msg.image || (msg.name | profilePicture)) }}"></div>
|
||||
<div class="msg-area">
|
||||
<div>{{ msg.text }}</div>
|
||||
<span>{{ msg.time }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<a href>See all messages</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
263
src/app/theme/components/msgCenter/msgCenter.scss
Normal file
263
src/app/theme/components/msgCenter/msgCenter.scss
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
@import '../../sass/conf/conf';
|
||||
|
||||
/* msg center */
|
||||
@-webkit-keyframes pulsate {
|
||||
30% {
|
||||
-webkit-transform: scale(0.1, 0.1);
|
||||
opacity: 0.0;
|
||||
}
|
||||
35% {
|
||||
opacity: 1.0;
|
||||
}
|
||||
40% {
|
||||
-webkit-transform: scale(1.2, 1.2);
|
||||
opacity: 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
.al-msg-center {
|
||||
float: right;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
margin: 13px 47px 0 0;
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
margin-left: 30px;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
& > a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
position: relative;
|
||||
span {
|
||||
display: inline-block;
|
||||
min-width: 10px;
|
||||
padding: 2px 4px 2px 4px;
|
||||
color: #ffffff;
|
||||
vertical-align: baseline;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
border-radius: 13px;
|
||||
text-shadow: none;
|
||||
line-height: 11px;
|
||||
background-color: $danger;
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -14px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.notification-ring {
|
||||
border: 1px solid $danger;
|
||||
border-radius: 100px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
position: absolute;
|
||||
top: -18px;
|
||||
right: -27px;
|
||||
animation: pulsate 8s ease-out;
|
||||
animation-iteration-count: infinite;
|
||||
opacity: 0.0
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $danger;
|
||||
&.msg {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
&.msg {
|
||||
span {
|
||||
background-color: $primary;
|
||||
}
|
||||
.notification-ring {
|
||||
border-color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.open {
|
||||
& > a {
|
||||
color: $danger;
|
||||
&.msg {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $resXXS) {
|
||||
.al-msg-center {
|
||||
margin-right: 20px;
|
||||
li {
|
||||
margin-left: 20px;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.msg-block-header {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
margin: 0 0 0 6px;
|
||||
}
|
||||
|
||||
.top-dropdown-menu {
|
||||
width: 316px;
|
||||
left: auto;
|
||||
right: -47px;
|
||||
top: 26px;
|
||||
@include scrollbars(.4em, rgba(0, 0, 0, 0.5), #fff);
|
||||
.header {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid $border-light;
|
||||
font-size: 12px;
|
||||
strong {
|
||||
float: left;
|
||||
}
|
||||
& > a {
|
||||
float: right;
|
||||
margin-left: 12px;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
color: $default-text;
|
||||
}
|
||||
}
|
||||
}
|
||||
.msg-list {
|
||||
max-height: 296px;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
& > a {
|
||||
border-top: 1px solid $border-light;
|
||||
padding: 10px 12px;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
color: $default-text;
|
||||
font-size: 12px;
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
.img-area {
|
||||
float: left;
|
||||
width: 36px;
|
||||
img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
&.photo-msg-item {
|
||||
border-radius: 18px;
|
||||
}
|
||||
}
|
||||
& > div {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
&.comments {
|
||||
color: $warning;
|
||||
}
|
||||
&.orders {
|
||||
color: $warning;
|
||||
}
|
||||
i {
|
||||
width: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.msg-area {
|
||||
float: right;
|
||||
width: 230px;
|
||||
div {
|
||||
max-height: 34px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
span {
|
||||
font-style: italic;
|
||||
text-align: right;
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: #E2F0FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
& > a {
|
||||
border-top: 1px solid $border-light;
|
||||
display: block;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
color: $default-text;
|
||||
}
|
||||
}
|
||||
|
||||
&.profile-dropdown {
|
||||
width: 145px;
|
||||
top: 55px;
|
||||
right: -25px;
|
||||
a {
|
||||
text-align: left;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
color: $default-text;
|
||||
padding: 4px 16px 4px 20px;
|
||||
&.signout {
|
||||
border-top: 1px solid $border-light;
|
||||
}
|
||||
i {
|
||||
margin-right: 10px;
|
||||
}
|
||||
&:hover {
|
||||
background: #f4fcff;
|
||||
}
|
||||
}
|
||||
i.dropdown-arr {
|
||||
right: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
i.dropdown-arr {
|
||||
position: absolute;
|
||||
top: -22px;
|
||||
right: 42px;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 11px solid transparent;
|
||||
border-bottom-color: rgba(0, 0, 0, .15);
|
||||
&:after {
|
||||
top: -9px;
|
||||
left: 0px;
|
||||
margin-left: -10px;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 10px solid transparent;
|
||||
border-bottom-color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 415px) {
|
||||
.top-dropdown-menu {
|
||||
right: -81px;
|
||||
i.dropdown-arr {
|
||||
right: 75px;
|
||||
}
|
||||
}
|
||||
}
|
||||
1
src/app/theme/components/pageTop/index.ts
Normal file
1
src/app/theme/components/pageTop/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './pageTop.component.ts';
|
||||
31
src/app/theme/components/pageTop/pageTop.component.ts
Normal file
31
src/app/theme/components/pageTop/pageTop.component.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import {Component} from 'angular2/core';
|
||||
|
||||
import {ThemeGlobal} from '../../../theme';
|
||||
import {ProfilePicturePipe} from '../../pipes';
|
||||
import {MsgCenter} from '../../components/msgCenter';
|
||||
import {ScrollPosition} from '../../directives';
|
||||
|
||||
@Component({
|
||||
selector: 'page-top',
|
||||
styles: [require('./pageTop.scss')],
|
||||
template: require('./pageTop.html'),
|
||||
directives: [MsgCenter, ScrollPosition],
|
||||
pipes: [ProfilePicturePipe]
|
||||
})
|
||||
export class PageTop {
|
||||
isScrolled:Boolean = false;
|
||||
isMenuCollapsed:boolean = false;
|
||||
|
||||
|
||||
constructor(private _themeGlobal:ThemeGlobal) {
|
||||
}
|
||||
|
||||
toggleMenu() {
|
||||
this.isMenuCollapsed = !this.isMenuCollapsed;
|
||||
this._themeGlobal.setData('menu.isCollapsed', this.isMenuCollapsed);
|
||||
}
|
||||
|
||||
scrolledChanged(isScrolled) {
|
||||
this.isScrolled = isScrolled;
|
||||
}
|
||||
}
|
||||
25
src/app/theme/components/pageTop/pageTop.html
Normal file
25
src/app/theme/components/pageTop/pageTop.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<div class="page-top clearfix" scrollPosition maxHeight="50" (scrollChange)="scrolledChanged($event)"
|
||||
[ngClass]="{scrolled: isScrolled}">
|
||||
<a href="#/dashboard" class="al-logo clearfix"><span>Blur</span>Admin</a>
|
||||
<a (click)="toggleMenu()" class="collapse-menu-link ion-navicon"></a>
|
||||
|
||||
<div class="search">
|
||||
<i class="ion-ios-search-strong" ng-click="startSearch()"></i>
|
||||
<input id="searchInput" type="text" placeholder="Search for...">
|
||||
</div>
|
||||
|
||||
<div class="user-profile clearfix">
|
||||
<div class="dropdown al-user-profile">
|
||||
<a class="profile-toggle-link dropdown-toggle" id="user-profile-dd" data-toggle="dropdown" aria-expanded="false">
|
||||
<img src="{{ ( 'Nasta' | profilePicture ) }}">
|
||||
</a>
|
||||
<div class="dropdown-menu top-dropdown-menu profile-dropdown" aria-labelledby="user-profile-dd">
|
||||
<li class="dropdown-item"><i class="dropdown-arr"></i></li>
|
||||
<li class="dropdown-item"><a href="#/profile"><i class="fa fa-user"></i>Profile</a></li>
|
||||
<li class="dropdown-item"><a href><i class="fa fa-cog"></i>Settings</a></li>
|
||||
<li class="dropdown-item"><a href class="signout"><i class="fa fa-power-off"></i>Sign out</a></li>
|
||||
</div>
|
||||
</div>
|
||||
<msg-center></msg-center>
|
||||
</div>
|
||||
</div>
|
||||
180
src/app/theme/components/pageTop/pageTop.scss
Normal file
180
src/app/theme/components/pageTop/pageTop.scss
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
@import '../../sass/conf/conf';
|
||||
@import '../../components/msgCenter/msgCenter';
|
||||
|
||||
.page-top {
|
||||
@include bg-translucent-dark(0.5);
|
||||
position: fixed;
|
||||
z-index: 904;
|
||||
box-shadow: 2px 0px 3px rgba(0, 0, 0, 0.5);
|
||||
height: 66px;
|
||||
width: 100%;
|
||||
min-width: $resMin;
|
||||
padding: 0 32px 0 40px;
|
||||
|
||||
&.scrolled {
|
||||
@include bg-translucent-dark(0.85);
|
||||
}
|
||||
}
|
||||
|
||||
a.al-logo {
|
||||
color: #ffffff;
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
font-family: $font-family;
|
||||
white-space: nowrap;
|
||||
float: left;
|
||||
outline: none !important;
|
||||
line-height: 60px;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: $hoverlink;
|
||||
}
|
||||
|
||||
span {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
.user-profile {
|
||||
float: right;
|
||||
min-width: 230px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.al-user-profile {
|
||||
float: right;
|
||||
margin-right: 12px;
|
||||
transition: all .15s ease-in-out;
|
||||
padding: 0;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border: 0;
|
||||
opacity: 1;
|
||||
position: relative;
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
img {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
a.refresh-data {
|
||||
color: #ffffff;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
font-weight: $font-normal;
|
||||
float: right;
|
||||
margin-top: 13px;
|
||||
margin-right: 26px;
|
||||
|
||||
&:hover {
|
||||
color: $warning !important;
|
||||
}
|
||||
}
|
||||
|
||||
a.collapse-menu-link {
|
||||
font-size: 31px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
line-height: 42px;
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
float: left;
|
||||
margin: 11px 0 0 25px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color: $warning;
|
||||
}
|
||||
}
|
||||
|
||||
.al-skin-dropdown {
|
||||
float: right;
|
||||
margin-top: 14px;
|
||||
margin-right: 26px;
|
||||
|
||||
.tpl-skin-panel {
|
||||
max-height: 300px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-palette {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 13px;
|
||||
@include bg('theme/palette.png');
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.search {
|
||||
text-shadow: none;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
line-height: 25px;
|
||||
transition: all 0.5s ease;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 162px;
|
||||
float: left;
|
||||
margin: 20px 0 0 30px;
|
||||
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
i {
|
||||
width: 16px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding-left: 1px;
|
||||
font-size: 16px;
|
||||
margin-right: 13px;
|
||||
}
|
||||
input {
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
width: 120px;
|
||||
padding: 0;
|
||||
margin: 0 0 0 -3px;
|
||||
height: 27px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $resS) {
|
||||
.search {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $resXS) {
|
||||
.page-top {
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $resXXS) {
|
||||
.user-profile {
|
||||
min-width: 136px;
|
||||
}
|
||||
a.refresh-data {
|
||||
margin-right: 10px;
|
||||
}
|
||||
a.collapse-menu-link {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.al-skin-dropdown {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-toggle-link {
|
||||
cursor: pointer;
|
||||
}
|
||||
1
src/app/theme/components/sidebar/index.ts
Normal file
1
src/app/theme/components/sidebar/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './sidebar.component.ts';
|
||||
125
src/app/theme/components/sidebar/sidebar.component.ts
Normal file
125
src/app/theme/components/sidebar/sidebar.component.ts
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
import {Component, ElementRef, HostListener, ViewEncapsulation} from 'angular2/core';
|
||||
import {Router} from 'angular2/router';
|
||||
|
||||
import {ThemeGlobal, layoutSizes} from '../../../theme';
|
||||
import {SidebarService} from './sidebar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'sidebar',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
styles: [require('./sidebar.scss')],
|
||||
template: require('./sidebar.html'),
|
||||
providers: [SidebarService],
|
||||
directives: [],
|
||||
pipes: []
|
||||
})
|
||||
export class Sidebar {
|
||||
|
||||
menuItems:Array<any>;
|
||||
menuHeight:number;
|
||||
isMenuCollapsed:boolean;
|
||||
|
||||
showHoverElem:boolean;
|
||||
hoverElemHeight:number;
|
||||
hoverElemTop:number;
|
||||
|
||||
outOfArea:number = -200;
|
||||
|
||||
isMenuShouldCollapsed:boolean = false;
|
||||
|
||||
constructor(private _elementRef:ElementRef,
|
||||
private _router:Router,
|
||||
private _sidebarService:SidebarService,
|
||||
private _themeGlobal:ThemeGlobal) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.menuItems = this._sidebarService.getMenuItems();
|
||||
this.selectMenuItem();
|
||||
this._router.root.subscribe(() => this.selectMenuItem());
|
||||
}
|
||||
|
||||
// TODO: is it really the best event for this kind of things?
|
||||
ngAfterViewInit() {
|
||||
this.updateSidebarHeight();
|
||||
}
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onWindowResize($event) {
|
||||
|
||||
var isMenuShouldCollapsed = $event.target.innerWidth <= layoutSizes.resWidthCollapseSidebar;
|
||||
|
||||
if (this.isMenuShouldCollapsed !== isMenuShouldCollapsed) {
|
||||
this.menuCollapseStateChange(isMenuShouldCollapsed);
|
||||
}
|
||||
this.isMenuShouldCollapsed = isMenuShouldCollapsed;
|
||||
this.updateSidebarHeight();
|
||||
}
|
||||
|
||||
menuExpand() {
|
||||
this.menuCollapseStateChange(false);
|
||||
}
|
||||
|
||||
menuCollapse() {
|
||||
this.menuCollapseStateChange(true);
|
||||
}
|
||||
|
||||
menuCollapseStateChange(isCollapsed) {
|
||||
this.isMenuCollapsed = isCollapsed;
|
||||
this._themeGlobal.setData('menu.isCollapsed', this.isMenuCollapsed);
|
||||
}
|
||||
|
||||
hoverItem($event) {
|
||||
this.showHoverElem = true;
|
||||
this.hoverElemHeight = $event.currentTarget.clientHeight;
|
||||
// TODO: get rid of magic 66 constant
|
||||
this.hoverElemTop = $event.currentTarget.getBoundingClientRect().top - 66;
|
||||
}
|
||||
|
||||
updateSidebarHeight() {
|
||||
// TODO: get rid of magic 84 constant
|
||||
this.menuHeight = this._elementRef.nativeElement.childNodes[0].clientHeight - 84;
|
||||
}
|
||||
|
||||
toggleSubMenu($event, item) {
|
||||
var submenu = $($event.currentTarget).next();
|
||||
|
||||
if (this.isMenuCollapsed) {
|
||||
this.menuExpand();
|
||||
if (!item.expanded) {
|
||||
item.expanded = !item.expanded;
|
||||
submenu.slideToggle();
|
||||
}
|
||||
} else {
|
||||
item.expanded = !item.expanded;
|
||||
submenu.slideToggle();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: there is a bug in the router thus all child routers are considered as active
|
||||
private selectMenuItem() {
|
||||
let currentMenu;
|
||||
|
||||
let isCurrent = (instructions) => (instructions.filter(i => typeof i !== 'undefined').length > 0 ? this._router.isRouteActive(this._router.generate(instructions)) : false);
|
||||
let assignCurrent = (menu) => (menu.selected ? currentMenu = menu : null);
|
||||
|
||||
this.menuItems.forEach(function (menu: any) {
|
||||
|
||||
menu.selected = isCurrent([menu.name]);
|
||||
menu.expanded = menu.expanded || menu.selected;
|
||||
assignCurrent(menu);
|
||||
|
||||
if (menu.subMenu) {
|
||||
menu.subMenu.forEach(function (subMenu) {
|
||||
subMenu.selected = isCurrent([menu.name, subMenu.name]) && !subMenu.disabled;
|
||||
assignCurrent(menu);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// notifies all subscribers
|
||||
this._themeGlobal.setData('menu.activeLink', currentMenu);
|
||||
}
|
||||
}
|
||||
45
src/app/theme/components/sidebar/sidebar.html
Normal file
45
src/app/theme/components/sidebar/sidebar.html
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<aside class="al-sidebar" (mouseleave)="hoverElemTop=outOfArea">
|
||||
<ul class="al-sidebar-list">
|
||||
<li *ngFor="#item of menuItems" class="al-sidebar-list-item"
|
||||
[ngClass]="{'selected': item.selected, 'with-sub-menu': item.subMenu}">
|
||||
|
||||
<a *ngIf="!item.subMenu" [routerLink]="[item.name]" class="al-sidebar-list-link">
|
||||
<i class="{{ item.icon }}"></i><span>{{ item.title }}</span>
|
||||
</a>
|
||||
|
||||
<a *ngIf="item.subMenu" (mouseenter)="hoverItem($event, item)" (click)="toggleSubMenu($event, item)"
|
||||
class="al-sidebar-list-link">
|
||||
<i class="{{ item.icon }}"></i><span>{{ item.title }}</span>
|
||||
<b class="fa" [ngClass]="{'fa-angle-up': item.expanded, 'fa-angle-down': !item.expanded}"
|
||||
*ngIf="item.subMenu"></b>
|
||||
</a>
|
||||
|
||||
<ul *ngIf="item.subMenu" class="al-sidebar-sublist"
|
||||
[ngClass]="{expanded: item.expanded, 'slide-right': item.slideRight}">
|
||||
<li *ngFor="#subitem of item.subMenu"
|
||||
[ngClass]="{'selected': subitem.selected, 'with-sub-menu': subitem.subMenu}">
|
||||
<a (mouseenter)="hoverItem($event, item)" *ngIf="subitem.subMenu" (click)="toggleSubMenu($event, subitem);"
|
||||
class="al-sidebar-list-link subitem-submenu-link"><span>{{ subitem.title }}</span>
|
||||
<b class="fa" *ngIf="subitem.subMenu"
|
||||
[ngClass]="{'fa-angle-up': subitem.expanded, 'fa-angle-down': !subitem.expanded}"></b>
|
||||
</a>
|
||||
<ul *ngIf="subitem.subMenu" class="al-sidebar-sublist subitem-submenu-list"
|
||||
[ngClass]="{expanded: subitem.expanded, 'slide-right': subitem.slideRight}">
|
||||
<li *ngFor="#subSubitem of subitem.subMenu" (mouseenter)="hoverItem($event, item)"
|
||||
[ngClass]="{selected: subitem.selected}">
|
||||
<a (mouseenter)="hoverItem($event, item)" [routerLink]="[item.name, subitem.name, subSubitem.name]">
|
||||
{{ subSubitem.title }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a *ngIf="!subitem.subMenu" [routerLink]="[item.name, subitem.name]"
|
||||
(mouseenter)="hoverItem($event, item)" target="{{subitem.blank ? '_blank' : '_self'}}">
|
||||
{{ subitem.title}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<div class="sidebar-hover-elem" [ngStyle]="{top: hoverElemTop + 'px', height: hoverElemHeight + 'px'}"
|
||||
[ngClass]="{'show-hover-elem': showHoverElem }"></div>
|
||||
</aside>
|
||||
274
src/app/theme/components/sidebar/sidebar.scss
Normal file
274
src/app/theme/components/sidebar/sidebar.scss
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
@import '../../sass/conf/conf';
|
||||
|
||||
$sidebar-width: 180px;
|
||||
$angle-left: "\f100";
|
||||
$angle-right: "\f101";
|
||||
|
||||
.al-sidebar {
|
||||
width: $sidebar-width;
|
||||
top: $top-height;
|
||||
left: 0;
|
||||
z-index: 904;
|
||||
display: block;
|
||||
min-height: 100%;
|
||||
@include bg-translucent-dark(0.5);
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.al-sidebar-list {
|
||||
margin: 0;
|
||||
padding: 18px 0 0 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.al-sidebar-sublist .subitem-submenu-list {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.subitem-submenu-link {
|
||||
.fa {
|
||||
top: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.al-sidebar-list-item {
|
||||
display: block;
|
||||
position: relative;
|
||||
float: none;
|
||||
padding: 0;
|
||||
&.selected:not(.with-sub-menu) {
|
||||
background-color: $primary;
|
||||
a.al-sidebar-list-link {
|
||||
color: $default;
|
||||
b {
|
||||
color: $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.al-sidebar-list-link {
|
||||
display: block;
|
||||
height: 42px;
|
||||
padding-left: 18px;
|
||||
text-shadow: none;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
line-height: 42px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: $primary;
|
||||
b {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
i {
|
||||
margin-right: 18px;
|
||||
width: 16px;
|
||||
display: inline-block;
|
||||
}
|
||||
b {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
line-height: 14px;
|
||||
text-shadow: none;
|
||||
font-size: 18px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 12px;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
color: #cccccc;
|
||||
}
|
||||
}
|
||||
|
||||
.slimScrollBar, .slimScrollRail {
|
||||
border-radius: 0px !important;
|
||||
width: 4px !important;
|
||||
left: 176px;
|
||||
}
|
||||
|
||||
@mixin layout-collapsed() {
|
||||
.al-main {
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.al-footer {
|
||||
padding-left: 83px
|
||||
}
|
||||
}
|
||||
|
||||
@mixin default-sublist() {
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
position: relative;
|
||||
display: none;
|
||||
&.expanded {
|
||||
display: block;
|
||||
}
|
||||
> li {
|
||||
display: block;
|
||||
float: none;
|
||||
padding: 0;
|
||||
border-bottom: none;
|
||||
position: relative;
|
||||
a {
|
||||
display: block;
|
||||
text-shadow: none;
|
||||
font-size: 13px;
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
padding-left: 52px;
|
||||
height: auto;
|
||||
line-height: 29px;
|
||||
&:hover {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
&.selected:not(.with-sub-menu) > a {
|
||||
border: none;
|
||||
background-color: $primary;
|
||||
&:hover {
|
||||
color: $default;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.al-sidebar-sublist {
|
||||
@include default-sublist();
|
||||
}
|
||||
|
||||
.sidebar-hover-elem {
|
||||
width: 4px;
|
||||
background: $primary;
|
||||
position: absolute;
|
||||
top: -150px;
|
||||
left: 176px;
|
||||
transition: all 0.5s ease;
|
||||
transition-property: top, height;
|
||||
height: 42px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar-select-elem {
|
||||
display: block;
|
||||
top: 94px;
|
||||
}
|
||||
|
||||
@mixin sidebar-collapsed() {
|
||||
.al-sidebar {
|
||||
width: 52px;
|
||||
|
||||
.fa-angle-down, .fa-angle-up {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.al-sidebar-sublist {
|
||||
position: absolute;
|
||||
top: -1px;
|
||||
left: 52px;
|
||||
@include bg-translucent-dark(0.8);
|
||||
width: 0;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
transition: width 0.5s ease;
|
||||
&.slide-right {
|
||||
width: 135px;
|
||||
}
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
li {
|
||||
&:before {
|
||||
display: none;
|
||||
}
|
||||
a {
|
||||
padding-left: 18px;
|
||||
padding-right: 18px;
|
||||
min-width: 130px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-hover-elem, .sidebar-select-elem {
|
||||
left: 48px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin sidebar-hidden() {
|
||||
.al-sidebar {
|
||||
width: 0;
|
||||
}
|
||||
.sidebar-hover-elem, .sidebar-select-elem {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin sidebar-overlap() {
|
||||
.al-sidebar {
|
||||
width: $sidebar-width;
|
||||
@include bg-translucent-dark(0.75);
|
||||
transition: width 0.5s ease;
|
||||
|
||||
.fa-angle-down, .fa-angle-up {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.al-sidebar-sublist {
|
||||
@include default-sublist();
|
||||
top: auto;
|
||||
left: auto;
|
||||
background: none;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.sidebar-hover-elem, .sidebar-select-elem {
|
||||
left: $sidebar-width - 4;
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.menu-collapsed {
|
||||
@include layout-collapsed();
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: $resXS + 1) {
|
||||
.menu-collapsed {
|
||||
@include sidebar-collapsed();
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) and (min-width: $resXS) {
|
||||
@include layout-collapsed();
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
@include sidebar-overlap();
|
||||
}
|
||||
|
||||
@media (max-width: $resXS) {
|
||||
.menu-collapsed {
|
||||
@include sidebar-hidden();
|
||||
}
|
||||
.al-main {
|
||||
margin-left: 0;
|
||||
}
|
||||
.al-footer {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
130
src/app/theme/components/sidebar/sidebar.service.ts
Normal file
130
src/app/theme/components/sidebar/sidebar.service.ts
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
import {Injectable} from 'angular2/core';
|
||||
|
||||
@Injectable()
|
||||
export class SidebarService {
|
||||
|
||||
staticMenuItems = [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
name: 'Dashboard',
|
||||
icon: 'ion-android-home',
|
||||
selected: false,
|
||||
expanded: false,
|
||||
order: 0
|
||||
},
|
||||
{
|
||||
title: 'UI Features',
|
||||
name: 'Ui',
|
||||
icon: 'ion-android-laptop',
|
||||
selected: false,
|
||||
expanded: false,
|
||||
order: 200,
|
||||
subMenu: [
|
||||
{
|
||||
title: 'Typography',
|
||||
name: 'Typography',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Maps',
|
||||
name: 'Maps',
|
||||
icon: 'ion-ios-location-outline',
|
||||
selected: false,
|
||||
expanded: false,
|
||||
order: 300,
|
||||
subMenu: [
|
||||
{
|
||||
title: 'Google Maps',
|
||||
name: 'GoogleMaps',
|
||||
},
|
||||
{
|
||||
title: 'Leaflet Maps',
|
||||
name: 'LeafletMaps',
|
||||
},
|
||||
{
|
||||
title: 'Bubble Maps',
|
||||
name: 'BubbleMaps',
|
||||
},
|
||||
{
|
||||
title: 'Line Maps',
|
||||
name: 'LineMaps',
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Charts',
|
||||
name: 'Charts',
|
||||
icon: 'ion-stats-bars',
|
||||
selected: false,
|
||||
expanded: false,
|
||||
order: 400,
|
||||
subMenu: [
|
||||
{
|
||||
title: 'Chart Js',
|
||||
name: 'ChartJs',
|
||||
},
|
||||
{
|
||||
title: 'ChartistJs',
|
||||
name: 'ChartistJs',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Pages',
|
||||
icon: 'ion-document',
|
||||
selected: false,
|
||||
expanded: false,
|
||||
subMenu: [
|
||||
{
|
||||
title: 'Sign In',
|
||||
// name: 'SignIn',
|
||||
blank: true
|
||||
},
|
||||
{
|
||||
title: 'Sign Up',
|
||||
// name: 'SignUp',
|
||||
blank: true
|
||||
},
|
||||
{
|
||||
title: 'User Profile',
|
||||
// name: 'UserProfile'
|
||||
},
|
||||
{
|
||||
title: '404 Page',
|
||||
// name: 'NotFound',
|
||||
blank: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Menu Level 1',
|
||||
icon: 'ion-ios-more',
|
||||
selected: false,
|
||||
expanded: false,
|
||||
subMenu: [
|
||||
{
|
||||
title: 'Menu Level 1.1',
|
||||
disabled: true,
|
||||
selected: false,
|
||||
expanded: false
|
||||
},
|
||||
{
|
||||
title: 'Menu Level 1.2',
|
||||
subMenu: [{
|
||||
title: 'Menu Level 1.2.1',
|
||||
disabled: true,
|
||||
selected: false,
|
||||
expanded: false
|
||||
}]
|
||||
}
|
||||
]
|
||||
}];
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
getMenuItems() {
|
||||
return this.staticMenuItems;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue