+++ /dev/null
-<h1 class="sr-only" i18n>About</h1>
-<div class="margin-content">
- <div *ngIf="account" class="row no-gutters">
- <div class="block col-md-6 col-sm-12 pr-2">
- <h2 i18n class="small-title">DESCRIPTION</h2>
- <div class="content" [innerHtml]="getAccountDescription()"></div>
- </div>
-
- <div class="block col-md-6 col-sm-12">
- <h2 i18n class="small-title">STATS</h2>
-
- <div i18n class="content">Joined {{ account.createdAt | date }}</div>
- </div>
- </div>
-</div>
+++ /dev/null
-@import '_variables';
-@import '_mixins';
-
-.block {
- margin-bottom: 40px;
-
- .small-title {
- @include in-content-small-title;
-
- margin-bottom: 20px;
- }
-}
+++ /dev/null
-import { Subscription } from 'rxjs'
-import { Component, OnDestroy, OnInit } from '@angular/core'
-import { MarkdownService } from '@app/core'
-import { Account, AccountService } from '@app/shared/shared-main'
-
-@Component({
- selector: 'my-account-about',
- templateUrl: './account-about.component.html',
- styleUrls: [ './account-about.component.scss' ]
-})
-export class AccountAboutComponent implements OnInit, OnDestroy {
- account: Account
- descriptionHTML = ''
-
- private accountSub: Subscription
-
- constructor (
- private accountService: AccountService,
- private markdownService: MarkdownService
- ) { }
-
- ngOnInit () {
- // Parent get the account for us
- this.accountSub = this.accountService.accountLoaded
- .subscribe(async account => {
- this.account = account
- this.descriptionHTML = await this.markdownService.textMarkdownToHTML(this.account.description, true)
- })
- }
-
- ngOnDestroy () {
- if (this.accountSub) this.accountSub.unsubscribe()
- }
-
- getAccountDescription () {
- if (this.descriptionHTML) return this.descriptionHTML
-
- return $localize`No description`
- }
-}
}
updateSearch (value: string) {
- if (value === '') this.router.navigate(['../videos'], { relativeTo: this.route })
this.search = value
+ if (!this.search) {
+ this.router.navigate([ '../videos' ], { relativeTo: this.route })
+ return
+ }
+
+ this.videos = []
this.reloadVideos()
}
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { MetaGuard } from '@ngx-meta/core'
-import { AccountsComponent } from './accounts.component'
-import { AccountVideosComponent } from './account-videos/account-videos.component'
-import { AccountAboutComponent } from './account-about/account-about.component'
-import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component'
import { AccountSearchComponent } from './account-search/account-search.component'
+import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component'
+import { AccountVideosComponent } from './account-videos/account-videos.component'
+import { AccountsComponent } from './accounts.component'
const accountsRoutes: Routes = [
{
}
}
},
- {
- path: 'about',
- component: AccountAboutComponent,
- data: {
- meta: {
- title: $localize`About account`
- }
- }
- },
{
path: 'videos',
component: AccountVideosComponent,
-<div *ngIf="account" class="row">
- <div class="sub-menu">
-
- <div class="actor">
- <img [src]="account.avatarUrl" alt="Avatar" />
-
- <div class="actor-info">
- <div class="actor-names">
- <div class="actor-display-name">{{ account.displayName }}</div>
- <div class="actor-name">
- <span>{{ account.nameWithHost }}</span>
- <button [cdkCopyToClipboard]="account.nameWithHostForced" (click)="activateCopiedMessage()"
- class="btn btn-outline-secondary btn-sm copy-button"
- >
- <span class="glyphicon glyphicon-duplicate"></span>
- </button>
+<div *ngIf="account" class="root">
+ <div class="account-info">
+
+ <div class="account-avatar-row">
+ <img class="account-avatar" [src]="account.avatarUrl" alt="Avatar" />
+
+ <div>
+ <div class="section-label" i18n>PEERTUBE ACCOUNT</div>
+
+ <div class="actor-info">
+ <div>
+ <div class="actor-display-name">
+ <h1>{{ account.displayName }}</h1>
+
+ <my-user-moderation-dropdown
+ [prependActions]="prependModerationActions"
+ buttonSize="small" [account]="account" [user]="accountUser" placement="bottom-left auto"
+ (userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()"
+ ></my-user-moderation-dropdown>
+
+ <span *ngIf="accountUser?.blocked" [ngbTooltip]="accountUser.blockedReason" class="badge badge-danger" i18n>Banned</span>
+ <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>
+ </div>
+
+ <div class="actor-handle">
+ <span>@{{ account.nameWithHost }}</span>
+ <button [cdkCopyToClipboard]="account.nameWithHostForced" (click)="activateCopiedMessage()"
+ class="btn btn-outline-secondary btn-sm copy-button" title="Copy account handle" i18n-title
+ >
+ <span class="glyphicon glyphicon-duplicate"></span>
+ </button>
+ </div>
+
+ <div class="actor-counters">
+ <span i18n>{naiveAggregatedSubscribers(), plural, =1 {1 subscriber} other {{{ naiveAggregatedSubscribers() }} subscribers}}</span>
+
+ <span class="videos-count" *ngIf="accountVideosCount !== undefined" i18n>
+ {accountVideosCount, plural, =1 {1 videos} other {{{ accountVideosCount }} videos}}
+ </span>
+ </div>
</div>
- <span *ngIf="accountUser?.blocked" [ngbTooltip]="accountUser.blockedReason" class="badge badge-danger" i18n>Banned</span>
- <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>
-
- <my-user-moderation-dropdown
- [prependActions]="prependModerationActions"
- buttonSize="small" [account]="account" [user]="accountUser" placement="bottom-left auto"
- (userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()"
- ></my-user-moderation-dropdown>
- </div>
- <div class="actor-followers" [title]="accountFollowerTitle">
- {{ subscribersDisplayFor(naiveAggregatedSubscribers) }}
</div>
</div>
+ </div>
- <div class="right-buttons">
- <a *ngIf="isAccountManageable && !isInSmallView" routerLink="/my-account" class="btn btn-outline-tertiary mr-2" i18n>Manage account</a>
- <my-subscribe-button *ngIf="videoChannels" [account]="account" [videoChannels]="videoChannels"></my-subscribe-button>
- </div>
+ <div class="description" [ngClass]="{ expanded: accountDescriptionExpanded }">
+ <div class="description-html" [innerHTML]="accountDescriptionHTML"></div>
+
+ <div class="created-at" i18n>Account created on {{ account.createdAt | date }}</div>
</div>
- <div class="links w-100">
- <ng-template #linkTemplate let-item="item">
- <a [routerLink]="item.routerLink" routerLinkActive="active" class="title-page">{{ item.label }}</a>
- </ng-template>
+ <div *ngIf="!accountDescriptionExpanded" class="show-more" role="button"
+ (click)="accountDescriptionExpanded = !accountDescriptionExpanded"
+ title="Show the complete description" i18n-title i18n
+ >
+ Show more...
+ </div>
- <list-overflow [items]="links" [itemTemplate]="linkTemplate"></list-overflow>
+ <div class="buttons">
+ <a *ngIf="isManageable() && !isInSmallView()" routerLink="/my-account" class="peertube-button-link orange-button" i18n>
+ Manage account
+ </a>
- <simple-search-input (searchChanged)="searchChanged($event)" name="search-videos" i18n-placeholder placeholder="Search videos"></simple-search-input>
+ <my-subscribe-button *ngIf="videoChannels" [account]="account" [videoChannels]="videoChannels"></my-subscribe-button>
</div>
</div>
- <div class="margin-content">
- <router-outlet (activate)="onOutletLoaded($event)"></router-outlet>
+ <div class="links">
+ <ng-template #linkTemplate let-item="item">
+ <a [routerLink]="item.routerLink" routerLinkActive="active" class="title-page">{{ item.label }}</a>
+ </ng-template>
+
+ <list-overflow [hidden]="hideMenu" [items]="links" [itemTemplate]="linkTemplate"></list-overflow>
+
+ <simple-search-input
+ [alwaysShow]="!isInSmallView()" (searchChanged)="searchChanged($event)"
+ (inputDisplayChanged)="onSearchInputDisplayChanged($event)" name="search-videos"
+ i18n-iconTitle icon-title="Search account videos"
+ i18n-placeholder placeholder="Search account videos"
+ ></simple-search-input>
</div>
+
+ <router-outlet (activate)="onOutletLoaded($event)"></router-outlet>
</div>
<ng-container *ngIf="prependModerationActions">
-// Bootstrap grid utilities require functions, variables and mixins
-@import 'node_modules/bootstrap/scss/functions';
-@import 'node_modules/bootstrap/scss/variables';
-@import 'node_modules/bootstrap/scss/mixins';
-@import 'node_modules/bootstrap/scss/grid';
-
@import '_variables';
@import '_mixins';
-
-.sub-menu {
- @include sub-menu-with-actor;
-
- .actor {
- width: 100%;
- }
+@import '_actor';
+@import '_miniature';
+
+.root {
+ --myGlobalPadding: 60px;
+ --myImgMargin: 30px;
+ --myFontSize: 16px;
+ --myGreyFontSize: 16px;
}
-.margin-content {
- // margin-content is required, but child views have their own margins
- // that match views outside the scope of accounts, so we only align
- // them with the margins of .sub-menu when required.
- margin: 0;
+.section-label {
+ @include section-label-responsive;
}
-.right-buttons {
- display: flex;
- height: max-content;
- margin-left: auto;
- margin-top: 10px;
-
- @include media-breakpoint-down(lg) {
- flex-flow: column-reverse;
+.links {
+ @include fluid-videos-miniature-layout;
- a {
- margin-top: 0.25rem;
- margin-right: 0 !important;
- }
- }
-
- a {
- @include peertube-button-outline;
- }
-
- my-subscribe-button {
- min-height: 30px;
- }
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ max-width: 800px;
}
my-user-moderation-dropdown,
.copy-button {
border: none;
- padding: 5px;
- margin-top: -2px;
+}
+
+.account-info {
+ display: grid;
+ grid-template-columns: 1fr min-content;
+ grid-template-rows: auto auto;
+
+ background-color: pvar(--submenuColor);
+ margin-bottom: 45px;
+ padding: var(--myGlobalPadding) var(--myGlobalPadding) 0 var(--myGlobalPadding);
+ font-size: var(--myFontSize);
+}
+
+.account-avatar-row {
+ @include avatar-row-responsive(var(--myImgMargin), var(--myGreyFontSize));
+}
+
+.description {
+ grid-column: 1 / 3;
+}
+
+.created-at {
+ margin-top: 15px;
+ color: pvar(--greyForegroundColor);
+ padding-bottom: 60px;
+}
+
+.show-more {
+ @include show-more-description;
+
+ display: none;
+ text-align: center;
+}
+
+.buttons {
+ grid-column: 2;
+ grid-row: 1;
+
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ align-content: flex-start;
+
+ > *:not(:last-child) {
+ margin-bottom: 15px;
+ }
+}
+
+@media screen and (max-width: $small-view) {
+ .root {
+ --myGlobalPadding: 45px;
+ --myChannelImgMargin: 15px;
+ }
+
+ .account-info {
+ display: block;
+ padding-bottom: 60px;
+ }
+
+ .description:not(.expanded) {
+ max-height: 70px;
+
+ @include fade-text(30px, pvar(--submenuColor));
+ }
+
+ .show-more {
+ display: block;
+ }
+
+ .buttons {
+ justify-content: center;
+ }
}
@media screen and (max-width: $mobile-view) {
- .sub-menu {
- .actor {
- flex-direction: column;
- align-items: center;
-
- img,
- .actor-info .actor-names .actor-display-name {
- margin-right: 0;
- }
-
- .actor-info {
- .actor-names {
- flex-direction: column;
- align-items: center;
- }
-
- my-user-moderation-dropdown {
- margin-left: 0;
- }
-
- .actor-followers {
- text-align: center;
- }
- }
-
- .right-buttons {
- margin-left: 0;
- }
- }
+ .root {
+ --myGlobalPadding: 15px;
+ --myFontSize: 14px;
+ --myGreyFontSize: 13px;
+ }
+
+ .account-info {
+ display: block;
+ padding-bottom: 30px;
+ }
+
+ .links {
+ margin: auto !important;
+ width: min-content;
+ }
+
+ .show-more {
+ margin-bottom: 30px;
}
}
import { catchError, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
-import { AuthService, Notifier, RedirectService, RestExtractor, ScreenService, UserService } from '@app/core'
-import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
+import { AuthService, MarkdownService, Notifier, RedirectService, RestExtractor, ScreenService, UserService } from '@app/core'
+import {
+ Account,
+ AccountService,
+ DropdownAction,
+ ListOverflowItem,
+ VideoChannel,
+ VideoChannelService,
+ VideoService
+} from '@app/shared/shared-main'
import { AccountReportComponent } from '@app/shared/shared-moderation'
-import { User, UserRight } from '@shared/models'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
+import { User, UserRight } from '@shared/models'
import { AccountSearchComponent } from './account-search/account-search.component'
@Component({
})
export class AccountsComponent implements OnInit, OnDestroy {
@ViewChild('accountReportModal') accountReportModal: AccountReportComponent
+
accountSearch: AccountSearchComponent
account: Account
accountUser: User
+
videoChannels: VideoChannel[] = []
+
links: ListOverflowItem[] = []
+ hideMenu = false
- isAccountManageable = false
accountFollowerTitle = ''
+ accountVideosCount: number
+ accountDescriptionHTML = ''
+ accountDescriptionExpanded = false
+
prependModerationActions: DropdownAction<any>[]
private routeSub: Subscription
private restExtractor: RestExtractor,
private redirectService: RedirectService,
private authService: AuthService,
+ private videoService: VideoService,
+ private markdown: MarkdownService,
private screenService: ScreenService
) {
}
this.links = [
{ label: $localize`VIDEO CHANNELS`, routerLink: 'video-channels' },
- { label: $localize`VIDEOS`, routerLink: 'videos' },
- { label: $localize`ABOUT`, routerLink: 'about' }
+ { label: $localize`VIDEOS`, routerLink: 'videos' }
]
}
if (this.routeSub) this.routeSub.unsubscribe()
}
- get naiveAggregatedSubscribers () {
+ naiveAggregatedSubscribers () {
return this.videoChannels.reduce(
(acc, val) => acc + val.followersCount,
this.account.followersCount // accumulator starts with the base number of subscribers the account has
)
}
- get isInSmallView () {
+ isUserLoggedIn () {
+ return this.authService.isLoggedIn()
+ }
+
+ isInSmallView () {
return this.screenService.isInSmallView()
}
+ isManageable () {
+ if (!this.isUserLoggedIn()) return false
+
+ return this.account?.userId === this.authService.getUser().id
+ }
+
onUserChanged () {
- this.getUserIfNeeded(this.account)
+ this.loadUserIfNeeded(this.account)
}
onUserDeleted () {
if (this.accountSearch) this.accountSearch.updateSearch(search)
}
- private onAccount (account: Account) {
+ onSearchInputDisplayChanged (displayed: boolean) {
+ this.hideMenu = this.isInSmallView() && displayed
+ }
+
+ private async onAccount (account: Account) {
+ this.accountFollowerTitle = $localize`${account.followersCount} direct account followers`
+
this.prependModerationActions = undefined
- this.account = account
+ this.accountDescriptionHTML = await this.markdown.textMarkdownToHTML(account.description)
- if (this.authService.isLoggedIn()) {
- this.authService.userInformationLoaded.subscribe(
- () => {
- this.isAccountManageable = this.account.userId && this.account.userId === this.authService.getUser().id
-
- const followers = this.subscribersDisplayFor(account.followersCount)
- this.accountFollowerTitle = $localize`${followers} direct account followers`
-
- // It's not our account, we can report it
- if (!this.isAccountManageable) {
- this.prependModerationActions = [
- {
- label: $localize`Report this account`,
- handler: () => this.showReportModal()
- }
- ]
- }
- }
- )
- }
+ // After the markdown renderer to avoid layout changes
+ this.account = account
- this.getUserIfNeeded(account)
+ this.updateModerationActions()
+ this.loadUserIfNeeded(account)
+ this.loadAccountVideosCount()
}
private showReportModal () {
this.accountReportModal.show()
}
- private getUserIfNeeded (account: Account) {
+ private loadUserIfNeeded (account: Account) {
if (!account.userId || !this.authService.isLoggedIn()) return
const user = this.authService.getUser()
)
}
}
+
+ private updateModerationActions () {
+ if (!this.authService.isLoggedIn()) return
+
+ this.authService.userInformationLoaded.subscribe(
+ () => {
+ if (this.isManageable()) return
+
+ // It's not our account, we can report it
+ this.prependModerationActions = [
+ {
+ label: $localize`Report this account`,
+ handler: () => this.showReportModal()
+ }
+ ]
+ }
+ )
+ }
+
+ private loadAccountVideosCount () {
+ this.videoService.getAccountVideos({
+ account: this.account,
+ videoPagination: {
+ currentPage: 1,
+ itemsPerPage: 0
+ },
+ sort: '-publishedAt'
+ }).subscribe(res => this.accountVideosCount = res.total)
+ }
}
import { SharedModerationModule } from '@app/shared/shared-moderation'
import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription'
import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature'
-import { AccountAboutComponent } from './account-about/account-about.component'
+import { AccountSearchComponent } from './account-search/account-search.component'
import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component'
import { AccountVideosComponent } from './account-videos/account-videos.component'
-import { AccountSearchComponent } from './account-search/account-search.component'
import { AccountsRoutingModule } from './accounts-routing.module'
import { AccountsComponent } from './accounts.component'
AccountsComponent,
AccountVideosComponent,
AccountVideoChannelsComponent,
- AccountAboutComponent,
AccountSearchComponent
],
<ng-template #ownerTemplate>
<div class="owner-block">
<div class="avatar-row">
- <img [src]="videoChannel.ownerAvatarUrl" alt="Owner account avatar" />
+ <img class="channel-avatar" [src]="videoChannel.ownerAvatarUrl" alt="Owner account avatar" />
<div class="actor-info">
<h4>{{ videoChannel.ownerAccount.displayName }}</h4>
@import '_variables';
@import '_mixins';
+@import '_actor';
@import '_miniature';
.root {
}
.section-label {
- color: pvar(--mainColor);
- font-size: 12px;
- margin-bottom: 15px;
- font-weight: $font-bold;
- letter-spacing: 2.5px;
+ @include section-label-responsive;
}
.links {
}
.channel-avatar-row {
- display: flex;
- grid-column: 1;
- margin-bottom: 30px;
-
- img {
- @include channel-avatar(120px);
- }
-
- > div {
- margin-left: var(--myChannelImgMargin);
- }
-
- .actor-info {
- display: flex;
-
- > div:first-child {
- flex-grow: 1;
- }
- }
-
- .actor-display-name {
- display: flex;
- flex-wrap: wrap;
- }
-
- h1 {
- font-size: 28px;
- font-weight: $font-bold;
- margin: 0;
- }
-
- .actor-handle,
- .actor-counters {
- color: pvar(--greyForegroundColor);
- font-size: var(--myGreyChannelFontSize);
- }
-
- .actor-counters > *:not(:last-child)::after {
- content: '•';
- margin: 0 10px;
- color: pvar(--mainColor);
- }
+ @include avatar-row-responsive(var(--myChannelImgMargin), var(--myGreyChannelFontSize));
}
.channel-description {
}
.show-more {
+ @include show-more-description;
+
display: none;
- color: pvar(--mainColor);
- cursor: pointer;
- margin: 10px auto 45px auto;
}
-
.channel-buttons {
display: flex;
flex-wrap: wrap;
width: min-content;
}
- .section-label {
- font-size: 10px;
- letter-spacing: 2.1px;
- margin-bottom: 5px;
- }
-
- .channel-avatar-row {
- margin-bottom: 15px;
-
- h1 {
- font-size: 22px;
- }
-
- img {
- @include channel-avatar(80px);
- }
- }
-
.show-more {
margin-bottom: 30px;
}
isManageable () {
if (!this.isUserLoggedIn()) return false
- return this.videoChannel.ownerAccount.userId === this.authService.getUser().id
+ return this.videoChannel?.ownerAccount.userId === this.authService.getUser().id
}
activateCopiedMessage () {
-<span>
- <my-global-icon iconName="search" aria-label="Search" role="button" (click)="showInput()"></my-global-icon>
-
+<div class="root">
<input
#ref
type="text"
[(ngModel)]="value"
- (focusout)="focusLost()"
(keyup.enter)="searchChange()"
- [hidden]="!shown"
+ [hidden]="!inputShown"
[name]="name"
[placeholder]="placeholder"
>
-</span>
+
+ <my-global-icon iconName="search" aria-label="Search" role="button" (click)="onIconClick()" [title]="iconTitle"></my-global-icon>
+
+ <my-global-icon *ngIf="!alwaysShow && inputShown" i18n-title title="Close search" iconName="cross" (click)="hideInput()"></my-global-icon>
+</div>
@import '_variables';
@import '_mixins';
-span {
- opacity: .6;
-
- &:focus-within {
- opacity: 1;
- }
+.root {
+ display: flex;
}
my-global-icon {
- height: 18px;
- position: relative;
- top: -2px;
-}
+ height: 26px;
+ width: 26px;
+ margin-left: 10px;
+ cursor: pointer;
-input {
- @include peertube-input-text(150px);
+ &:hover {
+ color: pvar(--mainHoverColor);
+ }
- height: 22px; // maximum height for the account/video-channels links
- padding-left: 10px;
- background-color: transparent;
- border: none;
+ &[iconName=search] {
+ color: pvar(--mainColor);
+ }
- &::placeholder {
- font-size: 15px;
+ &[iconName=cross] {
+ color: pvar(--mainForegroundColor);
}
}
+
+input {
+ @include peertube-input-text(200px);
+}
-import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
-import { ActivatedRoute, Router } from '@angular/router'
import { Subject } from 'rxjs'
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
+import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
+import { ActivatedRoute, Router } from '@angular/router'
@Component({
selector: 'simple-search-input',
@Input() name = 'search'
@Input() placeholder = $localize`Search`
+ @Input() iconTitle = $localize`Search`
+ @Input() alwaysShow = true
@Output() searchChanged = new EventEmitter<string>()
+ @Output() inputDisplayChanged = new EventEmitter<boolean>()
value = ''
- shown: boolean
+ inputShown: boolean
private searchSubject = new Subject<string>()
.subscribe(value => this.searchChanged.emit(value))
this.searchSubject.next(this.value)
+
+ if (this.isInputShown()) this.showInput(false)
}
- showInput () {
- this.shown = true
- setTimeout(() => this.input.nativeElement.focus())
+ isInputShown () {
+ if (this.alwaysShow) return true
+
+ return this.inputShown
+ }
+
+ onIconClick () {
+ if (!this.isInputShown()) {
+ this.showInput()
+ return
+ }
+
+ this.searchChange()
+ }
+
+ showInput (focus = true) {
+ this.inputShown = true
+ this.inputDisplayChanged.emit(this.inputShown)
+
+ if (focus) {
+ setTimeout(() => this.input.nativeElement.focus())
+ }
+ }
+
+ hideInput () {
+ this.inputShown = false
+
+ if (this.isInputShown() === false) {
+ this.inputDisplayChanged.emit(this.inputShown)
+ }
}
focusLost () {
- if (this.value !== '') return
- this.shown = false
+ if (this.value) return
+
+ this.hideInput()
}
searchChange () {
- this.router.navigate(['./search'], { relativeTo: this.route })
+ this.router.navigate([ './search' ], { relativeTo: this.route })
+
this.searchSubject.next(this.value)
}
}
--- /dev/null
+@import '_variables';
+
+@mixin section-label-responsive {
+ color: pvar(--mainColor);
+ font-size: 12px;
+ margin-bottom: 15px;
+ font-weight: $font-bold;
+ letter-spacing: 2.5px;
+
+ @media screen and (max-width: $mobile-view) {
+ font-size: 10px;
+ letter-spacing: 2.1px;
+ margin-bottom: 5px;
+ }
+}
+
+@mixin show-more-description {
+ color: pvar(--mainColor);
+ cursor: pointer;
+ margin: 10px auto 45px auto;
+}
+
+@mixin avatar-row-responsive ($img-margin, $grey-font-size) {
+ display: flex;
+ grid-column: 1;
+ margin-bottom: 30px;
+
+ .channel-avatar {
+ @include channel-avatar(120px);
+ }
+
+ .account-avatar {
+ @include avatar(120px);
+ }
+
+ > div {
+ margin-left: $img-margin;
+ }
+
+ .actor-info {
+ display: flex;
+
+ > div:first-child {
+ flex-grow: 1;
+ }
+ }
+
+ .actor-display-name {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ h1 {
+ font-size: 28px;
+ font-weight: $font-bold;
+ margin: 0;
+ }
+
+ .actor-handle,
+ .actor-counters {
+ color: pvar(--greyForegroundColor);
+ font-size: $grey-font-size;
+ }
+
+ .actor-counters > *:not(:last-child)::after {
+ content: '•';
+ margin: 0 10px;
+ color: pvar(--mainColor);
+ }
+
+ @media screen and (max-width: $mobile-view) {
+ margin-bottom: 15px;
+
+ h1 {
+ font-size: 22px;
+ }
+
+ .channel-avatar {
+ @include channel-avatar(80px);
+ }
+
+ .account-avatar {
+ @include avatar(120px);
+ }
+ }
+}