Add features table on signup
authorChocobozzz <me@florianbigard.com>
Tue, 28 Aug 2018 15:39:29 +0000 (17:39 +0200)
committerChocobozzz <me@florianbigard.com>
Tue, 28 Aug 2018 15:39:29 +0000 (17:39 +0200)
18 files changed:
client/src/app/+about/about-peertube/about-peertube.component.html
client/src/app/+about/about-peertube/about-peertube.component.scss
client/src/app/+about/about.component.scss [deleted file]
client/src/app/+about/about.component.ts
client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
client/src/app/shared/instance/instance-features-table.component.html [new file with mode: 0644]
client/src/app/shared/instance/instance-features-table.component.scss [new file with mode: 0644]
client/src/app/shared/instance/instance-features-table.component.ts [new file with mode: 0644]
client/src/app/shared/shared.module.ts
client/src/app/signup/signup.component.html
client/src/app/signup/signup.component.scss
client/src/app/signup/signup.component.ts
client/src/app/videos/+video-watch/video-watch.component.scss
client/src/assets/images/global/tick.svg [new file with mode: 0644]
client/src/sass/application.scss
client/src/sass/include/_bootstrap.scss
client/src/sass/include/_variables.scss
server/controllers/api/config.ts

index 55ac344f96a75b8c40e54bbd1adc2a13db9999ca..13ce89f751ef286e1d66605d100f205db520da30 100644 (file)
@@ -1,6 +1,6 @@
-<div i18n class="about-peertube-title">
+<h1 i18n class="about-peertube-title">
   About PeerTube
-</div>
+</h1>
 
 <div class="description">
   <p i18n>PeerTube is a federated (ActivityPub) video streaming platform using P2P (WebTorrent) directly in the web browser.</p>
 </div>
 
 <div id="p2p-privacy">
-  <div i18n class="section-title">P2P & Privacy</div>
+  <h3 i18n class="section-title">P2P & Privacy</h3>
 
   <p i18n>
     PeerTube uses the BitTorrent protocol to share bandwidth between users.
     This implies that your IP address is stored in the instance's BitTorrent tracker as long as you download or watch the video.
   </p>
 
-  <h4 i18n class="p2p-privacy-title">What are the consequences?</h4>
+  <h6 i18n class="p2p-privacy-title">What are the consequences?</h6>
 
   <p i18n>
     In theory, someone with enough technical skills could create a script that tracks which IP is downloading which video.
@@ -64,7 +64,7 @@
     There are much more effective ways to get that kind of information.
   </p>
 
-  <h4 i18n class="p2p-privacy-title">How does PeerTube compare with YouTube?</h4>
+  <h6 i18n class="p2p-privacy-title">How does PeerTube compare with YouTube?</h6>
 
   <p i18n>
     The threats to privacy in YouTube are different from PeerTube's.
@@ -72,7 +72,7 @@
     Moreover, YouTube is owned by Google/Alphabet, a company that tracks you across many websites (via AdSense or Google Analytics).
   </p>
 
-  <h4 i18n class="p2p-privacy-title">What can I do to limit the exposure of my IP address?</h4>
+  <h6 i18n class="p2p-privacy-title">What can I do to limit the exposure of my IP address?</h6>
 
   <p i18n>
     Your IP address is public so every time you consult a website, there is a number of actors (in addition to the final website) seeing your IP in their connection logs: ISP/routers/trackers/CDN and more.
@@ -80,7 +80,7 @@
     Thinking that removing P2P from PeerTube will give you back anonymity doesn't make sense.
   </p>
 
-  <h4 i18n class="p2p-privacy-title">What will be done to mitigate this problem?</h4>
+  <h6 i18n class="p2p-privacy-title">What will be done to mitigate this problem?</h6>
 
   <p i18n>
     PeerTube is only in beta, and want to deliver the best countermeasures possible by the time the stable is released.
index 1d8579ec1cd18eb650ffa6671145cbe9b622645e..0d2e2bb68d65342919083a8b72723b7e9f021b3b 100644 (file)
@@ -2,7 +2,7 @@
 @import '_mixins';
 
 .about-peertube-title {
-  font-size: 20px;
+  font-size: 25px;
   font-weight: bold;
   margin-bottom: 15px;
 }
diff --git a/client/src/app/+about/about.component.scss b/client/src/app/+about/about.component.scss
deleted file mode 100644 (file)
index e69de29..0000000
index 7b65d920f115d3ef1e9953cfb7b91f907a5535ca..0c91cd75f8373924be1dc3958bcc22f2d678b2b1 100644 (file)
@@ -2,8 +2,7 @@ import { Component } from '@angular/core'
 
 @Component({
   selector: 'my-about',
-  templateUrl: './about.component.html',
-  styleUrls: [ './about.component.scss' ]
+  templateUrl: './about.component.html'
 })
 
 export class AboutComponent {
index 3b6dabcb956b86b04563232ec1d1be6ac8e764a9..248b0df50b1568f82e51743cddfadd29460d9aee 100644 (file)
@@ -64,6 +64,14 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
     super()
   }
 
+  get videoQuotaOptions () {
+    return EditCustomConfigComponent.videoQuotaOptions
+  }
+
+  get videoQuotaDailyOptions () {
+    return EditCustomConfigComponent.videoQuotaDailyOptions
+  }
+
   getResolutionKey (resolution: string) {
     return 'transcodingResolution' + resolution
   }
diff --git a/client/src/app/shared/instance/instance-features-table.component.html b/client/src/app/shared/instance/instance-features-table.component.html
new file mode 100644 (file)
index 0000000..ba170f0
--- /dev/null
@@ -0,0 +1,28 @@
+<div class="feature-table">
+
+  <table class="table">
+    <tr>
+      <td i18n class="label">Video quota</td>
+
+      <td class="value">
+        <ng-container *ngIf="initialUserVideoQuota !== -1">
+          {{ initialUserVideoQuota | bytes: 0 }}
+
+          <my-help helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
+        </ng-container>
+
+        <ng-container i18n *ngIf="initialUserVideoQuota === -1">
+          Unlimited
+        </ng-container>
+      </td>
+    </tr>
+
+    <tr *ngFor="let feature of features">
+      <td class="label">{{ feature.label }}</td>
+      <td>
+        <span *ngIf="feature.value === true" class="glyphicon glyphicon-ok"></span>
+        <span *ngIf="feature.value === false" class="glyphicon glyphicon-remove"></span>
+      </td>
+    </tr>
+  </table>
+</div>
\ No newline at end of file
diff --git a/client/src/app/shared/instance/instance-features-table.component.scss b/client/src/app/shared/instance/instance-features-table.component.scss
new file mode 100644 (file)
index 0000000..d597a03
--- /dev/null
@@ -0,0 +1,20 @@
+@import '_variables';
+@import '_mixins';
+
+table {
+  font-size: 14px;
+  max-width: 400px;
+
+  .label {
+    font-weight: $font-semibold;
+    min-width: 330px;
+  }
+
+  .glyphicon-ok {
+    color: $green;
+  }
+
+  .glyphicon-remove {
+    color: $red;
+  }
+}
\ No newline at end of file
diff --git a/client/src/app/shared/instance/instance-features-table.component.ts b/client/src/app/shared/instance/instance-features-table.component.ts
new file mode 100644 (file)
index 0000000..1aad5aa
--- /dev/null
@@ -0,0 +1,84 @@
+import { Component, OnInit } from '@angular/core'
+import { ServerService } from '@app/core'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+
+@Component({
+  selector: 'my-instance-features-table',
+  templateUrl: './instance-features-table.component.html',
+  styleUrls: [ './instance-features-table.component.scss' ]
+})
+export class InstanceFeaturesTableComponent implements OnInit {
+  features: { label: string, value?: boolean }[] = []
+  quotaHelpIndication = ''
+
+  constructor (
+    private i18n: I18n,
+    private serverService: ServerService
+  ) {
+  }
+
+  get initialUserVideoQuota () {
+    return this.serverService.getConfig().user.videoQuota
+  }
+
+  ngOnInit () {
+    this.serverService.configLoaded
+        .subscribe(() => {
+          this.buildFeatures()
+          this.buildQuotaHelpIndication()
+        })
+  }
+
+  private buildFeatures () {
+    const config = this.serverService.getConfig()
+
+    this.features = [
+      {
+        label: this.i18n('Transcode your videos in multiple resolutions'),
+        value: config.transcoding.enabledResolutions.length !== 0
+      },
+      {
+        label: this.i18n('HTTP import (YouTube, Vimeo, direct URL...)'),
+        value: config.import.videos.http.enabled
+      },
+      {
+        label: this.i18n('Torrent import'),
+        value: config.import.videos.torrent.enabled
+      }
+    ]
+
+  }
+
+  private getApproximateTime (seconds: number) {
+    const hours = Math.floor(seconds / 3600)
+    let pluralSuffix = ''
+    if (hours > 1) pluralSuffix = 's'
+    if (hours > 0) return `~ ${hours} hour${pluralSuffix}`
+
+    const minutes = Math.floor(seconds % 3600 / 60)
+
+    return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
+  }
+
+  private buildQuotaHelpIndication () {
+    if (this.initialUserVideoQuota === -1) return
+
+    const initialUserVideoQuotaBit = this.initialUserVideoQuota * 8
+
+    // 1080p: ~ 6Mbps
+    // 720p: ~ 4Mbps
+    // 360p: ~ 1.5Mbps
+    const fullHdSeconds = initialUserVideoQuotaBit / (6 * 1000 * 1000)
+    const hdSeconds = initialUserVideoQuotaBit / (4 * 1000 * 1000)
+    const normalSeconds = initialUserVideoQuotaBit / (1.5 * 1000 * 1000)
+
+    const lines = [
+      this.i18n('{{seconds}} of full HD videos', { seconds: this.getApproximateTime(fullHdSeconds) }),
+      this.i18n('{{seconds}} of HD videos', { seconds: this.getApproximateTime(hdSeconds) }),
+      this.i18n('{{seconds}} of average quality videos', { seconds: this.getApproximateTime(normalSeconds) })
+    ]
+
+    this.quotaHelpIndication = lines.join('<br />')
+  }
+
+}
index 413159059c8e6865d1464dd4b1eca5f45dea9003..2cbaaf4aedabc0578f369713c59de15d42121581 100644 (file)
@@ -51,6 +51,7 @@ import { VideoImportService } from '@app/shared/video-import/video-import.servic
 import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
 import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
 import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
+import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
 
 @NgModule({
   imports: [
@@ -86,7 +87,8 @@ import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/u
     HelpComponent,
     ReactiveFileComponent,
     PeertubeCheckboxComponent,
-    SubscribeButtonComponent
+    SubscribeButtonComponent,
+    InstanceFeaturesTableComponent
   ],
 
   exports: [
@@ -119,6 +121,7 @@ import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/u
     ReactiveFileComponent,
     PeertubeCheckboxComponent,
     SubscribeButtonComponent,
+    InstanceFeaturesTableComponent,
 
     NumberFormatterPipe,
     ObjectLengthPipe,
index 5fd630b095949ea619867b2b3d1168bed91ee4d1..f7b8f587b0e52a408503b8afff439f2ae6480c52 100644 (file)
@@ -4,19 +4,7 @@
     Create an account
   </div>
 
-  <div class="initial-user-quota">
-    <span i18n class="initial-user-quota-label">Initial video quota:</span>
-
-    <span *ngIf="initialUserVideoQuota !== -1">
-      {{ initialUserVideoQuota | bytes: 0 }}
-
-      <my-help helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
-    </span>
-
-    <ng-container i18n *ngIf="initialUserVideoQuota === -1">
-      Unlimited
-    </ng-container>
-  </div>
+  <my-instance-features-table></my-instance-features-table>
 
   <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
 
index 1c992faf5d22bd1d3e598804c55a8e30bcef0f14..a98c3c732510d7763ffce9e5a9d87e9aad05d3d1 100644 (file)
@@ -1,13 +1,10 @@
 @import '_variables';
 @import '_mixins';
 
-.initial-user-quota {
-  font-size: 15px;
-  margin-bottom: 20px;
+my-instance-features-table {
+  display: block;
 
-  .initial-user-quota-label {
-    font-weight: $font-semibold;
-  }
+  margin-bottom: 40px;
 }
 
 .form-group-terms {
 }
 
 .input-group {
-  @include peertube-input-group(340px);
+  @include peertube-input-group(400px);
 }
 
 input:not([type=submit]) {
-  @include peertube-input-text(340px);
+  @include peertube-input-text(400px);
   display: block;
 
   &#username {
index ed68487ae10ae9aa524eece634e1fb2b6ff1d687..47f9bc6f4c5e778d8d6e02ffe0c21acc7f0ee428 100644 (file)
@@ -1,6 +1,5 @@
 import { Component, OnInit } from '@angular/core'
 import { Router } from '@angular/router'
-import { ServerService } from '@app/core/server'
 import { NotificationsService } from 'angular2-notifications'
 import { UserCreate } from '../../../../shared'
 import { FormReactive, UserService, UserValidatorsService } from '../shared'
@@ -15,7 +14,6 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val
 })
 export class SignupComponent extends FormReactive implements OnInit {
   error: string = null
-  quotaHelpIndication = ''
 
   constructor (
     protected formValidatorService: FormValidatorService,
@@ -24,16 +22,11 @@ export class SignupComponent extends FormReactive implements OnInit {
     private notificationsService: NotificationsService,
     private userService: UserService,
     private redirectService: RedirectService,
-    private serverService: ServerService,
     private i18n: I18n
   ) {
     super()
   }
 
-  get initialUserVideoQuota () {
-    return this.serverService.getConfig().user.videoQuota
-  }
-
   get instanceHost () {
     return window.location.host
   }
@@ -45,9 +38,6 @@ export class SignupComponent extends FormReactive implements OnInit {
       email: this.userValidatorsService.USER_EMAIL,
       terms: this.userValidatorsService.USER_TERMS
     })
-
-    this.serverService.configLoaded
-      .subscribe(() => this.buildQuotaHelpIndication())
   }
 
   signup () {
@@ -67,37 +57,4 @@ export class SignupComponent extends FormReactive implements OnInit {
       err => this.error = err.message
     )
   }
-
-  private getApproximateTime (seconds: number) {
-    const hours = Math.floor(seconds / 3600)
-    let pluralSuffix = ''
-    if (hours > 1) pluralSuffix = 's'
-    if (hours > 0) return `~ ${hours} hour${pluralSuffix}`
-
-    const minutes = Math.floor(seconds % 3600 / 60)
-    if (minutes > 1) pluralSuffix = 's'
-
-    return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
-  }
-
-  private buildQuotaHelpIndication () {
-    if (this.initialUserVideoQuota === -1) return
-
-    const initialUserVideoQuotaBit = this.initialUserVideoQuota * 8
-
-    // 1080p: ~ 6Mbps
-    // 720p: ~ 4Mbps
-    // 360p: ~ 1.5Mbps
-    const fullHdSeconds = initialUserVideoQuotaBit / (6 * 1000 * 1000)
-    const hdSeconds = initialUserVideoQuotaBit / (4 * 1000 * 1000)
-    const normalSeconds = initialUserVideoQuotaBit / (1.5 * 1000 * 1000)
-
-    const lines = [
-      this.i18n('{{seconds}} of full HD videos', { seconds: this.getApproximateTime(fullHdSeconds) }),
-      this.i18n('{{seconds}} of HD videos', { seconds: this.getApproximateTime(hdSeconds) }),
-      this.i18n('{{seconds}} of average quality videos', { seconds: this.getApproximateTime(normalSeconds) })
-    ]
-
-    this.quotaHelpIndication = lines.join('<br />')
-  }
 }
index 6b18dc88a9df5c4bd7fde78889c1679f47664f24..9bd510c9fb82116af596167d0c139bdfd90270ad 100644 (file)
             }
 
             &.action-button-like.activated {
-              background-color: #39CC0B;
+              background-color: $green;
 
               .icon-like {
                 background-image: url('../../../assets/images/video/like-white.svg');
             }
 
             &.action-button-dislike.activated {
-              background-color: #FF0000;
+              background-color: $red;
 
               .icon-dislike {
                 background-image: url('../../../assets/images/video/dislike-white.svg');
diff --git a/client/src/assets/images/global/tick.svg b/client/src/assets/images/global/tick.svg
new file mode 100644 (file)
index 0000000..230caa1
--- /dev/null
@@ -0,0 +1,12 @@
+<?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" stroke-linecap="round">
+        <g id="Artboard-4" transform="translate(-356.000000, -115.000000)" stroke="#585858" stroke-width="2">
+            <g id="8" transform="translate(356.000000, 115.000000)">
+                <path d="M21,6 L9,18" id="Path-14"></path>
+                <path d="M9,13 L4,18" id="Path-14" transform="translate(6.500000, 15.500000) scale(-1, 1) translate(-6.500000, -15.500000) "></path>
+            </g>
+        </g>
+    </g>
+</svg>
index b2d7c2bec9bea155248c70ad5b56ba04bdf29684..9c4811fec3f66eddeb4b26d3cd2813e74ea24840 100644 (file)
@@ -53,12 +53,12 @@ label {
 
 .form-error {
   display: block;
-  color: $red-error;
+  color: $red;
   margin-top: 5px;
 }
 
 .input-error {
-  border-color: $red-error !important;
+  border-color: $red !important;
 }
 
 .glyphicon-black {
index 5abec02d5a592e27056412bcc440f9d6c5531369..a8777af712c8d213d4a1489a517ba06b50c2c3ce 100644 (file)
@@ -21,7 +21,7 @@ $nav-pills-link-active-color: #000;
 //@import '~bootstrap/scss/images';
 //@import '~bootstrap/scss/code';
 @import '~bootstrap/scss/grid';
-//@import '~bootstrap/scss/tables';
+@import '~bootstrap/scss/tables';
 @import '~bootstrap/scss/forms';
 @import '~bootstrap/scss/buttons';
 //@import '~bootstrap/scss/transitions';
index e6db9864276b70f83f022e5ff050869b3ab3929f..ba7abeef1fe8c946c7562c952d290fdb19aaf132 100644 (file)
@@ -10,7 +10,9 @@ $orange-hoover-color: #F97D46;
 
 $black-background: #000;
 $grey-background: #f6f2f2;
-$red-error: #FF0000;
+
+$red: #FF0000;
+$green: #39CC0B;
 
 $grey-actor-name: #777272;
 
index 8dfc3deb445cba68f48c8bf691482323b27de74c..25ddd1fa6d828bd701e3e2a4677098f0305a49e1 100644 (file)
@@ -43,7 +43,7 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
   const allowedForCurrentIP = isSignupAllowedForCurrentIP(req.ip)
 
   const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
-   .filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
+   .filter(key => CONFIG.TRANSCODING.ENABLED === CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
    .map(r => parseInt(r, 10))
 
   const json: ServerConfig = {