]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Improve accessibility
authorChocobozzz <me@florianbigard.com>
Wed, 15 Mar 2023 13:20:26 +0000 (14:20 +0100)
committerChocobozzz <me@florianbigard.com>
Wed, 15 Mar 2023 13:28:27 +0000 (14:28 +0100)
34 files changed:
client/src/app/+search/search.component.html
client/src/app/app.component.html
client/src/app/app.component.ts
client/src/app/menu/menu.component.html
client/src/app/menu/menu.component.scss
client/src/app/menu/notification.component.html
client/src/app/shared/shared-forms/markdown-textarea.component.html
client/src/app/shared/shared-forms/markdown-textarea.component.scss
client/src/app/shared/shared-instance/instance-about-accordion.component.html
client/src/app/shared/shared-instance/instance-about-accordion.component.scss
client/src/app/shared/shared-main/angular/link.component.scss
client/src/app/shared/shared-main/angular/link.component.ts
client/src/app/shared/shared-main/feeds/feed.component.html
client/src/app/shared/shared-main/feeds/feed.component.scss
client/src/app/shared/shared-main/misc/help.component.html
client/src/app/shared/shared-main/misc/help.component.scss
client/src/app/shared/shared-share-modal/video-share.component.html
client/src/app/shared/shared-share-modal/video-share.component.scss
client/src/app/shared/shared-thumbnail/video-thumbnail.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-header.component.scss
client/src/app/shared/shared-video-miniature/video-miniature.component.html
client/src/app/shared/shared-video-miniature/video-miniature.component.scss
client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.html
client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.scss
client/src/sass/bootstrap.scss
client/src/sass/class-helpers/_common.scss
client/src/sass/class-helpers/_text.scss [new file with mode: 0644]
client/src/sass/class-helpers/index.scss
client/src/sass/include/_bootstrap-variables.scss
client/src/sass/include/_miniature.scss
client/src/sass/include/_mixins.scss
client/src/sass/ng-select.scss

index c07dbab082b76dc5edb944a572c355d462a3a5af..2530c87b759c8758e56cdbfd671465bd2169aa64 100644 (file)
@@ -22,7 +22,7 @@
       </div>
     </div>
 
-    <div class="results-filter collapse-transition" [ngbCollapse]="isSearchFilterCollapsed">
+    <div class="results-filter" [ngbCollapse]="isSearchFilterCollapsed" [animation]="true">
       <my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters>
 
       <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
index 6a833b039f974ae5cc40dae7696999ce67e1204e..5fefffaf49d765d1bbf5a5f5993362c29bad6dc4 100644 (file)
@@ -6,9 +6,11 @@
   <div class="root-header">
 
     <div class="top-left-block">
-      <span class="icon icon-menu" role="button" [title]="getToggleTitle()" (click)="menu.toggleMenu()"></span>
+      <span role="button" tabindex="0" [title]="getToggleTitle()" (click)="menu.toggleMenu()" (keyup.enter)="menu.toggleMenu()">
+        <span class="icon icon-menu"></span>
+      </span>
 
-      <a class="peertube-title c-hand" (click)="goToDefaultRoute()">
+      <a class="peertube-title c-hand" [routerLink]="getDefaultRoute()">
         <span class="icon icon-logo"></span>
         <span class="instance-name">{{ instanceName }}</span>
       </a>
@@ -22,7 +24,7 @@
   <div class="sub-header-container">
     <my-menu *ngIf="menu.isMenuDisplayed"></my-menu>
 
-    <div id="content" tabindex="-1" class="main-col" [ngClass]="{ expanded: menu.isMenuDisplayed === false }">
+    <div id="content" class="main-col" [ngClass]="{ expanded: menu.isMenuDisplayed === false }">
 
       <div class="main-row">
 
index e621ce432d4a8dcbb95ce80fabefca4fdd4d13a1..da3ffef2f7fbceb5f6b45fa9c5b45bf57fbc5315 100644 (file)
@@ -83,10 +83,6 @@ export class AppComponent implements OnInit, AfterViewInit {
     return this.serverConfig.instance.name
   }
 
-  goToDefaultRoute () {
-    return this.router.navigateByUrl(this.redirectService.getDefaultRoute())
-  }
-
   ngOnInit () {
     document.getElementById('incompatible-browser').className += ' browser-ok'
 
@@ -135,6 +131,10 @@ export class AppComponent implements OnInit, AfterViewInit {
     this.pluginService.initializeCustomModal(this.customModal)
   }
 
+  getDefaultRoute () {
+    return this.redirectService.getDefaultRoute()
+  }
+
   getToggleTitle () {
     if (this.menu.isDisplayed()) return $localize`Close the left menu`
 
index 6c52580100f7e571a300c6b5eff61639d54e2e54..0786b953b071707bbf5a24e09b4817f022ecbf5b 100644 (file)
@@ -7,7 +7,7 @@
             class="logged-in-more" ngbDropdown #dropdown="ngbDropdown" placement="bottom-left auto"
             [container]="dropdownContainer" (openChange)="onDropdownOpenChange($event)" autoClose="outside"
           >
-            <div ngbDropdownToggle>
+            <button class="border-0 text-start" ngbDropdownToggle>
               <my-actor-avatar [actor]="user.account" actorType="account" size="34"></my-actor-avatar>
 
               <div class="logged-in-info">
@@ -19,7 +19,7 @@
               <div class="dropdown-toggle-indicator">
                 <span class="chevron-down"></span>
               </div>
-            </div>
+            </button>
 
             <div ngbDropdownMenu>
               <a
 
               <div class="dropdown-divider"></div>
 
-              <a
+              <button
                 myPluginSelector pluginSelectorId="menu-user-dropdown-language-item"
                 ngbDropdownItem ngbDropdownToggle 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>
-              </a>
+              </button>
 
               <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles"
                 #settingsLanguagesSubtitles (click)="onActiveLinkScrollToAnchor(settingsLanguagesSubtitles)">
                 <span class="ms-auto muted">{{ nsfwPolicy }}</span>
               </a>
 
-              <a ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()">
+              <button ngbDropdownItem class="dropdown-item" (click)="toggleUseP2P()">
                 <my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon>
                 <ng-container i18n>Help share videos</ng-container>
 
                 <my-input-switch class="ms-auto" [checked]="user.p2pEnabled"></my-input-switch>
-              </a>
+              </button>
 
               <div class="dropdown-divider"></div>
 
       </div>
 
       <div *ngIf="!isLoggedIn" class="login-buttons-block">
-        <my-login-link className="peertube-button-link orange-button w-100"></my-login-link>
+        <my-login-link className="peertube-button-link orange-button w-100 text-truncate"></my-login-link>
 
-        <a *ngIf="isRegistrationAllowed()" routerLink="/signup" class="peertube-button-link create-account-button">
+        <a *ngIf="isRegistrationAllowed()" routerLink="/signup" class="peertube-button-link create-account-button text-truncate">
           <my-signup-label [requiresApproval]="requiresApproval"></my-signup-label>
         </a>
       </div>
index a51686601238b1ecf1e8ac21e111025baeeef7ef..4b1ed65ced9be0d89d66dfe059c86ca4ebb4bb84 100644 (file)
@@ -252,8 +252,6 @@ my-actor-avatar {
 
   > a,
   > my-login-link {
-    @include ellipsis;
-
     display: block;
     width: 100%;
 
index 7a62800f5de2fbb38d2b57735076b7ebcc878841..907828efb7cb070eb8a0478b165984b377392ef7 100644 (file)
@@ -3,15 +3,16 @@
   <div *ngIf="unreadNotifications >= 100" class="unread-notifications">99+</div>
 </ng-template>
 
-<div
+<button
   [ngbPopover]="popContent" autoClose="outside" placement="bottom" container={this} popoverClass="popover-notifications"
-  i18n-title title="View your notifications" [ngClass]="{ 'notification-inbox-popover': true, 'shown': opened, 'hidden': isInMobileView }"
+  i18n-title title="View your notifications"
+  class="border-0 text-start" [ngClass]="{ 'notification-inbox-popover': true, 'shown': opened, 'hidden': isInMobileView }"
   #popover="ngbPopover" (shown)="onPopoverShown()" (hidden)="onPopoverHidden()"
 >
   <ng-container *ngTemplateOutlet="notificationNumber"></ng-container>
 
   <my-global-icon iconName="bell"></my-global-icon>
-</div>
+</button>
 
 <div *ngIf="isInMobileView" i18n-title title="View your notifications" class="notification-inbox-link">
   <ng-container *ngTemplateOutlet="notificationNumber"></ng-container>
index 5a9ff1a156189596124248d4a738e76216b20e24..5d355a6d89c6f9cd2d3c74f83b05fac6027e02bd 100644 (file)
       </ng-template>
     </ng-container>
 
-    <my-global-icon
-      *ngIf="!isMaximized" role="button" [ngbTooltip]="maximizeInText"
-      class="maximize-button" iconName="fullscreen" (click)="onMaximizeClick()" [ngClass]="{ disabled: disabled }"
-    ></my-global-icon>
-
-    <my-global-icon
-      *ngIf="isMaximized" role="button" [ngbTooltip]="maximizeOutText"
-      class="maximize-button" iconName="exit-fullscreen" (click)="onMaximizeClick()" [ngClass]="{ disabled: disabled }"
-    ></my-global-icon>
+    <button (click)="onMaximizeClick()" class="maximize-button border-0 m-3" [disabled]="disabled">
+      <my-global-icon *ngIf="!isMaximized" [ngbTooltip]="maximizeInText" iconName="fullscreen"></my-global-icon>
+
+      <my-global-icon *ngIf="isMaximized" [ngbTooltip]="maximizeOutText" iconName="exit-fullscreen"></my-global-icon>
+    </button>
   </div>
 
   <div [ngbNavOutlet]="nav"></div>
index f4b74a2d415ca36fdbe01f4f13636efda505f013..1f30bf129c7c29bb25ff9e9ea312205226e78bc3 100644 (file)
@@ -23,7 +23,7 @@ $input-border-radius: 3px;
   }
 
   .nav-preview {
-    padding: 10px;
+    padding: 10px 0;
 
     border: 1px solid pvar(--inputBorderColor);
     border-top: 1px dashed pvar(--inputBorderColor);
@@ -38,14 +38,9 @@ $input-border-radius: 3px;
     border-bottom: 2px solid pvar(--mainColor);
 
     .maximize-button {
-      @include margin-left(15px);
-
       opacity: 0.6;
-      cursor: default;
-
-      &:not(.disabled) {
-        cursor: pointer;
 
+      &:not([disabled]) {
         &:hover,
         &:active {
           opacity: 1;
@@ -105,10 +100,6 @@ $input-border-radius: 3px;
 
       padding: 20px 0;
       width: 100% !important;
-
-      .maximize-button {
-        @include margin-right(15px);
-      }
     }
 
     textarea {
index 94077fafa06b93341e22f85c14aa5307cdbbcca7..ac8c018564880f5a0054a069c3839be16c9f93e8 100644 (file)
@@ -1,6 +1,6 @@
 <h2 *ngIf="displayInstanceName" class="instance-name">{{ about?.instance.name }}</h2>
 
-<div *ngIf="displayInstanceShortDescription" class="instance-short-description">{{ about?.instance.shortDescription }}</div>
+<div *ngIf="displayInstanceShortDescription" class="instance-short-description ellipsis-multiline-3">{{ about?.instance.shortDescription }}</div>
 
 <ngb-accordion #accordion="ngbAccordion" [closeOthers]="true">
   <ngb-panel *ngIf="panels.features" id="instance-features">
index ee9e4c3ee91312ceb59b4f0c82e4ae8b25d7c404..8337a7154d5c676e62f7f7cb9a07a4d9b59fadb5 100644 (file)
@@ -6,8 +6,7 @@
 }
 
 .instance-short-description {
-  @include ellipsis-multiline(1rem, 3, inherit);
-
+  font-size: 1rem;
   margin: 25px 0;
 }
 
index f54240d31b9129b7269160c62bd3c44f00da2a62..d288afab1130729849219a2693eaa63a8389bd54 100644 (file)
@@ -1,4 +1,4 @@
-.no-class {
+.inherit-parent {
   color: inherit;
   text-decoration: inherit;
   position: inherit;
index 1f5975589472880e12df07c1d41d1108b57b5577..f2093496fdf375fb0d9f148c40f4d885164c4fc0 100644 (file)
@@ -14,14 +14,17 @@ export class LinkComponent implements OnInit {
   @Input() title?: string
 
   @Input() className?: string
+  @Input() inheritParentCSS = false
 
   @Input() tabindex: string | number
 
   builtClasses: string
 
   ngOnInit () {
-    this.builtClasses = this.className
-      ? this.className
-      : 'no-class'
+    this.builtClasses = this.className || ''
+
+    if (!this.builtClasses || this.inheritParentCSS) {
+      this.builtClasses += ' inherit-parent'
+    }
   }
 }
index a748be873bba574bf6fde4ece583b0cd287c21cc..7032c4cd0eb589cf08bf9fca534911e30b76b603 100644 (file)
@@ -1,4 +1,4 @@
-<div class="feed" *ngIf="syndicationItems && syndicationItems.length !== 0">
+<button class="feed border-0 p-0" *ngIf="syndicationItems && syndicationItems.length !== 0">
   <my-global-icon
     role="button" aria-label="Open syndication dropdown" i18n-aria-label
     *ngIf="syndicationItems.length !== 0" [ngbPopover]="feedsList" [autoClose]="true" placement="bottom left auto"
@@ -9,4 +9,4 @@
   <ng-template #feedsList>
     <a *ngFor="let item of syndicationItems" [href]="item.url" target="_blank" rel="noopener noreferrer">{{ item.label }}</a>
   </ng-template>
-</div>
+</button>
index bf1f4eeebdd1715d51d0e89ed4636fc764dd29da..25afe9c6c92be2236c35ac5f1a2464463f590d77 100644 (file)
@@ -3,15 +3,19 @@
 
 .feed {
   width: 100%;
+  color: inherit;
 
   a {
-    color: #000;
+    color: pvar(--mainForegroundColor);
     display: block;
     min-width: 100px;
+
+    &:hover {
+      text-decoration: underline;
+    }
   }
 }
 
 my-global-icon {
-  cursor: pointer;
   width: 100%;
 }
index 360a476f6202ce165beb893cbbef83f62aa36541..0252ad5cb247a99201725fb86fcd5cc33c987018 100644 (file)
   </p>
 </ng-template>
 
-<span
-  role="button"
-  class="help-tooltip-button"
+<button
+  class="help-tooltip-button p-0 border-0 mx-1"
   [title]="title"
-  tabindex=0
   popoverClass="help-popover"
   [attr.aria-pressed]="isPopoverOpened"
   [ngbPopover]="tooltipTemplate"
@@ -36,4 +34,4 @@
   (onShown)="onPopoverShown()"
 >
   <my-global-icon [iconName]="iconName"></my-global-icon>
-</span>
+</button>
index 6ccef9f2cc4ad2bb4f4a74a5e547956c3f4c8848..46f533f61e371f47a2ac94ba04243df959245228 100644 (file)
@@ -2,12 +2,6 @@
 @use '_mixins' as *;
 
 .help-tooltip-button {
-  @include disable-outline;
-
-  cursor: pointer;
-  border: 0;
-  margin: 5px;
-
   my-global-icon {
     @include apply-svg-color(pvar(--greyForegroundColor));
 
index 01d35178344132b2c321cdd9643a7001f8ee80ae..5650fa94854e5dd824d54f68fe12d00ca839d96e 100644 (file)
@@ -1,7 +1,10 @@
 <ng-template #modal let-hide="close">
   <div class="modal-header">
     <h4 i18n class="modal-title">Share</h4>
-    <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
+
+    <button class="border-0 p-0" (click)="hide()">
+      <my-global-icon iconName="cross" aria-label="Close" role="button" ></my-global-icon>
+    </button>
   </div>
 
 
       <div [ngbNavOutlet]="nav"></div>
 
       <div class="filters">
-        <div>
-          <div class="form-group start-at" *ngIf="!video.isLive">
+        <div class="form-group start-at" *ngIf="!video.isLive">
+          <my-peertube-checkbox
+            inputName="startAt" [(ngModel)]="customizations.startAtCheckbox"
+            i18n-labelText labelText="Start at"
+          ></my-peertube-checkbox>
+
+          <my-timestamp-input
+            [timestamp]="customizations.startAt"
+            [maxTimestamp]="video.duration"
+            [disabled]="!customizations.startAtCheckbox"
+            [(ngModel)]="customizations.startAt"
+          >
+          </my-timestamp-input>
+        </div>
+
+        <div *ngIf="videoCaptions.length !== 0" class="form-group video-caption-block">
+          <my-peertube-checkbox
+            inputName="subtitleCheckbox" [(ngModel)]="customizations.subtitleCheckbox"
+            i18n-labelText labelText="Auto select subtitle"
+          ></my-peertube-checkbox>
+
+          <div class="peertube-select-container" [ngClass]="{ disabled: !customizations.subtitleCheckbox }">
+            <select [(ngModel)]="customizations.subtitle" [disabled]="!customizations.subtitleCheckbox" class="form-control">
+              <option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option>
+            </select>
+          </div>
+        </div>
+
+        <div class="form-group" *ngIf="isInVideoEmbedTab()">
+          <my-peertube-checkbox
+            inputName="onlyEmbedUrl" [(ngModel)]="customizations.onlyEmbedUrl"
+            i18n-labelText labelText="Only display embed URL"
+          ></my-peertube-checkbox>
+        </div>
+
+        <my-plugin-placeholder pluginId="share-modal-video-settings"></my-plugin-placeholder>
+
+        <div class="advanced-filters" [ngbCollapse]="isAdvancedCustomizationCollapsed" [animation]="true">
+          <div class="form-group stop-at" *ngIf="!video.isLive">
             <my-peertube-checkbox
-              inputName="startAt" [(ngModel)]="customizations.startAtCheckbox"
-              i18n-labelText labelText="Start at"
+              inputName="stopAt" [(ngModel)]="customizations.stopAtCheckbox"
+              i18n-labelText labelText="Stop at"
             ></my-peertube-checkbox>
 
             <my-timestamp-input
-              [timestamp]="customizations.startAt"
+              [timestamp]="customizations.stopAt"
               [maxTimestamp]="video.duration"
-              [disabled]="!customizations.startAtCheckbox"
-              [(ngModel)]="customizations.startAt"
+              [disabled]="!customizations.stopAtCheckbox"
+              [(ngModel)]="customizations.stopAt"
             >
             </my-timestamp-input>
           </div>
 
-          <div *ngIf="videoCaptions.length !== 0" class="form-group video-caption-block">
+          <div class="form-group">
             <my-peertube-checkbox
-              inputName="subtitleCheckbox" [(ngModel)]="customizations.subtitleCheckbox"
-              i18n-labelText labelText="Auto select subtitle"
+              inputName="autoplay" [(ngModel)]="customizations.autoplay"
+              i18n-labelText labelText="Autoplay"
             ></my-peertube-checkbox>
-
-            <div class="peertube-select-container" [ngClass]="{ disabled: !customizations.subtitleCheckbox }">
-              <select [(ngModel)]="customizations.subtitle" [disabled]="!customizations.subtitleCheckbox" class="form-control">
-                <option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option>
-              </select>
-            </div>
           </div>
 
-          <div class="form-group" *ngIf="isInVideoEmbedTab()">
+          <div class="form-group">
             <my-peertube-checkbox
-              inputName="onlyEmbedUrl" [(ngModel)]="customizations.onlyEmbedUrl"
-              i18n-labelText labelText="Only display embed URL"
+              inputName="muted" [(ngModel)]="customizations.muted"
+              i18n-labelText labelText="Muted"
             ></my-peertube-checkbox>
           </div>
 
-          <my-plugin-placeholder pluginId="share-modal-video-settings"></my-plugin-placeholder>
-        </div>
-
-        <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed">
-          <div>
-            <div class="form-group stop-at" *ngIf="!video.isLive">
-              <my-peertube-checkbox
-                inputName="stopAt" [(ngModel)]="customizations.stopAtCheckbox"
-                i18n-labelText labelText="Stop at"
-              ></my-peertube-checkbox>
-
-              <my-timestamp-input
-                [timestamp]="customizations.stopAt"
-                [maxTimestamp]="video.duration"
-                [disabled]="!customizations.stopAtCheckbox"
-                [(ngModel)]="customizations.stopAt"
-              >
-              </my-timestamp-input>
-            </div>
-
-            <div class="form-group">
-              <my-peertube-checkbox
-                inputName="autoplay" [(ngModel)]="customizations.autoplay"
-                i18n-labelText labelText="Autoplay"
-              ></my-peertube-checkbox>
-            </div>
-
-            <div class="form-group">
-              <my-peertube-checkbox
-                inputName="muted" [(ngModel)]="customizations.muted"
-                i18n-labelText labelText="Muted"
-              ></my-peertube-checkbox>
-            </div>
-
-            <div class="form-group" *ngIf="!video.isLive">
-              <my-peertube-checkbox
-                inputName="loop" [(ngModel)]="customizations.loop"
-                i18n-labelText labelText="Loop"
-              ></my-peertube-checkbox>
-            </div>
+          <div class="form-group" *ngIf="!video.isLive">
+            <my-peertube-checkbox
+              inputName="loop" [(ngModel)]="customizations.loop"
+              i18n-labelText labelText="Loop"
+            ></my-peertube-checkbox>
+          </div>
 
-            <div *ngIf="!isLocalVideo() && !isInVideoEmbedTab()" class="form-group">
-              <my-peertube-checkbox
-                inputName="originUrl" [(ngModel)]="customizations.originUrl"
-                i18n-labelText labelText="Use origin instance URL"
-              ></my-peertube-checkbox>
-            </div>
+          <div *ngIf="!isLocalVideo() && !isInVideoEmbedTab()" class="form-group">
+            <my-peertube-checkbox
+              inputName="originUrl" [(ngModel)]="customizations.originUrl"
+              i18n-labelText labelText="Use origin instance URL"
+            ></my-peertube-checkbox>
           </div>
 
           <ng-container *ngIf="isInVideoEmbedTab()">
           </ng-container>
         </div>
 
-        <div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button"
-             [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic">
-
+        <button
+          class="border-0 p-0 mt-4 mx-auto fw-semibold d-block"
+          (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed"
+          [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic"
+        >
           <ng-container *ngIf="isAdvancedCustomizationCollapsed">
             <span class="chevron-down"></span>
 
               Less customization
             </ng-container>
           </ng-container>
-        </div>
+        </button>
       </div>
     </div>
   </div>
index 7b6009f5ac4847d93a184f09f7fab796d2728e0f..c64e11f4dd23578ac864c3925f57d3c264d50f45 100644 (file)
@@ -42,12 +42,7 @@ my-input-text {
   }
 
   .advanced-filters-button {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    margin-top: 20px;
     font-weight: $font-semibold;
-    cursor: pointer;
   }
 
   .video-caption-block {
index 4fea0cc1c9a8b1dc5c12bdd177d0c0b563a40936..57fcdd89927b826e134e2d1c996f3136bec02576 100644 (file)
@@ -1,8 +1,8 @@
-<a *ngIf="!videoHref" [routerLink]="getVideoRouterLink()" [queryParams]="queryParams" class="video-thumbnail">
+<a *ngIf="!videoHref" [routerLink]="getVideoRouterLink()" [queryParams]="queryParams" class="video-thumbnail" tabindex="-1">
   <ng-container *ngTemplateOutlet="aContent"></ng-container>
 </a>
 
-<a *ngIf="videoHref" [href]="videoHref" [target]="videoTarget" class="video-thumbnail">
+<a *ngIf="videoHref" [href]="videoHref" [target]="videoTarget" class="video-thumbnail" tabindex="-1">
   <ng-container *ngTemplateOutlet="aContent"></ng-container>
 </a>
 
index 1f622933dedf069b116857f5e11e9a81cee92254..3d8ce22de4544de33053c6732091e0a8eaa096aa 100644 (file)
@@ -56,7 +56,7 @@
 
       <div [ngbNavOutlet]="resolutionNav"></div>
 
-      <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed">
+      <div class="advanced-filters" [ngbCollapse]="isAdvancedCustomizationCollapsed" [animation]="true">
         <div ngbNav #navMetadata="ngbNav" class="nav-tabs nav-metadata">
           <ng-container ngbNavItem>
             <a ngbNavLink i18n>Format</a>
index 1e92e19525899ec3b43566b3a85c76e8c6b5fd21..48bb0d8125b61e129a7ee85e6b60ac0bde610295 100644 (file)
@@ -12,8 +12,8 @@
 
   <div class="first-row">
     <div class="active-filters">
-      <div
-        class="pastille filters-toggle" (click)="areFiltersCollapsed = !areFiltersCollapsed" role="button"
+      <button
+        class="pastille filters-toggle" (click)="areFiltersCollapsed = !areFiltersCollapsed"
         [attr.aria-expanded]="!areFiltersCollapsed" aria-controls="collapseBasic"
         [ngClass]="{ active: !areFiltersCollapsed }"
       >
@@ -21,7 +21,7 @@
         <ng-container i18n *ngIf="!areFiltersCollapsed">Hide filters</ng-container>
 
         <my-global-icon iconName="chevrons-up"></my-global-icon>
-      </div>
+      </button>
 
       <div
         *ngFor="let activeFilter of filters.getActiveFilters()" (click)="resetFilter(activeFilter.key, activeFilter.canRemove)"
@@ -56,7 +56,7 @@
 
   </div>
 
-  <div class="collapse-transition" [ngbCollapse]="areFiltersCollapsed">
+  <div [ngbCollapse]="areFiltersCollapsed" [animation]="true">
     <div class="filters">
       <div class="form-group">
         <label class="with-description" for="languageOneOf" i18n>Languages:</label>
index a4e51982c7ef982a959b24bb749d4d9cd7f3c676..c65895a516f136c7dd1caf3c519686f7d0552d29 100644 (file)
   padding: 4px 15px;
   margin-bottom: 15px;
   cursor: pointer;
+
+  &:focus-visible {
+    outline: pvar(--mainColor) auto 1px;
+  }
 }
 
 .filters-toggle {
index 7d3c3dbfc6f1ec4d6ca3dcc408f22653d87825f6..42d13f458fa186f9ba3e89414591af1cccbc8ecb 100644 (file)
@@ -24,8 +24,8 @@
 
         <div class="w-100 d-flex flex-column">
           <my-link
-            [internalLink]="videoRouterLink" [href]="videoHref" [target]="videoTarget"
-            [title]="video.name"class="video-miniature-name" [ngClass]="{ 'blur-filter': isVideoBlur }" tabindex="-1"
+            [internalLink]="videoRouterLink" [href]="videoHref" [target]="videoTarget" [inheritParentCSS]="true"
+            [title]="video.name" class="video-miniature-name" className="ellipsis-multiline-2" [ngClass]="{ 'blur-filter': isVideoBlur }"
           >
             {{ video.name }}
           </my-link>
@@ -40,7 +40,7 @@
             </span>
           </span>
 
-          <a tabindex="-1" *ngIf="displayOptions.by" class="video-miniature-account" [routerLink]="[ '/c', video.byVideoChannel ]">
+          <a *ngIf="displayOptions.by" class="video-miniature-account" [routerLink]="[ '/c', video.byVideoChannel ]">
             <ng-container *ngIf="displayOwnerAccount()">{{ authorAccount }}</ng-container>
             <ng-container *ngIf="displayOwnerVideoChannel()">{{ authorChannel }}</ng-container>
           </a>
index a397efdca923ac8a0a424c9b53a9b028eb41905f..d48b005185409e585dd5fb7e219625065c7634cd 100644 (file)
@@ -167,7 +167,7 @@ my-actor-avatar {
   }
 
   .video-miniature-name {
-    @include ellipsis-multiline($video-miniature-row-name-font-size, 2);
+    font-size: $video-miniature-row-name-font-size;
   }
 
   .video-miniature-created-at-views,
index 1dd68b09e3706aa7170eb4bc3dda989ce263c468..3b34c71ceec0d575ea0696e77957df4d7368a2c5 100644 (file)
@@ -1,6 +1,6 @@
 <div class="miniature" [ngClass]="{ 'no-videos': playlist.videosLength === 0, 'to-manage': toManage, 'display-as-row': displayAsRow }">
   <my-link
-    [internalLink]="routerLink" [href]="playlistHref" [target]="playlistTarget"
+    [internalLink]="routerLink" [href]="playlistHref" [target]="playlistTarget" [inheritParentCSS]="true"
     [title]="playlist.description" class="miniature-thumbnail"
   >
     <img alt="" [attr.aria-labelledby]="playlist.displayName" [attr.src]="playlist.thumbnailUrl" />
@@ -16,8 +16,8 @@
 
   <div class="miniature-info">
     <my-link
-      [internalLink]="routerLink" [href]="playlistHref" [target]="playlistTarget"
-      [title]="playlist.description" class="miniature-name" tabindex="-1"
+      [internalLink]="routerLink" [href]="playlistHref" [target]="playlistTarget" [inheritParentCSS]="true"
+      [title]="playlist.description" class="miniature-name" className="ellipsis-multiline-2"
     >
       {{ playlist.displayName }}
     </my-link>
index d43afad28e978134717254701f8f451044e51486..2d8377e7ba2c6959b81dcc242b096dcfbfdc0a43 100644 (file)
@@ -95,7 +95,7 @@
   display: flex;
 
   .miniature-name {
-    @include ellipsis-multiline($video-miniature-row-name-font-size, 2);
+    font-size: $video-miniature-row-name-font-size;
   }
 
   .miniature-thumbnail {
index 4d956d65216e70ce03754797680b52f7fc3ff28a..d0465218486d93657fc9a0b61935bf19fce694ca 100644 (file)
@@ -15,6 +15,7 @@
 @import 'bootstrap/scss/grid';
 @import 'bootstrap/scss/forms';
 @import 'bootstrap/scss/buttons';
+@import 'bootstrap/scss/transitions';
 @import 'bootstrap/scss/dropdown';
 @import 'bootstrap/scss/button-group';
 @import 'bootstrap/scss/nav';
@@ -203,7 +204,6 @@ body {
   display: flex !important;
   align-items: center;
   height: 30px !important;
-  padding: 10px 15px !important;
 }
 
 .nav.nav-pills {
@@ -260,19 +260,6 @@ body {
   border-color: #dee2e6;
 }
 
-.collapse-transition {
-  // Animation when we show/hide the filters
-  transition: max-height 0.3s;
-  display: block !important;
-  overflow: hidden !important;
-  max-height: 0;
-
-  &.show {
-    max-height: 1500px;
-    overflow: inherit !important;
-  }
-}
-
 .accordion-button {
   font-size: 18px;
 
@@ -389,3 +376,8 @@ body {
     display: none;
   }
 }
+
+.text-truncate {
+  // Prevent invalid height in parent: https://stackoverflow.com/a/22425601
+  vertical-align: top;
+}
index 0a81a415d564340c4ed12547f9337a8e9c51a3e1..e42d7d587aaa319f1d43ff122fa94f7419cba5ca 100644 (file)
@@ -3,30 +3,6 @@
 @use '_variables' as *;
 @use '_mixins' as *;
 
-.link-orange {
-  color: pvar(--mainForegroundColor);
-  font-weight: $font-semibold;
-  border-bottom: 0.18em solid pvar(--mainColor);
-  display: inline-block;
-  line-height: 1.1;
-
-  &:hover {
-    color: pvar(--mainForegroundColor);
-    opacity: 0.8;
-  }
-}
-
-.underline-orange {
-  display: inline-block;
-  border-bottom: 0.19em solid pvar(--mainColor);
-}
-
-// ---------------------------------------------------------------------------
-
-.muted {
-  @include muted;
-}
-
 // ---------------------------------------------------------------------------
 
 .pt-badge {
diff --git a/client/src/sass/class-helpers/_text.scss b/client/src/sass/class-helpers/_text.scss
new file mode 100644 (file)
index 0000000..0fe698d
--- /dev/null
@@ -0,0 +1,47 @@
+@use '_badges' as *;
+@use '_icons' as *;
+@use '_variables' as *;
+@use '_mixins' as *;
+
+.link-orange {
+  color: pvar(--mainForegroundColor);
+  font-weight: $font-semibold;
+  border-bottom: 0.18em solid pvar(--mainColor);
+  display: inline-block;
+  line-height: 1.1;
+
+  &:hover {
+    color: pvar(--mainForegroundColor);
+    opacity: 0.8;
+  }
+}
+
+.underline-orange {
+  display: inline-block;
+  border-bottom: 0.19em solid pvar(--mainColor);
+}
+
+// ---------------------------------------------------------------------------
+
+.muted {
+  @include muted;
+}
+
+// ---------------------------------------------------------------------------
+
+@mixin ellipsis-multiline($number-of-lines) {
+  display: -webkit-box; /* stylelint-disable-line value-no-vendor-prefix */
+  -webkit-line-clamp: $number-of-lines;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+}
+
+.ellipsis-multiline-2 {
+  @include ellipsis-multiline(2);
+}
+
+.ellipsis-multiline-3 {
+  @include ellipsis-multiline(3);
+}
+
+// ---------------------------------------------------------------------------
index 28beb3b7f377f895647a100b966f1748f34220a7..4fe935ab1ef8be1db4b1f5668289ff706e75435f 100644 (file)
@@ -3,3 +3,4 @@
 @use './_custom-bootstrap-helpers';
 @use './_forms';
 @use './_menu';
+@use './_text';
index ca4a835f941576f9b9d0070962bdd491eedae18e..47ebe685c232db2702b1592020fdc07d49bc2a30 100644 (file)
@@ -41,6 +41,7 @@ $input-focus-bg: pvar(--inputBackgroundColor);
 $input-btn-focus-width: 0;
 $input-btn-focus-color: inherit;
 $input-focus-border-color: #ced4da;
+$input-focus-box-shadow: 0 0 0 0.25rem pvar(--mainColorLightest);
 
 $input-group-addon-color: pvar(--mainForegroundColor);
 $input-group-addon-bg: pvar(--greyBackgroundColor);
index a1b963400796b85b8275491753939cafc6b73d31..eb77f2c3d44d5a289fd6a0c1c21173ee5914a186 100644 (file)
@@ -2,9 +2,9 @@
 @use '_mixins' as *;
 
 @mixin miniature-name {
-  @include ellipsis-multiline(1.1em, 2);
   @include peertube-word-wrap(false);
 
+  font-size: 1.1em;
   transition: color 0.2s;
   font-weight: $font-semibold;
   color: pvar(--mainForegroundColor);
index 0f301dab2518debf065dbfbd828b6b7b5b3d71b8..004f49262538010062308e8f91ac4fabe8bfc279 100644 (file)
@@ -8,13 +8,16 @@
   &:focus,
   &:active {
     text-decoration: none !important;
+  }
+
+  &:focus:not(.focus-visible) {
     outline: none !important;
   }
 }
 
 @mixin disable-outline {
   &:focus:not(.focus-visible) {
-    outline: none;
+    outline: none !important;
   }
 }
 
   text-overflow: ellipsis;
 }
 
-@mixin ellipsis-multiline($font-size: 16px, $number-of-lines: 2, $line-height: $font-size) {
-  display: block;
-  /* Fallback for non-webkit */
-  display: -webkit-box; /* stylelint-disable-line value-no-vendor-prefix */
-  -webkit-line-clamp: $number-of-lines;
-  -webkit-box-orient: vertical;
-  /* Fallback for non-webkit */
-  font-size: $font-size;
-  line-height: $line-height;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  max-height: $font-size * $number-of-lines;
-}
-
 @mixin muted {
   color: pvar(--greyForegroundColor) !important;
 }
index 55494a5566553a84255bf27883c61cdf96da64c5..dfe1f6f0dac24e02d801f5c937f288d71fd22c63 100644 (file)
@@ -40,8 +40,7 @@ $ng-select-input-text: pvar(--mainForegroundColor);
 
   &.ng-select-focused {
     &:not(.ng-select-opened) > .ng-select-container {
-      border-color: #ccc !important;
-      box-shadow: none !important;
+      border-color: $ng-select-border !important;
     }
   }