Playlist videos component
authorChocobozzz <me@florianbigard.com>
Mon, 11 Mar 2019 15:23:33 +0000 (16:23 +0100)
committerChocobozzz <chocobozzz@cpy.re>
Mon, 18 Mar 2019 10:17:59 +0000 (11:17 +0100)
20 files changed:
client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.html
client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.scss
client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component.ts
client/src/app/menu/menu.component.html
client/src/app/menu/menu.component.scss
client/src/app/shared/buttons/action-dropdown.component.html
client/src/app/shared/images/global-icon.component.ts
client/src/app/shared/video-playlist/video-add-to-playlist.component.html
client/src/app/shared/video-playlist/video-add-to-playlist.component.scss
client/src/app/shared/video-playlist/video-playlist-miniature.component.scss
client/src/app/shared/video/video.model.ts
client/src/app/videos/+video-watch/video-watch.component.html
client/src/app/videos/+video-watch/video-watch.component.scss
client/src/assets/images/global/more-horizontal.html [new file with mode: 0644]
client/src/assets/images/global/more-vertical.html [new file with mode: 0644]
client/src/assets/images/video/more.html [deleted file]
client/src/sass/include/_miniature.scss
client/src/sass/include/_mixins.scss
client/src/sass/primeng-custom.scss
shared/models/videos/video.model.ts

index 28ea7a857e5e4f11ffa571fbd2021a7140a7a285..e2d09a36d575ea16732a471d88bf4abf8bc0d4de 100644 (file)
@@ -1,16 +1,61 @@
-<div class="no-results">No videos in this playlist.</div>
+<div i18n class="no-results" *ngIf="pagination.totalItems === 0">No videos in this playlist.</div>
 
 <div class="videos" myInfiniteScroller (nearOfBottom)="onNearOfBottom()">
   <div *ngFor="let video of videos" class="video">
-    <my-video-thumbnail [video]="video"></my-video-thumbnail>
+    <div class="position">{{ video.playlistElement.position }}</div>
 
-    <div class="video-info">
-      <div class="position">{{ video.playlistElement.position }}</div>
-
-      <a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
+    <my-video-thumbnail [video]="video" [nsfw]="isVideoBlur(video)"></my-video-thumbnail>
 
+    <div class="video-info">
       <a tabindex="-1" class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a>
       <a tabindex="-1" class="video-info-account" [routerLink]="[ '/accounts', video.byAccount ]">{{ video.byAccount }}</a>
+      <span tabindex="-1" class="video-info-timestamp">{{ formatTimestamp(video)}}</span>
+    </div>
+
+    <div class="more" ngbDropdown #moreDropdown="ngbDropdown" placement="bottom-right" (openChange)="onDropdownOpenChange()" autoClose="outside">
+      <my-global-icon iconName="more-vertical" ngbDropdownToggle role="button" class="icon-more"></my-global-icon>
+
+      <div ngbDropdownMenu>
+        <div class="dropdown-item" (click)="toggleDisplayTimestampsOptions($event, video)">
+          <my-global-icon iconName="edit"></my-global-icon> <ng-container i18n>Edit starts/stops at</ng-container>
+        </div>
+
+        <div class="timestamp-options" *ngIf="displayTimestampOptions">
+          <div>
+            <my-peertube-checkbox
+              inputName="startAt" [(ngModel)]="timestampOptions.startTimestampEnabled"
+              i18n-labelText labelText="Start at"
+            ></my-peertube-checkbox>
+
+            <my-timestamp-input
+              [timestamp]="timestampOptions.startTimestamp"
+              [maxTimestamp]="video.duration"
+              [disabled]="!timestampOptions.startTimestampEnabled"
+              [(ngModel)]="timestampOptions.startTimestamp"
+            ></my-timestamp-input>
+          </div>
+
+          <div>
+            <my-peertube-checkbox
+              inputName="stopAt" [(ngModel)]="timestampOptions.stopTimestampEnabled"
+              i18n-labelText labelText="Stop at"
+            ></my-peertube-checkbox>
+
+            <my-timestamp-input
+              [timestamp]="timestampOptions.stopTimestamp"
+              [maxTimestamp]="video.duration"
+              [disabled]="!timestampOptions.stopTimestampEnabled"
+              [(ngModel)]="timestampOptions.stopTimestamp"
+            ></my-timestamp-input>
+          </div>
+
+          <input type="submit" i18n-value value="Save" (click)="updateTimestamps(video)">
+        </div>
+
+        <span class="dropdown-item" (click)="removeFromPlaylist(video)">
+          <my-global-icon iconName="delete"></my-global-icon> <ng-container i18n>Delete from {{playlist?.displayName}}</ng-container>
+        </span>
+      </div>
     </div>
   </div>
 </div>
index 5e6774739fb643993a1068a8f5cc0ab97b73bdfe..3be10078e217cc129132a614d30c522c5d1867d6 100644 (file)
@@ -1,2 +1,96 @@
 @import '_variables';
 @import '_mixins';
+@import '_miniature';
+
+.videos {
+  .video {
+    display: flex;
+    align-items: center;
+    padding: 10px;
+    border-bottom: 1px solid $separator-border-color;
+
+    &:hover {
+      background-color: rgba(0, 0, 0, 0.05);
+
+      .more {
+        display: block;
+      }
+    }
+
+    .position {
+      font-weight: $font-semibold;
+      margin-right: 10px;
+      color: $grey-foreground-color;
+    }
+
+    my-video-thumbnail {
+      display: flex; // Avoids an issue with line-height that adds space below the element
+      margin-right: 10px;
+
+      /deep/ .video-thumbnail {
+        @include miniature-thumbnail(130px, 72px);
+      }
+    }
+
+    .video-info {
+      display: flex;
+      flex-direction: column;
+
+      a {
+        @include disable-default-a-behaviour;
+
+        color: var(--mainForegroundColor);
+      }
+
+      .video-info-name {
+        font-size: 18px;
+        font-weight: $font-semibold;
+      }
+
+      .video-info-account, .video-info-timestamp {
+        color: $grey-foreground-color;
+      }
+    }
+
+    .more {
+      justify-self: flex-end;
+      margin-left: auto;
+      cursor: pointer;
+      display: none;
+
+      &.show {
+        display: block;
+      }
+
+      .icon-more {
+        @include apply-svg-color($grey-foreground-color);
+
+        &::after {
+          border: none;
+        }
+      }
+
+      .dropdown-item {
+        @include dropdown-with-icon-item;
+      }
+
+      .timestamp-options {
+        padding-top: 0;
+        padding-left: 35px;
+        margin-bottom: 15px;
+
+        > div {
+          display: flex;
+          align-items: center;
+        }
+
+        input {
+          @include peertube-button;
+          @include orange-button;
+
+          margin-top: 10px;
+        }
+      }
+    }
+  }
+}
index 8b70a9b1abbe94582aaf043816be68398ae77e3e..76aff3d4fc0c3aab8d4f9e772924dfe1daeb4323 100644 (file)
@@ -1,5 +1,5 @@
-import { Component, OnDestroy, OnInit } from '@angular/core'
-import { Notifier } from '@app/core'
+import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
+import { Notifier, ServerService } from '@app/core'
 import { AuthService } from '../../core/auth'
 import { ConfirmService } from '../../core/confirm'
 import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
@@ -7,6 +7,12 @@ import { Video } from '@app/shared/video/video.model'
 import { Subscription } from 'rxjs'
 import { ActivatedRoute } from '@angular/router'
 import { VideoService } from '@app/shared/video/video.service'
+import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
+import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { secondsToTime } from '../../../assets/player/utils'
+import { VideoPlaylistElementUpdate } from '@shared/models'
+import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
 
 @Component({
   selector: 'my-account-video-playlist-elements',
@@ -14,7 +20,10 @@ import { VideoService } from '@app/shared/video/video.service'
   styleUrls: [ './my-account-video-playlist-elements.component.scss' ]
 })
 export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestroy {
+  @ViewChild('moreDropdown') moreDropdown: NgbDropdown
+
   videos: Video[] = []
+  playlist: VideoPlaylist
 
   pagination: ComponentPagination = {
     currentPage: 1,
@@ -22,21 +31,35 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
     totalItems: null
   }
 
+  displayTimestampOptions = false
+
+  timestampOptions: {
+    startTimestampEnabled: boolean
+    startTimestamp: number
+    stopTimestampEnabled: boolean
+    stopTimestamp: number
+  } = {} as any
+
   private videoPlaylistId: string | number
   private paramsSub: Subscription
 
   constructor (
     private authService: AuthService,
+    private serverService: ServerService,
     private notifier: Notifier,
     private confirmService: ConfirmService,
     private route: ActivatedRoute,
-    private videoService: VideoService
+    private i18n: I18n,
+    private videoService: VideoService,
+    private videoPlaylistService: VideoPlaylistService
   ) {}
 
   ngOnInit () {
     this.paramsSub = this.route.params.subscribe(routeParams => {
       this.videoPlaylistId = routeParams[ 'videoPlaylistId' ]
       this.loadElements()
+
+      this.loadPlaylistInfo()
     })
   }
 
@@ -44,6 +67,46 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
     if (this.paramsSub) this.paramsSub.unsubscribe()
   }
 
+  isVideoBlur (video: Video) {
+    return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig())
+  }
+
+  removeFromPlaylist (video: Video) {
+    this.videoPlaylistService.removeVideoFromPlaylist(this.playlist.id, video.id)
+        .subscribe(
+          () => {
+            this.notifier.success(this.i18n('Video removed from {{name}}', { name: this.playlist.displayName }))
+
+            this.videos = this.videos.filter(v => v.id !== video.id)
+          },
+
+          err => this.notifier.error(err.message)
+        )
+
+    this.moreDropdown.close()
+  }
+
+  updateTimestamps (video: Video) {
+    const body: VideoPlaylistElementUpdate = {}
+
+    body.startTimestamp = this.timestampOptions.startTimestampEnabled ? this.timestampOptions.startTimestamp : null
+    body.stopTimestamp = this.timestampOptions.stopTimestampEnabled ? this.timestampOptions.stopTimestamp : null
+
+    this.videoPlaylistService.updateVideoOfPlaylist(this.playlist.id, video.id, body)
+        .subscribe(
+          () => {
+            this.notifier.success(this.i18n('Timestamps updated'))
+
+            video.playlistElement.startTimestamp = body.startTimestamp
+            video.playlistElement.stopTimestamp = body.stopTimestamp
+          },
+
+          err => this.notifier.error(err.message)
+        )
+
+    this.moreDropdown.close()
+  }
+
   onNearOfBottom () {
     // Last page
     if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
@@ -52,6 +115,50 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
     this.loadElements()
   }
 
+  formatTimestamp (video: Video) {
+    const start = video.playlistElement.startTimestamp
+    const stop = video.playlistElement.stopTimestamp
+
+    const startFormatted = secondsToTime(start, true, ':')
+    const stopFormatted = secondsToTime(stop, true, ':')
+
+    if (start === null && stop === null) return ''
+
+    if (start !== null && stop === null) return this.i18n('Starts at ') + startFormatted
+    if (start === null && stop !== null) return this.i18n('Stops at ') + stopFormatted
+
+    return this.i18n('Starts at ') + startFormatted + this.i18n(' and stops at ') + stopFormatted
+  }
+
+  onDropdownOpenChange () {
+    this.displayTimestampOptions = false
+  }
+
+  toggleDisplayTimestampsOptions (event: Event, video: Video) {
+    event.preventDefault()
+
+    this.displayTimestampOptions = !this.displayTimestampOptions
+
+    if (this.displayTimestampOptions === true) {
+      this.timestampOptions = {
+        startTimestampEnabled: false,
+        stopTimestampEnabled: false,
+        startTimestamp: 0,
+        stopTimestamp: video.duration
+      }
+
+      if (video.playlistElement.startTimestamp) {
+        this.timestampOptions.startTimestampEnabled = true
+        this.timestampOptions.startTimestamp = video.playlistElement.startTimestamp
+      }
+
+      if (video.playlistElement.stopTimestamp) {
+        this.timestampOptions.stopTimestampEnabled = true
+        this.timestampOptions.stopTimestamp = video.playlistElement.stopTimestamp
+      }
+    }
+  }
+
   private loadElements () {
     this.videoService.getPlaylistVideos(this.videoPlaylistId, this.pagination)
         .subscribe(({ totalVideos, videos }) => {
@@ -59,4 +166,11 @@ export class MyAccountVideoPlaylistElementsComponent implements OnInit, OnDestro
           this.pagination.totalItems = totalVideos
         })
   }
+
+  private loadPlaylistInfo () {
+    this.videoPlaylistService.getVideoPlaylist(this.videoPlaylistId)
+      .subscribe(playlist => {
+        this.playlist = playlist
+      })
+  }
 }
index 1e532ec13b0786c6bad275c4affaaacc921afd12..5622b3a31a03e684316da1b33f38028c0f18c40f 100644 (file)
@@ -10,7 +10,7 @@
         </div>
 
         <div class="logged-in-more" ngbDropdown placement="bottom-right">
-          <span class="glyphicon glyphicon-option-vertical" ngbDropdownToggle role="button"></span>
+          <my-global-icon iconName="more-vertical" ngbDropdownToggle role="button"></my-global-icon>
 
           <div ngbDropdownMenu>
             <a *ngIf="user.account" i18n [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="dropdown-item">
index 137df6fc1a92d45aaf9b3bc5530f7aa2d9e9ae07..7b392b5990dc11991eef1cccdf45bc4effb98c1d 100644 (file)
@@ -65,9 +65,10 @@ menu {
     .logged-in-more {
       margin-right: 20px;
 
-      .glyphicon {
+      my-global-icon {
+        @include apply-svg-color(var(--mainBackgroundColor));
+
         cursor: pointer;
-        font-size: 18px;
 
         &::after {
           border: none;
index 114b1d71f68ab2953c9ccfeac092ee3b7186e2c6..6999474d64bccb0bdaaeb86f0229cfc0395305c0 100644 (file)
@@ -3,7 +3,7 @@
     class="action-button" [ngClass]="{ small: buttonSize === 'small', grey: theme === 'grey', orange: theme === 'orange' }"
     ngbDropdownToggle role="button"
   >
-    <my-global-icon *ngIf="!label" class="more-icon" iconName="more"></my-global-icon>
+    <my-global-icon *ngIf="!label" class="more-icon" iconName="more-horizontal"></my-global-icon>
     <span *ngIf="label" class="dropdown-toggle">{{ label }}</span>
   </div>
 
index 3fda7ee4d8ae1b499e2b158c89dff0531d5928fa..093e88033bb213c5fe7615767d1faaacaebd47f5 100644 (file)
@@ -23,7 +23,8 @@ const icons = {
   'dislike': require('../../../assets/images/video/dislike.html'),
   'heart': require('../../../assets/images/video/heart.html'),
   'like': require('../../../assets/images/video/like.html'),
-  'more': require('../../../assets/images/video/more.html'),
+  'more-horizontal': require('../../../assets/images/global/more-horizontal.html'),
+  'more-vertical': require('../../../assets/images/global/more-vertical.html'),
   'share': require('../../../assets/images/video/share.html'),
   'upload': require('../../../assets/images/video/upload.html'),
   'playlist-add': require('../../../assets/images/video/playlist-add.html')
index ed3cd8dc5bc7043c78bf59f56ee7ffdb0a740382..f85e50d6d4a530c5ea56478ea7f9b740e2cfb108 100644 (file)
@@ -2,10 +2,10 @@
   <div class="first-row">
     <div i18n class="title">Save to</div>
 
-    <div i18n class="options" (click)="displayOptions = !displayOptions">
+    <div class="options" (click)="displayOptions = !displayOptions">
       <my-global-icon iconName="cog"></my-global-icon>
 
-      Options
+      <span i18n>Options</span>
     </div>
   </div>
 
index 68dcda1ebf00003de0628b9e9e5d6dcf9a0dda66..bc0d55912bcdea8547197cba3f5fa97adbf485bf 100644 (file)
@@ -18,6 +18,8 @@
     }
 
     .options {
+      display: flex;
+      align-items: center;
       font-size: 14px;
       cursor: pointer;
 
@@ -25,7 +27,8 @@
         @include apply-svg-color(#333);
 
         width: 16px;
-        height: 16px;
+        height: 23px;
+        margin-right: 3px;
       }
     }
   }
index f8cd47f730b1719d179e3a601d7e02ef514eca0a..72158eb10258f3d8f8ffa38a9a97875a32e77ac7 100644 (file)
@@ -29,7 +29,8 @@
       padding: 0 10px;
       display: flex;
       align-items: center;
-      font-size: 15px;
+      font-size: 14px;
+      font-weight: $font-semibold;
     }
   }
 
index c936a8207468f5a9e16d344189af49907c915056..95b5e36713b35f3211178fe2895622c5639a1d4c 100644 (file)
@@ -1,5 +1,5 @@
 import { User } from '../'
-import { Video as VideoServerModel, VideoPrivacy, VideoState } from '../../../../../shared'
+import { PlaylistElement, Video as VideoServerModel, VideoPrivacy, VideoState } from '../../../../../shared'
 import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
 import { VideoConstant } from '../../../../../shared/models/videos/video-constant.model'
 import { durationToString, getAbsoluteAPIUrl } from '../misc/utils'
@@ -47,6 +47,8 @@ export class Video implements VideoServerModel {
   blacklisted?: boolean
   blacklistedReason?: string
 
+  playlistElement?: PlaylistElement
+
   account: {
     id: number
     uuid: string
@@ -125,6 +127,8 @@ export class Video implements VideoServerModel {
     this.blacklistedReason = hash.blacklistedReason
 
     this.userHistory = hash.userHistory
+
+    this.playlistElement = hash.playlistElement
   }
 
   isVideoNSFWForUser (user: User, serverConfig: ServerConfig) {
index 615b88bd66d20d84710c78ed57a36a17ed4f2553..394c31f23fc830963b2ede2a98c6d9a9b59fa026 100644 (file)
@@ -91,7 +91,7 @@
 
                   <div class="action-dropdown" ngbDropdown placement="top" role="button">
                     <div class="action-button" ngbDropdownToggle role="button">
-                      <my-global-icon class="more-icon" iconName="more"></my-global-icon>
+                      <my-global-icon class="more-icon" iconName="more-horizontal"></my-global-icon>
                     </div>
 
                     <div ngbDropdownMenu>
index ff321fdbce7f57f56fb697f468fb5bee58bb8427..44040e90d699c24c52f568a6dad60b7d9eb007ec 100644 (file)
@@ -228,15 +228,7 @@ $other-videos-width: 260px;
             display: inline-block;
 
             .dropdown-menu .dropdown-item {
-              padding: 6px 24px;
-
-              my-global-icon {
-                width: 24px;
-
-                margin-right: 10px;
-                position: relative;
-                top: -2px;
-              }
+              @include dropdown-with-icon-item;
             }
           }
         }
diff --git a/client/src/assets/images/global/more-horizontal.html b/client/src/assets/images/global/more-horizontal.html
new file mode 100644 (file)
index 0000000..39dcad1
--- /dev/null
@@ -0,0 +1,9 @@
+<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">
+    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g transform="translate(-444.000000, -115.000000)" fill="#000000">
+            <g id="10" transform="translate(444.000000, 115.000000)">
+                <path d="M10,12 C10,10.8954305 10.8877296,10 12,10 C13.1045695,10 14,10.8877296 14,12 C14,13.1045695 13.1122704,14 12,14 C10.8954305,14 10,13.1122704 10,12 Z M17,12 C17,10.8954305 17.8877296,10 19,10 C20.1045695,10 21,10.8877296 21,12 C21,13.1045695 20.1122704,14 19,14 C17.8954305,14 17,13.1122704 17,12 Z M3,12 C3,10.8954305 3.88772964,10 5,10 C6.1045695,10 7,10.8877296 7,12 C7,13.1045695 6.11227036,14 5,14 C3.8954305,14 3,13.1122704 3,12 Z" id="Combined-Shape"></path>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/client/src/assets/images/global/more-vertical.html b/client/src/assets/images/global/more-vertical.html
new file mode 100644 (file)
index 0000000..9bff87a
--- /dev/null
@@ -0,0 +1,11 @@
+<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">
+  <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+    <g id="Artboard-4" transform="translate(-268.000000, -1046.000000)" fill="#000000">
+      <g id="Extras" transform="translate(48.000000, 1046.000000)">
+        <g id="more-vertical" transform="translate(220.000000, 0.000000)">
+          <path d="M10,12 C10,10.8954305 10.8877296,10 12,10 C13.1045695,10 14,10.8877296 14,12 C14,13.1045695 13.1122704,14 12,14 C10.8954305,14 10,13.1122704 10,12 Z M10,5 C10,3.8954305 10.8877296,3 12,3 C13.1045695,3 14,3.88772964 14,5 C14,6.1045695 13.1122704,7 12,7 C10.8954305,7 10,6.11227036 10,5 Z M10,19 C10,17.8954305 10.8877296,17 12,17 C13.1045695,17 14,17.8877296 14,19 C14,20.1045695 13.1122704,21 12,21 C10.8954305,21 10,20.1122704 10,19 Z" id="Combined-Shape"/>
+        </g>
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/client/src/assets/images/video/more.html b/client/src/assets/images/video/more.html
deleted file mode 100644 (file)
index 39dcad1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<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">
-    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
-        <g transform="translate(-444.000000, -115.000000)" fill="#000000">
-            <g id="10" transform="translate(444.000000, 115.000000)">
-                <path d="M10,12 C10,10.8954305 10.8877296,10 12,10 C13.1045695,10 14,10.8877296 14,12 C14,13.1045695 13.1122704,14 12,14 C10.8954305,14 10,13.1122704 10,12 Z M17,12 C17,10.8954305 17.8877296,10 19,10 C20.1045695,10 21,10.8877296 21,12 C21,13.1045695 20.1122704,14 19,14 C17.8954305,14 17,13.1122704 17,12 Z M3,12 C3,10.8954305 3.88772964,10 5,10 C6.1045695,10 7,10.8877296 7,12 C7,13.1045695 6.11227036,14 5,14 C3.8954305,14 3,13.1122704 3,12 Z" id="Combined-Shape"></path>
-            </g>
-        </g>
-    </g>
-</svg>
index 36d4e84d36a4a1ad99a3a3ba3ec9ed9f4ea7eaad..25a024aaca2a007a2cd9926e2a681374f1439c2d 100644 (file)
@@ -28,15 +28,15 @@ $play-overlay-transition: 0.2s ease;
 $play-overlay-height: 26px;
 $play-overlay-width: 18px;
 
-@mixin miniature-thumbnail {
+@mixin miniature-thumbnail($width: $video-thumbnail-width, $height: $video-thumbnail-height) {
   @include disable-outline;
 
   display: inline-block;
   position: relative;
   border-radius: 3px;
   overflow: hidden;
-  width: $video-thumbnail-width;
-  height: $video-thumbnail-height;
+  width: $width;
+  height: $height;
   background-color: #ececec;
   transition: filter $play-overlay-transition;
 
@@ -45,8 +45,8 @@ $play-overlay-width: 18px;
     right: 0;
     bottom: 0;
 
-    width: $video-thumbnail-width;
-    height: $video-thumbnail-height;
+    width: inherit;
+    height: inherit;
     opacity: 0;
     background-color: rgba(0, 0, 0, 0.7);
 
@@ -87,8 +87,8 @@ $play-overlay-width: 18px;
   }
 
   img {
-    width: $video-thumbnail-width;
-    height: $video-thumbnail-height;
+    width: inherit;
+    height: inherit;
 
     &.blur-filter {
       filter: blur(5px);
index 3eefdb6fb054a2807f3ca703ff7869727c8ee319..7faeec6bdcc0893e370b9f38a0d5cfe4b7b67420 100644 (file)
     align-items: center;
   }
 }
+
+@mixin dropdown-with-icon-item {
+  padding: 6px 24px;
+
+  my-global-icon {
+    width: 24px;
+
+    margin-right: 10px;
+    position: relative;
+    top: -2px;
+  }
+}
index 6e502b0288592e6b4a58692f826942d0251f1f15..6de14537904f51d2d08cf4b629de3551fb333145 100644 (file)
@@ -62,11 +62,9 @@ p-table {
     tr {
       &:hover {
         background-color: var(--submenuColor) !important;
-      }
 
-      &:not(:hover) {
-        .action-cell * {
-          display: none !important;
+        .action-cell .dropdown-root {
+          display: block !important;
         }
       }
 
@@ -140,6 +138,14 @@ p-table {
     padding: 0 !important;
     text-align: center;
 
+    .dropdown-root {
+      display: none !important;
+
+      &.show {
+        display: block !important;
+      }
+    }
+
     my-edit-button + my-delete-button {
       margin-left: 5px;
     }
index 6e7a6831ebf24969e136ad721af11c0d6a753bf6..963268674c2129d29255f8b1499e9a87a4c63cd5 100644 (file)
@@ -18,6 +18,12 @@ export interface VideoFile {
   fps: number
 }
 
+export interface PlaylistElement {
+  position: number
+  startTimestamp: number
+  stopTimestamp: number
+}
+
 export interface Video {
   id: number
   uuid: string
@@ -55,11 +61,7 @@ export interface Video {
     currentTime: number
   }
 
-  playlistElement?: {
-    position: number
-    startTimestamp: number
-    stopTimestamp: number
-  }
+  playlistElement?: PlaylistElement
 }
 
 export interface VideoDetails extends Video {