"@babel/core": "^7.15.0",
"@babel/preset-env": "^7.15.0",
"@neos21/bootstrap3-glyphicons": "^1.0.1",
- "@ng-bootstrap/ng-bootstrap": "^11.0.0",
+ "@ng-bootstrap/ng-bootstrap": "^12.1.2",
"@ng-select/ng-select": "^8.1.1",
"@ngx-loading-bar/core": "^6.0.0",
"@ngx-loading-bar/http-client": "^6.0.0",
"@peertube/p2p-media-loader-hlsjs": "^1.0.8",
"@peertube/videojs-contextmenu": "^5.5.0",
"@peertube/xliffmerge": "^2.0.3",
+ "@popperjs/core": "^2.11.5",
"@types/chart.js": "^2.9.16",
"@types/core-js": "^2.5.2",
"@types/debug": "^4.1.5",
"angular2-hotkeys": "^13.1.0",
"angularx-qrcode": "13.0.3",
"babel-loader": "^8.2.2",
- "bootstrap": "^4.1.3",
+ "bootstrap": "^5.1.3",
"buffer": "^6.0.3",
"cache-chunk-store": "^3.0.0",
"chart.js": "^3.5.1",
<div class="row">
- <h1 class="sr-only" i18n>Follows</h1>
+ <h1 class="visually-hidden" i18n>Follows</h1>
+
<div class="col-xl-6 col-md-12">
<h2 i18n class="subtitle">Follower instances ({{ followersPagination.totalItems }})</h2>
.no-results {
justify-content: flex-start;
+ align-items: flex-start;
}
.show-more {
</div>
<div class="instance-badges" *ngIf="categories.length !== 0 || languages.length !== 0">
- <span *ngFor="let category of categories" class="badge badge-primary category">{{ category }}</span>
+ <span *ngFor="let category of categories" class="pt-badge badge-primary">{{ category }}</span>
- <span *ngFor="let language of languages" class="badge badge-secondary language">{{ language }}</span>
+ <span *ngFor="let language of languages" class="pt-badge badge-secondary">{{ language }}</span>
</div>
<div class="short-description">
</div>
<div class="col-md-12 col-xl-6" myPluginSelector pluginSelectorId="about-instance-features">
- <h2 class="sr-only" i18n>FEATURES</h2>
+ <h2 class="visually-hidden" i18n>FEATURES</h2>
<my-instance-features-table></my-instance-features-table>
</div>
}
.instance-badges {
- font-size: 16px;
margin-bottom: 20px;
+ font-size: 16px;
- .badge {
+ .pt-badge {
@include margin-right(5px);
-
- font-size: 12px;
- font-weight: $font-semibold;
-
- &.category {
- background-color: pvar(--mainColor);
- }
}
}
-<div class="row">
+<div>
<div class="sub-menu" [ngClass]="{ 'sub-menu-fixed': !isBroadcastMessageDisplayed }">
<div class="links">
-<h1 class="sr-only" i18n>Video channels</h1>
+<h1 class="visually-hidden" i18n>Video channels</h1>
<div class="margin-content">
(userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()"
></my-user-moderation-dropdown>
- <span *ngIf="accountUser?.blocked" [ngbTooltip]="accountUser.blockedReason" class="badge badge-danger" i18n>Banned</span>
+ <span *ngIf="accountUser?.blocked" [ngbTooltip]="accountUser.blockedReason" class="pt-badge badge-danger" i18n>Banned</span>
<my-account-block-badges [account]="account"></my-account-block-badges>
</div>
}
}
+.pt-badge {
+ @include margin-right(5px);
+}
+
@media screen and (max-width: $small-view) {
.root {
--myGlobalTopPadding: 45px;
<ng-container [formGroup]="form">
- <div class="form-row mt-5"> <!-- cache grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-form-description">
Some files are not federated, and fetched when necessary. Define their caching policies.
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
-
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="cache">
<div class="form-group" formGroupName="previews">
<label i18n for="cachePreviewsSize">Number of previews to keep in cache</label>
</div>
</div>
- <div class="form-row mt-4"> <!-- cache grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-form-description">
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
-
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="instance">
<ng-container formGroupName="customizations">
<div class="form-group">
<ng-container [formGroup]="form">
- <div class="form-row mt-5"> <!-- appearance grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-form-description">
Use <a routerLink="/admin/plugins">plugins & themes</a> for more involved changes, or <a routerLink="/admin/config/edit-custom" fragment="advanced-configuration">add slight customizations</a>.
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="theme">
<div class="form-group">
</div>
</div>
- <div class="form-row mt-4"> <!-- broadcast grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-for-description">
Display a message on your instance
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="broadcastMessage">
</div>
</div>
- <div class="form-row mt-4"> <!-- new users grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-for-description">
Manage <a routerLink="/admin/users">users</a> to set their quota individually.
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="signup">
<div class="form-group">
</div>
</div>
- <div class="form-row mt-4"> <!-- videos grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="import">
<ng-container formGroupName="videos">
- <div class="form-group mt-4">
+ <div class="form-group">
<label i18n for="importConcurrency">Import jobs concurrency</label>
- <span i18n class="muted ml-1">allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart.</span>
+ <span i18n class="muted ms-1">allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart.</span>
<div class="number-with-unit">
<input type="number" name="importConcurrency" formControlName="concurrency" />
</div>
</div>
- <div class="form-row mt-4"> <!-- video channels grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group" formGroupName="videoChannels">
<label i18n for="videoChannelsMaxPerUser">Max video channels per user</label>
</div>
</div>
- <div class="form-row mt-4"> <!-- search grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="search">
<ng-container formGroupName="remoteUri">
</div>
</div>
- <div class="form-row mt-4"> <!-- federation grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-form-description">
Manage <a routerLink="/admin/follows">relations</a> with other instances.
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="followers">
<ng-container formGroupName="instance">
</div>
</div>
- <div class="form-row mt-4"> <!-- administrators grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group" formGroupName="admin">
<label i18n for="adminEmail">Admin email</label>
</div>
</div>
- <div class="form-row mt-4"> <!-- Twitter grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-form-description">
Provide the Twitter account representing your instance to improve link previews.
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="services">
<ng-container formGroupName="twitter">
-<h1 class="sr-only" i18n>Configuration</h1>
+<h1 class="visually-hidden" i18n>Configuration</h1>
<div class="alert alert-warning" *ngIf="!isUpdateAllowed()" i18n>
Updating instance configuration from the web interface is disabled by the system administrator.
<div [ngbNavOutlet]="nav"></div>
- <div class="form-row mt-4"> <!-- submit placement block -->
+ <div class="row mt-4"> <!-- submit placement block -->
<div class="col-md-7 col-xl-5"></div>
<div class="col-md-5 col-xl-5">
opacity: 0.5;
}
-
-.form-group-right {
- padding-top: 2px;
-}
-
ngb-tabset:not(.previews) ::ng-deep {
.nav-link {
font-size: 105%;
<ng-container formGroupName="instanceCustomHomepage">
- <div class="form-row mt-5"> <!-- homepage grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <div class="row mt-5"> <!-- homepage grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<div i18n class="inner-form-title">INSTANCE HOMEPAGE</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group">
<label i18n for="instanceCustomHomepageContent">Homepage</label>
<ng-container formGroupName="instance">
- <div class="form-row mt-5"> <!-- instance grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
-
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group">
<label i18n for="instanceName">Name</label>
</div>
</div>
- <div class="form-row mt-4"> <!-- moderation & nsfw grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
- <div i18n class="inner-for-description">
+ <div i18row="inner-for-description">
Manage <a routerLink="/admin/users">users</a> to build a moderation team.
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
-
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group">
<my-peertube-checkbox inputName="instanceIsNSFW" formControlName="isNSFW">
<ng-template ptTemplate="label">
</div>
</div>
- <div class="form-row mt-4"> <!-- you and your instance grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group">
<label i18n for="instanceAdministrator">Who is behind the instance?</label><my-help helpType="markdownText"></my-help>
</div>
</div>
- <div class="form-row mt-4"> <!-- other information grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group">
<label i18n for="instanceHardwareInformation">What server/hardware does the instance run on?</label>
<ng-container [formGroup]="form">
- <div class="form-row mt-5">
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <div class="row mt-5">
+ <div class="col-12 col-lg-4 col-xl-3">
<div i18n class="inner-form-title">LIVE</div>
<div i18n class="inner-form-description">
Enable users of your instance to stream live.
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="live">
</div>
</div>
- <div class="form-row"> <!-- transcoding live streams grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<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="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="live">
<ng-container formGroupName="transcoding">
<div class="form-group" [ngClass]="getDisabledLiveTranscodingClass()">
<label i18n for="liveTranscodingThreads">Live resolutions to generate</label>
- <div class="ml-2 mt-2 d-flex flex-column">
+ <div class="ms-2 mt-2 d-flex flex-column">
<ng-container formGroupName="resolutions">
<div class="form-group" *ngFor="let resolution of liveResolutions">
<div class="form-group" [ngClass]="getDisabledLiveTranscodingClass()">
<label i18n for="liveTranscodingThreads">Live transcoding threads</label>
- <span class="muted ml-1">
+ <span class="muted ms-1">
<ng-container *ngIf="getTotalTranscodingThreads().atMost" i18n>
will claim at most {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with VOD transcoding
</ng-container>
<div class="form-group mt-4" [ngClass]="getDisabledLiveTranscodingClass()">
<label i18n for="liveTranscodingProfile">Live transcoding profile</label>
- <span class="muted ml-1" i18n>new live transcoding profiles can be added by PeerTube plugins</span>
+ <span class="muted ms-1" i18n>new live transcoding profiles can be added by PeerTube plugins</span>
<my-select-options
id="liveTranscodingProfile"
<ng-container [formGroup]="form">
- <div class="form-row mt-4"> <!-- transcoding grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3"></div>
- <div class="form-group form-group-right col-12 col-lg-8">
+ <div class="row mt-4"> <!-- transcoding grid -->
+ <div class="col-12 col-lg-4 col-xl-3"></div>
+ <div class="col-12 col-lg-8">
<div class="callout callout-info">
<span i18n>
</div>
</div>
- <div class="form-row mt-2"> <!-- transcoding grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<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
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="transcoding">
- <div class="form-group mb-0 col-12 col-xl-11">
+ <div class="col-12 col-xl-11">
<my-peertube-checkbox inputName="transcodingEnabled" formControlName="enabled" [recommended]="true">
<ng-template ptTemplate="label">
<ng-container i18n>Transcoding enabled</ng-container>
<div class="form-group" [ngClass]="getTranscodingDisabledClass()">
<label i18n>Resolutions to generate per enabled format</label>
- <div class="ml-2 mt-2 d-flex flex-column">
+ <div class="ms-2 mt-2 d-flex flex-column">
<ng-container formGroupName="resolutions">
<div class="form-group" *ngFor="let resolution of resolutions">
<my-peertube-checkbox
<div class="form-group mt-4" [ngClass]="getTranscodingDisabledClass()">
<label i18n for="transcodingThreads">Transcoding threads</label>
- <span class="muted ml-1">
+ <span class="muted ms-1">
<ng-container *ngIf="getTotalTranscodingThreads().atMost" i18n>
will claim at most {{ getTotalTranscodingThreads().value }} {{ getTotalTranscodingThreads().unit }} with live transcoding
</ng-container>
<div *ngIf="formErrors.transcoding.threads" class="form-error">{{ formErrors.transcoding.threads }}</div>
</div>
- <div class="form-group mt-4" [ngClass]="getTranscodingDisabledClass()">
+ <div class="form-group" [ngClass]="getTranscodingDisabledClass()">
<label i18n for="transcodingConcurrency">Transcoding jobs concurrency</label>
- <span class="muted ml-1" i18n>allows to transcode multiple files in parallel. ⚠️ Requires a PeerTube restart</span>
+ <span class="muted ms-1" i18n>allows to transcode multiple files in parallel. ⚠️ Requires a PeerTube restart</span>
<div class="number-with-unit">
<input type="number" name="transcodingConcurrency" formControlName="concurrency" />
<div *ngIf="formErrors.transcoding.concurrency" class="form-error">{{ formErrors.transcoding.concurrency }}</div>
</div>
- <div class="form-group mt-4" [ngClass]="getTranscodingDisabledClass()">
+ <div class="form-group" [ngClass]="getTranscodingDisabledClass()">
<label i18n for="transcodingProfile">Transcoding profile</label>
- <span class="muted ml-1" i18n>new transcoding profiles can be added by PeerTube plugins</span>
+ <span class="muted ms-1" i18n>new transcoding profiles can be added by PeerTube plugins</span>
<my-select-options
id="transcodingProfile"
</div>
</div>
- <div class="form-row mt-2"> <!-- video studio grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <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>
<div i18n class="inner-form-description">
Allows your users to edit their video (cut, add intro/outro, add a watermark etc)
</div>
</div>
- <div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="videoStudio">
<div class="form-group" [ngClass]="getTranscodingDisabledClass()">
>
<ng-template pTemplate="caption">
<div class="caption">
- <div class="ml-auto">
+ <div class="ms-auto">
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
</div>
</div>
</td>
<td *ngIf="follow.state === 'accepted'">
- <span class="badge badge-green" i18n>Accepted</span>
+ <span class="pt-badge badge-green" i18n>Accepted</span>
</td>
<td *ngIf="follow.state === 'pending'">
- <span class="badge badge-yellow" i18n>Pending</span>
+ <span class="pt-badge badge-yellow" i18n>Pending</span>
</td>
<td>{{ follow.score }}</td>
</a>
</div>
- <div class="ml-auto">
+ <div class="ms-auto">
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
</div>
</div>
</td>
<td *ngIf="follow.state === 'accepted'">
- <span class="badge badge-green" i18n>Accepted</span>
+ <span class="pt-badge badge-green" i18n>Accepted</span>
</td>
<td *ngIf="follow.state === 'pending'">
- <span class="badge badge-yellow" i18n>Pending</span>
+ <span class="pt-badge badge-yellow" i18n>Pending</span>
</td>
<td>{{ follow.createdAt | date: 'short' }}</td>
>
<ng-template pTemplate="caption">
<div class="caption">
- <div class="ml-auto">
+ <div class="ms-auto">
<my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter>
</div>
</div>
</td>
<td>
- <span *ngIf="videoBlock.video.nsfw" class="badge badge-red" i18n>NSFW</span>
+ <span *ngIf="videoBlock.video.nsfw" class="pt-badge badge-red" i18n>NSFW</span>
</td>
<td>
- <span *ngIf="videoBlock.unfederated" class="badge badge-blue" i18n>Unfederated</span>
+ <span *ngIf="videoBlock.unfederated" class="pt-badge badge-blue" i18n>Unfederated</span>
</td>
<td>
</my-action-dropdown>
</div>
- <div class="ml-auto right-form">
+ <div class="ms-auto right-form">
<my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter>
<my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button>
</div>
</ng-template>
-<div class="form-row" *ngIf="!isInBigView()"> <!-- hidden on large screens, as it is then displayed on the right side of the form -->
+<div class="row d-xxl-none"> <!-- hidden on large screens, as it is then displayed on the right side of the form -->
<div class="col-12 col-xl-3"></div>
<div class="col-12 col-xl-9">
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
-<div class="form-row mt-4"> <!-- user grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-4"> <!-- user grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<div class="anchor" id="user"></div> <!-- user anchor -->
<div *ngIf="isCreation()" class="account-title" i18n>NEW USER</div>
<div *ngIf="!isCreation() && user" class="account-title">
</div>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9" [ngClass]="{ 'form-row': isInBigView() }">
-
- <form role="form" (ngSubmit)="formValidated()" [formGroup]="form" [ngClass]="{ 'col-5': isInBigView() }">
- <div class="form-group" *ngIf="isCreation()">
- <label i18n for="username">Username</label>
- <input
- type="text" id="username" i18n-placeholder placeholder="john" class="form-control"
- formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
- >
- <div *ngIf="formErrors.username" class="form-error">
- {{ formErrors.username }}
+ <div class="col-12 col-lg-8 col-xl-9">
+ <div class="row">
+ <form class="col" role="form" (ngSubmit)="formValidated()" [formGroup]="form">
+ <div class="form-group" *ngIf="isCreation()">
+ <label i18n for="username">Username</label>
+ <input
+ type="text" id="username" i18n-placeholder placeholder="john" class="form-control"
+ formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
+ >
+ <div *ngIf="formErrors.username" class="form-error">
+ {{ formErrors.username }}
+ </div>
</div>
- </div>
- <div class="form-group" *ngIf="isCreation()">
- <label i18n for="channelName">Channel name</label>
- <input
- type="text" id="channelName" i18n-placeholder placeholder="john_channel" class="form-control"
- formControlName="channelName" [ngClass]="{ 'input-error': formErrors['channelName'] }"
- >
- <div *ngIf="formErrors.channelName" class="form-error">
- {{ formErrors.channelName }}
+ <div class="form-group" *ngIf="isCreation()">
+ <label i18n for="channelName">Channel name</label>
+ <input
+ type="text" id="channelName" i18n-placeholder placeholder="john_channel" class="form-control"
+ formControlName="channelName" [ngClass]="{ 'input-error': formErrors['channelName'] }"
+ >
+ <div *ngIf="formErrors.channelName" class="form-error">
+ {{ formErrors.channelName }}
+ </div>
</div>
- </div>
- <div class="form-group">
- <label i18n for="email">Email</label>
- <input
- type="text" id="email" i18n-placeholder placeholder="mail@example.com" class="form-control"
- formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
- autocomplete="off" [readonly]="user && user.pluginAuth !== null"
- >
- <div *ngIf="formErrors.email" class="form-error">
- {{ formErrors.email }}
+ <div class="form-group">
+ <label i18n for="email">Email</label>
+ <input
+ type="text" id="email" i18n-placeholder placeholder="mail@example.com" class="form-control"
+ formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
+ autocomplete="off" [readonly]="user && user.pluginAuth !== null"
+ >
+ <div *ngIf="formErrors.email" class="form-error">
+ {{ formErrors.email }}
+ </div>
</div>
- </div>
- <div class="form-group" *ngIf="isCreation()">
- <label i18n for="password">Password</label>
- <my-help *ngIf="isPasswordOptional()">
- <ng-template ptTemplate="customHtml">
- <ng-container i18n>
- If you leave the password empty, an email will be sent to the user.
- </ng-container>
- </ng-template>
- </my-help>
-
- <my-input-toggle-hidden
- formControlName="password" inputId="password" [ngClass]="{ 'input-error': formErrors['password'] }" autocomplete="new-password"
- ></my-input-toggle-hidden>
-
- <div *ngIf="formErrors.password" class="form-error">
- {{ formErrors.password }}
+ <div class="form-group" *ngIf="isCreation()">
+ <label i18n for="password">Password</label>
+ <my-help *ngIf="isPasswordOptional()">
+ <ng-template ptTemplate="customHtml">
+ <ng-container i18n>
+ If you leave the password empty, an email will be sent to the user.
+ </ng-container>
+ </ng-template>
+ </my-help>
+
+ <my-input-toggle-hidden
+ formControlName="password" inputId="password" [ngClass]="{ 'input-error': formErrors['password'] }" autocomplete="new-password"
+ ></my-input-toggle-hidden>
+
+ <div *ngIf="formErrors.password" class="form-error">
+ {{ formErrors.password }}
+ </div>
</div>
- </div>
- <div class="form-group">
- <label i18n for="role">Role</label>
- <div class="peertube-select-container">
- <select id="role" formControlName="role" class="form-control">
- <option *ngFor="let role of roles" [value]="role.value">
- {{ role.label }}
- </option>
- </select>
+ <div class="form-group">
+ <label i18n for="role">Role</label>
+ <div class="peertube-select-container">
+ <select id="role" formControlName="role" class="form-control">
+ <option *ngFor="let role of roles" [value]="role.value">
+ {{ role.label }}
+ </option>
+ </select>
+ </div>
+
+ <div *ngIf="formErrors.role" class="form-error">
+ {{ formErrors.role }}
+ </div>
</div>
- <div *ngIf="formErrors.role" class="form-error">
- {{ formErrors.role }}
+ <div class="form-group">
+ <label i18n for="videoQuota">Video quota</label>
+
+ <my-select-custom-value
+ id="videoQuota"
+ [items]="videoQuotaOptions"
+ formControlName="videoQuota"
+ i18n-inputSuffix inputSuffix="bytes" inputType="number"
+ [clearable]="false"
+ ></my-select-custom-value>
+
+ <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()">
+ Transcoding is enabled. The video quota only takes into account <strong>original</strong> video size. <br />
+ At most, this user could upload ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}.
+ </div>
+
+ <div *ngIf="formErrors.videoQuota" class="form-error">
+ {{ formErrors.videoQuota }}
+ </div>
</div>
- </div>
- <div class="form-group">
- <label i18n for="videoQuota">Video quota</label>
-
- <my-select-custom-value
- id="videoQuota"
- [items]="videoQuotaOptions"
- formControlName="videoQuota"
- i18n-inputSuffix inputSuffix="bytes" inputType="number"
- [clearable]="false"
- ></my-select-custom-value>
-
- <div i18n class="transcoding-information" *ngIf="isTranscodingInformationDisplayed()">
- Transcoding is enabled. The video quota only takes into account <strong>original</strong> video size. <br />
- At most, this user could upload ~ {{ computeQuotaWithTranscoding() | bytes: 0 }}.
- </div>
+ <div class="form-group">
+ <label i18n for="videoQuotaDaily">Daily video quota</label>
- <div *ngIf="formErrors.videoQuota" class="form-error">
- {{ formErrors.videoQuota }}
- </div>
- </div>
+ <my-select-custom-value
+ id="videoQuotaDaily"
+ [items]="videoQuotaDailyOptions"
+ formControlName="videoQuotaDaily"
+ i18n-inputSuffix inputSuffix="bytes" inputType="number"
+ [clearable]="false"
+ ></my-select-custom-value>
- <div class="form-group">
- <label i18n for="videoQuotaDaily">Daily video quota</label>
-
- <my-select-custom-value
- id="videoQuotaDaily"
- [items]="videoQuotaDailyOptions"
- formControlName="videoQuotaDaily"
- i18n-inputSuffix inputSuffix="bytes" inputType="number"
- [clearable]="false"
- ></my-select-custom-value>
-
- <div *ngIf="formErrors.videoQuotaDaily" class="form-error">
- {{ formErrors.videoQuotaDaily }}
+ <div *ngIf="formErrors.videoQuotaDaily" class="form-error">
+ {{ formErrors.videoQuotaDaily }}
+ </div>
</div>
- </div>
- <div class="form-group" *ngIf="!isCreation() && getAuthPlugins().length !== 0">
- <label i18n for="pluginAuth">Auth plugin</label>
+ <div class="form-group" *ngIf="!isCreation() && getAuthPlugins().length !== 0">
+ <label i18n for="pluginAuth">Auth plugin</label>
- <div class="peertube-select-container">
- <select id="pluginAuth" formControlName="pluginAuth" class="form-control">
- <option [value]="null" i18n>None (local authentication)</option>
- <option *ngFor="let authPlugin of getAuthPlugins()" [value]="authPlugin">{{ authPlugin }}</option>
- </select>
+ <div class="peertube-select-container">
+ <select id="pluginAuth" formControlName="pluginAuth" class="form-control">
+ <option [value]="null" i18n>None (local authentication)</option>
+ <option *ngFor="let authPlugin of getAuthPlugins()" [value]="authPlugin">{{ authPlugin }}</option>
+ </select>
+ </div>
</div>
- </div>
- <div class="form-group">
- <my-peertube-checkbox
- inputName="byPassAutoBlock" formControlName="byPassAutoBlock"
- i18n-labelText labelText="Doesn't need review before a video goes public"
- ></my-peertube-checkbox>
- </div>
+ <div class="form-group">
+ <my-peertube-checkbox
+ inputName="byPassAutoBlock" formControlName="byPassAutoBlock"
+ i18n-labelText labelText="Doesn't need review before a video goes public"
+ ></my-peertube-checkbox>
+ </div>
- <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
- </form>
+ <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
+ </form>
- <div *ngIf="isInBigView()" class="col-7">
- <ng-template *ngTemplateOutlet="dashboard"></ng-template>
+ <div class="d-none d-xxl-block col-7">
+ <ng-template *ngTemplateOutlet="dashboard"></ng-template>
+ </div>
</div>
-
</div>
</div>
-<div *ngIf="!isCreation() && user && user.pluginAuth === null" class="form-row mt-4"> <!-- danger zone grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div *ngIf="!isCreation() && user && user.pluginAuth === null" class="row mt-4"> <!-- danger zone grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<div class="anchor" id="danger"></div> <!-- danger zone anchor -->
<div i18n class="account-title account-title-danger">DANGER ZONE</div>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9" [ngClass]="{ 'form-row': isInBigView() }">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="danger-zone">
<div class="form-group reset-password-email">
.concat(this.serverConfig.plugin.registeredExternalAuths.map(p => p.npmName))
}
- isInBigView () {
- return this.screenService.getWindowInnerWidth() > 1600
- }
-
buildRoles () {
const authUser = this.auth.getUser()
<form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
- <div class="form-group">
+ <div class="input-group">
+ <input id="password" [attr.type]="showPassword ? 'text' : 'password'" class="form-control"
+ formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
+ >
+ <button class="btn btn-sm btn-outline-secondary" (click)="togglePasswordVisibility()" type="button">
+ <ng-container *ngIf="!showPassword" i18n>Show</ng-container>
+ <ng-container *ngIf="!!showPassword" i18n>Hide</ng-container>
+ </button>
+ </div>
- <div class="input-group">
- <input id="password" [attr.type]="showPassword ? 'text' : 'password'" class="form-control"
- formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
- >
- <div class="input-group-append">
- <button class="btn btn-sm btn-outline-secondary" (click)="togglePasswordVisibility()" type="button">
- <ng-container *ngIf="!showPassword" i18n>Show</ng-container>
- <ng-container *ngIf="!!showPassword" i18n>Hide</ng-container>
- </button>
- </div>
- </div>
- <div *ngIf="formErrors.password" class="form-error">
- {{ formErrors.password }}
- </div>
+ <div *ngIf="formErrors.password" class="form-error">
+ {{ formErrors.password }}
</div>
<input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
@use '_variables' as *;
@use '_mixins' as *;
-input:not([type=submit]):not([type=checkbox]) {
+input[type=text],
+input[type=password] {
@include peertube-input-text(340px);
-
- display: block;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- border-right: 0;
}
input[type=submit] {
margin-top: 10px;
}
-
-.input-group-append {
- height: 30px;
-}
</a>
</div>
- <div class="ml-auto">
+ <div class="ms-auto">
<my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter>
</div>
</my-user-moderation-dropdown>
</td>
- <td *ngIf="isSelected('username')">
+ <td *ngIf="isSelected('username')" class="cell-username">
<a i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer" [routerLink]="[ '/a/' + user.username ]">
<div class="chip two-lines">
<my-actor-avatar [account]="user?.account" size="32"></my-actor-avatar>
</div>
</a>
- <div *ngIf="user.accountMutedStatus.mutedByInstance" class="badges-username badge badge-red" i18n>Muted</div>
- <div *ngIf="user.blocked" class="badges-username badge badge-red" i18n>Banned</div>
+ <div *ngIf="user.accountMutedStatus.mutedByInstance" class="pt-badge badge-red" i18n>Muted</div>
+ <div *ngIf="user.blocked" class="pt-badge badge-red" i18n>Banned</div>
</td>
<td *ngIf="isSelected('role')">
- <span *ngIf="user.blocked" class="badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span>
- <span *ngIf="!user.blocked" class="badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span>
+ <span *ngIf="user.blocked" class="pt-badge badge-banned" i18n-title title="The user was banned">{{ user.roleLabel }}</span>
+ <span *ngIf="!user.blocked" class="pt-badge" [ngClass]="getRoleClass(user.role)">{{ user.roleLabel }}</span>
</td>
<td *ngIf="isSelected('email')" [title]="user.email">
@use '_variables' as *;
@use '_mixins' as *;
+@use '~bootstrap/scss/functions' as *;
.add-button {
@include create-button;
font-weight: $font-semibold;
}
-.badges-username {
- margin-left: 15px;
+.cell-username .pt-badge {
+ @include margin-left(15px);
}
.user-table-primary-text .glyphicon {
</my-action-dropdown>
</div>
- <div class="ml-auto right-form">
+ <div class="ms-auto right-form">
<my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter>
<my-button i18n-label label="Refresh" icon="refresh" (click)="reloadData()"></my-button>
</td>
<td>
- <span class="badge badge-blue" *ngIf="video.isLocal">Local</span>
- <span class="badge badge-purple" *ngIf="!video.isLocal">Remote</span>
+ <span class="pt-badge badge-blue" *ngIf="video.isLocal">Local</span>
+ <span class="pt-badge badge-purple" *ngIf="!video.isLocal">Remote</span>
- <span [ngClass]="getPrivacyBadgeClass(video)" class="badge">{{ video.privacy.label }}</span>
+ <span [ngClass]="getPrivacyBadgeClass(video)" class="pt-badge">{{ video.privacy.label }}</span>
- <span *ngIf="video.nsfw" class="badge badge-red" i18n>NSFW</span>
+ <span *ngIf="video.nsfw" class="pt-badge badge-red" i18n>NSFW</span>
- <span *ngIf="isUnpublished(video)" class="badge badge-yellow" i18n>{{ video.state.label }}</span>
+ <span *ngIf="isUnpublished(video)" class="pt-badge badge-yellow" i18n>{{ video.state.label }}</span>
- <span *ngIf="isAccountBlocked(video)" class="badge badge-red" i18n>Account muted</span>
- <span *ngIf="isServerBlocked(video)" class="badge badge-red" i18n>Server muted</span>
+ <span *ngIf="isAccountBlocked(video)" class="pt-badge badge-red" i18n>Account muted</span>
+ <span *ngIf="isServerBlocked(video)" class="pt-badge badge-red" i18n>Server muted</span>
- <span *ngIf="isVideoBlocked(video)" class="badge badge-red" i18n>Blocked</span>
+ <span *ngIf="isVideoBlocked(video)" class="pt-badge badge-red" i18n>Blocked</span>
</td>
<td>
- <span *ngIf="isHLS(video)" class="badge badge-blue">HLS</span>
- <span *ngIf="isWebTorrent(video)" class="badge badge-blue">WebTorrent ({{ video.files.length }})</span>
- <span *ngIf="video.isLive" class="badge badge-blue">Live</span>
+ <span *ngIf="isHLS(video)" class="pt-badge badge-blue">HLS</span>
+ <span *ngIf="isWebTorrent(video)" class="pt-badge badge-blue">WebTorrent ({{ video.files.length }})</span>
+ <span *ngIf="video.isLive" class="pt-badge badge-blue">Live</span>
<span *ngIf="!isImport(video) && !video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span>
</td>
</ul>
</div>
- <my-embed class="ml-auto" [video]="video"></my-embed>
+ <my-embed class="ms-auto" [video]="video"></my-embed>
</div>
</td>
</tr>
width: 50%;
}
-.badge {
- @include peertube-badge;
-
- margin-right: 5px;
+.pt-badge {
+ @include margin-right(5px);
}
.video-info > div {
<ng-container *ngFor="let plugin of plugins" >
<my-plugin-card [plugin]="plugin" [version]="plugin.latestVersion" [pluginType]="pluginType">
<div ngProjectAs="badges">
- <span i18n *ngIf="plugin.installed" class="badge badge-success">Installed</span>
+ <span i18n *ngIf="plugin.installed" class="pt-badge badge-success">Installed</span>
- <span *ngIf="plugin.official" class="badge badge-primary" i18n i18n-title title="This plugin is developed by Framasoft">
+ <span *ngIf="plugin.official" class="pt-badge badge-primary" i18n i18n-title title="This plugin is developed by Framasoft">
Official
</span>
</div>
}
}
-.badge {
+.pt-badge {
@include margin-left(15px);
font-size: 13px;
- font-weight: $font-semibold;
}
.alert {
<span i18n="Selector for the list displaying jobs, filtering by their state">any</span>
</ng-option>
<ng-option *ngFor="let state of jobStates" [value]="state">
- <span class="badge" [ngClass]="getJobStateClass(state)">{{ state }}</span>
+ <span class="pt-badge" [ngClass]="getJobStateClass(state)">{{ state }}</span>
</ng-option>
</ng-select>
</div>
<td class="job-priority c-hand" [pRowToggler]="job">{{ job.priority }}</td>
<td class="job-state c-hand" [pRowToggler]="job" *ngIf="jobState === 'all'">
- <span class="badge" [ngClass]="getJobStateClass(job.state)">{{ job.state }}</span>
+ <span class="pt-badge" [ngClass]="getJobStateClass(job.state)">{{ job.state }}</span>
</td>
<td *ngIf="hasGlobalProgress()" class="job-progress c-hand" [pRowToggler]="job">
</ng-container>
<ng-container *ngIf="jobState !== 'all'">
- <ng-container *ngIf="jobType === 'all'" i18n>No <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span> jobs found.</ng-container>
- <ng-container *ngIf="jobType !== 'all'" i18n>No <code>{{ jobType }}</code> jobs found that are <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span>.</ng-container>
+ <ng-container *ngIf="jobType === 'all'" i18n>No <span class="pt-badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span> jobs found.</ng-container>
+ <ng-container *ngIf="jobType !== 'all'" i18n>No <code>{{ jobType }}</code> jobs found that are <span class="pt-badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span>.</ng-container>
</ng-container>
</div>
</div>
.job-error {
color: #ff0000;
}
-
-.select-filter-block .badge {
- @include peertube-badge;
-}
<div class="margin-content">
<form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
- <div class="form-row"> <!-- channel grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <div class="row"> <!-- channel grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<div *ngIf="isCreation()" class="video-channel-title" i18n>NEW CHANNEL</div>
<div *ngIf="!isCreation() && videoChannel" class="video-channel-title" i18n>CHANNEL</div>
</div>
-
- <div class="form-group col-12 col-lg-8 col-xl-9">
+
+ <div class="col-12 col-lg-8 col-xl-9">
<h6 i18n>Banner image of the channel</h6>
-
+
<my-actor-banner-edit
*ngIf="videoChannel" [previewImage]="isCreation()"
[actor]="videoChannel" (bannerChange)="onBannerChange($event)" (bannerDelete)="onBannerDelete()"
></my-actor-banner-edit>
-
+
<my-actor-avatar-edit
*ngIf="videoChannel" [previewImage]="isCreation()"
[actor]="videoChannel" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()"
[displayUsername]="!isCreation()" [displaySubscribers]="!isCreation()"
></my-actor-avatar-edit>
-
+
<div class="form-group" *ngIf="isCreation()">
<label i18n for="name">Name</label>
+
<div class="input-group">
<input
type="text" id="name" i18n-placeholder placeholder="Example: my_channel"
formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" class="form-control"
>
- <div class="input-group-append">
- <span class="input-group-text">@{{ instanceHost }}</span>
- </div>
+ <div class="input-group-text">@{{ instanceHost }}</div>
</div>
<div *ngIf="formErrors['name']" class="form-error">
{{ formErrors['name'] }}
</div>
</div>
-
+
<div class="form-group">
<label i18n for="display-name">Display name</label>
<input
{{ formErrors['display-name'] }}
</div>
</div>
-
+
<div class="form-group">
<label i18n for="description">Description</label>
<textarea
{{ formErrors.description }}
</div>
</div>
-
+
<div class="form-group">
<label for="support">Support</label>
<my-help
{{ formErrors.support }}
</div>
</div>
-
+
<div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()">
<my-peertube-checkbox
inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate"
i18n-labelText labelText="Overwrite support field of all videos of this channel"
></my-peertube-checkbox>
</div>
-
+
</div>
</div>
-
- <div class="form-row"> <!-- submit placement block -->
+
+ <div class="row"> <!-- submit placement block -->
<div class="col-md-7 col-xl-5"></div>
<div class="col-md-5 col-xl-5 d-inline-flex">
<input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
</div>
</div>
- </form>
-</div>
\ No newline at end of file
+ </form>
+</div>
max-width: 500px;
}
-.input-group {
- @include peertube-input-group(fit-content);
-}
-
-.input-group-append {
- height: 30px;
-}
-
-input {
- &[type=text] {
- @include peertube-input-text(340px);
+input[type=text] {
+ @include peertube-input-text(340px);
- display: block;
+ display: block;
- &#name {
- width: auto;
- flex-grow: 1;
- }
+ &#name {
+ width: auto;
+ flex-grow: 1;
}
+}
- &[type=submit] {
- @include peertube-button;
- @include orange-button;
- @include margin-left(auto);
- }
+input[type=submit] {
+ @include peertube-button;
+ @include orange-button;
+ @include margin-left(auto);
}
textarea {
<ng-container i18n>Applications</ng-container>
</h1>
-<div class="form-row"> <!-- built-in token grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row"> <!-- built-in token grid -->
+
+ <div class="group col-12 col-lg-4 col-xl-3">
<h2 i18n class="applications-title">SUBSCRIPTION FEED</h2>
<div i18n class="applications-description">
Use third-party feed aggregators to retrieve the list of videos from
</div>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="form-group">
<label i18n for="feed-url">Feed URL</label>
</div>
</div>
-<div class="form-row mt-4"> <!-- submit placement block -->
+<div class="row mt-4"> <!-- submit placement block -->
<div class="col-md-7 col-xl-5"></div>
<div class="col-md-5 col-xl-5">
<input (click)="renewToken()" type="submit" i18n-value value="Renew token">
-<h1 class="sr-only" i18n>Notifications</h1>
+<h1 class="visually-hidden" i18n>Notifications</h1>
<div class="header">
<a routerLink="/my-account/settings" fragment="notifications" i18n>
<my-global-icon iconName="cog" aria-hidden="true"></my-global-icon>
Notification preferences
</a>
- <div class="peertube-select-container peertube-select-button ml-2 mr-2">
+ <div class="peertube-select-container peertube-select-button ms-2 me-2">
<select [(ngModel)]="notificationSortType" (ngModelChange)="onChangeSortColumn()" class="form-control">
<option value="undefined" disabled>Sort by</option>
<option value="createdAt" i18n>Newest first</option>
</select>
</div>
- <button class="btn ml-auto" [disabled]="!hasUnreadNotifications()" (click)="markAllAsRead()">
+ <button class="btn ms-auto" [disabled]="!hasUnreadNotifications()" (click)="markAllAsRead()">
<ng-container *ngIf="hasUnreadNotifications()">
<my-global-icon iconName="tick" aria-hidden="true"></my-global-icon>
font-size: 100%;
}
-.form-group:first-child {
- margin-bottom: 15px;
-}
-
input#username + .muted {
margin-top: 5px;
}
-<h1 class="sr-only" i18n>Settings</h1>
-<div class="form-row"> <!-- preview -->
- <div class="form-group col-12 col-lg-4 col-xl-3"></div>
+<h1 class="visually-hidden" i18n>Settings</h1>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+<div class="row"> <!-- preview -->
+ <div class="col-12 col-lg-4 col-xl-3"></div>
+
+ <div class="col-12 col-lg-8 col-xl-9">
<my-actor-avatar-edit [actor]="user.account" (avatarChange)="onAvatarChange($event)" (avatarDelete)="onAvatarDelete()"></my-actor-avatar-edit>
</div>
</div>
-<div class="form-row"> <!-- profile settings grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-3"> <!-- profile settings grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<h2 i18n class="account-title">PROFILE SETTINGS</h2>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<my-user-quota [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-quota>
</div>
</div>
-<div class="form-row mt-5"> <!-- interface grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-5"> <!-- interface grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<h2 i18n class="account-title">INTERFACE</h2>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<my-user-interface-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-interface-settings>
</div>
</div>
-<div class="form-row mt-5"> <!-- video settings grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-5"> <!-- video settings grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<div class="anchor" id="video-settings"></div> <!-- video settings anchor -->
<h2 i18n class="account-title">VIDEO SETTINGS</h2>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<my-user-video-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-user-video-settings>
</div>
</div>
-<div class="form-row mt-5"> <!-- notifications grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-5"> <!-- notifications grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<div class="anchor" id="notifications"></div> <!-- notifications anchor -->
<h2 i18n class="account-title">NOTIFICATIONS</h2>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<my-account-notification-preferences [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-notification-preferences>
</div>
</div>
-<div class="form-row mt-5" *ngIf="user.pluginAuth === null"> <!-- password grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-5" *ngIf="user.pluginAuth === null"> <!-- password grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<h2 i18n class="account-title">PASSWORD</h2>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<my-account-change-password></my-account-change-password>
</div>
</div>
-<div class="form-row mt-5"> <!-- email grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-5"> <!-- email grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<h2 i18n class="account-title">EMAIL</h2>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<my-account-change-email></my-account-change-email>
</div>
</div>
-<div class="form-row mt-5"> <!-- danger zone grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+<div class="row mt-5"> <!-- danger zone grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<h2 i18n class="account-title account-title-danger">DANGER ZONE</h2>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<my-account-danger-zone [user]="user"></my-account-danger-zone>
</div>
</div>
@use '_variables' as *;
@use '_mixins' as *;
+@use '~bootstrap/scss/functions' as *;
.account-title {
@include settings-big-title;
}
}
-.form-group {
+.row > div {
max-width: 500px;
}
-<div class="row">
+<div class="root">
<my-top-menu-dropdown [menuEntries]="menuEntries"></my-top-menu-dropdown>
<div class="margin-content pb-5" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }">
@use '_variables' as *;
@use '_mixins' as *;
-.row {
+.root {
@include sub-menu-h1;
flex-direction: column;
<h1>
<my-global-icon iconName="channel" aria-hidden="true"></my-global-icon>
<ng-container i18n>My channels</ng-container>
- <span class="badge badge-secondary">{{ totalItems }}</span>
+ <span *ngIf="totalItems" class="pt-badge badge-secondary">{{ totalItems }}</span>
</h1>
<my-channels-setup-message [hideLink]="true"></my-channels-setup-message>
<span>
<my-global-icon iconName="follower" aria-hidden="true"></my-global-icon>
<ng-container i18n>My followers</ng-container>
- <span class="badge badge-secondary"> {{ pagination.totalItems }}</span>
+ <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary"> {{ pagination.totalItems }}</span>
</span>
</h1>
<span>
<my-global-icon iconName="subscriptions" aria-hidden="true"></my-global-icon>
<ng-container i18n>My subscriptions</ng-container>
- <span class="badge badge-secondary"> {{ pagination.totalItems }}</span>
+ <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary"> {{ pagination.totalItems }}</span>
</span>
</h1>
<h1>
<my-global-icon iconName="history" aria-hidden="true"></my-global-icon>
- <ng-container i18n>My watch history</ng-container> <span class="badge badge-secondary">{{ pagination.totalItems }}</span>
+ <ng-container i18n>My watch history</ng-container>
+ <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary">{{ pagination.totalItems }}</span>
</h1>
<div class="top-buttons">
-<div class="row">
+<div class="root">
<my-top-menu-dropdown [menuEntries]="menuEntries"></my-top-menu-dropdown>
<div class="margin-content pb-5" [ngClass]="{ 'offset-content': !isBroadcastMessageDisplayed }">
@use '_variables' as *;
@use '_mixins' as *;
-.row {
+.root {
@include sub-menu-h1;
flex-direction: column;
<td>{{ videoChangeOwnership.createdAt | date: 'short' }}</td>
<td>
- <span class="badge"
+ <span class="pt-badge"
[ngClass]="getStatusClass(videoChangeOwnership.status)">{{ videoChangeOwnership.status }}</span>
</td>
</tr>
</td>
<td>
- <span class="badge" [ngClass]="getVideoImportStateClass(videoImport.state.id)">
+ <span class="pt-badge" [ngClass]="getVideoImportStateClass(videoImport.state.id)">
{{ videoImport.state.label }}
</span>
</td>
<form role="form" (ngSubmit)="formValidated()" [formGroup]="form">
- <div class="form-row"> <!-- playlist grid -->
- <div class="form-group col-12 col-lg-4 col-xl-3">
+ <div class="row"> <!-- playlist grid -->
+ <div class="col-12 col-lg-4 col-xl-3">
<div *ngIf="isCreation()" class="video-playlist-title" i18n>NEW PLAYLIST</div>
<div *ngIf="!isCreation() && videoPlaylistToUpdate" class="video-playlist-title" i18n>PLAYLIST</div>
</div>
- <div class="form-group col-12 col-lg-8 col-xl-9">
+ <div class="col-12 col-lg-8 col-xl-9">
<div class="col-md-12 col-xl-6">
<div class="form-group">
</div>
</div>
- <div class="form-row"> <!-- submit placement block -->
+ <div class="row"> <!-- submit placement block -->
<div class="col-md-7 col-xl-5"></div>
<div class="col-md-5 col-xl-5 d-inline-flex">
<input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
<h1>
<my-global-icon iconName="playlists" aria-hidden="true"></my-global-icon>
- <ng-container i18n>My playlists</ng-container> <span class="badge badge-secondary">{{ pagination.totalItems }}</span>
+ <ng-container i18n>My playlists</ng-container>
+ <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary">{{ pagination.totalItems }}</span>
</h1>
<my-channels-setup-message></my-channels-setup-message>
</div>
<div class="modal-footer">
- <div class="form-group inputs">
+ <div class="inputs">
<input
type="button" role="button" i18n-value value="Cancel" class="peertube-button grey-button"
(click)="dismiss()" (key.enter)="dismiss()"
p-autocomplete {
display: block;
}
-
-.form-group {
- margin: 20px 0;
-}
<span>
<my-global-icon iconName="videos" aria-hidden="true"></my-global-icon>
<ng-container i18n>My videos</ng-container>
- <span class="badge badge-secondary"> {{ pagination.totalItems }}</span>
+ <span *ngIf="pagination.totalItems" class="pt-badge badge-secondary"> {{ pagination.totalItems }}</span>
</span>
<div>
<div class="root">
<div *ngIf="status !== 403 && status !== 418" class="box">
<strong>{{ status }}.</strong>
- <span class="ml-1 muted" i18n>That's an error.</span>
+ <span class="ms-1 muted" i18n>That's an error.</span>
<div class="text mt-4">
<ng-container *ngIf="type === 'video'" i18n>We couldn't find any video tied to the URL {{ pathname }} you were looking for.</ng-container>
<div *ngIf="status === 403" class="box">
<strong>{{ status }}.</strong>
- <span class="ml-1 muted" i18n>You are not authorized here.</span>
+ <span class="ms-1 muted" i18n>You are not authorized here.</span>
<div class="text mt-4">
<ng-container *ngIf="type === 'video'" i18n>You might need to check your account is allowed by the video or instance owner.</ng-container>
<div *ngIf="status === 418" class="box">
<strong>{{ status }}.</strong>
- <span class="ml-1 muted">I'm a teapot.</span>
+ <span class="ms-1 muted">I'm a teapot.</span>
<div class="text mt-4" i18n="Description of a tea flavour, keeping the 'requested entity body' as a technical expression referring to a web request">
The requested entity body blends sweet bits with a mellow earthiness.
</div>
<div class="row">
- <div class="pl-0 col-sm-6">
+ <div class="ps-0 col-sm-6">
<input
(change)="onDurationOrPublishedUpdated()"
(keydown.enter)="$event.preventDefault()"
class="form-control"
>
</div>
- <div class="pr-0 col-sm-6">
+ <div class="pe-0 col-sm-6">
<input
(change)="onDurationOrPublishedUpdated()"
(keydown.enter)="$event.preventDefault()"
margin-bottom: 1rem;
}
-.form-group {
- margin-bottom: 25px;
-}
-
input[type=text] {
@include peertube-input-text(100%);
display: block;
<div class="results-header">
<div class="first-line">
<div class="results-counter" *ngIf="pagination.totalItems">
- <span class="mr-1" i18n>{{ pagination.totalItems | myNumberFormatter }} {pagination.totalItems, plural, =1 {result} other {results}}</span>
+ <span class="me-1" i18n>{{ pagination.totalItems | myNumberFormatter }} {pagination.totalItems, plural, =1 {result} other {results}}</span>
- <span class="mr-1" i18n *ngIf="advancedSearch.searchTarget === 'local'">on this instance</span>
- <span class="mr-1" i18n *ngIf="advancedSearch.searchTarget === 'search-index'">on the vidiverse</span>
+ <span class="me-1" i18n *ngIf="advancedSearch.searchTarget === 'local'">on this instance</span>
+ <span class="me-1" i18n *ngIf="advancedSearch.searchTarget === 'search-index'">on the vidiverse</span>
<span *ngIf="currentSearch" i18n>for <span class="search-value">{{ currentSearch }}</span></span>
</div>
<div
- class="results-filter-button ml-auto" (click)="isSearchFilterCollapsed = !isSearchFilterCollapsed" role="button"
+ class="results-filter-button ms-auto" (click)="isSearchFilterCollapsed = !isSearchFilterCollapsed" role="button"
[attr.aria-expanded]="!isSearchFilterCollapsed" aria-controls="collapseBasic"
>
<span class="icon icon-filter"></span>
<ng-container i18n>
Filters
- <span *ngIf="numberOfFilters() > 0" class="badge badge-secondary">{{ numberOfFilters() }}</span>
+ <span *ngIf="numberOfFilters() > 0" class="pt-badge badge-secondary">{{ numberOfFilters() }}</span>
</ng-container>
</div>
</div>
(click)="onClick(i)"
>
<div class="step-index">
- <ng-container *ngIf="!isCompleted(step)"><span class="sr-only" i18n>Step</span> {{ i + 1 }}</ng-container>
+ <ng-container *ngIf="!isCompleted(step)"><span class="visually-hidden" i18n>Step</span> {{ i + 1 }}</ng-container>
<my-global-icon *ngIf="isCompleted(step)" iconName="tick"></my-global-icon>
</div>
type="text" id="name" i18n-placeholder placeholder="Example: my_super_channel"
formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }"
>
- <div class="input-group-append">
- <span class="input-group-text">@{{ instanceHost }}</span>
- </div>
+ <div class="input-group-text">@{{ instanceHost }}</div>
</div>
<div class="name-information" i18n>
<form role="form" [formGroup]="form">
- <div class="form-group form-group-terms">
+ <div class="form-group">
<my-peertube-checkbox inputName="terms" formControlName="terms">
<ng-template ptTemplate="label">
- <ng-container i18n>
+ <ng-container i18n>
I am at least {{ minimumAge }} years old and agree
to the <a class="terms-anchor" (click)="onTermsClick($event)" href='#'>Terms</a>
<ng-container *ngIf="hasCodeOfConduct"> and to the <a (click)="onCodeOfConductClick($event)" href='#'>Code of Conduct</a></ng-container>
type="text" id="username" i18n-placeholder="Username choice placeholder in the registration form" placeholder="e.g. jane_doe"
formControlName="username" class="form-control" [ngClass]="{ 'input-error': formErrors['username'] }"
>
- <div class="input-group-append">
- <span class="input-group-text">@{{ instanceHost }}</span>
- </div>
+ <span class="input-group-text">@{{ instanceHost }}</span>
</div>
<div class="name-information" i18n>
}
}
-.form-group-terms {
- margin: 30px 0;
-}
-
-.input-group {
- @include peertube-input-group(100%);
-}
-
-.input-group-append {
- height: 30px;
-}
-
-.form-group-terms {
- width: 100% !important;
-}
-
input:not([type=submit]) {
@include peertube-input-text(100%);
display: block;
height: 100%;
min-height: 300px;
- .form-group {
- margin-bottom: 25px;
- }
-
input {
@include peertube-input-text(100%);
display: block;
.label-tags + span {
font-size: 15px;
}
-
- .advanced-settings .form-group {
- margin-bottom: 20px;
- }
}
.captions-header {
<div class="margin-content">
<div class="title-page title-page-single">
- <span class="mr-1" i18n>Update</span>
+ <span class="me-1" i18n>Update</span>
<a [routerLink]="getVideoUrl()">{{ video?.name }}</a>
</div>
<div class="avatar-and-textarea">
<my-actor-avatar [account]="user?.account" size="25"></my-actor-avatar>
- <div class="form-group">
+ <div class="textarea-wrapper">
<textarea i18n-placeholder placeholder="Add comment..." myAutoResize
[readonly]="(user === null) ? true : false"
(click)="openVisitorModal($event)"
@include margin-right(10px);
}
- .form-group {
+ .textarea-wrapper {
flex-grow: 1;
- margin: 0;
position: relative;
}
{{ comment.account.displayName }}
</span>
- <span class="comment-account-fid ml-1">{{ comment.by }}</span>
+ <span class="comment-account-fid ms-1">{{ comment.by }}</span>
</a>
</div>
<my-feed [syndicationItems]="syndicationItems"></my-feed>
- <div ngbDropdown class="d-inline-block ml-4 dropdown-root">
+ <div ngbDropdown class="d-inline-block ms-4 dropdown-root">
<button class="btn btn-sm btn-outline-secondary" id="dropdown-sort-comments" ngbDropdownToggle i18n>
SORT BY
</button>
<ng-template i18n #noAuthorComments>View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}}</ng-template>
- <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader>
+ <my-small-loader class="comment-thread-loading ms-1" [loading]="threadLoading[comment.id]"></my-small-loader>
</div>
</my-video-comment>
<div class="privacy-concerns" *ngIf="display">
<div class="privacy-concerns-text">
- <span class="mr-2">
+ <span class="me-2">
<strong i18n>Friendly Reminder: </strong>
<ng-container i18n>
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.
<div class="playlist-display-name">
{{ playlist.displayName }}
- <span *ngIf="isUnlistedPlaylist()" class="badge badge-warning" i18n>Unlisted</span>
- <span *ngIf="isPrivatePlaylist()" class="badge badge-danger" i18n>Private</span>
- <span *ngIf="isPublicPlaylist()" class="badge badge-info" i18n>Public</span>
+ <span *ngIf="isUnlistedPlaylist()" class="pt-badge badge-warning" i18n>Unlisted</span>
+ <span *ngIf="isPrivatePlaylist()" class="pt-badge badge-danger" i18n>Private</span>
+ <span *ngIf="isPublicPlaylist()" class="pt-badge badge-info" i18n>Public</span>
</div>
<div class="playlist-by-index">
.playlist-info {
padding: 5px 30px;
background-color: pvar(--greyBackgroundColor);
+ }
+
+ .playlist-display-name {
+ font-size: 18px;
+ font-weight: $font-semibold;
+ margin-bottom: 5px;
- .playlist-display-name {
- font-size: 18px;
- font-weight: $font-semibold;
- margin-bottom: 5px;
+ .pt-badge {
+ @include margin-left(5px);
}
+ }
- .playlist-by-index {
- color: pvar(--greyForegroundColor);
- display: flex;
+ .playlist-by-index {
+ color: pvar(--greyForegroundColor);
+ display: flex;
- .playlist-by {
- @include margin-right(5px);
- }
+ .playlist-by {
+ @include margin-right(5px);
+ }
- .playlist-index span:first-child::after {
- content: '/';
- margin: 0 3px;
- }
+ .playlist-index span:first-child::after {
+ content: '/';
+ margin: 0 3px;
}
+ }
- .playlist-controls {
- display: flex;
- margin: 10px 0;
+ .playlist-controls {
+ display: flex;
+ margin: 10px 0;
- my-global-icon:not(:last-child) {
- @include margin-right(.5rem);
- }
+ my-global-icon:not(:last-child) {
+ @include margin-right(.5rem);
+ }
- my-global-icon {
- &:not(.active) {
- opacity: .5;
- }
+ my-global-icon {
+ &:not(.active) {
+ opacity: .5;
+ }
- ::ng-deep {
- cursor: pointer;
- }
+ ::ng-deep {
+ cursor: pointer;
}
}
}
<div class="video-info-channel-left d-flex">
<my-video-avatar-channel [video]="video" [showChannel]="!isChannelDisplayNameGeneric()"></my-video-avatar-channel>
- <div class="video-info-channel-left-links ml-1">
+ <div class="video-info-channel-left-links ms-1">
<ng-container *ngIf="!isChannelDisplayNameGeneric()">
<a [routerLink]="[ '/c', video.byVideoChannel ]" i18n-title title="Channel page">
{{ video.channel.displayName }}
-<h1 class="sr-only" i18n>Discover</h1>
+<h1 class="visually-hidden" i18n>Discover</h1>
<div class="margin-content">
<div class="no-results" i18n *ngIf="notResults">No results.</div>
<div class="d-flex justify-content-between">
<label class="small-title" i18n>GLOBAL SEARCH</label>
<div class="advanced-search-status muted">
- <span *ngIf="serverConfig" class="mr-1" i18n>using {{ serverConfig.search.searchIndex.url }}</span>
+ <span *ngIf="serverConfig" class="me-1" i18n>using {{ serverConfig.search.searchIndex.url }}</span>
<i class="glyphicon glyphicon-globe"></i>
</div>
</div>
<label class="small-title" i18n>ADVANCED SEARCH</label>
<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="mr-1" i18n>any instance</span>
- <span *ngIf="!canSearchAnyURI()" class="mr-1" i18n>only followed instances</span>
+ <span *ngIf="canSearchAnyURI()" class="me-1" i18n>any instance</span>
+ <span *ngIf="!canSearchAnyURI()" class="me-1" i18n>only followed instances</span>
<i [ngClass]="canSearchAnyURI() ? 'glyphicon glyphicon-ok-sign' : 'glyphicon glyphicon-exclamation-sign'"></i>
</span>
</div>
<a tabindex="-1" class="d-flex flex-auto flex-items-center p-2" [class.focus-visible]="active">
- <div class="flex-shrink-0 mr-2 text-center">
+ <div class="flex-shrink-0 me-2 text-center">
<my-global-icon iconName="search"></my-global-icon>
</div>
- <img class="avatar mr-2 flex-shrink-0 d-none" alt="" aria-label="Team" src="" width="28" height="28">
+ <img class="avatar me-2 flex-shrink-0 d-none" alt="" aria-label="Team" src="" width="28" height="28">
<div
- class="flex-auto overflow-hidden text-left no-wrap css-truncate css-truncate-target"
+ class="flex-auto overflow-hidden text-start no-wrap css-truncate css-truncate-target"
[attr.aria-label]="result.text" [innerHTML]="result.text | highlight : highlight"
></div>
- <div class="border rounded flex-shrink-0 px-1 bg-gray text-gray-light ml-1 f6">
+ <div class="border rounded flex-shrink-0 px-1 bg-gray text-gray-light ms-1 f6">
<span *ngIf="result.type === 'search-instance'" i18n>In this instance's network</span>
<span *ngIf="result.type === 'search-index'" i18n>In the vidiverse</span>
</div>
>
<my-global-icon iconName="language" aria-hidden="true"></my-global-icon>
<span i18n>Interface:</span>
- <span class="ml-auto muted">{{ currentInterfaceLanguage }}</span>
+ <span class="ms-auto muted">{{ currentInterfaceLanguage }}</span>
</a>
<a ngbDropdownItem ngbDropdownToggle 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="ml-auto muted">{{ videoLanguages.join(', ') }}</span>
+ <span class="ms-auto muted">{{ videoLanguages.join(', ') }}</span>
</a>
<a ngbDropdownItem ngbDropdownToggle class="dropdown-item settings-sensitive" routerLink="/my-account/settings"
<my-global-icon class="hover-display-toggle" [hidden]="user.nsfwPolicy === 'display'" iconName="sensitive" aria-hidden="true"></my-global-icon>
<my-global-icon class="hover-display-toggle" [hidden]="user.nsfwPolicy !== 'display'" iconName="unsensitive" aria-hidden="true"></my-global-icon>
<span i18n>Sensitive:</span>
- <span class="ml-auto muted">{{ nsfwPolicy }}</span>
+ <span class="ms-auto muted">{{ nsfwPolicy }}</span>
</a>
<a 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="ml-auto" [checked]="user.p2pEnabled"></my-input-switch>
+ <my-input-switch class="ms-auto" [checked]="user.p2pEnabled"></my-input-switch>
</a>
<div class="dropdown-divider"></div>
<div class="footer-copyleft">
<small class="d-inline" i18n-title title="powered by PeerTube - CopyLeft 2015-2022">
- <a href="https://joinpeertube.org" class="mr-1" target="_blank" rel="noopener noreferrer" i18n>powered by PeerTube</a>
+ <a href="https://joinpeertube.org" class="me-1" target="_blank" rel="noopener noreferrer" i18n>powered by PeerTube</a>
<a href="https://github.com/Chocobozzz/PeerTube/blob/develop/LICENSE" target="_blank" rel="noopener noreferrer">
<span aria-label="copyleft" class="d-inline-block" style="transform: rotateY(180deg)">©</span> 2015-2022
<div>
<button
*ngIf="unreadNotifications"
- i18n-title title="Mark all as read" class="glyphicon glyphicon-ok mr-2"
+ i18n-title title="Mark all as read" class="glyphicon glyphicon-ok me-2"
(click)="markAllAsRead()"
></button>
<a
></my-user-notifications>
<a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" #notifications (click)="onNavigate(notifications)">
- <my-global-icon class="mr-1" iconName="bell" aria-hidden="true"></my-global-icon>
+ <my-global-icon class="me-1" iconName="bell" aria-hidden="true"></my-global-icon>
<span i18n>See all your notifications</span>
</a>
</div>
<div class="modal-body" >
<div [innerHtml]="message"></div>
- <div *ngIf="inputLabel && expectedInputValue" class="form-group">
+ <div *ngIf="inputLabel && expectedInputValue" class="form-group mt-3">
<label for="confirmInput">{{ inputLabel }}</label>
<input type="text" id="confirmInput" name="confirmInput" [(ngModel)]="inputValue" />
</div>
@include peertube-input-text(100%);
display: block;
}
-
-.form-group {
- margin: 20px 0;
-}
</a>
<a [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reporter:"' + abuse.reporterAccount.displayName + '"' }"
- class="ml-auto muted abuse-details-links" i18n
+ class="ms-auto muted abuse-details-links" i18n
>
- {abuse.countReportsForReporter, plural, =1 {1 report} other {{{ abuse.countReportsForReporter }} reports}}<span class="ml-1 glyphicon glyphicon-flag"></span>
+ {abuse.countReportsForReporter, plural, =1 {1 report} other {{{ abuse.countReportsForReporter }} reports}}<span class="ms-1 glyphicon glyphicon-flag"></span>
</a>
</span>
</div>
</a>
<a *ngIf="isAdminView" [routerLink]="[ '.' ]" [queryParams]="{ 'search': 'reportee:"' +abuse.flaggedAccount.displayName + '"' }"
- class="ml-auto muted abuse-details-links" i18n
+ class="ms-auto muted abuse-details-links" i18n
>
- {abuse.countReportsForReportee, plural, =1 {1 report} other {{{ abuse.countReportsForReportee }} reports}}<span class="ml-1 glyphicon glyphicon-flag"></span>
+ {abuse.countReportsForReportee, plural, =1 {1 report} other {{{ abuse.countReportsForReportee }} reports}}<span class="ms-1 glyphicon glyphicon-flag"></span>
</a>
</span>
</div>
<div class="mt-3 d-flex">
<span class="moderation-expanded-label">
<ng-container i18n>Report</ng-container>
- <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': '#' + abuse.id }" class="ml-1 muted">#{{ abuse.id }}</a>
+ <a [routerLink]="[ '.' ]" [queryParams]="{ 'search': '#' + abuse.id }" class="ms-1 muted">#{{ abuse.id }}</a>
</span>
<span class="moderation-expanded-text" [innerHTML]="abuse.reasonHtml"></span>
</div>
>
<ng-template pTemplate="caption">
<div class="caption">
- <div class="ml-auto">
+ <div class="ms-auto">
<my-advanced-input-filter [filters]="inputFilters" (search)="onSearch($event)"></my-advanced-input-filter>
</div>
</div>
<div *ngIf="editable && !hasAvatar()" class="actor-img-edit-button" [ngbTooltip]="avatarFormat" placement="right" container="body">
<my-global-icon iconName="upload"></my-global-icon>
- <label class="sr-only" for="avatarfile" i18n>Upload a new avatar</label>
+ <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>
#avatarPopover="ngbPopover" [ngbPopover]="avatarEditContent" popoverClass="popover-image-info" autoClose="outside" placement="right"
>
<my-global-icon iconName="edit"></my-global-icon>
- <label class="sr-only" for="avatarMenu" i18n>Change your avatar</label>
+ <label class="visually-hidden" for="avatarMenu" i18n>Change your avatar</label>
</div>
</div>
.actor {
display: flex;
+}
- my-actor-avatar {
- @include margin-right(15px);
- }
+my-actor-avatar {
+ @include margin-right(15px);
+}
+
+.actor-info {
+ display: inline-flex;
+ flex-direction: column;
+}
+
+.actor-info-display-name {
+ font-size: 20px;
+ font-weight: $font-bold;
- .actor-info {
- display: inline-flex;
- flex-direction: column;
-
- .actor-info-display-name {
- font-size: 20px;
- font-weight: $font-bold;
-
- @media screen and (max-width: $small-view) {
- font-size: 16px;
- }
- }
-
- .actor-info-username {
- position: relative;
- font-size: 14px;
- color: pvar(--greyForegroundColor);
- }
-
- .actor-info-followers {
- font-size: 15px;
- padding-bottom: .5rem;
- }
+ @media screen and (max-width: $small-view) {
+ font-size: 16px;
}
}
+.actor-info-username {
+ position: relative;
+ font-size: 14px;
+ color: pvar(--greyForegroundColor);
+}
+
+.actor-info-followers {
+ font-size: 15px;
+ padding-bottom: .5rem;
+}
+
.actor-img-edit-container {
position: relative;
width: 0;
-<div class="input-group has-feedback has-clear">
- <div *ngIf="hasFilters()" class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body">
- <div class="input-group-text" ngbDropdownToggle>
+<div class="input-group has-clear" ngbDropdown placement="bottom-left auto" container="body">
+
+ <ng-container *ngIf="hasFilters()">
+ <div class="input-group-text c-hand" ngbDropdownToggle>
<span class="caret" aria-haspopup="menu" role="button"></span>
</div>
</button>
</ng-container>
</div>
- </div>
+ </ng-container>
<input
type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..."
+ class="last-in-group"
[(ngModel)]="searchValue"
(keyup)="onInputSearch($event)"
>
- <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="onResetTableFilter()"></a>
- <span class="sr-only" i18n>Clear filters</span>
+ <a class="glyphicon glyphicon-remove-sign form-control-clear" title="Clear filter" i18n-title (click)="onResetTableFilter()"></a>
</div>
width: 18px;
height: 18px;
-
&.no-visible {
@include margin-right($size + $margin);
<div (click)="update()">
<input type="checkbox" [checked]="checked"/>
- <label class="ml-auto">Toggle</label>
+ <label class="ms-auto">Toggle</label>
</div>
-<div class="input-group input-group-sm">
+<div class="input-group">
<input
[id]="inputId" [autocomplete]="autocomplete" [value]="value" [placeholder]="placeholder" [tabindex]="tabindex"
[(ngModel)]="value" (ngModelChange)="update()" [readonly]="readonly"
#input (click)="input.select()" (input)="update()" (change)="update()" [type]="inputType" class="form-control"
/>
- <div *ngIf="withToggle || withCopy" class="input-group-append">
- <button *ngIf="withToggle" (click)="toggle()" type="button" class="btn btn-outline-secondary eye-button" [title]="toggleTitle">
- <span class="glyphicon glyphicon-eye-{{ show ? 'open' : 'close' }}"></span>
- </button>
+ <button *ngIf="withToggle" (click)="toggle()" type="button" class="btn btn-outline-secondary eye-button" [title]="toggleTitle">
+ <span class="glyphicon glyphicon-eye-{{ show ? 'open' : 'close' }}"></span>
+ </button>
- <button
- *ngIf="withCopy" [cdkCopyToClipboard]="input.value" (click)="activateCopiedMessage()" type="button"
- class="btn btn-outline-secondary text-uppercase" i18n-title title="Copy"
- >
- <span class="glyphicon glyphicon-duplicate"></span>
- Copy
- </button>
- </div>
+ <button
+ *ngIf="withCopy" [cdkCopyToClipboard]="input.value" (click)="activateCopiedMessage()" type="button"
+ class="btn btn-outline-secondary text-uppercase" i18n-title title="Copy"
+ >
+ <span class="glyphicon glyphicon-duplicate"></span>
+ <span class="copy-text">Copy</span>
+ </button>
</div>
@include peertube-input-text(auto);
@include padding-left(15px !important);
@include padding-right(15px !important);
+}
- // set again properties of peertube-input-text that are overridden by .input-group
- font-size: 15px !important;
+.btn {
+ font-size: 15px;
}
-.eye-button {
- line-height: 1 !important;
+.copy-text {
+ font-size: 14px;
+ margin-left: 5px;
+ vertical-align: top;
}
<div class="root flex-column">
<div class="d-flex">
- <label class="form-group-checkbox">
+ <label>
<input
type="checkbox"
[(ngModel)]="checked"
<div *ngIf="recommended" class="recommended" i18n>Recommended</div>
</div>
- <div class="ml-4 d-flex flex-column">
+ <div class="ms-4 d-flex flex-column">
<small class="wrapper mt-2 muted">
<ng-content select="description"></ng-content>
</small>
.root {
display: flex;
- .form-group-checkbox {
+ label {
display: flex;
align-items: center;
[searchable]="searchable"
>
<ng-option *ngFor="let channel of channels" [value]="channel.id">
- <img alt="" class="avatar mr-1" [src]="channel.avatarPath" />
+ <img alt="" class="avatar me-1" [src]="channel.avatarPath" />
{{ channel.label }}
</ng-option>
</ng-select>
>
<ng-template ng-optgroup-tmp let-item="item" let-item$="item$" let-index="index">
- <div class="form-group-checkbox">
+ <div class="checkbox-wrapper">
<input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/>
<span role="checkbox" [attr.aria-checked]="item$.selected"></span>
<span>{{ item.group }}</span>
</ng-template>
<ng-template ng-option-tmp let-item="item" let-item$="item$" let-index="index">
- <div class="form-group-checkbox">
+ <div class="checkbox-wrapper">
<input id="item-{{index}}" type="checkbox" [ngModel]="item$.selected"/>
<span role="checkbox" [attr.aria-checked]="item$.selected"></span>
<span>{{ item.label }}</span>
align-items: center;
}
- .form-group-checkbox {
+ .checkbox-wrapper {
display: flex;
align-items: center;
font-size: 15px;
margin-bottom: 15px;
}
-
-ngb-accordion ::ng-deep {
- .card {
- border-color: var(--mainBackgroundColor);
-
- .card-header {
- background-color: unset;
- padding: 0;
-
- + .collapse.show {
- background-color: var(--submenuBackgroundColor);
- }
- }
- }
-
- .btn {
- @include peertube-button;
- @include grey-button;
-
- border-radius: unset;
- width: 100%;
- }
-}
<div *ngIf="serverConfig" class="feature-table">
- <table class="table" *ngIf="serverConfig">
+ <table *ngIf="serverConfig">
<caption i18n>Features found on this instance</caption>
<tr>
<th i18n class="label" scope="row">PeerTube version</th>
table {
font-size: 14px;
color: pvar(--mainForegroundColor);
+ width: 100%;
.label,
.sub-label {
}
}
+ th,
td {
- vertical-align: middle;
+ padding: 0.75rem;
+ border-top: 1px solid #dee2e6;
}
caption {
<div class="root">
- <div class="input-group has-feedback has-clear">
+ <div class="input-group has-clear">
<input
#ref
type="text"
[placeholder]="placeholder"
>
- <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="onResetFilter()"></a>
- <span class="sr-only" i18n>Clear filters</span>
+ <a class="glyphicon glyphicon-remove-sign form-control-clear" title="Clear filter" i18n-title (click)="onResetFilter()"></a>
</div>
<my-global-icon iconName="search" aria-label="Search" role="button" (click)="onIconClick()" [title]="iconTitle"></my-global-icon>
-<span *ngIf="account.mutedByUser" class="badge badge-danger" i18n>Muted</span>
-<span *ngIf="account.mutedServerByUser" class="badge badge-danger" i18n>Instance muted</span>
-<span *ngIf="account.mutedByInstance" class="badge badge-danger" i18n>Muted by your instance</span>
-<span *ngIf="account.mutedServerByInstance" class="badge badge-danger" i18n>Instance muted by your instance</span>
+<span *ngIf="account.mutedByUser" class="pt-badge badge-danger" i18n>Muted</span>
+<span *ngIf="account.mutedServerByUser" class="pt-badge badge-danger" i18n>Instance muted</span>
+<span *ngIf="account.mutedByInstance" class="pt-badge badge-danger" i18n>Muted by your instance</span>
+<span *ngIf="account.mutedServerByInstance" class="pt-badge badge-danger" i18n>Instance muted by your instance</span>
@use '_variables' as *;
@use '_mixins' as *;
-.badge {
+.pt-badge {
@include margin-right(10px);
- height: fit-content;
font-size: 12px;
}
>
<ng-template pTemplate="caption">
<div class="caption">
- <div class="ml-auto">
+ <div class="ms-auto">
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
</div>
</div>
<form novalidate [formGroup]="form" (ngSubmit)="report()">
<div class="row">
- <div class="col-5 form-group">
+ <div class="col-5">
<label i18n for="reportPredefinedReasons">What is the issue?</label>
- <div class="ml-2 mt-2 d-flex flex-column">
+ <div class="ms-2 mt-2 d-flex flex-column">
<ng-container formGroupName="predefinedReasons">
<div class="form-group" *ngFor="let reason of predefinedReasons">
</ng-container>
</div>
-
</div>
<div class="col-7">
<form novalidate [formGroup]="form" (ngSubmit)="report()">
<div class="row">
- <div class="col-5 form-group">
+ <div class="col-12 col-md-5">
+ <label i18n for="reportPredefinedReasons">What is the issue?</label>
- <label i18n for="reportPredefinedReasons">What is the issue?</label>
+ <div class="ms-2 mt-2 d-flex flex-column">
+ <ng-container formGroupName="predefinedReasons">
- <div class="ml-2 mt-2 d-flex flex-column">
- <ng-container formGroupName="predefinedReasons">
+ <div class="form-group" *ngFor="let reason of predefinedReasons">
+ <my-peertube-checkbox [inputName]="reason.id" [formControlName]="reason.id" [labelText]="reason.label">
+ <ng-template *ngIf="reason.help" ptTemplate="help">
+ <div [innerHTML]="reason.help"></div>
+ </ng-template>
- <div class="form-group" *ngFor="let reason of predefinedReasons">
- <my-peertube-checkbox [inputName]="reason.id" [formControlName]="reason.id" [labelText]="reason.label">
- <ng-template *ngIf="reason.help" ptTemplate="help">
- <div [innerHTML]="reason.help"></div>
- </ng-template>
-
- <ng-container *ngIf="reason.description" ngProjectAs="description">
- <div [innerHTML]="reason.description"></div>
- </ng-container>
- </my-peertube-checkbox>
- </div>
-
- </ng-container>
- </div>
+ <ng-container *ngIf="reason.description" ngProjectAs="description">
+ <div [innerHTML]="reason.description"></div>
+ </ng-container>
+ </my-peertube-checkbox>
+ </div>
+ </ng-container>
+ </div>
</div>
- <div class="col-7">
- <div class="row justify-content-center">
- <div class="col-12 col-lg-9 mb-2">
- <my-embed [video]="video"></my-embed>
- </div>
- </div>
+ <div class="col-12 col-md-7">
+ <my-embed [video]="video"></my-embed>
- <div class="mb-1 start-at" formGroupName="timestamp">
+ <div class="mb-1 mt-3 start-at" formGroupName="timestamp">
<my-peertube-checkbox
formControlName="hasStart"
i18n-labelText labelText="Start at"
</a>
</div>
- <div class="ml-auto">
+ <div class="ms-auto">
<my-advanced-input-filter (search)="onSearch($event)"></my-advanced-input-filter>
</div>
</div>
</div>
</div>
- <div class="form-group">
+ <div class="form-group" *ngIf="isInVideoEmbedTab()">
<my-peertube-checkbox
- *ngIf="isInVideoEmbedTab()"
inputName="onlyEmbedUrl" [(ngModel)]="customizations.onlyEmbedUrl"
i18n-labelText labelText="Only display embed URL"
></my-peertube-checkbox>
}
}
- .form-group {
- margin-bottom: 0;
- height: 34px;
- display: flex;
- align-items: center;
- }
-
.video-caption-block {
display: flex;
align-items: center;
<form role="form" (ngSubmit)="updateDetails()" [formGroup]="form">
- <div class="form-group form-group-select">
+ <div class="form-group">
<div class="anchor" id="video-sensitive-content-policy"></div> <!-- video-sensitive-content-policy anchor -->
<label i18n for="nsfwPolicy">Default policy on videos containing sensitive content</label>
<my-help>
</div>
</div>
- <div class="form-group form-group-select">
+ <div class="form-group">
<div class="anchor" id="video-languages-subtitles"></div> <!-- video-languages-subtitles anchor -->
<label i18n for="videoLanguages">Only display videos in the following languages/subtitles</label>
<my-help>
.peertube-select-container {
@include peertube-select-container(340px);
-
- margin-bottom: 30px;
}
my-select-languages {
display: block;
}
-
-.form-group-select {
- margin-bottom: 30px;
-}
<form novalidate [formGroup]="form" (ngSubmit)="formValidated()">
- <div class="form-group mb-2">
+ <div class="form-group">
<input type="email"
formControlName="text"
class="form-control"
<div class="modal-body" *ngIf="live">
<div>
- <div class="badge badge-info" *ngIf="live.permanentLive" i18n>Permanent/Recurring live</div>
- <div class="badge badge-info" *ngIf="live.saveReplay" i18n>Replay will be saved</div>
+ <div class="pt-badge badge-blue" *ngIf="live.permanentLive" i18n>Permanent/Recurring live</div>
+ <div class="pt-badge badge-blue" *ngIf="live.saveReplay" i18n>Replay will be saved</div>
</div>
<div class="alert alert-info">
<label i18n>Latest live sessions</label>
<div class="journal-session" *ngFor="let session of latestLiveSessions">
- <span i18n class="badge badge-success" *ngIf="!getErrorLabel(session)">Success</span>
- <span class="badge badge-danger" *ngIf="getErrorLabel(session)">{{ getErrorLabel(session) }}</span>
+ <span i18n class="pt-badge badge-success" *ngIf="!getErrorLabel(session)">Success</span>
+ <span class="pt-badge badge-danger" *ngIf="getErrorLabel(session)">{{ getErrorLabel(session) }}</span>
<span i18n>Started on {{ session.startDate | date:'medium' }}</span>
<span i18n *ngIf="session.endDate">Ended on {{ session.endDate | date:'medium' }}</span>
margin: 1rem 0;
}
-.badge {
+.pt-badge {
+ @include margin-right(5px);
+
font-size: 13px;
- margin-right: 5px;
}
.journal-session {
margin-bottom: 5px;
- span:not(.badge, :last-child)::after {
+ span:not(.pt-badge, :last-child)::after {
margin: 3px;
content: '•';
}
<ng-template ngbNavContent>
<div class="nav-content">
- <div class="input-group input-group-sm">
- <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" />
-
- <div class="input-group-append" *ngIf="!isConfidentialVideo()">
- <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
- <span class="glyphicon glyphicon-duplicate"></span>
- </button>
- </div>
+ <div class="input-group">
+ <input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getLink()" />
+
+ <button
+ *ngIf="!isConfidentialVideo()" type="button" class="btn btn-outline-secondary"
+ [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()"
+ >
+ <span class="glyphicon glyphicon-duplicate"></span>
+ </button>
</div>
</div>
</ng-template>
<ng-template ngbNavContent>
<div class="nav-content">
- <div class="input-group input-group-sm">
- <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" />
- <div class="input-group-append" *ngIf="!isConfidentialVideo()">
- <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
- <span class="glyphicon glyphicon-duplicate"></span>
- </button>
- </div>
+ <div class="input-group">
+ <input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getLink()" />
+
+ <button
+ *ngIf="!isConfidentialVideo()" type="button" class="btn btn-outline-secondary"
+ [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()"
+ >
+ <span class="glyphicon glyphicon-duplicate"></span>
+ </button>
</div>
</div>
</ng-template>
margin-top: 30px;
}
+.input-group > input {
+ @include peertube-input-text(auto);
+
+ font-size: 14px;
+ padding: 0 5px;
+}
+
.advanced-filters-button {
display: flex;
justify-content: center;
<div class="action-block">
<ng-container *ngFor="let action of headerActions">
- <a *ngIf="action.routerLink" class="ml-2" [routerLink]="action.routerLink" routerLinkActive="active">
+ <a *ngIf="action.routerLink" class="ms-2" [routerLink]="action.routerLink" routerLinkActive="active">
<ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container>
</a>
- <a *ngIf="!action.routerLink && !action.href && action.click" class="ml-2" (click)="action.click($event)" (key.enter)="action.click($event)">
+ <a *ngIf="!action.routerLink && !action.href && action.click" class="ms-2" (click)="action.click($event)" (key.enter)="action.click($event)">
<ng-container *ngTemplateOutlet="actionContent; context:{ $implicit: action }"></ng-container>
</a>
- <a *ngIf="!action.routerLink && action.href && action.click" class="ml-2" (click)="action.click($event)" (key.enter)="action.click($event)" [href]="action.href">
+ <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>
</a>
[attr.title]="playlistElement.video.name"
>{{ playlistElement.video.name }}</a>
- <span *ngIf="isVideoPrivate()" class="badge badge-yellow">Private</span>
+ <span *ngIf="isVideoPrivate()" class="pt-badge badge-yellow">Private</span>
</div>
<span class="video-miniature-created-at-views">
padding-right: 5px;
}
- .badge {
- @include peertube-badge;
- margin-right: 5px;
+ .pt-badge {
+ @include margin-right(5px);
}
}
margin: 1rem auto;
}
+a {
+ text-decoration: none;
+}
+
strong {
font-weight: $font-semibold;
}
label {
font-weight: $font-bold;
font-size: 15px;
+ margin-bottom: 0.5rem;
}
code {
vertical-align: middle;
}
+.form-group {
+ margin-bottom: 1rem;
+}
+
.form-error,
.form-warning {
display: block;
max-width: initial;
}
-.glyphicon-black {
- color: #000;
-}
-
-.row {
- margin: 0 !important;
-}
-
.main-col {
@include margin-left($menu-width);
margin-top: 10px;
}
+.callout {
+ padding: 1.25rem;
+ border: 1px solid #eee;
+ border-radius: .25rem;
+ position: relative;
+
+ > label {
+ position: relative;
+ top: -5px;
+ left: -10px;
+ color: #6c757d !important;
+ }
+
+ &:not(.callout-light) {
+ border-left-width: .25rem;
+ }
+
+ &.callout-info {
+ border-color: pvar(--mainColorLightest);
+ border-left-color: pvar(--mainColor);
+ }
+}
+
@media screen and (max-width: #{breakpoint(xxl)}) {
.main-col {
--horizontalMarginContent: #{math.div($not-expanded-horizontal-margins, 2)};
@import '~bootstrap/scss/functions';
@import '~bootstrap/scss/variables';
-
@import '~bootstrap/scss/mixins';
+@import '~bootstrap/scss/utilities';
+
@import '~bootstrap/scss/root';
@import '~bootstrap/scss/reboot';
@import '~bootstrap/scss/type';
@import '~bootstrap/scss/grid';
-@import '~bootstrap/scss/tables';
@import '~bootstrap/scss/forms';
@import '~bootstrap/scss/buttons';
@import '~bootstrap/scss/dropdown';
@import '~bootstrap/scss/button-group';
-@import '~bootstrap/scss/input-group';
@import '~bootstrap/scss/nav';
@import '~bootstrap/scss/card';
-@import '~bootstrap/scss/badge';
+@import '~bootstrap/scss/accordion';
@import '~bootstrap/scss/alert';
@import '~bootstrap/scss/close';
@import '~bootstrap/scss/modal';
@import '~bootstrap/scss/tooltip';
@import '~bootstrap/scss/popover';
-@import '~bootstrap/scss/utilities';
+
+@import '~bootstrap/scss/helpers';
+@import '~bootstrap/scss/utilities/api';
@import '~@neos21/bootstrap3-glyphicons/assets/stylesheets/bootstrap3-glyphicons';
animation: spin 0.7s infinite linear;
}
-.glyphicon-duplicate {
- font-size: 70%;
-}
-
.flex-auto {
flex: auto;
}
.c-hand {
- cursor: pointer;
+ cursor: pointer !important;
}
@keyframes spin {
}
}
-.btn-group > .btn:not(:first-child) {
- border-top-left-radius: 0 !important;
- border-bottom-left-radius: 0 !important;
-}
-
.dropdown-menu {
- border-radius: 3px;
- box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
font-size: 15px;
-
color: pvar(--mainForegroundColor);
background-color: pvar(--mainBackgroundColor);
.dropdown-item {
padding: 3px 15px;
- color: pvar(--mainForegroundColor);
- background-color: pvar(--mainBackgroundColor);
-
&.active {
color: pvar(--mainBackgroundColor) !important;
background-color: pvar(--mainHoverColor);
opacity: 0.9;
}
- a:active,
- &:hover {
- color: pvar(--mainForegroundColor) !important;
- background-color: pvar(--mainBackgroundHoverColor);
- }
-
&::after {
display: none;
}
}
- button {
- @include disable-default-a-behaviour;
- }
-
a {
@include disable-default-a-behaviour;
}
}
-.badge {
- line-height: 1.1;
-}
-
@media screen and (min-width: #{breakpoint(md)}) {
.modal::before {
vertical-align: middle;
}
.input-group {
- > .form-control {
- flex: initial;
+ > .btn,
+ > .input-group-text {
+ height: $button-height;
}
- input.form-control {
- width: unset !important;
- flex-grow: 1;
+ > .input-group-text {
+ font-size: 15px;
+ line-height: normal;
+ opacity: 0.9;
}
- .input-group-prepend + input {
- border-top-left-radius: 0 !important;
- border-bottom-left-radius: 0 !important;
+ .input-group-text > .dropdown-toggle {
+ display: flex;
+ }
+
+ .last-in-group {
+ border-top-right-radius: 3px !important;
+ border-bottom-right-radius: 3px !important;
}
}
-.has-feedback.has-clear {
+.has-clear {
position: relative;
input {
.form-control-clear {
color: rgba(0, 0, 0, 0.4);
- /*
- * Enable pointer events as they have been disabled since Bootstrap 3.3
- * See https://github.com/twbs/bootstrap/pull/14104
- */
- pointer-events: all;
display: flex;
justify-content: center;
align-items: center;
display: none;
}
}
-
-.callout {
- padding: 1.25rem;
- border: 1px solid #eee;
- border-radius: .25rem;
-
- > label {
- position: relative;
- top: -5px;
- left: -10px;
- color: #6c757d !important;
- }
-
- &:not(.callout-light) {
- border-left-width: .25rem;
- }
-
- &.callout-info {
- border-color: pvar(--mainColorLightest);
- border-left-color: pvar(--mainColor);
- }
-}
-
-// Override these properties for Bidi support
-@each $size, $length in $spacers {
- .ml-#{$size} {
- @include margin-left($length);
- }
-
- .mr-#{$size} {
- @include margin-right($length);
- }
-
- .pl-#{$size} {
- @include padding-left($length);
- }
-
- .pr-#{$size} {
- @include padding-right($length);
- }
-}
@use '_variables' as *;
@use '_mixins' as *;
+@use '_badges' as *;
.peertube-button {
@include peertube-button;
.muted {
color: pvar(--greyForegroundColor) !important;
}
+
+.pt-badge {
+ @include peertube-badge;
+}
--- /dev/null
+@use '_variables' as *;
+@use '_mixins' as *;
+
+@mixin peertube-badge {
+ display: inline-block;
+ border-radius: .25rem;
+ padding: .25em .4em;
+ font-size: 75%;
+ font-weight: $font-semibold;
+ line-height: 1.1;
+
+ &.badge-primary {
+ color: pvar(--mainBackgroundColor);
+ background-color: pvar(--mainColor);
+ }
+
+ &.badge-secondary {
+ color: pvar(--mainBackgroundColor);
+ background-color: pvar(--greyForegroundColor);
+ opacity: 0.7;
+ }
+
+ &.badge-banned,
+ &.badge-danger,
+ &.badge-red {
+ background-color: #ffcdd2;
+ color: #c63737;
+ }
+
+ &.badge-banned {
+ text-decoration: line-through;
+ }
+
+ &.badge-yellow,
+ &.badge-warning {
+ background-color: #feedaf;
+ color: #8a5340;
+ }
+
+ &.badge-brown {
+ background-color: #ffd8b2;
+ color: #805b36;
+ }
+
+ &.badge-green,
+ &.badge-success {
+ background-color: #c8e6c9;
+ color: #256029;
+ }
+
+ &.badge-blue,
+ &.badge-info {
+ background-color: #b3e5fc;
+ color: #23547b;
+ }
+
+ &.badge-purple {
+ background-color: #eccfff;
+ color: #694382;
+ }
+}
-$dropdown-link-active-bg: inherit;
+@use '_variables' as *;
$modal-footer-border-width: 0;
$modal-md: 600px;
$nav-pills-link-active-bg: #F0F0F0;
$nav-pills-link-active-color: #000;
+
+$dropdown-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
+$dropdown-border-radius: 3px;
+$dropdown-link-active-color: pvar(--mainForegroundColor);
+$dropdown-link-active-bg: pvar(--mainBackgroundHoverColor);
+
+$accordion-button-active-bg: pvar(--mainColorLightest);
+$accordion-button-active-color: pvar(--mainForegroundColor);
display: inline-block;
height: $button-height;
width: $width;
+ max-width: $width;
color: pvar(--inputForegroundColor);
background-color: pvar(--inputBackgroundColor);
border: 1px solid #C6C6C6;
}
}
-@mixin peertube-input-group($width) {
- width: $width;
- min-height: $button-height;
- padding-top: 0;
- padding-bottom: 0;
- flex-wrap: nowrap;
-
- .input-group-text {
- font-size: 14px;
- color: #808080;
- }
-}
-
@mixin peertube-textarea ($width, $height) {
@include peertube-input-text($width);
cursor: default;
}
}
+
select[disabled] {
background-color: #f9f9f9;
}
}
}
-@mixin peertube-badge {
- border-radius: 2px;
- padding: 1/4em 1/2em;
- text-transform: uppercase;
- font-weight: $font-bold;
- font-size: 12px;
- letter-spacing: 1/3px;
-
- &.badge-banned,
- &.badge-red {
- background-color: #ffcdd2;
- color: #c63737;
- }
-
- &.badge-banned {
- text-decoration: line-through;
- }
-
- &.badge-yellow {
- background-color: #feedaf;
- color: #8a5340;
- }
-
- &.badge-brown {
- background-color: #ffd8b2;
- color: #805b36;
- }
-
- &.badge-green {
- background-color: #c8e6c9;
- color: #256029;
- }
-
- &.badge-blue {
- background-color: #b3e5fc;
- color: #23547b;
- }
-
- &.badge-purple {
- background-color: #eccfff;
- color: #694382;
- }
-}
-
@mixin actor-avatar-size ($size) {
display: inline-block;
width: $size;
vertical-align: top;
}
- .badge {
+ .pt-badge {
@include margin-left(7px);
+
vertical-align: top;
}
}
@use 'sass:math';
+@use '~bootstrap/scss/functions' as *;
$small-view: 800px;
$mobile-view: 500px;
+@use '~bootstrap/scss/functions' as *;
+
$primary-foreground-color: #fff;
$primary-foreground-opacity: 0.9;
$primary-foreground-opacity-hover: 1;
}
}
- .badge {
- @include peertube-badge;
+ .pt-badge {
+ font-size: 12px;
+ text-transform: uppercase;
}
}
.btn-group,
.dropdown-root,
.action-dropdown,
-.input-group-prepend,
.column-toggle {
z-index: inherit !important;
}
resolved "https://registry.yarnpkg.com/@neos21/bootstrap3-glyphicons/-/bootstrap3-glyphicons-1.0.7.tgz#b3f62f0dc54b383afcc26d44fcb3bb0ca1bd4de2"
integrity sha512-JfvPdx8W2+kVhW+8fj2kIJNS0tesU21hrWF7TBHtYDHpVfcFGU/yn3Eh02sJiNfZABkutP3oU0Ftw8LGF43Jng==
-"@ng-bootstrap/ng-bootstrap@^11.0.0":
- version "11.0.0"
- resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-11.0.0.tgz#16855620bff7ab7b965d4f49907c44b0f5bd5020"
- integrity sha512-qDnB0+jbpQ4wjXpM4NPRAtwmgTDUCjGavoeRDZHOvFfYvx/MBf1RTjZEqTJ1Yqq1pKP4BWpzxCgVTunfnpmsjA==
+"@ng-bootstrap/ng-bootstrap@^12.1.2":
+ version "12.1.2"
+ resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-12.1.2.tgz#19f21313234fe21090ba50a7721046ed5d9928e1"
+ integrity sha512-p27c+mYVdHiJMYrj5hwClVJxLdiZxafAqlbw1sdJh2xJ1rGOe+H/kCf5YDRbhlHqRN+34Gr0RQqIUeD1I2V8hg==
dependencies:
tslib "^2.3.0"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
+"@popperjs/core@^2.11.5":
+ version "2.11.5"
+ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
+ integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
+
"@schematics/angular@13.3.0":
version "13.3.0"
resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-13.3.0.tgz#c1a4d2ca25218d8cc7f220fc8323ba306bf7aa55"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
-bootstrap@^4.1.3:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.1.tgz#bc25380c2c14192374e8dec07cf01b2742d222a2"
- integrity sha512-0dj+VgI9Ecom+rvvpNZ4MUZJz8dcX7WCX+eTID9+/8HgOkv3dsRzi8BGeZJCQU6flWQVYxwTQnEZFrmJSEO7og==
+bootstrap@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.3.tgz#ba081b0c130f810fa70900acbc1c6d3c28fa8f34"
+ integrity sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==
brace-expansion@^1.1.7:
version "1.1.11"