-
- {URIPolicy, select, only-followed {only followed instances} other {any instance}}
-
+
+ any instance
+ only followed instances
+
diff --git a/client/src/app/header/search-typeahead.component.scss b/client/src/app/header/search-typeahead.component.scss
index 6d7511c70..a55e78326 100644
--- a/client/src/app/header/search-typeahead.component.scss
+++ b/client/src/app/header/search-typeahead.component.scss
@@ -3,6 +3,30 @@
@import '_bootstrap-variables';
@import '~bootstrap/scss/mixins/_breakpoints';
+#search-video {
+ @include peertube-input-text($search-input-width);
+ padding-left: 10px;
+ padding-right: 40px; // For the search icon
+ font-size: 14px;
+
+ &::placeholder {
+ color: var(--inputPlaceholderColor);
+ }
+}
+
+.icon.icon-search {
+ @include icon(25px);
+ height: 21px;
+
+ background-color: var(--mainForegroundColor);
+ mask: url('../../assets/images/header/search.svg') no-repeat 50% 50%;
+
+ // yolo
+ position: absolute;
+ margin-left: -35px;
+ margin-top: 5px;
+}
+
.jump-to-suggestions {
top: 100%;
left: 0;
@@ -42,7 +66,7 @@ my-suggestions ::ng-deep ul {
}
#typeahead-container {
- ::ng-deep input {
+ input {
border: 1px solid var(--mainBackgroundColor) !important;
box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 20px 0px;
flex-grow: 1;
@@ -56,12 +80,12 @@ my-suggestions ::ng-deep ul {
@media screen and (max-width: $small-view) {
flex: 1;
- ::ng-deep input {
+ input {
width: unset;
}
}
- ::ng-deep span {
+ span {
right: 10px;
}
diff --git a/client/src/app/header/search-typeahead.component.ts b/client/src/app/header/search-typeahead.component.ts
index 9b414bc56..c265f2c83 100644
--- a/client/src/app/header/search-typeahead.component.ts
+++ b/client/src/app/header/search-typeahead.component.ts
@@ -1,16 +1,15 @@
import {
Component,
- ViewChild,
- ElementRef,
AfterViewInit,
OnInit,
OnDestroy,
- QueryList
+ QueryList,
+ ViewChild,
+ ElementRef
} from '@angular/core'
-import { Router, NavigationEnd, Params, ActivatedRoute } from '@angular/router'
+import { Router, Params, ActivatedRoute } from '@angular/router'
import { AuthService, ServerService } from '@app/core'
-import { I18n } from '@ngx-translate/i18n-polyfill'
-import { filter, first, tap, map } from 'rxjs/operators'
+import { first, tap } from 'rxjs/operators'
import { ListKeyManager } from '@angular/cdk/a11y'
import { UP_ARROW, DOWN_ARROW, ENTER } from '@angular/cdk/keycodes'
import { SuggestionComponent, Result } from './suggestion.component'
@@ -24,19 +23,16 @@ import { ServerConfig } from '@shared/models'
styleUrls: [ './search-typeahead.component.scss' ]
})
export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewInit {
- @ViewChild('contentWrapper', { static: true }) contentWrapper: ElementRef
+ @ViewChild('searchVideo', { static: true }) searchInput: ElementRef
hasChannel = false
inChannel = false
newSearch = true
- searchInput: HTMLInputElement
+ search = ''
serverConfig: ServerConfig
- URIPolicyText: string
- inAllText: string
inThisChannelText: string
- globalSearchIndex = 'https://index.joinpeertube.org'
keyboardEventsManager: ListKeyManager
results: any[] = []
@@ -45,30 +41,10 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
private authService: AuthService,
private router: Router,
private route: ActivatedRoute,
- private serverService: ServerService,
- private i18n: I18n
- ) {
- this.URIPolicyText = this.i18n('Determines whether you can resolve any distant content, or if your instance only allows doing so for instances it follows.')
- this.inAllText = this.i18n('In all PeerTube')
- this.inThisChannelText = this.i18n('In this channel')
- }
+ private serverService: ServerService
+ ) {}
ngOnInit () {
- this.router.events
- .pipe(filter(e => e instanceof NavigationEnd))
- .subscribe((event: NavigationEnd) => {
- this.hasChannel = event.url.startsWith('/videos/watch')
- this.inChannel = event.url.startsWith('/video-channels')
- this.computeResults()
- })
-
- this.router.events
- .pipe(
- filter(e => e instanceof NavigationEnd),
- map(() => getParameterByName('search', window.location.href))
- )
- .subscribe(searchQuery => this.searchInput.value = searchQuery || '')
-
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
}
@@ -78,53 +54,52 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
}
ngAfterViewInit () {
- this.searchInput = this.contentWrapper.nativeElement.childNodes[0]
- this.searchInput.addEventListener('input', this.computeResults.bind(this))
- this.searchInput.addEventListener('keyup', this.handleKeyUp.bind(this))
- }
-
- get hasSearch () {
- return !!this.searchInput && !!this.searchInput.value
+ this.search = getParameterByName('search', window.location.href) || ''
}
get activeResult () {
return this.keyboardEventsManager && this.keyboardEventsManager.activeItem && this.keyboardEventsManager.activeItem.result
}
- get showHelp () {
- return this.hasSearch && this.newSearch && this.activeResult && this.activeResult.type === 'search-global' || false
+ get showInstructions () {
+ return !this.search
}
- get URIPolicy (): 'only-followed' | 'any' {
- return (
- this.authService.isLoggedIn()
- ? this.serverConfig.search.remoteUri.users
- : this.serverConfig.search.remoteUri.anonymous
- )
- ? 'any'
- : 'only-followed'
+ get showHelp () {
+ return this.search && this.newSearch && this.activeResult && this.activeResult.type === 'search-global' || false
+ }
+
+ get anyURI () {
+ if (!this.serverConfig) return false
+ return this.authService.isLoggedIn()
+ ? this.serverConfig.search.remoteUri.users
+ : this.serverConfig.search.remoteUri.anonymous
+ }
+
+ onSearchChange () {
+ this.computeResults()
}
computeResults () {
this.newSearch = true
let results: Result[] = []
- if (this.hasSearch) {
+ if (this.search) {
results = [
/* Channel search is still unimplemented. Uncomment when it is.
{
- text: this.searchInput.value,
+ text: this.search,
type: 'search-channel'
},
*/
{
- text: this.searchInput.value,
+ text: this.search,
type: 'search-instance',
default: true
},
/* Global search is still unimplemented. Uncomment when it is.
{
- text: this.searchInput.value,
+ text: this.search,
type: 'search-global'
},
*/
@@ -137,7 +112,8 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
// if we're not in a channel or one of its videos/playlits, show all channel-related results
if (!(this.hasChannel || this.inChannel)) return !result.type.includes('channel')
// if we're in a channel, show all channel-related results except for the channel redirection itself
- if (this.inChannel) return !(result.type === 'channel')
+ if (this.inChannel) return result.type !== 'channel'
+ // all other result types are kept
return true
}
)
@@ -187,7 +163,7 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
Object.assign(queryParams, this.route.snapshot.queryParams)
}
- Object.assign(queryParams, { search: this.searchInput.value })
+ Object.assign(queryParams, { search: this.search })
const o = this.authService.isLoggedIn()
? this.loadUserLanguagesIfNeeded(queryParams)
diff --git a/client/src/app/header/suggestion.component.html b/client/src/app/header/suggestion.component.html
index 894cacb95..edde2023a 100644
--- a/client/src/app/header/suggestion.component.html
+++ b/client/src/app/header/suggestion.component.html
@@ -9,15 +9,9 @@
-
- {{ inThisChannelText }}
-
-
- {{ inThisInstanceText }}
-
-
- {{ inAllText }}
-
+ In this channel
+ In this instance
+ In the vidiverse
↵
diff --git a/client/src/app/header/suggestion.component.ts b/client/src/app/header/suggestion.component.ts
index bdcb3e03f..69641b511 100644
--- a/client/src/app/header/suggestion.component.ts
+++ b/client/src/app/header/suggestion.component.ts
@@ -1,6 +1,5 @@
-import { Input, Component, Output, EventEmitter, OnInit } from '@angular/core'
+import { Input, Component, Output, EventEmitter, OnInit, ChangeDetectionStrategy } from '@angular/core'
import { RouterLink } from '@angular/router'
-import { I18n } from '@ngx-translate/i18n-polyfill'
import { ListKeyManagerOption } from '@angular/cdk/a11y'
export type Result = {
@@ -13,28 +12,17 @@ export type Result = {
@Component({
selector: 'my-suggestion',
templateUrl: './suggestion.component.html',
- styleUrls: [ './suggestion.component.scss' ]
+ styleUrls: [ './suggestion.component.scss' ],
+ changeDetection: ChangeDetectionStrategy.OnPush
})
export class SuggestionComponent implements OnInit, ListKeyManagerOption {
@Input() result: Result
@Input() highlight: string
@Output() selected = new EventEmitter()
- inAllText: string
- inThisChannelText: string
- inThisInstanceText: string
-
disabled = false
active = false
- constructor (
- private i18n: I18n
- ) {
- this.inAllText = this.i18n('In the vidiverse')
- this.inThisChannelText = this.i18n('In this channel')
- this.inThisInstanceText = this.i18n('In this instance')
- }
-
getLabel () {
return this.result.text
}
diff --git a/client/src/app/header/suggestions.component.html b/client/src/app/header/suggestions.component.html
new file mode 100644
index 000000000..8d017d78d
--- /dev/null
+++ b/client/src/app/header/suggestions.component.html
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/client/src/app/header/suggestions.component.ts b/client/src/app/header/suggestions.component.ts
index fac7fe2f9..ee3ef73c2 100644
--- a/client/src/app/header/suggestions.component.ts
+++ b/client/src/app/header/suggestions.component.ts
@@ -1,16 +1,10 @@
-import { Input, QueryList, Component, Output, AfterViewInit, EventEmitter, ViewChildren } from '@angular/core'
+import { Input, QueryList, Component, Output, AfterViewInit, EventEmitter, ViewChildren, ChangeDetectionStrategy } from '@angular/core'
import { SuggestionComponent } from './suggestion.component'
@Component({
selector: 'my-suggestions',
- template: `
-
- `
+ templateUrl: './suggestions.component.html',
+ changeDetection: ChangeDetectionStrategy.OnPush
})
export class SuggestionsComponent implements AfterViewInit {
@Input() results: any[]
@@ -20,7 +14,7 @@ export class SuggestionsComponent implements AfterViewInit {
ngAfterViewInit () {
this.listItems.changes.subscribe(
- val => this.init.emit({ items: this.listItems })
+ _ => this.init.emit({ items: this.listItems })
)
}
diff --git a/client/src/app/shared/angular/highlight.pipe.ts b/client/src/app/shared/angular/highlight.pipe.ts
index 4199d833e..e219b3823 100644
--- a/client/src/app/shared/angular/highlight.pipe.ts
+++ b/client/src/app/shared/angular/highlight.pipe.ts
@@ -5,48 +5,50 @@ import { SafeHtml } from '@angular/platform-browser'
@Pipe({ name: 'highlight' })
export class HighlightPipe implements PipeTransform {
/* use this for single match search */
- static SINGLE_MATCH: string = "Single-Match"
+ static SINGLE_MATCH = 'Single-Match'
/* use this for single match search with a restriction that target should start with search string */
- static SINGLE_AND_STARTS_WITH_MATCH: string = "Single-And-StartsWith-Match"
+ static SINGLE_AND_STARTS_WITH_MATCH = 'Single-And-StartsWith-Match'
/* use this for global search */
- static MULTI_MATCH: string = "Multi-Match"
+ static MULTI_MATCH = 'Multi-Match'
- constructor() {}
- transform(
+ // tslint:disable-next-line:no-empty
+ constructor () {}
+
+ transform (
contentString: string = null,
stringToHighlight: string = null,
- option: string = "Single-And-StartsWith-Match",
- caseSensitive: boolean = false,
- highlightStyleName: string = "search-highlight"
+ option = 'Single-And-StartsWith-Match',
+ caseSensitive = false,
+ highlightStyleName = 'search-highlight'
): SafeHtml {
- if (stringToHighlight && contentString && option) {
- let regex: any = ""
- let caseFlag: string = !caseSensitive ? "i" : ""
- switch (option) {
- case "Single-Match": {
- regex = new RegExp(stringToHighlight, caseFlag)
- break
- }
- case "Single-And-StartsWith-Match": {
- regex = new RegExp("^" + stringToHighlight, caseFlag)
- break
- }
- case "Multi-Match": {
- regex = new RegExp(stringToHighlight, "g" + caseFlag)
- break
- }
- default: {
- // default will be a global case-insensitive match
- regex = new RegExp(stringToHighlight, "gi")
- }
- }
- const replaced = contentString.replace(
- regex,
- (match) => `${match}`
- )
- return replaced
- } else {
- return contentString
+ if (stringToHighlight && contentString && option) {
+ let regex: any = ''
+ const caseFlag: string = !caseSensitive ? 'i' : ''
+ switch (option) {
+ case 'Single-Match': {
+ regex = new RegExp(stringToHighlight, caseFlag)
+ break
+ }
+ case 'Single-And-StartsWith-Match': {
+ regex = new RegExp("^" + stringToHighlight, caseFlag)
+ break
+ }
+ case 'Multi-Match': {
+ regex = new RegExp(stringToHighlight, 'g' + caseFlag)
+ break
+ }
+ default: {
+ // default will be a global case-insensitive match
+ regex = new RegExp(stringToHighlight, 'gi')
+ }
}
+ const replaced = contentString.replace(
+ regex,
+ (match) => `${match}`
+ )
+ return replaced
+ } else {
+ return contentString
+ }
}
}
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index 6bf345789..560414e90 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -1,5 +1,6 @@
$icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/';
+@import '_bootstrap-variables';
@import '_variables';
@import '_mixins';
@@ -234,7 +235,7 @@ table {
}
}
-@media screen and (max-width: 1600px) {
+@media screen and (max-width: #{map-get($grid-breakpoints, xxl)}) {
.main-col {
&.expanded {
.margin-content {
@@ -245,7 +246,7 @@ table {
}
}
-@media screen and (max-width: 900px) {
+@media screen and (max-width: #{map-get($grid-breakpoints, lg)}) {
.main-col {
&.expanded {
.margin-content {
diff --git a/client/src/sass/bootstrap.scss b/client/src/sass/bootstrap.scss
index be5879b50..e10b84596 100644
--- a/client/src/sass/bootstrap.scss
+++ b/client/src/sass/bootstrap.scss
@@ -52,7 +52,7 @@ $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/';
}
-@media screen and (min-width: 768px) {
+@media screen and (min-width: #{map-get($grid-breakpoints, md)}) {
.modal:before {
vertical-align: middle;
content: " ";
diff --git a/client/src/sass/include/_bootstrap-variables.scss b/client/src/sass/include/_bootstrap-variables.scss
index 7f413836b..b3ab0eb2b 100644
--- a/client/src/sass/include/_bootstrap-variables.scss
+++ b/client/src/sass/include/_bootstrap-variables.scss
@@ -13,8 +13,9 @@ $grid-breakpoints: (
md: 768px,
// Large screen / desktop
lg: 900px,
- // Extra large screen / wide desktop
- xl: 1200px
+ // Extra large screens / wide desktops
+ xl: 1200px,
+ xxl: 1600px
);
$container-max-widths: (
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss
index ed2cacdd1..4766e4490 100644
--- a/client/src/sass/include/_mixins.scss
+++ b/client/src/sass/include/_mixins.scss
@@ -445,7 +445,6 @@
@mixin actor-owner {
@include disable-default-a-behaviour;
- display: inline-table;
font-size: 13px;
margin-top: 4px;
color: var(--mainForegroundColor);
@@ -488,14 +487,15 @@
.actor-names {
display: flex;
align-items: center;
+ flex-wrap: wrap;
.actor-display-name {
font-size: 23px;
font-weight: $font-bold;
+ margin-right: 7px;
}
.actor-name {
- margin-left: 7px;
position: relative;
top: 3px;
font-size: 14px;
@@ -503,6 +503,10 @@
}
}
+ .actor-lower {
+ grid-area: lower;
+ }
+
.actor-followers {
font-size: 15px;
}
@@ -522,6 +526,11 @@
margin-bottom: 0;
text-transform: uppercase;
font-weight: 600;
+ font-size: 110%;
+
+ @media screen and (max-width: $mobile-view) {
+ font-size: 130%;
+ }
}
}
}
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss
index d0e1a8c9c..d8db3f3f8 100644
--- a/client/src/sass/include/_variables.scss
+++ b/client/src/sass/include/_variables.scss
@@ -1,3 +1,5 @@
+@import '_bootstrap-variables';
+
$small-view: 800px;
$mobile-view: 500px;