Begin new menu design
authorChocobozzz <florian.bigard@gmail.com>
Fri, 1 Dec 2017 08:20:19 +0000 (09:20 +0100)
committerChocobozzz <florian.bigard@gmail.com>
Fri, 1 Dec 2017 09:55:56 +0000 (10:55 +0100)
30 files changed:
client/config/webpack.common.js
client/package.json
client/src/app/app.component.html
client/src/app/app.component.scss
client/src/app/app.component.ts
client/src/app/app.module.ts
client/src/app/core/core.module.ts
client/src/app/core/index.ts
client/src/app/core/menu/index.ts [deleted file]
client/src/app/core/menu/menu-admin.component.html [deleted file]
client/src/app/core/menu/menu-admin.component.ts [deleted file]
client/src/app/core/menu/menu.component.html [deleted file]
client/src/app/core/menu/menu.component.scss [deleted file]
client/src/app/core/menu/menu.component.ts [deleted file]
client/src/app/menu/index.ts [new file with mode: 0644]
client/src/app/menu/menu-admin.component.html [new file with mode: 0644]
client/src/app/menu/menu-admin.component.ts [new file with mode: 0644]
client/src/app/menu/menu.component.html [new file with mode: 0644]
client/src/app/menu/menu.component.scss [new file with mode: 0644]
client/src/app/menu/menu.component.ts [new file with mode: 0644]
client/src/app/shared/search/search.component.html
client/src/app/shared/search/search.component.scss
client/src/assets/logo.png [deleted file]
client/src/assets/logo.svg [new file with mode: 0644]
client/src/assets/menu/administration.svg [new file with mode: 0644]
client/src/assets/menu/recently-added.svg [new file with mode: 0644]
client/src/assets/menu/trending.svg [new file with mode: 0644]
client/src/sass/_variables.scss
client/src/sass/application.scss
client/yarn.lock

index 9cd33d2ed0b4b35a579bc3dd3ab9b64d5282441c..583f4ba07a428187753cbcf2948691f219e878dc 100644 (file)
@@ -153,7 +153,7 @@ module.exports = function (options) {
           ]
         },
         { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'url-loader?limit=10000&minetype=application/font-woff' },
-        { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'file-loader' },
+        { test: /\.(otf|ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'url-loader?limit=10000' },
 
         /* Raw loader support for *.html
          * Returns file content as string
index 39b3185cc33af438253b3e310cb47b2e69b21013..c551c995ae5871044efb0bb3e031d12679e38ba9 100644 (file)
@@ -70,7 +70,7 @@
     "markdown-it": "^8.4.0",
     "ng-router-loader": "^2.0.0",
     "ngc-webpack": "3.2.2",
-    "ngx-bootstrap": "1.9.3",
+    "ngx-bootstrap": "2.0.0-beta.9",
     "ngx-chips": "1.5.3",
     "node-sass": "^4.1.1",
     "normalize.css": "^7.0.0",
@@ -86,6 +86,7 @@
     "sass-resources-loader": "^1.2.1",
     "script-ext-html-webpack-plugin": "^1.3.2",
     "source-map-loader": "^0.2.1",
+    "source-sans-pro": "^2.0.10",
     "standard": "^10.0.0",
     "string-replace-loader": "^1.0.3",
     "style-loader": "^0.19.0",
index 8a826e7834d45e6c2e5236a623a5cfe6fd490af5..f4672c7ec5d3fe9f7f1626bbe38b72bc1d9a0362 100644 (file)
@@ -1,7 +1,7 @@
 <div class="container-fluid">
   <div class="row header">
 
-    <div class="col-md-2 col-sm-3 col-xs-3 top-left-block" [ngClass]="{ 'border-bottom': isMenuDisplayed === false }">
+    <div class="top-left-block" [ngClass]="{ 'border-bottom': isMenuDisplayed === false }">
       <div class="hamburger-block" (click)="toggleMenu()">
         <span class="glyphicon glyphicon-menu-hamburger"></span>
       </div>
       </div>
     </div>
 
-    <!-- Used for the fixed title -->
-    <div class="col-md-2 col-sm-3 col-xs-3 fake-title-block"></div>
-
-    <!-- We need to reset col-md-* because my-search is in fixed position -->
-    <my-search class="col-md-10 col-sm-9 col-xs-9"></my-search>
+    <div class="header-right">
+      <my-search></my-search>
+    </div>
   </div>
 
-  <div class="row">
-    <div class="col-md-2 col-sm-3 col-xs-3 title-menu-left">
+  <div class="row sub-header-container">
+    <div class="title-menu-left">
 
       <div class="title-menu-left-block menu">
         <my-menu *ngIf="isMenuDisplayed && isInAdmin() === false"></my-menu>
       </div>
     </div>
 
-    <!-- Used for the fixed menu -->
-    <div class="fake-menu col-md-2 col-sm-3 col-xs-3">
-    </div>
-
     <div class="main-col" [ngClass]="getMainColClasses()">
 
       <div class="main-row">
index a656d5c29812e8745a1ba5a383f32083be68c906..28e86097cc0e54476ba48598de21344bcc0b5346 100644 (file)
@@ -2,10 +2,23 @@
   min-height: calc(100vh - #{$header-height} - #{$footer-height} - #{$footer-margin});
 }
 
+.main-col {
+  margin-left: $menu-width;
+
+  &.expanded {
+    margin-left: 0;
+  }
+}
+
+.sub-header-container {
+  margin-top: $header-height;
+}
+
 .title-menu-left {
   position: fixed;
   height: calc(100vh - #{$header-height});
   padding: 0;
+  width: $menu-width;
 
   .title-menu-left-block.menu {
     height: 100%;
 
 .header {
   height: $header-height;
-
-  .fake-title-block {
-    display: inline-block;
-  }
+  position: fixed;
+  width: 100%;
+  background-color: #fff;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.16);
+  display: flex;
 
   .top-left-block {
-    z-index: 100;
-    background-color: #fff;
-    border-right: 1px solid $header-border-color;
+    width: $menu-width;
+    z-index: 1001;
     height: $header-height;
     line-height: $header-height;
     margin-top: 0;
     margin-bottom: 0;
     display: flex;
-    position: fixed;
     padding: 0;
 
-    &.border-bottom {
-      border-bottom: 1px solid $header-border-color;
-    }
-
     .hamburger-block {
-      margin-right: 15px;
-      margin-left: 15px;
+      margin-right: 10px;
+      margin-left: 25px;
 
       .glyphicon {
         cursor: pointer;
-        position: relative;
-        top: 4px;
       }
     }
 
       a {
         color: inherit !important;
         display: block;
-        background: url('../assets/logo.png') no-repeat;
-        background-size: contain;
-        background-position: center;
-        height: 100%;
-        margin: auto;
-        width: 135px;
+        background: url('../assets/logo.svg') no-repeat;
+        width: 24px;
+        height: 24px;
 
         &:hover {
           color: inherit !important;
     }
   }
 
-  my-search {
-    position: fixed;
-    z-index: 1000;
-    // Fix col-md-* padding
-    padding: 0;
-  }
-
-  .search-col {
-    height: 100%;
-    margin-left: -15px;
-    padding: 0;
+  .header-right {
+    text-align: right;
+    height: $header-height;
+    margin-left: $menu-width;
+    flex-grow: 1;
   }
 }
 
index 9b699fafdd4561bfc97c2aceed2ddfac8150986a..b1818c298eb0545b31ec433bde20c9a60516e190 100644 (file)
@@ -1,8 +1,6 @@
 import { Component, OnInit } from '@angular/core'
 import { Router } from '@angular/router'
-
 import { AuthService, ServerService } from './core'
-import { UserService } from './shared'
 
 @Component({
   selector: 'my-app',
@@ -62,20 +60,9 @@ export class AppComponent implements OnInit {
   }
 
   getMainColClasses () {
-    const colSizes = {
-      md: 10,
-      sm: 9,
-      xs: 9
-    }
-
     // Take all width is the menu is not displayed
-    if (this.isMenuDisplayed === false) {
-      Object.keys(colSizes).forEach(col => colSizes[col] = 12)
-    }
-
-    const classes = []
-    Object.keys(colSizes).forEach(col => classes.push(`col-${col}-${colSizes[col]}`))
+    if (this.isMenuDisplayed === false) return [ 'expanded' ]
 
-    return classes
+    return []
   }
 }
index e71641e0dbd3fe774979bd880bea006ae64947df..342589003ccbe75d352cd27cd4738c08aff650c2 100644 (file)
@@ -20,6 +20,7 @@ import { LoginModule } from './login'
 import { SignupModule } from './signup'
 import { SharedModule } from './shared'
 import { VideosModule } from './videos'
+import { MenuComponent, MenuAdminComponent } from './menu'
 
 export function metaFactory (): MetaLoader {
   return new MetaStaticLoader({
@@ -47,7 +48,10 @@ const APP_PROVIDERS = [
 @NgModule({
   bootstrap: [ AppComponent ],
   declarations: [
-    AppComponent
+    AppComponent,
+
+    MenuComponent,
+    MenuAdminComponent
   ],
   imports: [
     BrowserModule,
index c4ce2b637df7a4fb75cad592ac48cfefbc80d8e7..75262e6cfcbc62ccec69225c0b3b6dbfcd472b03 100644 (file)
@@ -26,17 +26,13 @@ import { throwIfAlreadyLoaded } from './module-import-guard'
   ],
 
   declarations: [
-    ConfirmComponent,
-    MenuComponent,
-    MenuAdminComponent
+    ConfirmComponent
   ],
 
   exports: [
     SimpleNotificationsModule,
 
-    ConfirmComponent,
-    MenuComponent,
-    MenuAdminComponent
+    ConfirmComponent
   ],
 
   providers: [
index 8358261ae6b9de7619e4d1a39b990de3e4eb70eb..3c01e05aafc55e70b2af9fcca6a1e3d67a216918 100644 (file)
@@ -1,6 +1,5 @@
 export * from './auth'
 export * from './server'
 export * from './confirm'
-export * from './menu'
 export * from './routing'
 export * from './core.module'
diff --git a/client/src/app/core/menu/index.ts b/client/src/app/core/menu/index.ts
deleted file mode 100644 (file)
index c905ed2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './menu.component'
-export * from './menu-admin.component'
diff --git a/client/src/app/core/menu/menu-admin.component.html b/client/src/app/core/menu/menu-admin.component.html
deleted file mode 100644 (file)
index 9857b2e..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<menu>
-  <div class="panel-block">
-    <a *ngIf="hasUsersRight()" routerLink="/admin/users" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-user"></span>
-      List users
-    </a>
-
-    <a *ngIf="hasServerFollowRight()" routerLink="/admin/follows" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-cloud"></span>
-      Manage follows
-    </a>
-
-    <a *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-alert"></span>
-      Video abuses
-    </a>
-
-    <a *ngIf="hasVideoBlacklistRight()" routerLink="/admin/video-blacklist" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-eye-close"></span>
-      Video blacklist
-    </a>
-
-    <a *ngIf="hasJobsRight()" routerLink="/admin/jobs" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-tasks"></span>
-      Jobs
-    </a>
-  </div>
-
-  <div class="panel-block">
-    <a routerLink="/videos/list" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-cog"></span>
-      Quit admin.
-    </a>
-  </div>
-</menu>
diff --git a/client/src/app/core/menu/menu-admin.component.ts b/client/src/app/core/menu/menu-admin.component.ts
deleted file mode 100644 (file)
index ea8d5f5..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import { Component } from '@angular/core'
-
-import { AuthService } from '../auth/auth.service'
-import { UserRight } from '../../../../../shared'
-
-@Component({
-  selector: 'my-menu-admin',
-  templateUrl: './menu-admin.component.html',
-  styleUrls: [ './menu.component.scss' ]
-})
-export class MenuAdminComponent {
-  constructor (private auth: AuthService) {}
-
-  hasUsersRight () {
-    return this.auth.getUser().hasRight(UserRight.MANAGE_USERS)
-  }
-
-  hasServerFollowRight () {
-    return this.auth.getUser().hasRight(UserRight.MANAGE_SERVER_FOLLOW)
-  }
-
-  hasVideoAbusesRight () {
-    return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES)
-  }
-
-  hasVideoBlacklistRight () {
-    return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
-  }
-
-  hasJobsRight () {
-    return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
-  }
-}
diff --git a/client/src/app/core/menu/menu.component.html b/client/src/app/core/menu/menu.component.html
deleted file mode 100644 (file)
index fcde23f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<menu>
-  <div class="panel-block">
-    <div class="block-title">Account</div>
-
-    <div id="panel-user-login" class="panel-button">
-      <a *ngIf="!isLoggedIn" routerLink="/login" routerLinkActive="active">
-        <span class="hidden-xs glyphicon glyphicon-log-in"></span>
-        Login
-      </a>
-
-      <a *ngIf="isLoggedIn" (click)="logout()">
-        <span class="hidden-xs glyphicon glyphicon-log-out"></span>
-        Logout
-      </a>
-    </div>
-
-    <a *ngIf="!isLoggedIn && isRegistrationAllowed()" routerLink="/signup" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-user"></span>
-      Signup
-    </a>
-
-    <a *ngIf="isLoggedIn" routerLink="/account" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-user"></span>
-      My account
-    </a>
-
-    <a *ngIf="isLoggedIn" routerLink="/videos/mine" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-folder-open"></span>
-      My videos
-    </a>
-  </div>
-
-  <div class="panel-block">
-    <div class="block-title">Videos</div>
-
-    <a routerLink="/videos/list" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-list"></span>
-      See videos
-    </a>
-
-    <a *ngIf="isLoggedIn" routerLink="/videos/upload" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-cloud-upload"></span>
-      Upload a video
-    </a>
-  </div>
-
-  <div *ngIf="userHasAdminAccess" class="panel-block">
-    <div class="block-title">Other</div>
-
-    <a [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active">
-      <span class="hidden-xs glyphicon glyphicon-cog"></span>
-      Administration
-    </a>
-  </div>
-</menu>
diff --git a/client/src/app/core/menu/menu.component.scss b/client/src/app/core/menu/menu.component.scss
deleted file mode 100644 (file)
index 45679c3..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-menu {
-  background-color: $black-background;
-  padding: 15px;
-  margin: 0;
-  height: 100%;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  overflow: hidden;
-  z-index: 1000;
-
-  @media screen and (max-width: 550px) {
-    font-size: 90%;
-  }
-
-  @media screen and (min-width: 1200px) {
-    padding: 25px;
-  }
-
-  .panel-block {
-    margin-bottom: 15px;
-  }
-
-  .block-title {
-    text-transform: uppercase;
-    font-weight: bold;
-    color: $menu-color-block;
-    margin-bottom: 10px;
-  }
-
-  a {
-    display: block;
-    margin-left: 5px;
-    height: 30px;
-    color: $menu-color-link;
-    cursor: pointer;
-    transition: color 0.3s;
-
-    &:hover, &:focus {
-      text-decoration: none !important;
-      outline: none !important;
-    }
-
-    .glyphicon {
-      margin-right: 15px;
-    }
-
-    &:hover, &.active {
-      color: #fff;
-    }
-  }
-}
diff --git a/client/src/app/core/menu/menu.component.ts b/client/src/app/core/menu/menu.component.ts
deleted file mode 100644 (file)
index d2bd715..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-import { Component, OnInit } from '@angular/core'
-import { Router } from '@angular/router'
-
-import { AuthService, AuthStatus } from '../auth'
-import { ServerService } from '../server'
-import { UserRight } from '../../../../../shared/models/users/user-right.enum'
-
-@Component({
-  selector: 'my-menu',
-  templateUrl: './menu.component.html',
-  styleUrls: [ './menu.component.scss' ]
-})
-export class MenuComponent implements OnInit {
-  isLoggedIn: boolean
-  userHasAdminAccess = false
-
-  private routesPerRight = {
-    [UserRight.MANAGE_USERS]: '/admin/users',
-    [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
-    [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/video-abuses',
-    [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/video-blacklist'
-  }
-
-  constructor (
-    private authService: AuthService,
-    private serverService: ServerService,
-    private router: Router
-  ) {}
-
-  ngOnInit () {
-    this.isLoggedIn = this.authService.isLoggedIn()
-    this.computeIsUserHasAdminAccess()
-
-    this.authService.loginChangedSource.subscribe(
-      status => {
-        if (status === AuthStatus.LoggedIn) {
-          this.isLoggedIn = true
-          this.computeIsUserHasAdminAccess()
-          console.log('Logged in.')
-        } else if (status === AuthStatus.LoggedOut) {
-          this.isLoggedIn = false
-          this.computeIsUserHasAdminAccess()
-          console.log('Logged out.')
-        } else {
-          console.error('Unknown auth status: ' + status)
-        }
-      }
-    )
-  }
-
-  isRegistrationAllowed () {
-    return this.serverService.getConfig().signup.allowed
-  }
-
-  getFirstAdminRightAvailable () {
-    const user = this.authService.getUser()
-    if (!user) return undefined
-
-    const adminRights = [
-      UserRight.MANAGE_USERS,
-      UserRight.MANAGE_SERVER_FOLLOW,
-      UserRight.MANAGE_VIDEO_ABUSES,
-      UserRight.MANAGE_VIDEO_BLACKLIST
-    ]
-
-    for (const adminRight of adminRights) {
-      if (user.hasRight(adminRight)) {
-        return adminRight
-      }
-    }
-
-    return undefined
-  }
-
-  getFirstAdminRouteAvailable () {
-    const right = this.getFirstAdminRightAvailable()
-
-    return this.routesPerRight[right]
-  }
-
-  logout () {
-    this.authService.logout()
-    // Redirect to home page
-    this.router.navigate(['/videos/list'])
-  }
-
-  private computeIsUserHasAdminAccess () {
-    const right = this.getFirstAdminRightAvailable()
-
-    this.userHasAdminAccess = right !== undefined
-  }
-}
diff --git a/client/src/app/menu/index.ts b/client/src/app/menu/index.ts
new file mode 100644 (file)
index 0000000..c905ed2
--- /dev/null
@@ -0,0 +1,2 @@
+export * from './menu.component'
+export * from './menu-admin.component'
diff --git a/client/src/app/menu/menu-admin.component.html b/client/src/app/menu/menu-admin.component.html
new file mode 100644 (file)
index 0000000..9857b2e
--- /dev/null
@@ -0,0 +1,35 @@
+<menu>
+  <div class="panel-block">
+    <a *ngIf="hasUsersRight()" routerLink="/admin/users" routerLinkActive="active">
+      <span class="hidden-xs glyphicon glyphicon-user"></span>
+      List users
+    </a>
+
+    <a *ngIf="hasServerFollowRight()" routerLink="/admin/follows" routerLinkActive="active">
+      <span class="hidden-xs glyphicon glyphicon-cloud"></span>
+      Manage follows
+    </a>
+
+    <a *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active">
+      <span class="hidden-xs glyphicon glyphicon-alert"></span>
+      Video abuses
+    </a>
+
+    <a *ngIf="hasVideoBlacklistRight()" routerLink="/admin/video-blacklist" routerLinkActive="active">
+      <span class="hidden-xs glyphicon glyphicon-eye-close"></span>
+      Video blacklist
+    </a>
+
+    <a *ngIf="hasJobsRight()" routerLink="/admin/jobs" routerLinkActive="active">
+      <span class="hidden-xs glyphicon glyphicon-tasks"></span>
+      Jobs
+    </a>
+  </div>
+
+  <div class="panel-block">
+    <a routerLink="/videos/list" routerLinkActive="active">
+      <span class="hidden-xs glyphicon glyphicon-cog"></span>
+      Quit admin.
+    </a>
+  </div>
+</menu>
diff --git a/client/src/app/menu/menu-admin.component.ts b/client/src/app/menu/menu-admin.component.ts
new file mode 100644 (file)
index 0000000..1babf5e
--- /dev/null
@@ -0,0 +1,33 @@
+import { Component } from '@angular/core'
+
+import { AuthService } from '../core/auth/auth.service'
+import { UserRight } from '../../../../shared'
+
+@Component({
+  selector: 'my-menu-admin',
+  templateUrl: './menu-admin.component.html',
+  styleUrls: [ './menu.component.scss' ]
+})
+export class MenuAdminComponent {
+  constructor (private auth: AuthService) {}
+
+  hasUsersRight () {
+    return this.auth.getUser().hasRight(UserRight.MANAGE_USERS)
+  }
+
+  hasServerFollowRight () {
+    return this.auth.getUser().hasRight(UserRight.MANAGE_SERVER_FOLLOW)
+  }
+
+  hasVideoAbusesRight () {
+    return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES)
+  }
+
+  hasVideoBlacklistRight () {
+    return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
+  }
+
+  hasJobsRight () {
+    return this.auth.getUser().hasRight(UserRight.MANAGE_JOBS)
+  }
+}
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html
new file mode 100644 (file)
index 0000000..bb0caae
--- /dev/null
@@ -0,0 +1,48 @@
+<menu>
+  <div *ngIf="isLoggedIn" class="logged-in-block">
+    <div class="logged-in-info">
+      <div class="logged-in-username">{{ user.username  }}</div>
+      <div class="logged-in-email">{{ user.email }}</div>
+    </div>
+
+    <div class="logged-in-more" dropdown placement="right" container="body">
+      <span class="glyphicon glyphicon-option-vertical" dropdownToggle></span>
+
+      <ul *dropdownMenu class="dropdown-menu">
+        <li>
+          <a (click)="logout($event)" class="dropdown-item" title="Log out" href="#">
+            Log out
+          </a>
+        </li>
+      </ul>
+    </div>
+  </div>
+
+  <div *ngIf="!isLoggedIn" class="button-block">
+    <a routerLink="/login"class="login-button">Login</a>
+    <a *ngIf="isRegistrationAllowed()" routerLink="/signup" class="create-account-button">Create an account</a>
+  </div>
+
+  <div class="panel-block">
+    <div class="block-title">Videos</div>
+
+    <a routerLink="/videos/list" routerLinkActive="active">
+      <span class="icon icon-videos-trending"></span>
+      Trending
+    </a>
+
+    <a routerLink="/videos/list" routerLinkActive="active">
+      <span class="icon icon-videos-recently-added"></span>
+      Recently added
+    </a>
+  </div>
+
+  <div *ngIf="userHasAdminAccess" class="panel-block">
+    <div class="block-title">More</div>
+
+    <a [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active">
+      <span class="icon icon-administration"></span>
+      Administration
+    </a>
+  </div>
+</menu>
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss
new file mode 100644 (file)
index 0000000..8a49106
--- /dev/null
@@ -0,0 +1,131 @@
+menu {
+  background-color: $black-background;
+  margin: 0;
+  padding: 0;
+  height: 100%;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  z-index: 1000;
+  color: $menu-color;
+
+  @media screen and (max-width: 550px) {
+    font-size: 90%;
+  }
+
+  .logged-in-block {
+    height: 100px;
+    background-color: rgba(255, 255, 255, 0.15);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 35px;
+
+    .logged-in-info {
+      flex-grow: 1;
+      margin-left: 40px;
+
+      .logged-in-username {
+        font-size: 16px;
+        font-weight: $font-semibold;
+      }
+
+      .logged-in-email {
+        font-size: 13px;
+        color: #C6C6C6;
+      }
+    }
+
+    .logged-in-more {
+      margin-right: 20px;
+
+      .glyphicon {
+        cursor: pointer;
+        font-size: 18px;
+      }
+    }
+  }
+
+  .button-block {
+    margin: 30px 25px 35px 25px;
+
+    .login-button, .create-account-button {
+      font-weight: $font-semibold;
+      font-size: 15px;
+      height: $button-height;
+      line-height: $button-height;
+      width: 190px;
+      border-radius: 3px;
+      text-align: center;
+
+      &.login-button {
+        background-color: $orange-color;
+        margin-bottom: 10px;
+      }
+
+      &.create-account-button {
+        background-color: rgba(255, 255, 255, 0.25);
+      }
+    }
+  }
+
+  .block-title {
+    text-transform: uppercase;
+    font-weight: $font-bold; // Bold
+    font-size: 13px;
+    margin-bottom: 25px;
+  }
+
+  .panel-block {
+    margin-bottom: 45px;
+    margin-left: 26px;
+
+    a {
+      display: flex;
+
+      .icon {
+        width: 22px;
+        height: 22px;
+        display: inline-block;
+        margin-right: 18px;
+        background-size: contain;
+
+        &.icon-videos-trending {
+          position: relative;
+          top: -2px;
+          background-image: url('../../assets/menu/trending.svg');
+        }
+
+        &.icon-videos-recently-added {
+          width: 23px;
+          height: 23px;
+          position: relative;
+          top: -1px;
+          background-image: url('../../assets/menu/recently-added.svg');
+        }
+
+        &.icon-administration {
+          width: 23px;
+          height: 23px;
+
+          background-image: url('../../assets/menu/administration.svg');
+        }
+      }
+    }
+  }
+
+  a {
+    color: $menu-color;
+    height: 22px;
+    line-height: 22px;
+    display: block;
+    font-size: 16px;
+    cursor: pointer;
+    margin-bottom: 15px;
+
+    &:hover, &:focus {
+      text-decoration: none !important;
+      outline: none !important;
+    }
+  }
+}
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts
new file mode 100644 (file)
index 0000000..4c35bb3
--- /dev/null
@@ -0,0 +1,97 @@
+import { Component, OnInit } from '@angular/core'
+import { Router } from '@angular/router'
+import { UserRight } from '../../../../shared/models/users/user-right.enum'
+import { AuthService, AuthStatus, ServerService } from '../core'
+import { User } from '../shared/users/user.model'
+
+@Component({
+  selector: 'my-menu',
+  templateUrl: './menu.component.html',
+  styleUrls: [ './menu.component.scss' ]
+})
+export class MenuComponent implements OnInit {
+  user: User
+  isLoggedIn: boolean
+  userHasAdminAccess = false
+
+  private routesPerRight = {
+    [UserRight.MANAGE_USERS]: '/admin/users',
+    [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
+    [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/video-abuses',
+    [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/video-blacklist'
+  }
+
+  constructor (
+    private authService: AuthService,
+    private serverService: ServerService,
+    private router: Router
+  ) {}
+
+  ngOnInit () {
+    this.isLoggedIn = this.authService.isLoggedIn()
+    if (this.isLoggedIn === true) this.user = this.authService.getUser()
+    this.computeIsUserHasAdminAccess()
+
+    this.authService.loginChangedSource.subscribe(
+      status => {
+        if (status === AuthStatus.LoggedIn) {
+          this.isLoggedIn = true
+          this.user = this.authService.getUser()
+          this.computeIsUserHasAdminAccess()
+          console.log('Logged in.')
+        } else if (status === AuthStatus.LoggedOut) {
+          this.isLoggedIn = false
+          this.user = undefined
+          this.computeIsUserHasAdminAccess()
+          console.log('Logged out.')
+        } else {
+          console.error('Unknown auth status: ' + status)
+        }
+      }
+    )
+  }
+
+  isRegistrationAllowed () {
+    return this.serverService.getConfig().signup.allowed
+  }
+
+  getFirstAdminRightAvailable () {
+    const user = this.authService.getUser()
+    if (!user) return undefined
+
+    const adminRights = [
+      UserRight.MANAGE_USERS,
+      UserRight.MANAGE_SERVER_FOLLOW,
+      UserRight.MANAGE_VIDEO_ABUSES,
+      UserRight.MANAGE_VIDEO_BLACKLIST
+    ]
+
+    for (const adminRight of adminRights) {
+      if (user.hasRight(adminRight)) {
+        return adminRight
+      }
+    }
+
+    return undefined
+  }
+
+  getFirstAdminRouteAvailable () {
+    const right = this.getFirstAdminRightAvailable()
+
+    return this.routesPerRight[right]
+  }
+
+  logout (event: Event) {
+    event.preventDefault()
+
+    this.authService.logout()
+    // Redirect to home page
+    this.router.navigate(['/videos/list'])
+  }
+
+  private computeIsUserHasAdminAccess () {
+    const right = this.getFirstAdminRightAvailable()
+
+    this.userHasAdminAccess = right !== undefined
+  }
+}
index 75e9dfa5920be1953c18b97f8c45517322ee3e5c..0e3de150cea7a1444765e57a63bf770dc19d75f8 100644 (file)
@@ -1,22 +1,6 @@
-<div class="input-group">
+<input
+  type="text" id="search-video" name="search-video" placeholder="Search"
+  [(ngModel)]="searchCriteria.value" (keyup.enter)="doSearch()"
+>
 
-  <span class="hidden-xs input-group-addon icon-addon">
-    <span class="glyphicon glyphicon-search"></span>
-  </span>
-
-  <input
-    type="text" id="search-video" name="search-video" class="form-control" placeholder="Search" class="form-control"
-    [(ngModel)]="searchCriteria.value" (keyup.enter)="doSearch()"
-  >
-
-  <div class="input-group-btn" dropdown placement="bottom right">
-    <button id="simple-btn-keyboard-nav" type="button" class="btn btn-default" dropdownToggle>
-      {{ getStringChoice(searchCriteria.field) }} <span class="caret"></span>
-    </button>
-    <ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="simple-btn-keyboard-nav" *dropdownMenu>
-      <li *ngFor="let choice of choiceKeys" class="dropdown-item" role="menu-item">
-        <a class="dropdown-item" href="#" (click)="choose($event, choice)">{{ getStringChoice(choice) }}</a>
-      </li>
-    </ul>
-  </div>
-</div>
+<a routerLink="/videos/upload">Upload</a>
index 583f9586f0a5ce99cf1d370cb82ebbc3fe043e2f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,51 +0,0 @@
-.icon-addon {
-  background-color: #fff;
-  border-radius: 0;
-  border-color: $header-border-color;
-  border-width: 0 0 1px 0;
-  text-align: right;
-
-  .glyphicon-search {
-    width: 30px;
-    font-size: 20px;
-  }
-}
-
-input, button, .input-group {
-  height: 100%;
-}
-
-input, .input-group-btn {
-  border-radius: 0;
-  border-top: none;
-  border-left: none;
-}
-
-input {
-  height: $header-height;
-  border-right: none;
-  font-weight: bold;
-  box-shadow: none;
-
-  &, &:focus {
-    border-bottom: 1px solid $header-border-color !important;
-    outline: none !important;
-    box-shadow: none !important;
-  }
-}
-
-button {
-
-  &, &:hover, &:focus, &:active, &:visited {
-    background-color: #fff !important;
-    border-color: $header-border-color !important;
-    color: #858585 !important;
-    outline: none !important;
-
-    height: $header-height;
-    border-width: 0 0 1px 0;
-    font-weight: bold;
-    text-decoration: none;
-    box-shadow: none;
-  }
-}
diff --git a/client/src/assets/logo.png b/client/src/assets/logo.png
deleted file mode 100644 (file)
index c1d77a2..0000000
Binary files a/client/src/assets/logo.png and /dev/null differ
diff --git a/client/src/assets/logo.svg b/client/src/assets/logo.svg
new file mode 100644 (file)
index 0000000..8777acd
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   viewBox="2799 -911 16 22"
+   version="1.1"
+   id="svg13"
+   sodipodi:docname="logo.svg"
+   width="16"
+   height="22"
+   inkscape:version="0.92.2 5c3e80d, 2017-08-06">
+  <metadata
+     id="metadata17">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1916"
+     inkscape:window-height="1040"
+     id="namedview15"
+     showgrid="false"
+     inkscape:zoom="29.790476"
+     inkscape:cx="-1.1827326"
+     inkscape:cy="12.088"
+     inkscape:window-x="0"
+     inkscape:window-y="18"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg13" />
+  <defs
+     id="defs4">
+    <style
+       id="style2">
+      .cls-3 {
+        fill: #211f20;
+      }
+
+      .cls-4 {
+        fill: #737373;
+      }
+
+      .cls-5 {
+        fill: #f1680d;
+      }
+
+      .cls-6 {
+        fill: #fff;
+      }
+    </style>
+  </defs>
+  <g
+     id="Artboard_1"
+     data-name="Artboard – 1"
+     class="cls-1"
+     transform="translate(0.03356777,-1.9929667)">
+    <g
+       id="Symbol_3_1"
+       data-name="Symbol 3 – 1"
+       transform="translate(2759,-975)">
+      <g
+         id="Group_44"
+         data-name="Group 44"
+         transform="translate(0,2.333)">
+        <path
+           id="Path_4"
+           data-name="Path 4"
+           class="cls-3"
+           d="m -949,-500 v 10.667 l 8,-5.333"
+           transform="translate(989,564)"
+           inkscape:connector-curvature="0"
+           style="fill:#211f20" />
+        <path
+           id="Path_5"
+           data-name="Path 5"
+           class="cls-4"
+           d="m -949,-500 v 10.667 l 8,-5.333"
+           transform="translate(989,574.667)"
+           inkscape:connector-curvature="0"
+           style="fill:#737373" />
+        <path
+           id="Path_6"
+           data-name="Path 6"
+           class="cls-5"
+           d="m -949,-500 v 10.667 l 8,-5.333"
+           transform="translate(997,569.333)"
+           inkscape:connector-curvature="0"
+           style="fill:#f1680d" />
+        <path
+           id="Path_7"
+           data-name="Path 7"
+           class="cls-6"
+           d="M 0,0 V 10.667 L 8,5.333 Z"
+           transform="rotate(180,24,40)"
+           inkscape:connector-curvature="0"
+           style="fill:#ffffff" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/client/src/assets/menu/administration.svg b/client/src/assets/menu/administration.svg
new file mode 100644 (file)
index 0000000..b6da837
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
+    <title>filter</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Artboard-4" transform="translate(-444.000000, -247.000000)" fill="#808080">
+            <g id="70" transform="translate(444.000000, 247.000000)">
+                <path d="M8.82929429,17 L20.0066023,17 C20.5552407,17 21,17.4438648 21,18 C21,18.5522847 20.5550537,19 20.0066023,19 L8.82929429,19 C8.41745788,20.1651924 7.30621883,21 6,21 C4.34314575,21 3,19.6568542 3,18 C3,16.3431458 4.34314575,15 6,15 C7.30621883,15 8.41745788,15.8348076 8.82929429,17 Z M9.17070571,13 L3.99339768,13 C3.44475929,13 3,12.5561352 3,12 C3,11.4477153 3.44494629,11 3.99339768,11 L9.17070571,11 C9.58254212,9.83480763 10.6937812,9 12,9 C13.3062188,9 14.4174579,9.83480763 14.8292943,11 L20.0066023,11 C20.5552407,11 21,11.4438648 21,12 C21,12.5522847 20.5550537,13 20.0066023,13 L14.8292943,13 C14.4174579,14.1651924 13.3062188,15 12,15 C10.6937812,15 9.58254212,14.1651924 9.17070571,13 Z M15.1659641,6.98648118 C15.1124525,6.99537358 15.05751,7 15.0014977,7 L3.99850233,7 C3.44704472,7 3,6.55613518 3,6 C3,5.44771525 3.44748943,5 3.99850233,5 L15.0014977,5 C15.0575314,5 15.1124871,5.00458274 15.1660053,5.01340035 C15.5740343,3.84121344 16.6887792,3 18,3 C19.6568542,3 21,4.34314575 21,6 C21,7.65685425 19.6568542,9 18,9 C16.688735,9 15.5739592,8.15872988 15.1659641,6.98648118 Z M18,7 C18.5522847,7 19,6.55228475 19,6 C19,5.44771525 18.5522847,5 18,5 C17.4477153,5 17,5.44771525 17,6 C17,6.55228475 17.4477153,7 18,7 Z M12,13 C12.5522847,13 13,12.5522847 13,12 C13,11.4477153 12.5522847,11 12,11 C11.4477153,11 11,11.4477153 11,12 C11,12.5522847 11.4477153,13 12,13 Z M6,19 C6.55228475,19 7,18.5522847 7,18 C7,17.4477153 6.55228475,17 6,17 C5.44771525,17 5,17.4477153 5,18 C5,18.5522847 5.44771525,19 6,19 Z" id="Combined-Shape"></path>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/client/src/assets/menu/recently-added.svg b/client/src/assets/menu/recently-added.svg
new file mode 100644 (file)
index 0000000..6473837
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Artboard-4" transform="translate(-92.000000, -115.000000)">
+            <g id="2" transform="translate(92.000000, 115.000000)">
+                <circle id="Oval-1" stroke="#808080" stroke-width="2" cx="12" cy="12" r="10"></circle>
+                <rect id="Rectangle-1" fill="#808080" x="11" y="7" width="2" height="10" rx="1"></rect>
+                <rect id="Rectangle-1" fill="#808080" x="7" y="11" width="10" height="2" rx="1"></rect>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/client/src/assets/menu/trending.svg b/client/src/assets/menu/trending.svg
new file mode 100644 (file)
index 0000000..ffc65cc
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
+    <title>graph</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
+        <g id="Artboard-4" transform="translate(-444.000000, -203.000000)" stroke-width="2" stroke="#808080">
+            <g id="50" transform="translate(444.000000, 203.000000)">
+                <polyline id="Path-96" points="3 3 3 21.006249 21.0246733 21.006249"></polyline>
+                <polyline id="Path-101" points="6 18 11 12 14 13 19 7"></polyline>
+                <polygon id="Path-102" points="20 9 20 6 17 6"></polygon>
+            </g>
+        </g>
+    </g>
+</svg>
index f0ffb43ba9c461f09f8636bbadb580b0bdcf2b19..640746722f35eb0a0b2e9f91206b855b794470ff 100644 (file)
@@ -1,12 +1,19 @@
+$font-regular: 400;
+$font-semibold: 600;
+$font-bold: 700;
+
 $grey-color: #555;
+$orange-color: #F1680D;
 
-$black-background: #1d2125;
+$black-background: #000;
 $grey-background: #f6f2f2;
 
-$menu-color-link: #9cabb8;
-$menu-color-block: #686f77;
+$button-height: 30px;
+
+$menu-color: #fff;
+$menu-width: 240px;
 
-$header-height: 65px;
+$header-height: 50px;
 $header-border-color: #e9eff6;
 
 $footer-height: 30px;
index 47e1b6df04c4d6863a3d9bd538ff887b5442d93b..58f07612bfaa299476cf8fb2601ba38e81fbedaa 100644 (file)
@@ -1,3 +1,5 @@
+$FontPathSourceSansPro: "../fonts/source-sans-pro";
+@import '~source-sans-pro/source-sans-pro';
 @import '~primeng/resources/themes/bootstrap/theme.css';
 @import '~primeng/resources/primeng.css';
 @import '~video.js/dist/video-js.css';
@@ -7,6 +9,12 @@
   display: none !important;
 }
 
+body {
+  font-family: 'Source Sans Pro';
+  font-weight: $font-regular;
+  color: #000;
+}
+
 input.readonly {
   /* Force blank on readonly inputs */
   background-color: #fff !important;
index c5a47bb89d44d7655d7da3316e75db587b12140a..8f148e431b5c766c2691b83063d8173bfce37457 100644 (file)
@@ -4708,9 +4708,9 @@ ngc-webpack@3.2.2:
     source-map "^0.5.6"
     ts-node "^3.2.0"
 
-ngx-bootstrap@1.9.3:
-  version "1.9.3"
-  resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-1.9.3.tgz#28e75d14fb1beaee609383d7694de4eb3ba03b26"
+ngx-bootstrap@2.0.0-beta.9:
+  version "2.0.0-beta.9"
+  resolved "https://registry.yarnpkg.com/ngx-bootstrap/-/ngx-bootstrap-2.0.0-beta.9.tgz#9aa7c88269534e7a5440481f31b137549f749796"
 
 ngx-chips@1.5.3:
   version "1.5.3"
@@ -6602,6 +6602,10 @@ source-map@^0.6.1, source-map@~0.6.1:
   version "0.6.1"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
 
+source-sans-pro@^2.0.10:
+  version "2.0.10"
+  resolved "https://registry.yarnpkg.com/source-sans-pro/-/source-sans-pro-2.0.10.tgz#c1ca859cf164a088944c5e83745085e87cd533a9"
+
 spdx-correct@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"