]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add params to share modal
authorChocobozzz <me@florianbigard.com>
Wed, 12 Jun 2019 10:40:24 +0000 (12:40 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 12 Jun 2019 14:44:15 +0000 (16:44 +0200)
15 files changed:
client/src/app/search/search.component.html
client/src/app/search/search.component.scss
client/src/app/search/search.module.ts
client/src/app/shared/shared.module.ts
client/src/app/videos/+video-watch/modal/video-share.component.html
client/src/app/videos/+video-watch/modal/video-share.component.scss
client/src/app/videos/+video-watch/modal/video-share.component.ts
client/src/app/videos/+video-watch/video-watch.component.html
client/src/app/videos/+video-watch/video-watch.component.ts
client/src/assets/player/peertube-player-manager.ts
client/src/assets/player/utils.ts
client/src/assets/player/videojs-components/peertube-link-button.ts
client/src/sass/application.scss
client/src/sass/bootstrap.scss [new file with mode: 0644]
client/src/sass/include/_mixins.scss

index 0a9f78cb26c55ed7fa4e913d7ff05bf9e8455192..055f64cc8ee081eab67d43f7bfeeba2002724af0 100644 (file)
@@ -20,7 +20,7 @@
       </div>
     </div>
 
-    <div class="results-filter" [ngbCollapse]="isSearchFilterCollapsed">
+    <div class="results-filter collapse-transition" [ngbCollapse]="isSearchFilterCollapsed">
       <my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters>
     </div>
   </div>
index 4e3ce1c964dda45e2ca9335858e8dd730d615a0c..3343a276dc4f171ba57946d41501b05e9eaf9703 100644 (file)
         }
       }
     }
-
-    .results-filter {
-      // Animation when we show/hide the filters
-      transition: max-height 0.3s;
-      display: block !important;
-      overflow: hidden !important;
-      max-height: 0;
-
-      &.show {
-        max-height: 1500px;
-      }
-    }
   }
 
   .entry {
index 0411fbe24a537a99ae794bf78a017a9718626a9d..8b791621e09f4984d20664bf44fac55e477388aa 100644 (file)
@@ -4,14 +4,11 @@ import { SearchComponent } from '@app/search/search.component'
 import { SearchService } from '@app/search/search.service'
 import { SearchRoutingModule } from '@app/search/search-routing.module'
 import { SearchFiltersComponent } from '@app/search/search-filters.component'
-import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap'
 
 @NgModule({
   imports: [
     SearchRoutingModule,
-    SharedModule,
-
-    NgbCollapseModule
+    SharedModule
   ],
 
   declarations: [
index 1d49c7bc85d965e80987599c5eb5055ca1be89d4..eb57a2fff0fc6db07c5367d9006bd8feea2399fa 100644 (file)
@@ -53,7 +53,14 @@ import { VideoCaptionService } from '@app/shared/video-caption'
 import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component'
 import { VideoImportService } from '@app/shared/video-import/video-import.service'
 import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
-import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
+import {
+  NgbCollapseModule,
+  NgbDropdownModule,
+  NgbModalModule,
+  NgbPopoverModule,
+  NgbTabsetModule,
+  NgbTooltipModule
+} from '@ng-bootstrap/ng-bootstrap'
 import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
 import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
 import { OverviewService } from '@app/shared/overview'
@@ -100,6 +107,7 @@ import { FollowService } from '@app/shared/instance/follow.service'
     NgbPopoverModule,
     NgbTabsetModule,
     NgbTooltipModule,
+    NgbCollapseModule,
 
     ClipboardModule,
 
@@ -170,6 +178,7 @@ import { FollowService } from '@app/shared/instance/follow.service'
     NgbPopoverModule,
     NgbTabsetModule,
     NgbTooltipModule,
+    NgbCollapseModule,
 
     ClipboardModule,
 
index 955b2b80c4693a0c0ec806a722041c033f254cff..82e59d04da9f61e5ad7af9ec101cca76ed8d5da2 100644 (file)
   </div>
 
   <div class="modal-body">
+    <ngb-tabset class="root-tabset bootstrap" (tabChange)="onTabChange($event)">
 
-    <div class="start-at">
-      <my-peertube-checkbox
-        inputName="startAt" [(ngModel)]="startAtCheckbox"
-        i18n-labelText labelText="Start at"
-      ></my-peertube-checkbox>
-
-      <my-timestamp-input
-        [timestamp]="currentVideoTimestamp"
-        [maxTimestamp]="video.duration"
-        [disabled]="!startAtCheckbox"
-        [(ngModel)]="currentVideoTimestamp"
-      >
-      </my-timestamp-input>
-    </div>
+      <ngb-tab i18n-title title="URL" id="url">
+        <ng-template ngbTabContent>
+
+          <div class="tab-content">
+            <div class="input-group">
+              <input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoUrl()" />
+              <div class="input-group-append">
+                <button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
+                  <span class="glyphicon glyphicon-copy"></span>
+                </button>
+              </div>
+            </div>
+          </div>
+
+        </ng-template>
+      </ngb-tab>
+
+      <ngb-tab i18n-title title="QR-Code" id="qrcode">
+        <ng-template ngbTabContent>
+          <div class="tab-content">
+            <ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode>
+          </div>
+        </ng-template>
+      </ngb-tab>
+
+      <ngb-tab i18n-title title="Embed" id="embed">
+        <ng-template ngbTabContent>
+          <div class="tab-content">
+            <div class="input-group">
+              <input #shareInput (click)="shareInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoIframeCode()" />
+              <div class="input-group-append">
+                <button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
+                  <span class="glyphicon glyphicon-copy"></span>
+                </button>
+              </div>
+            </div>
+
+            <div i18n *ngIf="notSecure()" class="alert alert-warning">
+              The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
+            </div>
+          </div>
+        </ng-template>
+      </ngb-tab>
+
+    </ngb-tabset>
 
-    <div class="form-group">
-      <label i18n>URL</label>
-      <div class="input-group input-group-sm">
-        <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoUrl()" />
-        <div class="input-group-append">
-          <button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
-            <span class="glyphicon glyphicon-copy"></span>
-          </button>
+    <div class="filters">
+      <div>
+        <div class="form-group start-at">
+          <my-peertube-checkbox
+            inputName="startAt" [(ngModel)]="customizations.startAtCheckbox"
+            i18n-labelText labelText="Start at"
+          ></my-peertube-checkbox>
+
+          <my-timestamp-input
+            [timestamp]="customizations.startAt"
+            [maxTimestamp]="video.duration"
+            [disabled]="!customizations.startAtCheckbox"
+            [(ngModel)]="customizations.startAt"
+          >
+          </my-timestamp-input>
         </div>
-      </div>
-    </div>
 
-    <div class="form-group qr-code-group">
-      <label i18n>QR-Code</label>
-      <ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode>
-    </div>
+        <div *ngIf="videoCaptions.length !== 0" class="form-group video-caption-block">
+          <my-peertube-checkbox
+            inputName="subtitleCheckbox" [(ngModel)]="customizations.subtitleCheckbox"
+            i18n-labelText labelText="Auto select subtitle"
+          ></my-peertube-checkbox>
 
-    <div class="form-group">
-      <label i18n>Embed</label>
-      <div class="input-group input-group-sm">
-        <input #shareInput (click)="shareInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoIframeCode()" />
-        <div class="input-group-append">
-          <button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
-            <span class="glyphicon glyphicon-copy"></span>
-          </button>
+          <div class="peertube-select-container" [ngClass]="{ disabled: !customizations.subtitleCheckbox }">
+            <select [(ngModel)]="customizations.subtitle" [disabled]="!customizations.subtitleCheckbox">
+              <option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option>
+            </select>
+          </div>
         </div>
       </div>
-    </div>
 
-    <div i18n *ngIf="notSecure()" class="alert alert-warning">
-      The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites).
+      <div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button"
+           [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic">
+
+        <ng-container *ngIf="isAdvancedCustomizationCollapsed">
+          <span class="glyphicon glyphicon-menu-down"></span>
+
+          <ng-container i18n>
+            More customization
+          </ng-container>
+        </ng-container>
+
+        <ng-container *ngIf="!isAdvancedCustomizationCollapsed">
+          <span class="glyphicon glyphicon-menu-up"></span>
+
+          <ng-container i18n>
+            Less customization
+          </ng-container>
+        </ng-container>
+      </div>
+
+      <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed">
+        <div>
+          <div class="form-group stop-at">
+            <my-peertube-checkbox
+              inputName="stopAt" [(ngModel)]="customizations.stopAtCheckbox"
+              i18n-labelText labelText="Stop at"
+            ></my-peertube-checkbox>
+
+            <my-timestamp-input
+              [timestamp]="customizations.stopAt"
+              [maxTimestamp]="video.duration"
+              [disabled]="!customizations.stopAtCheckbox"
+              [(ngModel)]="customizations.stopAt"
+            >
+            </my-timestamp-input>
+          </div>
+
+          <div class="form-group">
+            <my-peertube-checkbox
+              inputName="autoplay" [(ngModel)]="customizations.autoplay"
+              i18n-labelText labelText="Autoplay"
+            ></my-peertube-checkbox>
+          </div>
+
+          <div class="form-group">
+            <my-peertube-checkbox
+              inputName="muted" [(ngModel)]="customizations.muted"
+              i18n-labelText labelText="Muted"
+            ></my-peertube-checkbox>
+          </div>
+
+          <div class="form-group">
+            <my-peertube-checkbox
+              inputName="loop" [(ngModel)]="customizations.loop"
+              i18n-labelText labelText="Loop"
+            ></my-peertube-checkbox>
+          </div>
+        </div>
+
+        <ng-container *ngIf="isInEmbedTab()">
+          <div class="form-group">
+            <my-peertube-checkbox
+              inputName="title" [(ngModel)]="customizations.title"
+              i18n-labelText labelText="Display video title"
+            ></my-peertube-checkbox>
+          </div>
+
+          <div class="form-group">
+            <my-peertube-checkbox
+              inputName="warningTitle" [(ngModel)]="customizations.warningTitle"
+              i18n-labelText labelText="Display privacy warning"
+            ></my-peertube-checkbox>
+          </div>
+
+          <div class="form-group">
+            <my-peertube-checkbox
+              inputName="controls" [(ngModel)]="customizations.controls"
+              i18n-labelText labelText="Display player controls"
+            ></my-peertube-checkbox>
+          </div>
+        </ng-container>
+      </div>
     </div>
   </div>
 
index 472a45920bf5d3945da2ea0d5004860e574d9e16..c48abf9e05affa1be8474111f405ee5d30023bc6 100644 (file)
@@ -1,5 +1,9 @@
-@import '~bootstrap/scss/functions';
-@import '~bootstrap/scss/variables';
+@import '_mixins';
+@import '_variables';
+
+.peertube-select-container {
+  @include peertube-select-container(200px);
+}
 
 .action-button-cancel {
   margin-right: 0 !important;
   text-align: center;
 }
 
-.start-at {
+.tab-content {
+  margin-top: 30px;
   display: flex;
   justify-content: center;
-  margin-top: 10px;
   align-items: center;
+  flex-direction: column;
+}
+
+.alert {
+  margin-top: 20px;
+}
+
+input.readonly {
+  font-size: 15px;
+}
+
+.filters {
+  margin-top: 30px;
+  padding-top: 30px;
+  border-top: 1px solid $separator-border-color;
+
+  .advanced-filters-button {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-top: 30px;
+    font-size: 16px;
+    font-weight: $font-semibold;
+    cursor: pointer;
+
+    .glyphicon {
+      margin-right: 5px;
+    }
+  }
+
+  .form-group {
+    margin-bottom: 0;
+    height: 34px;
+    display: flex;
+    align-items: center;
+  }
+
+  .video-caption-block {
+    display: flex;
+    align-items: center;
+
+    .peertube-select-container {
+      margin-left: 10px;
+    }
+  }
+
+  .start-at,
+  .stop-at {
+    width: 300px;
+    display: flex;
+    align-items: center;
 
-  my-timestamp-input {
-    margin-left: 10px;
+    my-timestamp-input {
+      margin-left: 10px;
+    }
   }
 }
index 6565d7f887fc9c556c920efbc46a775b522bf152..eaaf6b902877d27813286f83bc85f14c660f36c1 100644 (file)
@@ -3,8 +3,26 @@ import { Notifier } from '@app/core'
 import { VideoDetails } from '../../../shared/video/video-details.model'
 import { buildVideoEmbed, buildVideoLink } from '../../../../assets/player/utils'
 import { I18n } from '@ngx-translate/i18n-polyfill'
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
-import { durationToString } from '@app/shared/misc/utils'
+import { NgbModal, NgbTabChangeEvent } from '@ng-bootstrap/ng-bootstrap'
+import { VideoCaption } from '@shared/models'
+
+type Customizations = {
+  startAtCheckbox: boolean
+  startAt: number
+
+  stopAtCheckbox: boolean
+  stopAt: number
+
+  subtitleCheckbox: boolean
+  subtitle: string
+
+  loop: boolean
+  autoplay: boolean
+  muted: boolean
+  title: boolean
+  warningTitle: boolean
+  controls: boolean
+}
 
 @Component({
   selector: 'my-video-share',
@@ -15,9 +33,13 @@ export class VideoShareComponent {
   @ViewChild('modal') modal: ElementRef
 
   @Input() video: VideoDetails = null
+  @Input() videoCaptions: VideoCaption[] = []
 
-  currentVideoTimestamp: number
-  startAtCheckbox = false
+  activeId: 'url' | 'qrcode' | 'embed'
+  customizations: Customizations
+  isAdvancedCustomizationCollapsed = true
+
+  private currentVideoTimestamp: number
 
   constructor (
     private modalService: NgbModal,
@@ -26,19 +48,47 @@ export class VideoShareComponent {
   ) { }
 
   show (currentVideoTimestamp?: number) {
-    this.currentVideoTimestamp = currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0
+    this.currentVideoTimestamp = currentVideoTimestamp
+
+    let subtitle: string
+    if (this.videoCaptions.length !== 0) {
+      subtitle = this.videoCaptions[0].language.id
+    }
+
+    this.customizations = {
+      startAtCheckbox: false,
+      startAt: currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0,
+
+      stopAtCheckbox: false,
+      stopAt: this.video.duration,
+
+      subtitleCheckbox: false,
+      subtitle,
+
+      loop: false,
+      autoplay: false,
+      muted: false,
+
+      // Embed options
+      title: true,
+      warningTitle: true,
+      controls: true
+    }
 
     this.modalService.open(this.modal)
   }
 
   getVideoIframeCode () {
-    const embedUrl = buildVideoLink(this.getVideoTimestampIfEnabled(), this.video.embedUrl)
+    const options = this.getOptions(this.video.embedUrl)
 
+    const embedUrl = buildVideoLink(options)
     return buildVideoEmbed(embedUrl)
   }
 
   getVideoUrl () {
-    return buildVideoLink(this.getVideoTimestampIfEnabled())
+    const options = this.getOptions()
+
+    return buildVideoLink(options)
   }
 
   notSecure () {
@@ -49,9 +99,30 @@ export class VideoShareComponent {
     this.notifier.success(this.i18n('Copied'))
   }
 
-  private getVideoTimestampIfEnabled () {
-    if (this.startAtCheckbox === true) return this.currentVideoTimestamp
+  onTabChange (event: NgbTabChangeEvent) {
+    this.activeId = event.nextId as any
+  }
+
+  isInEmbedTab () {
+    return this.activeId === 'embed'
+  }
+
+  private getOptions (baseUrl?: string) {
+    return {
+      baseUrl,
+
+      startTime: this.customizations.startAtCheckbox ? this.customizations.startAt : undefined,
+      stopTime: this.customizations.stopAtCheckbox ? this.customizations.stopAt : undefined,
+
+      subtitle: this.customizations.subtitleCheckbox ? this.customizations.subtitle : undefined,
+
+      loop: this.customizations.loop,
+      autoplay: this.customizations.autoplay,
+      muted: this.customizations.muted,
 
-    return undefined
+      title: this.customizations.title,
+      warningTitle: this.customizations.warningTitle,
+      controls: this.customizations.controls
+    }
   }
 }
index 2e39b9c6bb8815a75378874fcf1faefa728448b0..6a02f630ad81532811cc7274258b70f0f546766b 100644 (file)
 
 <ng-template [ngIf]="video !== null">
   <my-video-support #videoSupportModal [video]="video"></my-video-support>
-  <my-video-share #videoShareModal [video]="video"></my-video-share>
+  <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions"></my-video-share>
 </ng-template>
index 29c472a425f153b73b003970483cbbb1cca329cb..3f1a98f89b3130a075bf65de6acd2deaed804d79 100644 (file)
@@ -50,9 +50,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
   playerElement: HTMLVideoElement
   theaterEnabled = false
   userRating: UserVideoRateType = null
-  video: VideoDetails = null
   descriptionLoading = false
 
+  video: VideoDetails = null
+  videoCaptions: VideoCaption[] = []
+
   playlist: VideoPlaylist = null
 
   completeDescriptionShown = false
@@ -339,6 +341,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
     urlOptions: CustomizationOptions & { playerMode: PlayerMode }
   ) {
     this.video = video
+    this.videoCaptions = videoCaptions
 
     // Re init attributes
     this.descriptionLoading = false
index 8f6237326aff094f6a759a4b0ed09ff0ea0807e7..083c621d21cc376e9003ae996d4b8c47981754c4 100644 (file)
@@ -446,7 +446,7 @@ export class PeertubePlayerManager {
         label: player.localize('Copy the video URL at the current time'),
         listener: function () {
           const player = this as videojs.Player
-          copyToClipboard(buildVideoLink(player.currentTime()))
+          copyToClipboard(buildVideoLink({ startTime: player.currentTime() }))
         }
       },
       {
index 3666899625720302c0d14dac1f12ff0040c17d6c..777abb568efe89fd46940e35a1b04c3e7d19b98f 100644 (file)
@@ -27,18 +27,55 @@ function isMobile () {
   return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
 }
 
-function buildVideoLink (time?: number, url?: string) {
-  if (!url) url = window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
+function buildVideoLink (options: {
+  baseUrl?: string,
 
-  if (time) {
-    const timeInt = Math.floor(time)
+  startTime?: number,
+  stopTime?: number,
 
-    const params = new URLSearchParams(window.location.search)
-    params.set('start', secondsToTime(timeInt))
+  subtitle?: string,
 
-    return url + '?' + params.toString()
+  loop?: boolean,
+  autoplay?: boolean,
+  muted?: boolean,
+
+  // Embed options
+  title?: boolean,
+  warningTitle?: boolean,
+  controls?: boolean
+} = {}) {
+  const { baseUrl } = options
+
+  const url = baseUrl
+    ? baseUrl
+    : window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
+
+  const params = new URLSearchParams(window.location.search)
+
+  if (options.startTime) {
+    const startTimeInt = Math.floor(options.startTime)
+    params.set('start', secondsToTime(startTimeInt))
+  }
+
+  if (options.stopTime) {
+    const stopTimeInt = Math.floor(options.stopTime)
+    params.set('stop', secondsToTime(stopTimeInt))
   }
 
+  if (options.subtitle) params.set('subtitle', options.subtitle)
+
+  if (options.loop === true) params.set('loop', '1')
+  if (options.autoplay === true) params.set('autoplay', '1')
+  if (options.muted === true) params.set('muted', '1')
+  if (options.title === false) params.set('title', '0')
+  if (options.warningTitle === false) params.set('warningTitle', '0')
+  if (options.controls === false) params.set('controls', '0')
+
+  let hasParams = false
+  params.forEach(() => hasParams = true)
+
+  if (hasParams) return url + '?' + params.toString()
+
   return url
 }
 
index fed8ea33e4b0ea8748d189774b42f5104bf270b0..4d0ea37f5c1439fb7a8c4daa0eb207f62e83a24d 100644 (file)
@@ -16,7 +16,7 @@ class PeerTubeLinkButton extends Button {
   }
 
   updateHref () {
-    this.el().setAttribute('href', buildVideoLink(this.player().currentTime()))
+    this.el().setAttribute('href', buildVideoLink({ startTime: this.player().currentTime() }))
   }
 
   handleClick () {
index d847662408bfd54768c1d505f9e6fe4cbc758cb6..c64a8ebf8b788ee30245c72ac004716e58c2491c 100644 (file)
@@ -12,6 +12,7 @@ $assets-path: '../assets/';
 @import './player/index';
 @import './loading-bar';
 
+@import './bootstrap';
 @import './primeng-custom';
 
 [hidden] {
@@ -181,128 +182,11 @@ label {
   font-weight: bold;
 }
 
-// Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d
-.glyphicon-refresh-animate {
-  animation: spin .7s infinite linear;
-}
-
 @keyframes spin {
   from { transform: scale(1) rotate(0deg);}
   to { transform: scale(1) rotate(360deg);}
 }
 
-// Bootstrap customizations
-.dropdown-menu {
-  border-radius: 3px;
-  box-shadow: 0 3px 6px;
-  font-size: 15px;
-
-  .dropdown-item {
-    padding: 3px 15px;
-
-    &:active {
-      color: #000 !important;
-    }
-  }
-
-  button {
-    @include disable-default-a-behaviour;
-  }
-
-  a {
-    @include disable-default-a-behaviour;
-    color: #000 !important;
-  }
-}
-
-.modal {
-  .modal-content {
-    background-color: var(--mainBackgroundColor);
-  }
-
-  .modal-header {
-    border-bottom: none;
-    margin-bottom: 5px;
-
-    .modal-title {
-      font-size: 20px;
-      font-weight: $font-semibold;
-    }
-
-    my-global-icon {
-      @include icon(24px);
-
-      position: relative;
-      top: 3px;
-      float: right;
-
-      margin: 0;
-      padding: 0;
-      opacity: 1;
-    }
-  }
-
-  .inputs {
-    margin-bottom: 0;
-    text-align: right;
-
-    .action-button-cancel {
-      @include peertube-button;
-      @include grey-button;
-
-      display: inline-block;
-      margin-right: 10px;
-    }
-
-    .action-button-submit {
-      @include peertube-button;
-      @include orange-button;
-    }
-  }
-}
-
-// Nav customizations
-.nav .nav-link {
-  display: flex !important;
-  align-items: center;
-  height: 30px !important;
-  padding: 10px 15px !important;
-}
-
-.nav.nav-pills {
-  font-size: 16px !important;
-
-  .nav-link.active {
-    font-weight: $font-semibold !important;
-  }
-
-  a {
-    @include disable-default-a-behaviour;
-
-    color: var(--mainForegroundColor);
-  }
-}
-
-ngb-tabset.bootstrap {
-
-  .nav-link {
-    &, & a {
-      @include disable-default-a-behaviour;
-
-      color: var(--mainForegroundColor) !important;
-    }
-  }
-
-  .nav-pills .nav-link.active {
-    color: #000 !important;
-  }
-}
-
-.nav-tabs .nav-link.active {
-  background-color: var(--mainBackgroundColor) !important;
-  border-bottom: none;
-}
-
 .orange-button {
   @include peertube-button;
   @include orange-button;
diff --git a/client/src/sass/bootstrap.scss b/client/src/sass/bootstrap.scss
new file mode 100644 (file)
index 0000000..12e7327
--- /dev/null
@@ -0,0 +1,138 @@
+$icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/';
+@import '_bootstrap';
+
+@import '_variables';
+@import '_mixins';
+
+// Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d
+.glyphicon-refresh-animate {
+  animation: spin .7s infinite linear;
+}
+
+@keyframes spin {
+  from { transform: scale(1) rotate(0deg);}
+  to { transform: scale(1) rotate(360deg);}
+}
+
+.dropdown-menu {
+  border-radius: 3px;
+  box-shadow: 0 3px 6px;
+  font-size: 15px;
+
+  .dropdown-item {
+    padding: 3px 15px;
+
+    &:active {
+      color: #000 !important;
+    }
+  }
+
+  button {
+    @include disable-default-a-behaviour;
+  }
+
+  a {
+    @include disable-default-a-behaviour;
+    color: #000 !important;
+  }
+}
+
+.modal {
+  .modal-content {
+    background-color: var(--mainBackgroundColor);
+  }
+
+  .modal-header {
+    border-bottom: none;
+    margin-bottom: 5px;
+
+    .modal-title {
+      font-size: 20px;
+      font-weight: $font-semibold;
+    }
+
+    my-global-icon {
+      @include icon(24px);
+
+      position: relative;
+      top: 3px;
+      float: right;
+
+      margin: 0;
+      padding: 0;
+      opacity: 1;
+    }
+  }
+
+  .inputs {
+    margin-bottom: 0;
+    text-align: right;
+
+    .action-button-cancel {
+      @include peertube-button;
+      @include grey-button;
+
+      display: inline-block;
+      margin-right: 10px;
+    }
+
+    .action-button-submit {
+      @include peertube-button;
+      @include orange-button;
+    }
+  }
+}
+
+// Nav customizations
+.nav .nav-link {
+  display: flex !important;
+  align-items: center;
+  height: 30px !important;
+  padding: 10px 15px !important;
+}
+
+.nav.nav-pills {
+  font-size: 16px !important;
+
+  .nav-link.active {
+    font-weight: $font-semibold !important;
+  }
+
+  a {
+    @include disable-default-a-behaviour;
+
+    color: var(--mainForegroundColor);
+  }
+}
+
+ngb-tabset.bootstrap {
+
+  .nav-link {
+    &, & a {
+      @include disable-default-a-behaviour;
+
+      color: var(--mainForegroundColor) !important;
+    }
+  }
+
+  .nav-pills .nav-link.active {
+    color: #000 !important;
+  }
+}
+
+.nav-tabs .nav-link.active {
+  background-color: var(--mainBackgroundColor) !important;
+  border-bottom: none;
+}
+
+.collapse-transition {
+  // Animation when we show/hide the filters
+  transition: max-height 0.3s;
+  display: block !important;
+  overflow: hidden !important;
+  max-height: 0;
+
+  &.show {
+    max-height: 1500px;
+  }
+}
index d4a2269a1b9767e3bbfc2c66b8b9631ae78cb76b..f608e9299a409c6f3842e1822a71186ca49172b1 100644 (file)
   position: relative;
   font-size: 15px;
 
+  &.disabled {
+    background-color: #E5E5E5;
+
+    select {
+      cursor: default;
+    }
+  }
+
   @media screen and (max-width: $width) {
     width: 100%;
   }
   }
 }
 
-@mixin peertube-select-disabled-container ($width) {
-  @include peertube-select-container($width);
-
-  background-color: #E5E5E5;
-
-  select {
-    cursor: default;
-  }
-}
-
 // Thanks: https://codepen.io/triss90/pen/XNEdRe/
 @mixin peertube-radio-container {
   input[type="radio"] {