]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Fix lint
authorChocobozzz <me@florianbigard.com>
Wed, 24 May 2023 13:27:15 +0000 (15:27 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 24 May 2023 13:27:15 +0000 (15:27 +0200)
100 files changed:
client/.eslintrc.json
client/e2e/wdio.local-test.conf.ts
client/e2e/wdio.local.conf.ts
client/src/app/+about/about-instance/about-instance.resolver.ts
client/src/app/+accounts/accounts.component.html
client/src/app/+admin/config/edit-custom-config/edit-advanced-configuration.component.html
client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html
client/src/app/+admin/config/edit-custom-config/edit-homepage.component.html
client/src/app/+admin/config/edit-custom-config/edit-instance-information.component.html
client/src/app/+admin/config/edit-custom-config/edit-live-configuration.component.html
client/src/app/+admin/config/edit-custom-config/edit-vod-transcoding.component.html
client/src/app/+admin/follows/following-list/following-list.component.html
client/src/app/+admin/follows/following-list/following-list.component.scss
client/src/app/+admin/overview/users/user-edit/user-edit.component.html
client/src/app/+admin/overview/users/user-list/user-list.component.html
client/src/app/+admin/overview/users/user-list/user-list.component.scss
client/src/app/+login/login.component.html
client/src/app/+login/login.component.ts
client/src/app/+manage/video-channel-edit/video-channel-create.component.ts
client/src/app/+manage/video-channel-edit/video-channel-edit.component.html
client/src/app/+manage/video-channel-edit/video-channel-update.component.ts
client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts
client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts
client/src/app/+my-library/+my-video-channels/my-video-channels.component.html
client/src/app/+my-library/+my-video-channels/my-video-channels.component.scss
client/src/app/+my-library/my-history/my-history.component.html
client/src/app/+my-library/my-ownership/my-ownership.component.html
client/src/app/+my-library/my-video-channel-syncs/my-video-channel-syncs.component.html
client/src/app/+my-library/my-video-channel-syncs/my-video-channel-syncs.component.scss
client/src/app/+my-library/my-video-playlists/my-video-playlist-edit.component.html
client/src/app/+my-library/my-video-playlists/my-video-playlists.component.html
client/src/app/+my-library/my-video-playlists/my-video-playlists.component.scss
client/src/app/+my-library/my-videos/my-videos.component.html
client/src/app/+reset-password/reset-password.component.ts
client/src/app/+search/search-filters.component.html
client/src/app/+search/search.component.html
client/src/app/+search/shared/abstract-lazy-load.resolver.ts
client/src/app/+signup/+register/custom-stepper.component.html
client/src/app/+signup/+register/custom-stepper.component.scss
client/src/app/+signup/+register/register.component.html
client/src/app/+signup/+register/register.component.scss
client/src/app/+video-channels/video-channels.component.html
client/src/app/+video-studio/edit/video-studio-edit.component.html
client/src/app/+video-studio/edit/video-studio-edit.component.ts
client/src/app/+videos/+video-edit/shared/video-edit.component.html
client/src/app/+videos/+video-edit/shared/video-edit.component.scss
client/src/app/+videos/+video-watch/shared/comment/video-comments.component.html
client/src/app/+videos/+video-watch/shared/comment/video-comments.component.scss
client/src/app/+videos/+video-watch/shared/information/privacy-concerns.component.html
client/src/app/+videos/+video-watch/shared/information/privacy-concerns.component.scss
client/src/app/+videos/+video-watch/shared/metadata/video-description.component.html
client/src/app/core/hotkeys/hotkeys.component.html
client/src/app/header/search-typeahead.component.html
client/src/app/menu/menu.component.html
client/src/app/menu/menu.component.scss
client/src/app/shared/form-validators/video-validators.ts
client/src/app/shared/shared-abuse-list/abuse-list-table.component.html
client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.html
client/src/app/shared/shared-actor-image-edit/actor-avatar-edit.component.scss
client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.html
client/src/app/shared/shared-actor-image-edit/actor-banner-edit.component.scss
client/src/app/shared/shared-actor-image/actor-avatar.component.ts
client/src/app/shared/shared-forms/input-switch.component.html
client/src/app/shared/shared-forms/preview-upload.component.html
client/src/app/shared/shared-icons/global-icon.component.ts
client/src/app/shared/shared-instance/instance-features-table.component.html
client/src/app/shared/shared-instance/instance-features-table.component.ts
client/src/app/shared/shared-main/angular/number-formatter.pipe.ts
client/src/app/shared/shared-main/buttons/action-dropdown.component.html
client/src/app/shared/shared-main/buttons/action-dropdown.component.ts
client/src/app/shared/shared-main/buttons/button.component.ts
client/src/app/shared/shared-main/date/date-toggle.component.html
client/src/app/shared/shared-main/loaders/loader.component.ts
client/src/app/shared/shared-main/users/user-notifications.component.html
client/src/app/shared/shared-main/users/user-quota.component.html
client/src/app/shared/shared-moderation/server-blocklist.component.html
client/src/app/shared/shared-moderation/server-blocklist.component.scss
client/src/app/shared/shared-tables/video-cell.component.html
client/src/app/shared/shared-thumbnail/video-thumbnail.component.html
client/src/app/shared/shared-video-live/live-stream-information.component.html
client/src/app/shared/shared-video-miniature/video-download.component.html
client/src/app/shared/shared-video-miniature/video-filters-header.component.html
client/src/app/shared/shared-video-miniature/video-filters.model.ts
client/src/app/shared/shared-video-miniature/videos-list.component.html
client/src/app/shared/shared-video-miniature/videos-selection.component.html
client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.html
client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.scss
client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.html
client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.scss
client/src/assets/player/shared/settings/settings-dialog.ts
client/src/assets/player/utils.ts
client/src/root-helpers/bytes.ts
client/src/root-helpers/logger.ts
client/src/root-helpers/plugins-manager.ts
client/src/sass/class-helpers/_buttons.scss
client/src/sass/class-helpers/_common.scss
client/src/sass/include/_mixins.scss
client/src/standalone/videos/embed.html
client/src/standalone/videos/test-embed.html
server/tests/api/live/live-save-replay.ts

index f7b207b58d0bdfe09c12c59c021e02ee0da902a9..a297cdc94c689a6c42b059fa57291976e7ae86cd 100644 (file)
@@ -18,8 +18,7 @@
       },
       "extends": [
         "../.eslintrc.json",
-        "plugin:@angular-eslint/ng-cli-compat",
-        "plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
+        "plugin:@angular-eslint/recommended",
         "plugin:@angular-eslint/template/process-inline-templates"
       ],
       "rules": {
         "object-shorthand": [
           "error",
           "properties"
+        ],
+        "quote-props": [
+          "error",
+          "consistent-as-needed"
         ]
       }
     },
         "*.html"
       ],
       "extends": [
-        "plugin:@angular-eslint/template/recommended"
+        "plugin:@angular-eslint/template/recommended",
+        "plugin:@angular-eslint/template/accessibility"
       ],
       "rules": {}
     }
index 3c19e4e9ad613ecc6e684e1739ec5947f53ddfe9..96ddc67cace96242d173a0fa75fd38467f9b7a88 100644 (file)
@@ -25,15 +25,15 @@ module.exports = {
 
     capabilities: [
       {
-        browserName: 'chrome',
-        acceptInsecureCerts: true,
+        'browserName': 'chrome',
+        'acceptInsecureCerts': true,
         'goog:chromeOptions': {
           args: [ '--disable-gpu', windowSizeArg ],
           prefs
         }
       },
       {
-        browserName: 'firefox',
+        'browserName': 'firefox',
         'moz:firefoxOptions': {
           binary: '/usr/bin/firefox-developer-edition',
           args: [ '--headless', windowSizeArg ],
index 903235b862e150e916414d4c8ab50f165ca3d0da..5cdd692901700f98759b7624b3238cabc3c25768 100644 (file)
@@ -20,14 +20,14 @@ module.exports = {
 
     capabilities: [
       {
-        browserName: 'chrome',
+        'browserName': 'chrome',
         'goog:chromeOptions': {
           args: [ '--headless', '--disable-gpu', windowSizeArg ],
           prefs
         }
       },
       {
-        browserName: 'firefox',
+        'browserName': 'firefox',
         'moz:firefoxOptions': {
           binary: '/usr/bin/firefox-developer-edition',
           args: [ '--headless', windowSizeArg ],
index 5c09b0f46f07f18d56832c3a59b682788cd0eadf..f52a95b88e6233003f5bf9613655b7a782089676 100644 (file)
@@ -16,7 +16,7 @@ export type ResolverData = {
 }
 
 @Injectable()
-export class AboutInstanceResolver  {
+export class AboutInstanceResolver {
 
   constructor (
     private instanceService: InstanceService,
index 2a49859643c6f69d2a8aaec699d66cd13dd4566a..66d10813479f9d8fb23cd0cba23584dd8eadbeff 100644 (file)
       <div class="description-html" [innerHTML]="accountDescriptionHTML"></div>
     </div>
 
-    <div *ngIf="hasShowMoreDescription()" class="show-more d-md-none d-block" role="button"
+    <button *ngIf="hasShowMoreDescription()" class="show-more d-md-none d-block button-unstyle"
       (click)="accountDescriptionExpanded = !accountDescriptionExpanded"
       title="Show the complete description" i18n-title i18n
     >
       Show more...
-    </div>
+    </button>
 
     <div class="buttons">
       <a *ngIf="isManageable()" routerLink="/my-account" class="peertube-button-link orange-button" i18n>
index a17b13fdf193f7b312cf6603aec54708bef0b16d..bbf946df0aa0d1f60c43faeb4deb8ff799a07918 100644 (file)
@@ -3,7 +3,7 @@
   <div class="row mt-5"> <!-- cache grid -->
 
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">CACHE</div>
+      <h2 i18n class="inner-form-title">CACHE</h2>
       <div i18n class="inner-form-description">
         Some files are not federated, and fetched when necessary. Define their caching policies.
       </div>
@@ -60,7 +60,7 @@
   <div class="row mt-4"> <!-- cache grid -->
     <div class="col-12 col-lg-4 col-xl-3">
       <div class="anchor" id="customizations"></div> <!-- customizations anchor -->
-      <div i18n class="inner-form-title">CUSTOMIZATIONS</div>
+      <h2 i18n class="inner-form-title">CUSTOMIZATIONS</h2>
       <div i18n class="inner-form-description">
         Slight modifications to your PeerTube instance for when creating a plugin or theme is overkill.
       </div>
index 9fc3323087c6b9f19a66c5de43d04b953164a739..50533ef73191a20cdbb761bfee17b97ee4977de2 100644 (file)
@@ -1,7 +1,7 @@
 <ng-container [formGroup]="form">
   <div class="row mt-5"> <!-- appearance grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">APPEARANCE</div>
+      <h2 i18n class="inner-form-title">APPEARANCE</h2>
       <div i18n class="inner-form-description">
         Use <a class="link-orange" routerLink="/admin/plugins">plugins & themes</a> for more involved changes, or add slight <a class="link-orange" routerLink="/admin/config/edit-custom" fragment="advanced-configuration">customizations</a>.
       </div>
@@ -91,7 +91,7 @@
 
   <div class="row mt-4"> <!-- broadcast grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">BROADCAST MESSAGE</div>
+      <h2 i18n class="inner-form-title">BROADCAST MESSAGE</h2>
       <div i18n class="inner-form-description">
         Display a message on your instance
       </div>
 
   <div class="row mt-4"> <!-- new users grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">NEW USERS</div>
+      <h2 i18n class="inner-form-title">NEW USERS</h2>
       <div i18n class="inner-form-description">
         Manage <a class="link-orange" routerLink="/admin/users">users</a> to set their quota individually.
       </div>
 
   <div class="row mt-4"> <!-- videos grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">VIDEOS</div>
+      <h2 i18n class="inner-form-title">VIDEOS</h2>
     </div>
 
     <div class="col-12 col-lg-8 col-xl-9">
 
   <div class="row mt-4"> <!-- video channels grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">VIDEO CHANNELS</div>
+      <h2 i18n class="inner-form-title">VIDEO CHANNELS</h2>
     </div>
 
     <div class="col-12 col-lg-8 col-xl-9">
 
   <div class="row mt-4"> <!-- search grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">SEARCH</div>
+      <h2 i18n class="inner-form-title">SEARCH</h2>
     </div>
 
     <div class="col-12 col-lg-8 col-xl-9">
 
   <div class="row mt-4"> <!-- federation grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">FEDERATION</div>
+      <h2 i18n class="inner-form-title">FEDERATION</h2>
       <div i18n class="inner-form-description">
         Manage <a class="link-orange" routerLink="/admin/follows">relations</a> with other instances.
       </div>
 
   <div class="row mt-4"> <!-- administrators grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">ADMINISTRATORS</div>
+      <h2 i18n class="inner-form-title">ADMINISTRATORS</h2>
     </div>
 
     <div class="col-12 col-lg-8 col-xl-9">
 
   <div class="row mt-4"> <!-- Twitter grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">TWITTER</div>
+      <h2 i18n class="inner-form-title">TWITTER</h2>
       <div i18n class="inner-form-description">
         Provide the Twitter account representing your instance to improve link previews.
         If you don't have a Twitter account, just leave the default value.
index 3d8414f5c799e54dec07360b9ecb85bf44f1f9bc..fd009367f92210e78d45bab0592cd7dcab39fd48 100644 (file)
@@ -4,7 +4,7 @@
 
     <div class="homepage row mt-5"> <!-- homepage grid -->
       <div class="col-12 col-lg-4 col-xl-3">
-        <div i18n class="inner-form-title">INSTANCE HOMEPAGE</div>
+        <h2 i18n class="inner-form-title">INSTANCE HOMEPAGE</h2>
       </div>
 
       <div class="col-12 col-lg-8 col-xl-9">
index ff79ecc88789686e2a37bb37d6c4b4038c0c3252..60f1aee2e0a67b2cb698fe821d2eac74d7302fbb 100644 (file)
@@ -4,7 +4,7 @@
 
     <div class="row mt-5"> <!-- instance grid -->
       <div class="col-12 col-lg-4 col-xl-3">
-        <div i18n class="inner-form-title">INSTANCE</div>
+        <h2 i18n class="inner-form-title">INSTANCE</h2>
       </div>
 
       <div class="col-12 col-lg-8 col-xl-9">
@@ -76,7 +76,7 @@
 
     <div class="row mt-4"> <!-- moderation & nsfw grid -->
       <div class="col-12 col-lg-4 col-xl-3">
-        <div i18n class="inner-form-title">MODERATION & NSFW</div>
+        <h2 i18n class="inner-form-title">MODERATION & NSFW</h2>
         <div i18n class="inner-form-description">
           Manage <a class="link-orange" routerLink="/admin/users">users</a> to build a moderation team.
         </div>
 
     <div class="row mt-4"> <!-- you and your instance grid -->
       <div class="col-12 col-lg-4 col-xl-3">
-        <div i18n class="inner-form-title">YOU AND YOUR INSTANCE</div>
+        <h2 i18n class="inner-form-title">YOU AND YOUR INSTANCE</h2>
       </div>
 
       <div class="col-12 col-lg-8 col-xl-9">
 
     <div class="row mt-4"> <!-- other information grid -->
       <div class="col-12 col-lg-4 col-xl-3">
-        <div i18n class="inner-form-title">OTHER INFORMATION</div>
+        <h2 i18n class="inner-form-title">OTHER INFORMATION</h2>
       </div>
 
       <div class="col-12 col-lg-8 col-xl-9">
index e9919741fab8148fa14381c4de43f2fddefe447a..1ba3bdfe07c403f368c1e4bcf5b23473b88702bb 100644 (file)
@@ -2,7 +2,7 @@
 
   <div class="row mt-5">
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">LIVE</div>
+      <h2 i18n class="inner-form-title">LIVE</h2>
       <div i18n class="inner-form-description">
         Enable users of your instance to stream live.
       </div>
@@ -89,7 +89,7 @@
 
   <div class="row"> <!-- transcoding live streams grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">TRANSCODING</div>
+      <h2 i18n class="inner-form-title">TRANSCODING</h2>
       <div i18n class="inner-form-description">
         Same as VOD transcoding, transcoding live streams so that they are in a streamable form that any device can play. Requires a beefy CPU, and then some.
       </div>
           </div>
 
           <div class="callout callout-light pt-2 mt-2 pb-0">
-            <label i18n>Output formats</label>
+            <h3 class="callout-title" i18n>Output formats</h3>
 
             <div class="form-group" [ngClass]="getDisabledLiveTranscodingClass()">
               <label i18n for="liveTranscodingThreads">Live resolutions to generate</label>
index d3fc2e481743272621e87cae5038a743a7274f82..fb750aca6b6cda8387da48b551fdcd3437934cce 100644 (file)
@@ -18,7 +18,7 @@
 
   <div class="row mt-4"> <!-- transcoding grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">TRANSCODING</div>
+      <h2 i18n class="inner-form-title">TRANSCODING</h2>
       <div i18n class="inner-form-description">
         Process uploaded videos so that they are in a streamable form that any device can play. Though costly in
         resources, this is a critical part of PeerTube, so tread carefully.
@@ -38,7 +38,7 @@
             <ng-container ngProjectAs="extra">
 
               <div class="callout callout-light pt-2 pb-0">
-                <label i18n>Input formats</label>
+                <h3 class="callout-title" i18n>Input formats</h3>
 
                 <div class="form-group" [ngClass]="getTranscodingDisabledClass()">
                   <my-peertube-checkbox
@@ -65,7 +65,7 @@
               </div>
 
               <div class="callout callout-light pt-2 mt-2 pb-0">
-                <label i18n>Output formats</label>
+                <h3 class="callout-title" i18n>Output formats</h3>
 
                 <ng-container formGroupName="webtorrent">
                   <div class="form-group" [ngClass]="getTranscodingDisabledClass()">
                 </ng-container>
 
                 <div class="form-group" [ngClass]="getTranscodingDisabledClass()">
-                  <label i18n>Resolutions to generate</label>
+                  <div class="mb-2 fw-bold" i18n>Resolutions to generate</div>
 
                   <div class="ms-2 d-flex flex-column">
                     <my-peertube-checkbox
 
   <div class="row mt-2"> <!-- video studio grid -->
     <div class="col-12 col-lg-4 col-xl-3">
-      <div i18n class="inner-form-title">VIDEO STUDIO</div>
+      <h2 i18n class="inner-form-title">VIDEO STUDIO</h2>
       <div i18n class="inner-form-description">
         Allows your users to edit their video (cut, add intro/outro, add a watermark etc)
       </div>
index 1605190f64ef40b3601885c2e003f5ce2d53c11d..f46f3637551bd09af56eebaeaf9c5a53037f93c3 100644 (file)
         >
         </my-action-dropdown>
 
-        <a *ngIf="!isInSelectionMode()" class="follow-button" (click)="openFollowModal()" (key.enter)="openFollowModal()">
+        <button *ngIf="!isInSelectionMode()" class="peertube-create-button" (click)="openFollowModal()">
           <my-global-icon iconName="following" aria-hidden="true"></my-global-icon>
           <ng-container i18n>Follow</ng-container>
-        </a>
+        </button>
       </div>
 
       <div class="ms-auto">
index 0de80e563582265949897cb1dd865958c53a8625..405ddae5ca4251f02667db60e9901e165435dc5d 100644 (file)
@@ -16,10 +16,6 @@ a {
   }
 }
 
-.follow-button {
-  @include create-button;
-}
-
 my-delete-button {
   max-width: 130px;
 }
index ce32268579682abd1e0c4cde2236bae1dc5b8a07..7b3eadac2fd3f51077dc086f31d5fd9aacfae52b 100644 (file)
 
     <div class="danger-zone">
       <div class="form-group">
-        <label i18n>Send a link to reset the password by email to the user</label>
+        <div class="mb-1 fw-bold" i18n>Send a link to reset the password by email to the user</div>
         <button (click)="resetPassword()" i18n>Ask for new password</button>
       </div>
 
       <div class="form-group">
-        <label i18n>Manually set the user password</label>
+        <div class="mb-1 fw-bold" i18n>Manually set the user password</div>
         <my-user-password [userId]="user.id" [username]="user.username"></my-user-password>
       </div>
 
       <div *ngIf="user.twoFactorEnabled" class="form-group">
-        <label i18n>This user has two factor authentication enabled</label>
+        <div class="mb-1 fw-bold" i18n>This user has two factor authentication enabled</div>
         <button (click)="disableTwoFactorAuth()" i18n>Disable two factor authentication</button>
       </div>
     </div>
index b7467d2cb6b35540f95a224548205d1dcffd2bca..8c90f5a450fa0506870c9d74b108f6b6aef307cf 100644 (file)
@@ -20,7 +20,7 @@
         >
         </my-action-dropdown>
 
-        <a *ngIf="!isInSelectionMode()" class="add-button" routerLink="/admin/users/create">
+        <a *ngIf="!isInSelectionMode()" class="peertube-create-button" routerLink="/admin/users/create">
           <my-global-icon iconName="user-add" aria-hidden="true"></my-global-icon>
           <ng-container i18n>Create user</ng-container>
         </a>
index 2a3b955d2d2e1db546fa877ffe9fe6b2114139a7..559a00251d96967e124a57cfbf32f23e2c3529ab 100644 (file)
@@ -2,10 +2,6 @@
 @use '_mixins' as *;
 @use 'bootstrap/scss/functions' as *;
 
-.add-button {
-  @include create-button;
-}
-
 tr.banned > td {
   background-color: lighten($color: $red, $amount: 40) !important;
 }
index 40049390e7fdf0c78e6d5d010b9f226de174212a..8ccc7361797292c720dd35a5d310c23438e4e00e 100644 (file)
           <input type="submit" class="peertube-button orange-button w-100" i18n-value value="Login" [disabled]="!form.valid">
 
           <div *ngIf="!otpStep" class="additional-links d-flex justify-content-center mt-4 mb-5">
-            <a i18n role="button" class="link-orange mx-3" (click)="openForgotPasswordModal()" i18n-title title="Click here to reset your password">I forgot my password</a>
+            <button i18n class="button-unstyle link-orange mx-3" (click)="openForgotPasswordModal()" i18n-title title="Click here to reset your password">
+              I forgot my password
+            </button>
 
             <ng-container *ngIf="signupAllowed">
-              <span>·</span>
+              <span class="lh-1">·</span>
               <a i18n routerLink="/signup" class="link-orange mx-3">Create an account</a>
             </ng-container>
           </div>
index ba0d412d61824e3046fb240b5ca357ce1b61375f..1e224db8cec5b4b29beba06d8e7126296fed60c5 100644 (file)
@@ -85,8 +85,8 @@ export class LoginComponent extends FormReactive implements OnInit, AfterViewIni
 
     // Avoid undefined errors when accessing form error properties
     this.buildForm({
-      username: LOGIN_USERNAME_VALIDATOR,
-      password: LOGIN_PASSWORD_VALIDATOR,
+      'username': LOGIN_USERNAME_VALIDATOR,
+      'password': LOGIN_PASSWORD_VALIDATOR,
       'otp-token': {
         VALIDATORS: [], // Will be set dynamically
         MESSAGES: USER_OTP_TOKEN_VALIDATOR.MESSAGES
index 3720668900e6a8751cbde736cb937feece931418..8ca94b0b384f81535b12f4d1fbbd6384cb09103e 100644 (file)
@@ -38,10 +38,10 @@ export class VideoChannelCreateComponent extends VideoChannelEdit implements OnI
 
   ngOnInit () {
     this.buildForm({
-      name: VIDEO_CHANNEL_NAME_VALIDATOR,
+      'name': VIDEO_CHANNEL_NAME_VALIDATOR,
       'display-name': VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR,
-      description: VIDEO_CHANNEL_DESCRIPTION_VALIDATOR,
-      support: VIDEO_CHANNEL_SUPPORT_VALIDATOR
+      'description': VIDEO_CHANNEL_DESCRIPTION_VALIDATOR,
+      'support': VIDEO_CHANNEL_SUPPORT_VALIDATOR
     })
   }
 
index 966a350d1dd9fc66703cc98240b87d97c35a82ca..58f65d994f9258e3eba268766dbc4816b59ab7bc 100644 (file)
@@ -10,8 +10,6 @@
       </div>
 
       <div class="col-12 col-lg-8 col-xl-9">
-        <label i18n>Banner image of the channel</label>
-
         <my-actor-banner-edit
           *ngIf="videoChannel" [previewImage]="isCreation()" class="d-block mb-4"
           [actor]="videoChannel" (bannerChange)="onBannerChange($event)" (bannerDelete)="onBannerDelete()"
index 3326a15052fb12457bd0287f139c26c6e2dee6c3..f9045db352f0ed72867d18ccac399d7715c7d8e4 100644 (file)
@@ -46,9 +46,9 @@ export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnI
 
     this.buildForm({
       'display-name': VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR,
-      description: VIDEO_CHANNEL_DESCRIPTION_VALIDATOR,
-      support: VIDEO_CHANNEL_SUPPORT_VALIDATOR,
-      bulkVideosSupportUpdate: null
+      'description': VIDEO_CHANNEL_DESCRIPTION_VALIDATOR,
+      'support': VIDEO_CHANNEL_SUPPORT_VALIDATOR,
+      'bulkVideosSupportUpdate': null
     })
 
     this.paramsSub = this.route.params.subscribe(routeParams => {
@@ -65,8 +65,8 @@ export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnI
 
             this.form.patchValue({
               'display-name': videoChannelToUpdate.displayName,
-              description: videoChannelToUpdate.description,
-              support: videoChannelToUpdate.support
+              'description': videoChannelToUpdate.description,
+              'support': videoChannelToUpdate.support
             })
           },
 
index ebb7ed2da301177060a36ebb7bd0f91df3a922c6..1e8fa2a56819cb2870bdf2f714a5d86a91087ac4 100644 (file)
@@ -29,7 +29,7 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
   ngOnInit () {
     this.buildForm({
       'new-email': USER_EMAIL_VALIDATOR,
-      password: USER_PASSWORD_VALIDATOR
+      'password': USER_PASSWORD_VALIDATOR
     })
 
     this.user = this.authService.getUser()
index 8621eb7aaafaedb2d5a4d400329cf74a8234ed0a..a2d1281904633c4a7595f754bc614d3e15bf809b 100644 (file)
@@ -25,17 +25,17 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit {
 
   ngOnInit () {
     this.buildForm({
-      username: null,
+      'username': null,
       'display-name': USER_DISPLAY_NAME_REQUIRED_VALIDATOR,
-      description: USER_DESCRIPTION_VALIDATOR
+      'description': USER_DESCRIPTION_VALIDATOR
     })
     this.form.controls['username'].disable()
 
     this.userInformationLoaded.subscribe(() => {
       this.form.patchValue({
-        username: this.user.username,
+        'username': this.user.username,
         'display-name': this.user.account.displayName,
-        description: this.user.account.description
+        'description': this.user.account.description
       })
     })
   }
index 5bef4a6ed2ca522b8975a6d0999be1ac7e88e496..0fe06198310578f43e40a5252ff93f8c1719a02f 100644 (file)
@@ -18,7 +18,7 @@
 <div class="video-channels-header d-flex justify-content-between gap-2">
   <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
 
-  <a class="create-button" routerLink="/manage/create">
+  <a class="peertube-create-button" routerLink="/manage/create">
     <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
     <ng-container i18n>Create video channel</ng-container>
   </a>
index 6c5be92404b337055f8d08bd46709b14570ba733..b4907db515d4a0cf75874fd3366ac58bf7aad44f 100644 (file)
@@ -17,10 +17,6 @@ h1 {
   }
 }
 
-.create-button {
-  @include create-button;
-}
-
 input[type=text] {
   @include peertube-input-text(300px);
 }
index 6791dab526eef0ffa5ec680648b436e13d8f8213..1046a8f8c03ac225a3337cde6b3756db327c8187 100644 (file)
@@ -10,8 +10,8 @@
   </div>
 
   <div class="history-switch">
-    <my-input-switch [(ngModel)]="videosHistoryEnabled" (ngModelChange)="onVideosHistoryChange()"></my-input-switch>
-    <label i18n>Track watch history</label>
+    <my-input-switch inputName="track-watch-history" [(ngModel)]="videosHistoryEnabled" (ngModelChange)="onVideosHistoryChange()"></my-input-switch>
+    <label for="track-watch-history" i18n>Track watch history</label>
   </div>
 
   <button class="delete-history" (click)="clearAllHistory()" i18n>
index d9a4f32bdbd6a45b2d0f8edd296de172fa4608a4..5db1a9bb2d957b90c0c3760f29c17e9b522c000b 100644 (file)
@@ -44,7 +44,7 @@
         <a [href]="videoChangeOwnership.video.url" class="video-table-video-link" [title]="videoChangeOwnership.video.name" target="_blank" rel="noopener noreferrer">
           <div class="video-table-video">
             <div class="video-table-video-image">
-              <img [src]="videoChangeOwnership.video.thumbnailPath">
+              <img [src]="videoChangeOwnership.video.thumbnailPath" alt="">
             </div>
             <div class="video-table-video-text">
               <div>
index 538bbd17882003235d234bc86cc134c3c5ad550c..5275fb51710255a735ecc037237a48306f4015f0 100644 (file)
@@ -20,7 +20,7 @@
   <ng-template pTemplate="caption">
     <div class="caption">
       <div class="left-buttons">
-        <a class="add-sync" routerLink="{{ getSyncCreateLink() }}">
+        <a class="peertube-create-button" routerLink="{{ getSyncCreateLink() }}">
           <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
           <ng-container i18n>Add synchronization</ng-container>
         </a>
index 6c09cc9ef6547b47940a18912db99303078a2302..153bfc6b1c0de5cf0643846348b77610bb4cfbab 100644 (file)
@@ -2,12 +2,9 @@
 @use '_mixins' as *;
 @use '_actor' as *;
 
-.add-sync {
-  @include create-button;
-}
-
 .actor {
   @include actor-row($min-height: auto, $separator: true);
+
   margin-bottom: 0;
   padding-bottom: 0;
   border: 0;
index e867f63b817b8642d51cc2363342bd2e249f8fff..a3c2aab44eeff34a2be3a8c61c83b58264e90c96 100644 (file)
@@ -61,7 +61,7 @@
         </div>
 
         <div class="form-group">
-          <label i18n>Channel</label>
+          <label for="videoChannelIdl" i18n>Channel</label>
 
           <my-select-channel
             labelForId="videoChannelIdl" [items]="userVideoChannels" formControlName="videoChannelId"
@@ -73,7 +73,7 @@
         </div>
 
         <div class="form-group">
-          <label i18n>Playlist thumbnail</label>
+          <label for="thumbnailfile" i18n>Playlist thumbnail</label>
 
           <my-preview-upload
             i18n-inputLabel inputLabel="Edit" inputName="thumbnailfile" formControlName="thumbnailfile"
index 3bab20a222dbcc0c9832849b4846087b0e0554be..ebcb0b1fd87d8cac94066bae72b3c5dbbe88c22a 100644 (file)
@@ -9,7 +9,7 @@
 <div class="video-playlists-header d-flex justify-content-between gap-2">
   <my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
 
-  <a class="create-button" routerLink="create">
+  <a class="peertube-create-button" routerLink="create">
     <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
     <ng-container i18n>Create playlist</ng-container>
   </a>
index 07e50e53f0d36767702b0e6a58be0edddf298e39..f22feaa48c6b47823cce113f0487a2910a05d9d7 100644 (file)
@@ -5,10 +5,6 @@ h1 {
   display: flex;
 }
 
-.create-button {
-  @include create-button;
-}
-
 input[type=text] {
   @include peertube-input-text(300px);
 }
index 9bb609ae8405ccfd21f15a46388049e5660284da..b95287151ccae34443395ec564bbc2dc71f290d0 100644 (file)
   #videosSelection
 >
   <ng-template ptTemplate="globalButtons">
-    <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
+    <button class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
       <my-global-icon iconName="delete" aria-hidden="true"></my-global-icon>
       <ng-container i18n>Delete</ng-container>
-    </span>
+    </button>
   </ng-template>
 
   <ng-template ptTemplate="rowButtons" let-video>
index a6c05bbfb0d47789aa047c687e72fa6d26e84d15..a998944580209108cb1373d1055e2607d1fbfd5e 100644 (file)
@@ -27,7 +27,7 @@ export class ResetPasswordComponent extends FormReactive implements OnInit {
 
   ngOnInit () {
     this.buildForm({
-      password: USER_PASSWORD_VALIDATOR,
+      'password': USER_PASSWORD_VALIDATOR,
       'password-confirm': RESET_PASSWORD_CONFIRM_VALIDATOR
     })
 
index 5bce009d5525bcfa1e9698c2bd6a0889c64ce275..ed0632a4dcdcb8f9ea076587eb08f092a556f545 100644 (file)
@@ -4,7 +4,7 @@
     <div class="col-lg-4 col-md-6 col-xs-12">
       <div class="form-group">
         <div class="radio-label label-container">
-          <label i18n>Sort</label>
+          <label for="sort" i18n>Sort</label>
           <button i18n class="reset-button reset-button-small" (click)="resetField('sort', '-match')" *ngIf="advancedSearch.sort !== '-match'">
             Reset
           </button>
@@ -18,7 +18,7 @@
 
       <div class="form-group">
         <div class="radio-label label-container">
-          <label i18n>Display only</label>
+          <label for="isLive" i18n>Display only</label>
           <button i18n class="reset-button reset-button-small" (click)="resetField('isLive')" *ngIf="advancedSearch.isLive !== undefined">
             Reset
           </button>
@@ -37,7 +37,7 @@
 
       <div class="form-group">
         <div class="radio-label label-container">
-          <label i18n>Display sensitive content</label>
+          <label for="sensitiveContent" i18n>Display sensitive content</label>
           <button i18n class="reset-button reset-button-small" (click)="resetField('nsfw')" *ngIf="advancedSearch.nsfw !== undefined">
             Reset
           </button>
@@ -56,7 +56,7 @@
 
       <div class="form-group">
         <div class="radio-label label-container">
-          <label i18n>Published date</label>
+          <label for="publishedDateRange" i18n>Published date</label>
           <button i18n class="reset-button reset-button-small" (click)="resetLocalField('publishedDateRange')" *ngIf="publishedDateRange !== undefined">
             Reset
           </button>
     <div class="col-lg-4 col-md-6 col-xs-12">
       <div class="form-group">
         <div class="radio-label label-container">
-          <label i18n>Duration</label>
+          <label for="durationRange" i18n>Duration</label>
           <button i18n class="reset-button reset-button-small" (click)="resetLocalField('durationRange')" *ngIf="durationRange !== undefined">
             Reset
           </button>
 
       <div class="form-group">
         <div class="radio-label label-container">
-          <label i18n>Result types</label>
+          <label for="resultType" i18n>Result types</label>
           <button i18n class="reset-button reset-button-small" (click)="resetField('resultType')" *ngIf="advancedSearch.resultType !== undefined">
             Reset
           </button>
 
       <div class="form-group" *ngIf="isSearchTargetEnabled()">
         <div class="radio-label label-container">
-          <label i18n>Search target</label>
+          <label for="searchTarget" i18n>Search target</label>
         </div>
 
         <div class="peertube-radio-container">
index 2530c87b759c8758e56cdbfd671465bd2169aa64..fef6f8e8cbc6bcbb727d2090cb8d8036aa499c5c 100644 (file)
@@ -10,8 +10,8 @@
         <span *ngIf="currentSearch" i18n>for <span class="search-value">{{ currentSearch }}</span></span>
       </div>
 
-      <div
-        class="results-filter-button ms-auto" (click)="isSearchFilterCollapsed = !isSearchFilterCollapsed" role="button"
+      <button
+        class="results-filter-button button-unstyle ms-auto" (click)="isSearchFilterCollapsed = !isSearchFilterCollapsed"
         [attr.aria-expanded]="!isSearchFilterCollapsed" aria-controls="collapseBasic"
       >
         <span class="icon icon-filter"></span>
@@ -19,7 +19,7 @@
           Filters
           <span *ngIf="numberOfFilters() > 0" class="pt-badge badge-secondary">{{ numberOfFilters() }}</span>
         </ng-container>
-      </div>
+      </button>
     </div>
 
     <div class="results-filter" [ngbCollapse]="isSearchFilterCollapsed" [animation]="true">
index 6940a7a9ba4749f44100f0b2005f86ff9266a807..6765ba15e1e5510b1277262aa7b61c6028f509eb 100644 (file)
@@ -4,7 +4,7 @@ import { ActivatedRouteSnapshot, Router } from '@angular/router'
 import { logger } from '@root-helpers/logger'
 import { ResultList } from '@shared/models'
 
-export abstract class AbstractLazyLoadResolver <T>  {
+export abstract class AbstractLazyLoadResolver <T> {
   protected router: Router
 
   resolve (route: ActivatedRouteSnapshot) {
index f43a4684228f0c99429f655f8461aaa728a1679c..f2687e520956687e64f921b780b66b301b71600e 100644 (file)
@@ -2,9 +2,10 @@
   <header *ngIf="steps.length > 2">
     <div class="header-steps">
       <ng-container *ngFor="let step of steps; let i = index; let isLast = last;">
-        <div
-          class="step-info" [ngClass]="{ active: selectedIndex === i, completed: isCompleted(step), 'c-hand': isAccessible(step) }" [attr.aria-current]="selectedIndex === i"
-          (click)="onClick(i)"
+        <button
+          class="step-info button-unstyle" [ngClass]="{ active: selectedIndex === i, completed: isCompleted(step) }"
+          [disabled]="!isAccessible(step)"
+          [attr.aria-current]="selectedIndex === i" (click)="onClick(i)"
         >
           <div class="step-index">
             <span class="visually-hidden" i18n>Step</span> {{ i + 1 }}
@@ -15,7 +16,7 @@
           </div>
 
           <div class="step-label">{{ step.label }}</div>
-        </div>
+        </button>
 
         <!-- Do no display if this is the last child -->
         <div *ngIf="!isLast" class="connector"></div>
index 919799716287fe4dbc085b00608a18d31cc51db9..264136b06eafe7af05c77aefc2ce9b5ffaa60936 100644 (file)
@@ -72,11 +72,6 @@ header {
   align-items: center;
   width: $index-block-height;
   opacity: 0.5;
-  cursor: default;
-
-  &.c-hand {
-    cursor: pointer;
-  }
 
   &.active,
   &.completed {
index 86763e8014f58240d5a91123e672e0a317d44f01..71bca63e3b4b37bedf97a24643d1a4538ae9ecf0 100644 (file)
@@ -92,9 +92,9 @@
             <button cdkStepperPrevious>{{ defaultPreviousStepButtonLabel }}</button>
 
             <div class="skip-step">
-              <span class="underline-orange" role="button" (click)="skipChannelCreation()">
+              <button class="underline-orange button-unstyle" (click)="skipChannelCreation()">
                 <strong i18n>I don't want to create a channel</strong>
-              </span>
+              </button>
 
               <div class="skip-step-description" i18n>You will be able to create a channel later</div>
             </div>
             [requiresEmailVerification]="requiresEmailVerification" [requiresApproval]="requiresApproval" [instanceName]="instanceName"
           ></my-signup-success-before-email>
 
-          <div *ngIf="signupError" class="steps-button">
+          <div *ngIf="signupError" class="step-buttons">
             <button cdkStepperPrevious>{{ defaultPreviousStepButtonLabel }}</button>
           </div>
         </cdk-step>
index 9904e4ab4ecc7489fef117ede54393424f0c2b79..ae0fdbb6ea658a8980e5706e0c8a197b62633870 100644 (file)
@@ -44,7 +44,19 @@ my-instance-about-accordion {
     }
   }
 
-  button,
+  > button {
+    @include peertube-button-big;
+
+    &[cdkStepperNext] {
+      @include orange-button;
+    }
+
+    &[cdkStepperPrevious] {
+      @include grey-button;
+    }
+  }
+
+  > button,
   .skip-step {
     margin-top: 20px;
     margin-bottom: 20px;
@@ -60,18 +72,6 @@ my-instance-about-accordion {
   }
 }
 
-button {
-  @include peertube-button-big;
-
-  &[cdkStepperNext] {
-    @include orange-button;
-  }
-
-  &[cdkStepperPrevious] {
-    @include grey-button;
-  }
-}
-
 .done-loader {
   display: flex;
   justify-content: center;
index d92aa072d628b8345b770f909e5096611e869930..fff160f2e9e9432e35d47432da6e90819b41dfd4 100644 (file)
       <div class="description-html" [innerHTML]="channelDescriptionHTML"></div>
     </div>
 
-    <div *ngIf="hasShowMoreDescription()" class="show-more" role="button"
+    <button *ngIf="hasShowMoreDescription()" class="show-more button-unstyle"
       (click)="channelDescriptionExpanded = !channelDescriptionExpanded"
       title="Show the complete description" i18n-title i18n
     >
       Show more...
-    </div>
+    </button>
 
     <div class="channel-buttons bottom">
       <ng-template *ngTemplateOutlet="buttonsTemplate"></ng-template>
index fe74062d2cd50b00ece693c183ccb0f7c99b3efb..c29b12157b39114db55c4d61bace2b334c9bafa7 100644 (file)
 
     <div class="information">
       <div>
-        <label i18n>Video before edition</label>
+        <div class="mb-1 fw-bold" i18n>Video before edition</div>
         <my-embed [video]="video"></my-embed>
       </div>
 
       <div *ngIf="!noEdition()">
-        <label i18n>Edition tasks:</label>
+        <div class="mb-1 fw-bold" i18n>Edition tasks:</div>
 
         <ol>
           <li *ngFor="let task of getTasksSummary()">{{ task }}</li>
index 94f7b5d0bbe7ecdaade5351b33e755cb8f2cae07..3d618fbe159c6587cf459fdc588fb4c4b4fd5fae 100644 (file)
@@ -43,7 +43,7 @@ export class VideoStudioEditComponent extends FormReactive implements OnInit {
     }
 
     this.buildForm({
-      cut: {
+      'cut': {
         start: null,
         end: null
       },
index b0da8497941e3dc4d23068a43282baafc75d1f2d..b607dabe95e6a78f5b8759d79eb9665d04be5fad 100644 (file)
@@ -22,7 +22,7 @@
             </div>
 
             <div class="form-group">
-              <label i18n class="label-tags">Tags</label>
+              <label for="label-tags" i18n class="label-tags">Tags</label>
 
               <my-help>
                 <ng-template ptTemplate="customHtml">
         <div class="captions">
 
           <div class="captions-header">
-            <a (click)="openAddCaptionModal()" class="create-caption">
+            <button (click)="openAddCaptionModal()" class="peertube-create-button">
               <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
               <ng-container i18n>Add another caption</ng-container>
-            </a>
+            </button>
           </div>
 
           <div class="form-group" *ngFor="let videoCaption of videoCaptions">
 
                 <div i18n class="caption-entry-state">Already uploaded on {{ videoCaption.updatedAt | date }}  &#10004;</div>
 
-                <span i18n class="caption-entry-edit" (click)="openEditCaptionModal(videoCaption)">Edit</span>
-                <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</span>
+                <button i18n class="caption-entry-edit" (click)="openEditCaptionModal(videoCaption)">Edit</button>
+                <button i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Delete</button>
               </ng-container>
 
               <ng-container *ngIf="videoCaption.action === 'CREATE'">
 
                 <div i18n class="caption-entry-state caption-entry-state-create">Will be created on update</div>
 
-                <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel create</span>
+                <button i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel create</button>
               </ng-container>
 
               <ng-container *ngIf="videoCaption.action === 'UPDATE'">
 
                 <div i18n class="caption-entry-state caption-entry-state-create">Will be edited on update</div>
 
-                <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel edition</span>
+                <button i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel edition</button>
               </ng-container>
 
               <ng-container *ngIf="videoCaption.action === 'REMOVE'">
 
                 <div i18n class="caption-entry-state caption-entry-state-delete">Will be deleted on update</div>
 
-                <span i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</span>
+                <button i18n class="caption-entry-delete" (click)="deleteCaption(videoCaption)">Cancel deletion</button>
               </ng-container>
             </div>
           </div>
index a8075cc6d6fe07c5b1fe690b789df07adf5a0223..1c6f7f5abc763a37cfda59d33ec51bfdbae95392 100644 (file)
@@ -29,10 +29,6 @@ my-peertube-checkbox {
   margin-bottom: 1rem;
 }
 
-.create-caption {
-  @include create-button;
-}
-
 .caption-entry {
   display: flex;
   height: 40px;
index e27942e665ac99d665351dbb22969074d2566702..a003a10eb69e577ab15d1641e1cd7abf04a335c4 100644 (file)
@@ -64,7 +64,7 @@
           (timestampClicked)="handleTimestampClicked($event)"
           [redraftValue]="commentReplyRedraftValue"
         >
-          <div *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2">
+          <button *ngIf="comment.totalReplies !== 0 && !threadComments[comment.id]" (click)="viewReplies(comment.id)" class="view-replies mb-2 button-unstyle">
             <span class="chevron-down"></span>
 
             <ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container>
@@ -81,7 +81,7 @@
             <ng-template i18n #noAuthorComments>View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}}</ng-template>
 
             <my-loader size="sm" class="ms-1" [loading]="threadLoading[comment.id]"></my-loader>
-          </div>
+          </button>
         </my-video-comment>
 
       </div>
index 5001ad168c2849fb9313af1723ba4c8d100cb59c..7720fe43beae156d90638ca0e3db498b798326e4 100644 (file)
     @include margin-left(5px);
 
     display: inline-block;
-    opacity: 0;
     transition: ease-in .2s opacity;
     width: 12px;
     position: relative;
     top: -3px;
   }
-
-  &:hover my-feed {
-    opacity: 1;
-  }
 }
 
 #dropdown-sort-comments {
index 7677ae8369ea4e0cf01195b9918bdc51bd2164e2..93c4ba7a7231f43861da55fbed4eebd60191e7eb 100644 (file)
@@ -6,10 +6,11 @@
         the sharing system used for this video implies that some technical information about your system (such as a public IP address) can be sent to other peers.
       </ng-container>
     </span>
+
     <a i18n i18n-title title="Get more information" target="_blank" rel="noopener noreferrer" href="/about/peertube#privacy">More information</a>
   </div>
 
-  <div i18n class="privacy-concerns-button privacy-concerns-okay" (click)="acceptedPrivacyConcern()">
+  <button i18n class="ms-2 peertube-button orange-button" (click)="acceptedPrivacyConcern()">
     OK
-  </div>
+  </button>
 </div>
index a6479c7ecd01f917ee2de2a3f9145fe4c4173f2f..f7f9dfd2f4e302cfafc2596f14e33769dbcf2f14 100644 (file)
@@ -50,31 +50,10 @@ a {
   transition: color 0.3s;
 
   &:hover {
-    color: #fff;
+    color: pvar(--mainBackgroundColor);
   }
 }
 
-.privacy-concerns-button {
-  @include margin-left(auto);
-
-  padding: 5px 8px 5px 7px;
-  border-radius: 3px;
-  white-space: nowrap;
-  cursor: pointer;
-  transition: background-color 0.3s;
-  font-weight: $font-semibold;
-
-  &:hover {
-    background-color: #000;
-  }
-}
-
-.privacy-concerns-okay {
-  @include margin-left(10px);
-
-  background-color: pvar(--mainColor);
-}
-
 @media screen and (max-width: 1300px) {
   .privacy-concerns {
     font-size: 12px;
index d847daff7d7705e155c85f066f6a98d47a772077..9db3018e613ae16910ee7c7796266b790360f8ec 100644 (file)
@@ -6,14 +6,20 @@
     myTimestampRouteTransformer
   ></div>
 
-  <div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description?.length >= 250" (click)="showMoreDescription()">
+  <button
+    *ngIf="completeDescriptionShown === false && video.description?.length >= 250"
+    (click)="showMoreDescription()" class="video-info-description-more button-unstyle"
+  >
     <ng-container i18n>Show more</ng-container>
     <span *ngIf="descriptionLoading === false" class="chevron-down"></span>
     <my-loader size="sm" class="description-loading" [loading]="descriptionLoading"></my-loader>
-  </div>
+  </button>
 
-  <div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-info-description-more">
+  <button
+    *ngIf="completeDescriptionShown === true"
+    (click)="showLessDescription()" class="video-info-description-more button-unstyle"
+  >
     <ng-container i18n>Show less</ng-container>
     <span *ngIf="descriptionLoading === false" class="chevron-up"></span>
-  </div>
+  </button>
 </div>
index 61f03be33e5ef87fb55403494e97c1512fb9c36f..b7a6b376b20a643ea6212a3d81f90d38dea43592 100644 (file)
@@ -13,6 +13,6 @@
         </tbody>
       </table>
     </div>
-    <div class="cfp-hotkeys-close" (click)="toggleCheatSheet()">&#215;</div>
+    <button class="button-unstyle cfp-hotkeys-close" (click)="toggleCheatSheet()">&#215;</button>
   </div>
-</div>
\ No newline at end of file
+</div>
index 783b4b53b35d8f306689895b32369cbeb011dd6a..c5ca4b9b942f42e730137f3684fc71e4800d373e 100644 (file)
@@ -14,7 +14,8 @@
     <ul [hidden]="!search || !areSuggestionsOpened" role="listbox" class="p-0 m-0">
       <li
         *ngFor="let result of results; let i = index" class="suggestion d-flex flex-justify-start flex-items-center p-0 f5"
-        role="option" aria-selected="true" (mouseenter)="onSuggestionHover(i)" (click)="onSuggestionClicked(result)"
+        role="option" aria-selected="true" tabindex="0"
+        (mouseenter)="onSuggestionHover(i)" (click)="onSuggestionClicked(result)" (keyup.enter)="onSuggestionClicked(result)"
       >
         <my-suggestion [result]="result" [highlight]="search"></my-suggestion>
       </li>
@@ -23,7 +24,7 @@
     <!-- suggestion help, not shown until one of the suggestions is selected and specific to that suggestion -->
     <div *ngIf="showSearchGlobalHelp()" id="typeahead-help" class="overflow-hidden">
       <div class="d-flex justify-content-between">
-        <label class="small-title" i18n>GLOBAL SEARCH</label>
+        <div class="small-title" i18n>GLOBAL SEARCH</div>
         <div class="advanced-search-status muted">
           <span *ngIf="serverConfig" class="me-1" i18n>using {{ serverConfig.search.searchIndex.url }}</span>
         </div>
@@ -35,7 +36,7 @@
     <div *ngIf="areInstructionsDisplayed()" id="typeahead-instructions" class="overflow-hidden">
       <span class="muted" i18n>Your query will be matched against video names or descriptions, channel names.</span>
       <div class="d-flex justify-content-between mt-3">
-        <label class="small-title" i18n>ADVANCED SEARCH</label>
+        <div class="small-title" i18n>ADVANCED SEARCH</div>
         <div class="advanced-search-status c-help">
           <span [ngClass]="canSearchAnyURI ? 'text-success' : 'muted'" i18n-title title="Determines whether you can resolve any distant content, or if this instance only allows doing so for instances it follows.">
             <span *ngIf="canSearchAnyURI()" class="me-1" i18n>any instance</span>
index 8b90fb78bade49224fe3f9661f463cad746d7769..10b3f15d906aa0382817c3df554af15f3dc45028 100644 (file)
@@ -5,7 +5,7 @@
         <div>
           <div
             class="logged-in-more" ngbDropdown #dropdown="ngbDropdown" placement="bottom-left auto"
-            container="body" (openChange)="onDropdownOpenChange($event)" autoClose="outside"
+            container="body" (openChange)="onDropdownOpenChange($event)"
           >
             <button class="border-0 text-start" ngbDropdownToggle>
               <my-actor-avatar [actor]="user.account" actorType="account" size="34"></my-actor-avatar>
 
               <button
                 myPluginSelector pluginSelectorId="menu-user-dropdown-language-item"
-                ngbDropdownItem ngbDropdownToggle class="dropdown-item" (click)="openLanguageChooser()"
+                ngbDropdownItem class="dropdown-item" (click)="openLanguageChooser()"
               >
                 <my-global-icon iconName="language" aria-hidden="true"></my-global-icon>
                 <span i18n>Interface:</span>
                 <span class="ms-auto muted">{{ currentInterfaceLanguage }}</span>
               </button>
 
-              <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles"
+              <a ngbDropdownItem class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles"
                 #settingsLanguagesSubtitles (click)="onActiveLinkScrollToAnchor(settingsLanguagesSubtitles)">
                 <my-global-icon iconName="video-lang" aria-hidden="true"></my-global-icon>
                 <span i18n>Videos:</span>
                 <span class="ms-auto muted">{{ videoLanguages.join(', ') }}</span>
               </a>
 
-              <a ngbDropdownItem ngbDropdownToggle class="dropdown-item settings-sensitive" routerLink="/my-account/settings"
+              <a ngbDropdownItem class="dropdown-item settings-sensitive" routerLink="/my-account/settings"
                 fragment="video-sensitive-content-policy" #settingsSensitiveContentPolicy
                 (click)="onActiveLinkScrollToAnchor(settingsSensitiveContentPolicy)"
               >
@@ -57,7 +57,7 @@
                 <span class="ms-auto muted">{{ nsfwPolicy }}</span>
               </a>
 
-              <button ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()">
+              <button class="dropdown-item" (click)="toggleUseP2P()" (mousedown)="$event.stopPropagation()" ngbDropdownItem>
                 <my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon>
                 <ng-container i18n>Help share videos</ng-container>
 
 
               <div class="dropdown-divider"></div>
 
-              <a *ngIf="!isInMobileView" ngbDropdownItem ngbDropdownToggle class="dropdown-item" (click)="openHotkeysCheatSheet()">
+              <button *ngIf="!isInMobileView" ngbDropdownItem class="dropdown-item" (click)="openHotkeysCheatSheet()">
                 <my-global-icon iconName="command" aria-hidden="true"></my-global-icon>
                 <ng-container i18n>Keyboard shortcuts</ng-container>
-              </a>
+              </button>
 
-              <a ngbDropdownItem ngbDropdownToggle (click)="logout($event)" class="dropdown-item" href="#">
+              <button ngbDropdownItem (click)="logout($event)" class="dropdown-item">
                 <my-global-icon iconName="sign-out" aria-hidden="true"></my-global-icon>
                 <ng-container i18n>Log out</ng-container>
-              </a>
+              </button>
             </div>
           </div>
 
 
     <div class="footer">
       <div class="footer-block">
-        <a *ngIf="!isLoggedIn" class="menu-link" (click)="openQuickSettings()">
+        <button *ngIf="!isLoggedIn" class="menu-link button-unstyle" (click)="openQuickSettings()">
           <my-global-icon iconName="cog" aria-hidden="true"></my-global-icon>
           <ng-container i18n>My settings</ng-container>
-        </a>
+        </button>
 
         <a class="menu-link" routerLink="/about" routerLinkActive="active">
           <my-global-icon iconName="help" aria-hidden="true"></my-global-icon>
       <div class="footer-bottom">
 
         <div class="footer-links">
-          <span *ngIf="isLoggedIn === false" role="button" (click)="openLanguageChooser()" class="c-hand" i18n>Interface: {{ currentInterfaceLanguage }}</span>
+          <button *ngIf="isLoggedIn === false" (click)="openLanguageChooser()" class="button-unstyle" i18n>Interface: {{ currentInterfaceLanguage }}</button>
 
           <div>
             <a i18n routerLink="/about/instance">Contact</a>
             <a i18n href="https://joinpeertube.org/faq" i18n-title title="Frequently asked questions about PeerTube" target="_blank" rel="noopener noreferrer">FAQ</a>
             <a i18n routerLink="/about/instance" fragment="statistics">Stats</a>
             <a i18n href="https://docs.joinpeertube.org/api/rest-reference.html" i18n-title title="API documentation" target="_blank" rel="noopener noreferrer">API</a>
-            <a role="button" (click)="openHotkeysCheatSheet()" class="c-hand" i18n>Keyboard shortcuts</a>
+            <button (click)="openHotkeysCheatSheet()" class="button-unstyle" i18n>Keyboard shortcuts</button>
           </div>
         </div>
 
index d88025c335ff895fb70638c6be5cd76cfb6551a4..08d6fb900c96990935203824b6ff7fb41211c18b 100644 (file)
@@ -20,6 +20,7 @@ $footer-links-base-opacity: .8;
   word-break: break-word;
   transition: background-color .1s ease-in-out;
   line-height: $line-height-normal;
+  width: 100%;
 
   &.active {
     background-color: rgba(255, 255, 255, 0.15);
@@ -113,16 +114,13 @@ my-notification {
       .dropdown-toggle-indicator {
         display: inherit !important;
       }
-
-      &.dropdown-toggle {
-        max-width: 88% !important;
-      }
     }
   }
 
   @include margin-left(13px);
 
   flex: 1;
+  min-width: 1px;
   border-radius: 25px;
   transition: all .1s ease-in-out;
   cursor: pointer;
@@ -140,22 +138,24 @@ my-notification {
   /* smartphones and touchscreens */
   @media (hover: none) and (pointer: coarse) {
     @include display-hints($is-mobile: true);
+  }
 
-    /* fill space when on mobile */
-    max-width: calc(100% - 80px);
-
-    &.dropdown-toggle {
-      max-width: 100%;
-    }
+  > .dropdown-toggle {
+    display: flex;
+    align-items: center;
+    width: 100%;
+    padding: 5px 7px;
 
-    .logged-in-info {
-      max-width: calc(100% - 45px) !important;
+    &::after {
+      // Disable bootstrap toggle
+      border: 0;
     }
   }
 
   .dropdown-toggle-indicator {
     position: relative;
     display: none;
+    width: 17px;
 
     span {
       position: absolute;
@@ -163,17 +163,6 @@ my-notification {
       color: #808080;
     }
   }
-
-  .dropdown-toggle::after {
-    border: 0;
-  }
-
-  > .dropdown-toggle:first-child {
-    display: flex;
-    align-items: center;
-    width: 100%;
-    padding: 5px 25px 5px 7px;
-  }
 }
 
 my-actor-avatar {
@@ -181,9 +170,8 @@ my-actor-avatar {
 }
 
 .logged-in-info {
-  max-width: 105px;
-
-  flex-grow: 1;
+  flex-shrink: 1;
+  min-width: 1px;
 }
 
 .logged-in-display-name,
@@ -286,7 +274,8 @@ my-actor-avatar {
     margin-bottom: 25px;
   }
 
-  a {
+  a,
+  button {
     min-height: 40px;
   }
 }
@@ -306,7 +295,7 @@ my-actor-avatar {
   }
 
   a,
-  span[role=button] {
+  button {
     @include margin-right(8px);
     @include disable-default-a-behaviour;
 
index ab6f21a350fe99e298165a96fb921d4042a7b4ba..a4bda8f16471f224902b1c8cef19e9bd48ea203c 100644 (file)
@@ -99,7 +99,7 @@ export const VIDEO_ORIGINALLY_PUBLISHED_AT_VALIDATOR: BuildFormValidator = {
 
 function arrayTagLengthValidator (min = 2, max = 30): ValidatorFn {
   return (control: AbstractControl): ValidationErrors => {
-    const array = control.value as Array<string>
+    const array = control.value as string[]
 
     if (array.every(e => e.length >= min && e.length <= max)) {
       return null
index ef96f8f0539508b7b1aa81062045eef2bed5ac64..2571cc952008cf2ed3232dab07bd173657fd3831 100644 (file)
         <my-global-icon *ngIf="isAbuseRejected(abuse)" [title]="abuse.state.label" iconName="cross"></my-global-icon>
       </td>
 
-      <td class="c-hand abuse-messages" (click)="openAbuseMessagesModal(abuse)">
-        <ng-container *ngIf="isLocalAbuse(abuse)">
+      <td class="abuse-messages">
+        <button class="button-unstyle" *ngIf="isLocalAbuse(abuse)" (click)="openAbuseMessagesModal(abuse)">
           {{ abuse.countMessages }}
 
           <my-global-icon iconName="message-circle"></my-global-icon>
-        </ng-container>
+        </button>
       </td>
 
       <td *ngIf="isAdminView()" class="internal-note" container="body" placement="left auto" [ngbTooltip]="abuse.moderationComment">
index a0f65a3d9b445be12181e41122bcaad53c39a9e8..c63b5b361ea27cbba3f715c4840592bc7eabde49 100644 (file)
@@ -2,29 +2,29 @@
   <div class="position-relative me-3">
     <my-actor-avatar [actor]="actor" [actorType]="getActorType()" [previewImage]="preview" size="100"></my-actor-avatar>
 
-    <div *ngIf="editable && !hasAvatar()" class="actor-img-edit-button" [ngbTooltip]="avatarFormat" placement="right" container="body">
+    <div *ngIf="editable && !hasAvatar()" class="actor-img-edit-button button-focus-within" [ngbTooltip]="avatarFormat" placement="right" container="body">
       <my-global-icon iconName="upload"></my-global-icon>
       <label class="visually-hidden" for="avatarfile" i18n>Upload a new avatar</label>
       <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/>
     </div>
 
     <div *ngIf="editable && hasAvatar()" ngbDropdown placement="right">
-      <div class="actor-img-edit-button" ngbDropdownToggle>
+      <button type="button" class="actor-img-edit-button" ngbDropdownToggle>
         <my-global-icon iconName="edit"></my-global-icon>
         <label class="visually-hidden" for="avatarMenu" i18n>Change your avatar</label>
-      </div>
+      </button>
 
       <div ngbDropdownMenu>
-        <div class="dropdown-item c-hand dropdown-file" [ngbTooltip]="avatarFormat">
+        <div class="dropdown-item dropdown-file button-focus-within" [ngbTooltip]="avatarFormat">
           <my-global-icon iconName="upload"></my-global-icon>
           <span for="avatarfile" i18n>Upload a new avatar</span>
           <input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange(avatarfileInput)"/>
         </div>
 
-        <div class="dropdown-item c-hand" (click)="deleteAvatar()" (key.enter)="deleteAvatar()">
+        <button type="button" class="dropdown-item" (click)="deleteAvatar()" (key.enter)="deleteAvatar()">
           <my-global-icon iconName="delete"></my-global-icon>
           <span i18n>Remove avatar</span>
-        </div>
+        </button>
       </div>
 
     </div>
index 01e2131ba7365ac8f03464bb5777c2bd399de57a..689c5873c551fb7596c3193d52e3433d07895732 100644 (file)
   right: 5px;
 }
 
+.button-focus-within:focus-within {
+  box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest);
+}
+
 .dropdown-item {
   @include dropdown-with-icon-item;
 }
index d6fe3709493185f4d37cc8bf6e089fa03e37fa5a..d4ddb2deb2bf544a4c8a65b05d9209f535389b86 100644 (file)
@@ -4,25 +4,25 @@
       <img *ngIf="hasBanner()" [src]="preview || actor.bannerUrl" alt="Banner" />
     </div>
 
-    <div *ngIf="!hasBanner()" class="actor-img-edit-button" [ngbTooltip]="bannerFormat" placement="right" container="body">
+    <div *ngIf="!hasBanner()" class="actor-img-edit-button button-focus-within" [ngbTooltip]="bannerFormat" placement="right" container="body">
       <ng-container *ngTemplateOutlet="uploadNewBanner"></ng-container>
     </div>
 
     <div *ngIf="hasBanner()" ngbDropdown placement="right">
-      <div class="actor-img-edit-button" ngbDropdownToggle>
+      <button type="button" class="actor-img-edit-button" ngbDropdownToggle>
         <my-global-icon iconName="edit"></my-global-icon>
         <label for="bannerMenu" i18n>Change your banner</label>
-      </div>
+      </button>
 
       <div ngbDropdownMenu>
-        <div class="dropdown-item c-hand dropdown-file" [ngbTooltip]="bannerFormat">
+        <div class="dropdown-item dropdown-file button-focus-within" [ngbTooltip]="bannerFormat">
           <ng-container *ngTemplateOutlet="uploadNewBanner"></ng-container>
         </div>
 
-        <div class="dropdown-item c-hand" (click)="deleteBanner()" (key.enter)="deleteBanner()">
+        <button type="button" class="dropdown-item" (click)="deleteBanner()">
           <my-global-icon iconName="delete"></my-global-icon>
           <span i18n>Remove banner</span>
-        </div>
+        </button>
       </div>
     </div>
   </div>
index b2c64fff79b86125fb4c674cd2d4800f35443bba..8e5a05603a32975cd87de4c5c8cef8fe4ccb0b1f 100644 (file)
   }
 }
 
+.button-focus-within:focus-within {
+  box-shadow: #{$focus-box-shadow-form} pvar(--mainColorLightest);
+}
+
 .dropdown-item {
   @include dropdown-with-icon-item;
 }
index 8e6ad4015510d2b41452800f8f0b3ad181e5ff64..f1c1aa03f388215b06a849776abb9ef414b4b1a0 100644 (file)
@@ -145,13 +145,13 @@ export class ActorAvatarComponent implements OnInit, OnChanges {
     // Keep consistency with CSS
     const themes = {
       '0123456789abc': 'blue',
-      def: 'green',
-      ghi: 'purple',
-      jkl: 'gray',
-      mno: 'yellow',
-      pqr: 'orange',
-      stvu: 'red',
-      wxyz: 'dark-blue'
+      'def': 'green',
+      'ghi': 'purple',
+      'jkl': 'gray',
+      'mno': 'yellow',
+      'pqr': 'orange',
+      'stvu': 'red',
+      'wxyz': 'dark-blue'
     }
 
     const theme = Object.keys(themes)
index 9a466055a3dce2f0f9a2bf33c3c9740f642e44b2..4017d4aa5fac1d1ddcd6ceb8836d170343b454f9 100644 (file)
@@ -1,4 +1,2 @@
-<div (click)="update()">
-  <input type="checkbox" [checked]="checked"/>
-  <label class="ms-auto">Toggle</label>
-</div>
+<input type="checkbox" [checked]="checked" [name]="inputName" [id]="inputName" (change)="update()" />
+<label [for]="inputName" class="ms-auto">Toggle</label>
index 11e7bdf7f61ab15a6e4b498ca74e18dad9c4b0c5..8a10a11b039295a67ae84aa06b60279801df04a1 100644 (file)
@@ -5,7 +5,7 @@
       icon="edit" (fileChanged)="onFileChanged($event)" [buttonTooltip]="getReactiveFileButtonTooltip()"
     ></my-reactive-file>
 
-    <img *ngIf="imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" [src]="imageSrc" class="preview" />
+    <img *ngIf="imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" [src]="imageSrc" class="preview" alt="Preview" i18n-alt />
     <div *ngIf="!imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" class="preview no-image"></div>
   </div>
 </div>
index 55eb45a75f4b7c0d25c43f2e58796bc49c5a0d1d..96179cbe643139436626ae19febc2c99eef392f2 100644 (file)
@@ -3,81 +3,81 @@ import { HooksService } from '@app/core/plugins/hooks.service'
 
 const icons = {
   // misc icons
-  npm: require('!!raw-loader?!../../../assets/images/misc/npm.svg').default,
-  markdown: require('!!raw-loader?!../../../assets/images/misc/markdown.svg').default,
-  language: require('!!raw-loader?!../../../assets/images/misc/language.svg').default,
+  'npm': require('!!raw-loader?!../../../assets/images/misc/npm.svg').default,
+  'markdown': require('!!raw-loader?!../../../assets/images/misc/markdown.svg').default,
+  'language': require('!!raw-loader?!../../../assets/images/misc/language.svg').default,
   'video-lang': require('!!raw-loader?!../../../assets/images/misc/video-lang.svg').default,
-  support: require('!!raw-loader?!../../../assets/images/misc/support.svg').default,
+  'support': require('!!raw-loader?!../../../assets/images/misc/support.svg').default,
   'peertube-x': require('!!raw-loader?!../../../assets/images/misc/peertube-x.svg').default,
-  robot: require('!!raw-loader?!../../../assets/images/misc/miscellaneous-services.svg').default, // material ui
-  videos: require('!!raw-loader?!../../../assets/images/misc/video-library.svg').default, // material ui
-  history: require('!!raw-loader?!../../../assets/images/misc/history.svg').default, // material ui
-  subscriptions: require('!!raw-loader?!../../../assets/images/misc/subscriptions.svg').default, // material ui
+  'robot': require('!!raw-loader?!../../../assets/images/misc/miscellaneous-services.svg').default, // material ui
+  'videos': require('!!raw-loader?!../../../assets/images/misc/video-library.svg').default, // material ui
+  'history': require('!!raw-loader?!../../../assets/images/misc/history.svg').default, // material ui
+  'subscriptions': require('!!raw-loader?!../../../assets/images/misc/subscriptions.svg').default, // material ui
   'playlist-add': require('!!raw-loader?!../../../assets/images/misc/playlist-add.svg').default, // material ui
-  follower: require('!!raw-loader?!../../../assets/images/misc/account-arrow-left.svg').default, // material ui
-  following: require('!!raw-loader?!../../../assets/images/misc/account-arrow-right.svg').default, // material ui
-  tip: require('!!raw-loader?!../../../assets/images/misc/tip.svg').default, // material ui
-  flame: require('!!raw-loader?!../../../assets/images/misc/flame.svg').default,
-  local: require('!!raw-loader?!../../../assets/images/misc/local.svg').default,
+  'follower': require('!!raw-loader?!../../../assets/images/misc/account-arrow-left.svg').default, // material ui
+  'following': require('!!raw-loader?!../../../assets/images/misc/account-arrow-right.svg').default, // material ui
+  'tip': require('!!raw-loader?!../../../assets/images/misc/tip.svg').default, // material ui
+  'flame': require('!!raw-loader?!../../../assets/images/misc/flame.svg').default,
+  'local': require('!!raw-loader?!../../../assets/images/misc/local.svg').default,
 
   // feather icons
-  copy: require('!!raw-loader?!../../../assets/images/feather/copy.svg').default,
-  flag: require('!!raw-loader?!../../../assets/images/feather/flag.svg').default,
-  playlists: require('!!raw-loader?!../../../assets/images/feather/list.svg').default,
-  syndication: require('!!raw-loader?!../../../assets/images/feather/syndication.svg').default,
-  help: require('!!raw-loader?!../../../assets/images/feather/help.svg').default,
-  alert: require('!!raw-loader?!../../../assets/images/feather/alert.svg').default,
-  globe: require('!!raw-loader?!../../../assets/images/feather/globe.svg').default,
-  home: require('!!raw-loader?!../../../assets/images/feather/home.svg').default,
-  trending: require('!!raw-loader?!../../../assets/images/feather/trending.svg').default,
-  search: require('!!raw-loader?!../../../assets/images/feather/search.svg').default,
-  upload: require('!!raw-loader?!../../../assets/images/feather/upload.svg').default,
-  dislike: require('!!raw-loader?!../../../assets/images/feather/dislike.svg').default,
-  like: require('!!raw-loader?!../../../assets/images/feather/like.svg').default,
-  no: require('!!raw-loader?!../../../assets/images/feather/no.svg').default,
+  'copy': require('!!raw-loader?!../../../assets/images/feather/copy.svg').default,
+  'flag': require('!!raw-loader?!../../../assets/images/feather/flag.svg').default,
+  'playlists': require('!!raw-loader?!../../../assets/images/feather/list.svg').default,
+  'syndication': require('!!raw-loader?!../../../assets/images/feather/syndication.svg').default,
+  'help': require('!!raw-loader?!../../../assets/images/feather/help.svg').default,
+  'alert': require('!!raw-loader?!../../../assets/images/feather/alert.svg').default,
+  'globe': require('!!raw-loader?!../../../assets/images/feather/globe.svg').default,
+  'home': require('!!raw-loader?!../../../assets/images/feather/home.svg').default,
+  'trending': require('!!raw-loader?!../../../assets/images/feather/trending.svg').default,
+  'search': require('!!raw-loader?!../../../assets/images/feather/search.svg').default,
+  'upload': require('!!raw-loader?!../../../assets/images/feather/upload.svg').default,
+  'dislike': require('!!raw-loader?!../../../assets/images/feather/dislike.svg').default,
+  'like': require('!!raw-loader?!../../../assets/images/feather/like.svg').default,
+  'no': require('!!raw-loader?!../../../assets/images/feather/no.svg').default,
   'cloud-download': require('!!raw-loader?!../../../assets/images/feather/cloud-download.svg').default,
-  clock: require('!!raw-loader?!../../../assets/images/feather/clock.svg').default,
-  cog: require('!!raw-loader?!../../../assets/images/feather/cog.svg').default,
-  delete: require('!!raw-loader?!../../../assets/images/feather/delete.svg').default,
-  bell: require('!!raw-loader?!../../../assets/images/feather/bell.svg').default,
+  'clock': require('!!raw-loader?!../../../assets/images/feather/clock.svg').default,
+  'cog': require('!!raw-loader?!../../../assets/images/feather/cog.svg').default,
+  'delete': require('!!raw-loader?!../../../assets/images/feather/delete.svg').default,
+  'bell': require('!!raw-loader?!../../../assets/images/feather/bell.svg').default,
   'sign-out': require('!!raw-loader?!../../../assets/images/feather/log-out.svg').default,
   'sign-in': require('!!raw-loader?!../../../assets/images/feather/log-in.svg').default,
-  download: require('!!raw-loader?!../../../assets/images/feather/download.svg').default,
+  'download': require('!!raw-loader?!../../../assets/images/feather/download.svg').default,
   'ownership-change': require('!!raw-loader?!../../../assets/images/feather/share.svg').default,
-  share: require('!!raw-loader?!../../../assets/images/feather/share-2.svg').default,
-  channel: require('!!raw-loader?!../../../assets/images/feather/tv.svg').default,
-  user: require('!!raw-loader?!../../../assets/images/feather/user.svg').default,
+  'share': require('!!raw-loader?!../../../assets/images/feather/share-2.svg').default,
+  'channel': require('!!raw-loader?!../../../assets/images/feather/tv.svg').default,
+  'user': require('!!raw-loader?!../../../assets/images/feather/user.svg').default,
   'user-x': require('!!raw-loader?!../../../assets/images/feather/user-x.svg').default,
-  users: require('!!raw-loader?!../../../assets/images/feather/users.svg').default,
+  'users': require('!!raw-loader?!../../../assets/images/feather/users.svg').default,
   'user-add': require('!!raw-loader?!../../../assets/images/feather/user-plus.svg').default,
-  add: require('!!raw-loader?!../../../assets/images/feather/plus-circle.svg').default,
+  'add': require('!!raw-loader?!../../../assets/images/feather/plus-circle.svg').default,
   'cloud-error': require('!!raw-loader?!../../../assets/images/feather/cloud-off.svg').default,
-  undo: require('!!raw-loader?!../../../assets/images/feather/corner-up-left.svg').default,
+  'undo': require('!!raw-loader?!../../../assets/images/feather/corner-up-left.svg').default,
   'circle-tick': require('!!raw-loader?!../../../assets/images/feather/check-circle.svg').default,
   'more-horizontal': require('!!raw-loader?!../../../assets/images/feather/more-horizontal.svg').default,
   'more-vertical': require('!!raw-loader?!../../../assets/images/feather/more-vertical.svg').default,
-  play: require('!!raw-loader?!../../../assets/images/feather/play.svg').default,
-  p2p: require('!!raw-loader?!../../../assets/images/feather/airplay.svg').default,
-  fullscreen: require('!!raw-loader?!../../../assets/images/feather/maximize.svg').default,
+  'play': require('!!raw-loader?!../../../assets/images/feather/play.svg').default,
+  'p2p': require('!!raw-loader?!../../../assets/images/feather/airplay.svg').default,
+  'fullscreen': require('!!raw-loader?!../../../assets/images/feather/maximize.svg').default,
   'exit-fullscreen': require('!!raw-loader?!../../../assets/images/feather/minimize.svg').default,
-  film: require('!!raw-loader?!../../../assets/images/feather/film.svg').default,
-  edit: require('!!raw-loader?!../../../assets/images/feather/edit-2.svg').default,
+  'film': require('!!raw-loader?!../../../assets/images/feather/film.svg').default,
+  'edit': require('!!raw-loader?!../../../assets/images/feather/edit-2.svg').default,
   'external-link': require('!!raw-loader?!../../../assets/images/feather/external-link.svg').default,
   'eye-open': require('!!raw-loader?!../../../assets/images/feather/eye.svg').default,
   'eye-close': require('!!raw-loader?!../../../assets/images/feather/eye-off.svg').default,
-  refresh: require('!!raw-loader?!../../../assets/images/feather/refresh-cw.svg').default,
-  command: require('!!raw-loader?!../../../assets/images/feather/command.svg').default,
-  go: require('!!raw-loader?!../../../assets/images/feather/arrow-up-right.svg').default,
-  cross: require('!!raw-loader?!../../../assets/images/feather/x.svg').default,
-  tick: require('!!raw-loader?!../../../assets/images/feather/check.svg').default,
-  columns: require('!!raw-loader?!../../../assets/images/feather/columns.svg').default,
-  live: require('!!raw-loader?!../../../assets/images/feather/live.svg').default,
-  repeat: require('!!raw-loader?!../../../assets/images/feather/repeat.svg').default,
+  'refresh': require('!!raw-loader?!../../../assets/images/feather/refresh-cw.svg').default,
+  'command': require('!!raw-loader?!../../../assets/images/feather/command.svg').default,
+  'go': require('!!raw-loader?!../../../assets/images/feather/arrow-up-right.svg').default,
+  'cross': require('!!raw-loader?!../../../assets/images/feather/x.svg').default,
+  'tick': require('!!raw-loader?!../../../assets/images/feather/check.svg').default,
+  'columns': require('!!raw-loader?!../../../assets/images/feather/columns.svg').default,
+  'live': require('!!raw-loader?!../../../assets/images/feather/live.svg').default,
+  'repeat': require('!!raw-loader?!../../../assets/images/feather/repeat.svg').default,
   'chevrons-up': require('!!raw-loader?!../../../assets/images/feather/chevrons-up.svg').default,
   'message-circle': require('!!raw-loader?!../../../assets/images/feather/message-circle.svg').default,
-  codesandbox: require('!!raw-loader?!../../../assets/images/feather/codesandbox.svg').default,
-  award: require('!!raw-loader?!../../../assets/images/feather/award.svg').default,
-  stats: require('!!raw-loader?!../../../assets/images/feather/stats.svg').default
+  'codesandbox': require('!!raw-loader?!../../../assets/images/feather/codesandbox.svg').default,
+  'award': require('!!raw-loader?!../../../assets/images/feather/award.svg').default,
+  'stats': require('!!raw-loader?!../../../assets/images/feather/stats.svg').default
 }
 
 export type GlobalIconName = keyof typeof icons
index 205f2bc975a7423239914e3dfbfc4db0c689462c..37f53b7c698a57731dbfda29f93072a641af0b7c 100644 (file)
@@ -11,7 +11,7 @@
     <tr>
       <th i18n class="label" scope="row">
         <div>Default NSFW/sensitive videos policy</div>
-        <div class="c-hand more-info" (click)="openQuickSettingsHighlight()">can be redefined by the users</div>
+        <span class="fs-7 fw-normal fst-italic">can be redefined by the users</span>
       </th>
 
       <td class="value">{{ buildNSFWLabel() }}</td>
index c3df7c594eb0bcc506db498d2b24584513a4b1a7..2e63f6c1752a101fbd6eda8e18fbce1074a756ed 100644 (file)
@@ -2,7 +2,6 @@ import { Component, OnInit } from '@angular/core'
 import { ServerService } from '@app/core'
 import { prepareIcu } from '@app/helpers'
 import { ServerConfig } from '@shared/models'
-import { PeertubeModalService } from '../shared-main/peertube-modal/peertube-modal.service'
 
 @Component({
   selector: 'my-instance-features-table',
@@ -14,8 +13,7 @@ export class InstanceFeaturesTableComponent implements OnInit {
   serverConfig: ServerConfig
 
   constructor (
-    private serverService: ServerService,
-    private modalService: PeertubeModalService
+    private serverService: ServerService
   ) { }
 
   get initialUserVideoQuota () {
@@ -69,10 +67,6 @@ export class InstanceFeaturesTableComponent implements OnInit {
     return this.serverService.getServerVersionAndCommit()
   }
 
-  openQuickSettingsHighlight () {
-    this.modalService.openQuickSettingsSubject.next()
-  }
-
   private getApproximateTime (seconds: number) {
     const hours = Math.floor(seconds / 3600)
 
index e0cb475fc50cf6ba23ee6fc818a58d6da2b9385e..00cfbc692b441dc88ea22d8d309ec4bf06693818 100644 (file)
@@ -17,7 +17,7 @@ export class NumberFormatterPipe implements PipeTransform {
     return +f
   }
 
-  private dictionary: Array<{ max: number, type: string }> = [
+  private dictionary: { max: number, type: string }[] = [
     { max: 1000, type: '' },
     { max: 1000000, type: 'K' },
     { max: 1000000000, type: 'M' }
index bbfab7b376f47483087f52159b93a0adbdd6c726..d4aa9f3800ee92476dd6bbcb3e94be3c35b3692d 100644 (file)
@@ -40,7 +40,7 @@
 
           <h6
             *ngIf="!action.linkBuilder && action.isHeader && areActionsDisplayed(actions, entry)" [ngClass]="{ 'with-icon': !!action.iconName }"
-            class="dropdown-header" [title]="action.title || ''" (click)="action.handler(entry)" (keyup.enter)="action.handler(entry)"
+            class="dropdown-header" [title]="action.title || ''"
           >
             <ng-container *ngTemplateOutlet="templateActionLabel; context:{ $implicit: action }"></ng-container>
           </h6>
index e39fbd66dde9aaf93269b91508708f166f71c011..7d24ff4ae899bab8f527b721c09def85cf77fd86 100644 (file)
@@ -55,7 +55,7 @@ export class ActionDropdownComponent<T> {
     return {}
   }
 
-  areActionsDisplayed (actions: Array<DropdownAction<T> | DropdownAction<T>[]>, entry: T): boolean {
+  areActionsDisplayed (actions: (DropdownAction<T> | DropdownAction<T>[])[], entry: T): boolean {
     return actions.some(a => {
       if (Array.isArray(a)) return this.areActionsDisplayed(a, entry)
 
index 63a59cbe136676ddafac894db8c66062850b8629..e3a83089172dd4f9a3ca9f59a28e31fb84363d5c 100644 (file)
@@ -31,7 +31,7 @@ export class ButtonComponent implements OnInit, OnChanges {
   private buildClasses () {
     this.classes = {
       [this.className]: true,
-      disabled: this.disabled,
+      'disabled': this.disabled,
       'icon-only': !this.label,
       'has-icon': !!this.icon,
       'responsive-label': this.responsiveLabel
index 14b6e7d7a432f7040dfdd1f3f0b9bc3de3704f9c..5277ae0e85617eeabe07f39f9b6607b63703fa37 100644 (file)
@@ -1,7 +1,10 @@
 <span
   class="date-toggle"
   [title]="getTitle()"
+  role="button"
+  tabindex="0"
   (click)="toggle()"
+  (keyup.enter)="toggle()"
 >
   {{ getContent() }}
 </span>
index bd038f8b5514fd4368ab2af10b981ac7b46985c7..be9e130e707b868ea508f34120ecbf0f28ce88fa 100644 (file)
@@ -10,8 +10,8 @@ export class LoaderComponent {
 
   private readonly sizes = {
     sm: {
-      width: '1rem',
-      height: '1rem',
+      'width': '1rem',
+      'height': '1rem',
       'border-width': '0.15rem'
     },
     xl: {
index a51e0829297ea8e245d023b583740d2d9d33a12d..351e4dc3f2e2868219058fde5aa459f7a3fc350a 100644 (file)
@@ -1,6 +1,7 @@
 <div *ngIf="componentPagination.totalItems === 0" class="no-notification" i18n>You don't have notifications.</div>
 
 <div class="notifications" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
+  <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->
   <div *ngFor="let notification of notifications" class="notification" [ngClass]="{ unread: !notification.read }" (click)="markAsRead(notification)">
 
     <ng-container [ngSwitch]="notification.type">
index 0e0d38c2ab3ebb85a451561c1eddaa8aaa2fdc16..ac9085bb3b34e17ee4cec79db5ec27eea75e9a38 100644 (file)
@@ -1,6 +1,7 @@
 <div class="user-quota mb-3">
   <div>
-    <label class="user-quota-title" tabindex="0" i18n>Total video quota</label>
+    <div class="mb-2 fw-bold" i18n>Total video quota</div>
+
     <div class="progress" tabindex="0" [ngbTooltip]="titleVideoQuota()">
       <div class="progress-bar" tabindex="0" role="progressbar" [style]="{ width: userVideoQuotaPercentage + '%' }"
         [attr.aria-valuenow]="userVideoQuotaUsed" aria-valuemin="0" [attr.aria-valuemax]="user.videoQuota"></div>
@@ -10,7 +11,8 @@
   </div>
 
   <div *ngIf="hasDailyQuota()" class="mt-3">
-    <label class="user-quota-title" tabindex="0" i18n>Daily video quota</label>
+    <div class="mb-2 fw-bold" i18n>Daily video quota</div>
+
     <div class="progress" tabindex="0" [ngbTooltip]="titleVideoQuotaDaily()">
       <div class="progress-bar" role="progressbar" [style]="{ width: userVideoQuotaDailyPercentage + '%' }"
         [attr.aria-valuenow]="userVideoQuotaUsedDaily" aria-valuemin="0" [attr.aria-valuemax]="user.videoQuotaDaily"></div>
index e07703cf4f6d1cd2f1be0e35f376e4e71d31a36d..1a13e0207fadbc413a3666723870bb83118dded3 100644 (file)
   <ng-template pTemplate="caption">
     <div class="caption">
       <div class="left-buttons">
-        <a class="block-button" (click)="addServersToBlock()" (key.enter)="addServersToBlock()">
+        <button class="peertube-create-button" (click)="addServersToBlock()" (key.enter)="addServersToBlock()">
           <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
           <ng-container i18n>Mute domain</ng-container>
-        </a>
+        </button>
       </div>
 
       <div class="ms-auto">
index 1a6b0435f0aaa5b607c37a02b69ffd136bbef334..10b9a40a1cd380671489f6d0898314b93c2e01a2 100644 (file)
@@ -20,7 +20,3 @@ a {
   @include peertube-button;
   @include grey-button;
 }
-
-.block-button {
-  @include create-button;
-}
index ea432b70e9bd8913f7acb83941283b3e832f1351..38e7dea172f7f47e21c02b8d169329a92333d1e7 100644 (file)
@@ -1,7 +1,7 @@
 <a [href]="getVideoUrl()" class="table-video-link" [title]="video.name" target="_blank" rel="noopener noreferrer">
   <div class="table-video">
     <div class="table-video-image">
-      <img [src]="video.thumbnailPath">
+      <img [src]="video.thumbnailPath" alt="">
 
       <ng-content select="[image]"></ng-content>
     </div>
index 57fcdd89927b826e134e2d1c996f3136bec02576..6c9a8b91cb5ff459474022eb2d1e1fe1f60b34ed 100644 (file)
 
   <div *ngIf="displayWatchLaterPlaylist" class="video-thumbnail-actions-overlay">
     <ng-container *ngIf="inWatchLaterPlaylist !== true">
-      <div class="video-thumbnail-watch-later-overlay" placement="left" [ngbTooltip]="addToWatchLaterText" container="body" (click)="onWatchLaterClick($event)">
+      <button class="video-thumbnail-watch-later-overlay button-unstyle" placement="left" [ngbTooltip]="addToWatchLaterText" container="body" (click)="onWatchLaterClick($event)">
         <my-global-icon iconName="clock" [attr.aria-label]="addToWatchLaterText" role="button"></my-global-icon>
-      </div>
+      </button>
     </ng-container>
 
     <ng-container *ngIf="inWatchLaterPlaylist === true">
-      <div class="video-thumbnail-watch-later-overlay" placement="left" [ngbTooltip]="addedToWatchLaterText" container="body" (click)="onWatchLaterClick($event)">
+      <button class="video-thumbnail-watch-later-overlay button-unstyle" placement="left" [ngbTooltip]="addedToWatchLaterText" container="body" (click)="onWatchLaterClick($event)">
         <my-global-icon iconName="tick" [attr.aria-label]="addedToWatchLaterText" role="button"></my-global-icon>
-      </div>
+      </button>
     </ng-container>
   </div>
 
index 8e61bdbb30d07ee708d781a6225af32d01221d1f..e385b429cc837cae75826cd9c11f6dd52aa39a78 100644 (file)
@@ -33,7 +33,7 @@
     </div>
 
     <div class="journal" *ngIf="latestLiveSessions.length !== 0">
-      <label i18n>Latest live sessions</label>
+      <div class="mb-2 fw-bold" i18n>Latest live sessions</div>
 
       <div class="journal-session" *ngFor="let session of latestLiveSessions">
         <span i18n class="pt-badge badge-success" *ngIf="!getErrorLabel(session)">Success</span>
index 3d8ce22de4544de33053c6732091e0a8eaa096aa..a3676e159e1a047064717967734d1ec9dc7c68ba 100644 (file)
         </div>
       </div>
 
-      <div
+      <button
         (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed"
-        role="button" class="advanced-filters-button"
+        class="advanced-filters-button button-unstyle"
         [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic"
       >
         <ng-container *ngIf="isAdvancedCustomizationCollapsed">
             Simple
           </ng-container>
         </ng-container>
-      </div>
+      </button>
     </ng-container>
   </div>
 
index 48bb0d8125b61e129a7ee85e6b60ac0bde610295..3d39c6fdc13597c404e8b57c16538ac2dd16a6db 100644 (file)
@@ -2,7 +2,7 @@
   <div class="label-description muted" i18n>
     Update
     <a routerLink="/my-account/settings" [fragment]="fragment">
-      <span (click)="onAccountSettingsClick($event)">your settings</span>
+      <button class="button-unstyle" (click)="onAccountSettingsClick($event)">your settings</button>
     </a
   ></div>
 </ng-template>
@@ -23,9 +23,9 @@
         <my-global-icon iconName="chevrons-up"></my-global-icon>
       </button>
 
-      <div
+      <button
         *ngFor="let activeFilter of filters.getActiveFilters()" (click)="resetFilter(activeFilter.key, activeFilter.canRemove)"
-        class="active-filter pastille" [ngClass]="{ 'can-remove': activeFilter.canRemove }" [title]="getFilterTitle(activeFilter.canRemove)"
+        class="active-filter pastille button-unstyle" [ngClass]="{ 'can-remove': activeFilter.canRemove }" [title]="getFilterTitle(activeFilter.canRemove)"
       >
         <span>
           {{ activeFilter.label }}
@@ -34,7 +34,7 @@
         </span>
 
         <my-global-icon *ngIf="activeFilter.canRemove" iconName="cross"></my-global-icon>
-      </div>
+      </button>
     </div>
 
     <ng-select
index 4069ab4b5db8732b7c581fee93a8a6f878a16228..6b4b72c75e30ea3f0d4cc628806ccf20b9ef307b 100644 (file)
@@ -37,7 +37,7 @@ export class VideoFilters {
   private activeFilters: { key: string, canRemove: boolean, label: string, value?: string }[] = []
   private defaultNSFWPolicy: NSFWPolicyType
 
-  private onChangeCallbacks: Array<() => void> = []
+  private onChangeCallbacks: (() => void)[] = []
   private oldFormObjectString: string
 
   private readonly hiddenFields: string[] = []
index 8c8bf80d90ee345984a25e0e205861263e76c6e3..909c86d3d0bdae959a7edb4cc9cff4022e5ed78f 100644 (file)
@@ -16,9 +16,9 @@
           <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container>
         </a>
 
-        <a *ngIf="!action.routerLink && !action.href && action.click" class="ms-2" (click)="action.click($event)" (key.enter)="action.click($event)">
+        <button *ngIf="!action.routerLink && !action.href && action.click" class="ms-2 button-unstyle" (click)="action.click($event)" (key.enter)="action.click($event)">
           <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container>
-        </a>
+        </button>
 
         <a *ngIf="!action.routerLink && action.href && action.click" class="ms-2" (click)="action.click($event)" (key.enter)="action.click($event)" [href]="action.href">
           <ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container>
index 6c6db4b966993da3b5da4f9124b848f215bd07e5..8931158a95698e44d3744d6271ef5345d580dc5f 100644 (file)
@@ -20,9 +20,9 @@
     <!-- Display only once -->
     <div class="action-selection-mode" *ngIf="isInSelectionMode() === true && i === 0">
       <div class="action-selection-mode-child">
-        <span i18n class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
+        <button i18n class="action-button action-button-cancel-selection" (click)="abortSelectionMode()">
           Cancel
-        </span>
+        </button>
 
         <ng-container *ngTemplateOutlet="globalButtonsTemplate"></ng-container>
       </div>
index 6d787796a65e9c922733e7fd3a0acdf64a034446..f2f69236c79a82ec82a545807a518fc0195ec09c 100644 (file)
       *ngFor="let playlist of videoPlaylists"
       class="playlist dropdown-item" [ngClass]="{ 'has-optional-row': playlist.optionalRowDisplayed }"
     >
-      <div class="primary-row" (click)="toggleMainPlaylist($event, playlist)">
+      <button class="primary-row button-unstyle" (click)="toggleMainPlaylist($event, playlist)">
         <my-peertube-checkbox
           [disabled]="isPresentMultipleTimes(playlist) || playlist.optionalRowDisplayed" [inputName]="getPrimaryInputName(playlist)"
           [ngModel]="isPrimaryCheckboxChecked(playlist)" [onPushWorkaround]="true"
         ></my-peertube-checkbox>
 
-        <label class="display-name">
+        <label [for]="getPrimaryInputName(playlist)" class="display-name">
           {{ playlist.displayName }}
         </label>
 
-        <div class="optional-row-icon" *ngIf="isPrimaryCheckboxChecked(playlist)" (click)="$event.stopPropagation(); toggleOptionalRow(playlist)">
+        <button class="optional-row-icon button-unstyle" *ngIf="isPrimaryCheckboxChecked(playlist)" (click)="$event.stopPropagation(); toggleOptionalRow(playlist)">
           <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
-        </div>
-      </div>
+        </button>
+      </button>
 
       <div class="optional-rows" *ngIf="playlist.optionalRowDisplayed">
         <div class="header-label" i18n>Start at</div>
     </div>
   </div>
 
-  <div class="new-playlist-button dropdown-item" (click)="openCreateBlock($event)" [hidden]="isNewPlaylistBlockOpened">
+  <button class="new-playlist-button dropdown-item" (click)="openCreateBlock($event)" [hidden]="isNewPlaylistBlockOpened">
     <my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
 
     <span i18n>Create a private playlist</span>
-  </div>
+  </button>
 
   <form class="new-playlist-block dropdown-item" *ngIf="isNewPlaylistBlockOpened" (ngSubmit)="createPlaylist()" [formGroup]="form">
     <div class="form-group">
index de2f1032b1b3061bc23b6bd9fe8dcb98529e9130..d1aa952665638a04edd6b9ee8a5744b8a9788940 100644 (file)
@@ -67,6 +67,8 @@
   }
 
   .optional-row-icon {
+    @include margin-left(5px);
+
     display: flex;
     align-items: center;
     font-size: 14px;
       width: 19px;
       height: 19px;
     }
+
+    &:hover {
+      opacity: 0.8;
+    }
   }
 }
 
index 40c58166d20ce408d10d45fa44552b9f80ebf16d..75afa0709832e4eac476db6dbd7e51d37fb32fc0 100644 (file)
 
     <div ngbDropdownMenu>
       <ng-container *ngIf="playlistElement.video">
-        <div class="dropdown-item" (click)="toggleDisplayTimestampsOptions($event, playlistElement)">
+        <button ngbDropdownItem (click)="toggleDisplayTimestampsOptions($event, playlistElement)">
           <my-global-icon iconName="edit" aria-hidden="true"></my-global-icon>
           <ng-container i18n>Edit starts/stops at</ng-container>
-        </div>
+        </button>
 
         <div class="timestamp-options" *ngIf="displayTimestampOptions">
           <div>
         </div>
       </ng-container>
 
-      <span class="dropdown-item" (click)="removeFromPlaylist(playlistElement)">
+      <button ngbDropdownItem (click)="removeFromPlaylist(playlistElement)">
         <my-global-icon iconName="delete" aria-hidden="true"></my-global-icon>
         <ng-container i18n>Delete from {{ playlist?.displayName }}</ng-container>
-      </span>
+      </button>
     </div>
   </div>
 </div>
index 0f085231c603dc5b7d9d7a9a3c9dffc5683dd881..cd9d0ce53f0d58bfde969443283b88f13a2545a0 100644 (file)
@@ -156,6 +156,7 @@ my-video-thumbnail,
     @include padding-left(35px);
 
     padding-top: 0;
+    margin-top: 5px;
     margin-bottom: 15px;
 
     > div {
index 8cd98967f5a9ad6417095a3469ad5710aa0ce675..f5fbbe7adfcfaacbebd5d37f20d13386877aadb7 100644 (file)
@@ -23,7 +23,7 @@ class SettingsDialog extends Component {
       innerHTML: '',
       tabIndex: -1
     }, {
-      role: 'dialog',
+      'role': 'dialog',
       'aria-labelledby': dialogLabelId,
       'aria-describedby': dialogDescriptionId
     })
index ffbe64408803e7074c7aa5dda2d3584687baaa14..cc303b80bb8f9791d4aec39c2eac02194bd1dd01 100644 (file)
@@ -32,7 +32,7 @@ function isSafari () {
 
 // https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
 // Don't import all Angular stuff, just copy the code with shame
-const dictionaryBytes: Array<{ max: number, type: string }> = [
+const dictionaryBytes: { max: number, type: string }[] = [
   { max: 1024, type: 'B' },
   { max: 1048576, type: 'KB' },
   { max: 1073741824, type: 'MB' },
index bda786cc60ee341b16c007b873ebcedf821161c7..7b1920a090cae30c6f6ac8640d04ee796286d842 100644 (file)
@@ -1,4 +1,4 @@
-const dictionary: Array<{ max: number, type: string }> = [
+const dictionary: { max: number, type: string }[] = [
   { max: 1024, type: 'B' },
   { max: 1048576, type: 'KB' },
   { max: 1073741824, type: 'MB' },
index 618be62cdd3e5a5eb54b502c61d395899029842c..8181c13f38455decda5f9e810fc33da1e995cee6 100644 (file)
@@ -59,7 +59,7 @@ class Logger {
     if (!payload) return
 
     const headers = new Headers({
-      Accept: 'application/json',
+      'Accept': 'application/json',
       'Content-Type': 'application/json'
     })
 
index f3416e44a09c5c2cac1d5ee7185eb15c4206e7fb..f99c7598d1196e074995fa9eedd1345b5132bf5f 100644 (file)
@@ -60,14 +60,14 @@ class PluginsManager {
   private loadingScopes: { [id in PluginClientScope]?: boolean } = {}
 
   private pluginsLoaded: { [ scope in PluginClientScope ]: ReplaySubject<boolean> } = {
-    common: new ReplaySubject<boolean>(1),
+    'common': new ReplaySubject<boolean>(1),
     'admin-plugin': new ReplaySubject<boolean>(1),
-    search: new ReplaySubject<boolean>(1),
+    'search': new ReplaySubject<boolean>(1),
     'video-watch': new ReplaySubject<boolean>(1),
-    signup: new ReplaySubject<boolean>(1),
-    login: new ReplaySubject<boolean>(1),
+    'signup': new ReplaySubject<boolean>(1),
+    'login': new ReplaySubject<boolean>(1),
     'video-edit': new ReplaySubject<boolean>(1),
-    embed: new ReplaySubject<boolean>(1),
+    'embed': new ReplaySubject<boolean>(1),
     'my-library': new ReplaySubject<boolean>(1),
     'video-channel': new ReplaySubject<boolean>(1)
   }
index fdbf6f9d23d1e43f54809eaea0214e72cc0bb49f..5079492d6f60fb9ad186ef8a67442225a7584a98 100644 (file)
 .peertube-button-icon {
   @include button-with-icon(18px, 3px, -1px);
 }
+
+.peertube-create-button {
+  @include peertube-button-link;
+  @include orange-button;
+  @include button-with-icon(20px, 5px, -1px);
+}
+
+.button-unstyle {
+  padding: 0;
+  border: 0;
+}
index e42d7d587aaa319f1d43ff122fa94f7419cba5ca..90fc7e299530b54b01382351aa9384a8d013215e 100644 (file)
   border-radius: 0.25rem;
   position: relative;
 
-  >label {
+  > .callout-title {
     position: relative;
     top: -5px;
     left: -10px;
     color: #6c757d !important;
+    font-size: 1rem;
+    font-weight: $font-bold;
+    margin-bottom: 0.5rem;
+    line-height: inherit;
   }
 
   &:not(.callout-light) {
index 1ce584f9b4d73fcd6d9af96d92391396f6ad5e98..7a100a53d7a8bc58c8f350591f41ae678ebadfd3 100644 (file)
   margin-bottom: 10px;
 }
 
-@mixin create-button {
-  @include peertube-button-link;
-  @include orange-button;
-  @include button-with-icon(20px, 5px, -1px);
-}
-
 @mixin row-blocks ($column-responsive: true, $min-height: 130px, $separator: true) {
   display: flex;
   min-height: $min-height;
index eab6f81a66ff367d4d06d5367fd228e5fad53c61..32bf5f6553a0a0ddc5761ee9a85ee1cbeb20dc08 100644 (file)
@@ -35,6 +35,7 @@
   <body id="custom-css" class="standalone-video-embed">
 
     <div id="error-block">
+      <!-- eslint-disable-next-line @angular-eslint/template/elements-content -->
       <h1 id="error-title"></h1>
 
       <div id="error-content"></div>
index 2b49186816311befbe0457e2c207c15580938e11..d818a45eeadc4934c511d731b43269e55c671776 100644 (file)
@@ -6,7 +6,7 @@
   <header>
     <div class="logo">
       <div class="icon">
-        <img src="../../assets/images/logo.svg">
+        <img src="../../assets/images/logo.svg" alt="">
       </div>
       <div>
         PeerTube
index 05ffe8af9e59ff974cc7f3dfff845c098e66638c..8985c9b394c1e02adb05061895d8f6bed8aeca7b 100644 (file)
@@ -164,7 +164,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should correctly have updated the live and federated it when streaming in the live', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
 
@@ -179,7 +179,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should correctly delete the video files after the stream ended', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       sessionEndDateMin = new Date()
       await stopFfmpeg(ffmpegCommand)
@@ -217,7 +217,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should correctly terminate the stream on blacklist and delete the live', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       await publishLiveAndBlacklist({ permanent: false, replay: false })
 
@@ -241,7 +241,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should correctly terminate the stream on delete and delete the video', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       await publishLiveAndDelete({ permanent: false, replay: false })
 
@@ -253,7 +253,7 @@ describe('Save replay setting', function () {
   describe('With save replay enabled on non permanent live', function () {
 
     it('Should correctly create and federate the "waiting for stream" live', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       liveVideoUUID = await createLiveWrapper({ permanent: false, replay: true, replaySettings: { privacy: VideoPrivacy.UNLISTED } })
 
@@ -265,7 +265,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should correctly have updated the live and federated it when streaming in the live', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
       await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
@@ -278,7 +278,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should correctly have saved the live and federated it after the streaming', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       const session = await servers[0].live.findLatestSession({ videoId: liveVideoUUID })
       expect(session.endDate).to.not.exist
@@ -319,7 +319,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should update the saved live and correctly federate the updated attributes', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       await servers[0].videos.update({ id: liveVideoUUID, attributes: { name: 'video updated', privacy: VideoPrivacy.PUBLIC } })
       await waitJobs(servers)
@@ -352,7 +352,7 @@ describe('Save replay setting', function () {
     })
 
     it('Should correctly terminate the stream on delete and delete the video', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       await publishLiveAndDelete({ permanent: false, replay: true, replaySettings: { privacy: VideoPrivacy.PUBLIC } })
 
@@ -367,7 +367,7 @@ describe('Save replay setting', function () {
     describe('With a first live and its replay', function () {
 
       it('Should correctly create and federate the "waiting for stream" live', async function () {
-        this.timeout(60000)
+        this.timeout(120000)
 
         liveVideoUUID = await createLiveWrapper({ permanent: true, replay: true, replaySettings: { privacy: VideoPrivacy.UNLISTED } })
 
@@ -379,7 +379,7 @@ describe('Save replay setting', function () {
       })
 
       it('Should correctly have updated the live and federated it when streaming in the live', async function () {
-        this.timeout(60000)
+        this.timeout(120000)
 
         ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
         await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
@@ -392,7 +392,7 @@ describe('Save replay setting', function () {
       })
 
       it('Should correctly have saved the live and federated it after the streaming', async function () {
-        this.timeout(60000)
+        this.timeout(120000)
 
         const liveDetails = await servers[0].videos.get({ id: liveVideoUUID })
 
@@ -457,7 +457,7 @@ describe('Save replay setting', function () {
       })
 
       it('Should correctly have updated the live and federated it when streaming in the live', async function () {
-        this.timeout(60000)
+        this.timeout(120000)
 
         ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
         await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
@@ -470,7 +470,7 @@ describe('Save replay setting', function () {
       })
 
       it('Should correctly have saved the live and federated it after the streaming', async function () {
-        this.timeout(60000)
+        this.timeout(120000)
 
         const liveDetails = await servers[0].videos.get({ id: liveVideoUUID })
 
@@ -547,7 +547,7 @@ describe('Save replay setting', function () {
       })
 
       it('Should correctly terminate the stream on delete and not save the video', async function () {
-        this.timeout(60000)
+        this.timeout(120000)
 
         const { liveDetails } = await publishLiveAndDelete({
           permanent: true,