diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html
index 2660c5377..f5a8dbd34 100644
--- a/client/src/app/app.component.html
+++ b/client/src/app/app.component.html
@@ -15,7 +15,7 @@
diff --git a/client/src/app/header/header.component.html b/client/src/app/header/header.component.html
index 074bebf21..561ee6c16 100644
--- a/client/src/app/header/header.component.html
+++ b/client/src/app/header/header.component.html
@@ -1,9 +1,9 @@
-
+
-
+
diff --git a/client/src/app/header/header.component.scss b/client/src/app/header/header.component.scss
index b602cf0a8..2f0a407fc 100644
--- a/client/src/app/header/header.component.scss
+++ b/client/src/app/header/header.component.scss
@@ -14,14 +14,6 @@ my-search-typeahead {
&::placeholder {
color: var(--inputPlaceholderColor);
}
-
- @media screen and (max-width: 800px) {
- width: calc(100% - 150px);
- }
-
- @media screen and (max-width: 600px) {
- width: calc(100% - 70px);
- }
}
.icon.icon-search {
@@ -45,10 +37,6 @@ my-search-typeahead {
color: var(--mainBackgroundColor) !important;
margin-right: 25px;
- @media screen and (max-width: 800px) {
- margin-right: 0;
- }
-
@media screen and (max-width: 600px) {
margin-right: 10px;
padding: 0 10px;
diff --git a/client/src/app/header/header.component.ts b/client/src/app/header/header.component.ts
index ca4a32cbc..d9311c554 100644
--- a/client/src/app/header/header.component.ts
+++ b/client/src/app/header/header.component.ts
@@ -1,9 +1,4 @@
-import { filter, first, map, tap } from 'rxjs/operators'
import { Component, OnInit } from '@angular/core'
-import { ActivatedRoute, NavigationEnd, Params, Router } from '@angular/router'
-import { getParameterByName } from '../shared/misc/utils'
-import { AuthService } from '@app/core'
-import { of } from 'rxjs'
import { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
@@ -17,46 +12,10 @@ export class HeaderComponent implements OnInit {
ariaLabelTextForSearch = ''
constructor (
- private router: Router,
- private route: ActivatedRoute,
- private auth: AuthService,
private i18n: I18n
) {}
ngOnInit () {
this.ariaLabelTextForSearch = this.i18n('Search videos, channels')
-
- this.router.events
- .pipe(
- filter(e => e instanceof NavigationEnd),
- map(() => getParameterByName('search', window.location.href))
- )
- .subscribe(searchQuery => this.searchValue = searchQuery || '')
- }
-
- doSearch () {
- const queryParams: Params = {}
-
- if (window.location.pathname === '/search' && this.route.snapshot.queryParams) {
- Object.assign(queryParams, this.route.snapshot.queryParams)
- }
-
- Object.assign(queryParams, { search: this.searchValue })
-
- const o = this.auth.isLoggedIn()
- ? this.loadUserLanguagesIfNeeded(queryParams)
- : of(true)
-
- o.subscribe(() => this.router.navigate([ '/search' ], { queryParams }))
- }
-
- private loadUserLanguagesIfNeeded (queryParams: any) {
- if (queryParams && queryParams.languageOneOf) return of(queryParams)
-
- return this.auth.userInformationLoaded
- .pipe(
- first(),
- tap(() => Object.assign(queryParams, { languageOneOf: this.auth.getUser().videoLanguages }))
- )
}
}
diff --git a/client/src/app/header/search-typeahead.component.scss b/client/src/app/header/search-typeahead.component.scss
index c410d4734..c2f5a1828 100644
--- a/client/src/app/header/search-typeahead.component.scss
+++ b/client/src/app/header/search-typeahead.component.scss
@@ -46,6 +46,18 @@ my-suggestions ::ng-deep ul {
transition: box-shadow .3s ease, width .2s ease;
}
+ @media screen and (min-width: 500px) {
+ margin-left: 10px;
+ }
+
+ @media screen and (max-width: 800px) {
+ flex: 1;
+
+ ::ng-deep input {
+ width: unset;
+ }
+ }
+
::ng-deep span {
right: 10px;
}
@@ -59,7 +71,9 @@ my-suggestions ::ng-deep ul {
&:focus,
::ng-deep &:focus-within {
& > div:last-child {
- display: initial !important;
+ @media screen and (min-width: 500px) {
+ display: initial !important;
+ }
#typeahead-help,
#typeahead-instructions,
diff --git a/client/src/app/header/search-typeahead.component.ts b/client/src/app/header/search-typeahead.component.ts
index 084bdd58b..514c04704 100644
--- a/client/src/app/header/search-typeahead.component.ts
+++ b/client/src/app/header/search-typeahead.component.ts
@@ -7,13 +7,15 @@ import {
OnDestroy,
QueryList
} from '@angular/core'
-import { Router, NavigationEnd } from '@angular/router'
+import { Router, NavigationEnd, Params, ActivatedRoute } from '@angular/router'
import { AuthService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
-import { filter } from 'rxjs/operators'
+import { filter, first, tap, map } from 'rxjs/operators'
import { ListKeyManager } from '@angular/cdk/a11y'
import { UP_ARROW, DOWN_ARROW, ENTER, TAB } from '@angular/cdk/keycodes'
-import { SuggestionComponent } from './suggestion.component'
+import { SuggestionComponent, Result } from './suggestion.component'
+import { of } from 'rxjs'
+import { getParameterByName } from '@app/shared/misc/utils'
@Component({
selector: 'my-search-typeahead',
@@ -41,6 +43,7 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
constructor (
private authService: AuthService,
private router: Router,
+ private route: ActivatedRoute,
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.')
@@ -50,12 +53,19 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
ngOnInit () {
this.router.events
- .pipe(filter(event => event instanceof NavigationEnd))
+ .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 || '')
}
ngOnDestroy () {
@@ -82,33 +92,33 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
computeResults () {
this.newSearch = true
- let results = [
- {
- text: 'Maître poney',
- type: 'channel'
- }
- ]
+ let results: Result[] = []
if (this.hasSearch) {
results = [
+ /* Channel search is still unimplemented. Uncomment when it is.
{
text: this.searchInput.value,
type: 'search-channel'
},
+ */
{
text: this.searchInput.value,
- type: 'search-instance'
+ type: 'search-instance',
+ default: true
},
+ /* Global search is still unimplemented. Uncomment when it is.
{
text: this.searchInput.value,
type: 'search-global'
},
+ */
...results
]
}
this.results = results.filter(
- result => {
+ (result: Result) => {
// 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
@@ -118,19 +128,26 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
)
}
+ setEventItems (event: { items: QueryList, index?: number }) {
+ event.items.forEach(e => {
+ if (this.keyboardEventsManager.activeItem && this.keyboardEventsManager.activeItem === e) {
+ this.keyboardEventsManager.activeItem.active = true
+ } else {
+ e.active = false
+ }
+ })
+ }
+
initKeyboardEventsManager (event: { items: QueryList, index?: number }) {
if (this.keyboardEventsManager) this.keyboardEventsManager.change.unsubscribe()
this.keyboardEventsManager = new ListKeyManager(event.items)
if (event.index !== undefined) {
this.keyboardEventsManager.setActiveItem(event.index)
- event.items.forEach(e => e.active = false)
- this.keyboardEventsManager.activeItem.active = true
+ } else {
+ this.keyboardEventsManager.setFirstItemActive()
}
this.keyboardEventsManager.change.subscribe(
- val => {
- event.items.forEach(e => e.active = false)
- this.keyboardEventsManager.activeItem.active = true
- }
+ _ => this.setEventItems(event)
)
}
@@ -141,17 +158,40 @@ export class SearchTypeaheadComponent implements OnInit, OnDestroy, AfterViewIni
handleKeyUp (event: KeyboardEvent, indexSelected?: number) {
event.stopImmediatePropagation()
if (this.keyboardEventsManager) {
- if (event.keyCode === TAB) {
- this.keyboardEventsManager.setNextItemActive()
- return false
- } else if (event.keyCode === DOWN_ARROW || event.keyCode === UP_ARROW) {
+ if (event.keyCode === DOWN_ARROW || event.keyCode === UP_ARROW) {
this.keyboardEventsManager.onKeydown(event)
return false
} else if (event.keyCode === ENTER) {
this.newSearch = false
- // this.router.navigate(this.keyboardEventsManager.activeItem.result)
+ this.doSearch()
return false
}
}
}
+
+ doSearch () {
+ const queryParams: Params = {}
+
+ if (window.location.pathname === '/search' && this.route.snapshot.queryParams) {
+ Object.assign(queryParams, this.route.snapshot.queryParams)
+ }
+
+ Object.assign(queryParams, { search: this.searchInput.value })
+
+ const o = this.authService.isLoggedIn()
+ ? this.loadUserLanguagesIfNeeded(queryParams)
+ : of(true)
+
+ o.subscribe(() => this.router.navigate([ '/search' ], { queryParams }))
+ }
+
+ private loadUserLanguagesIfNeeded (queryParams: any) {
+ if (queryParams && queryParams.languageOneOf) return of(queryParams)
+
+ return this.authService.userInformationLoaded
+ .pipe(
+ first(),
+ tap(() => Object.assign(queryParams, { languageOneOf: this.authService.getUser().videoLanguages }))
+ )
+ }
}
diff --git a/client/src/app/header/suggestion.component.ts b/client/src/app/header/suggestion.component.ts
index 75c44a583..bdcb3e03f 100644
--- a/client/src/app/header/suggestion.component.ts
+++ b/client/src/app/header/suggestion.component.ts
@@ -3,10 +3,11 @@ import { RouterLink } from '@angular/router'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { ListKeyManagerOption } from '@angular/cdk/a11y'
-type Result = {
+export type Result = {
text: string
type: 'channel' | 'suggestion' | 'search-channel' | 'search-instance' | 'search-global' | 'search-any'
- routerLink?: RouterLink
+ routerLink?: RouterLink,
+ default?: boolean
}
@Component({
@@ -39,7 +40,7 @@ export class SuggestionComponent implements OnInit, ListKeyManagerOption {
}
ngOnInit () {
- this.active = false
+ if (this.result.default) this.active = true
}
selectItem () {
diff --git a/client/src/app/header/suggestions.component.ts b/client/src/app/header/suggestions.component.ts
index 122c09388..fac7fe2f9 100644
--- a/client/src/app/header/suggestions.component.ts
+++ b/client/src/app/header/suggestions.component.ts
@@ -19,7 +19,6 @@ export class SuggestionsComponent implements AfterViewInit {
@Output() init = new EventEmitter()
ngAfterViewInit () {
- this.init.emit({ items: this.listItems })
this.listItems.changes.subscribe(
val => this.init.emit({ items: this.listItems })
)
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss
index 43654504c..cb5f90723 100644
--- a/client/src/app/menu/menu.component.scss
+++ b/client/src/app/menu/menu.component.scss
@@ -7,6 +7,7 @@
padding: 0;
width: $menu-width;
z-index: z(menu);
+ scrollbar-color: var(--actionButtonColor) var(--menuBackgroundColor);
}
menu {
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index e4840dd81..4ad14ea5b 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -47,6 +47,11 @@ body {
font-size: 14px;
}
+::selection {
+ color: var(--mainBackgroundColor);
+ background-color: var(--mainHoverColor);
+}
+
#incompatible-browser {
display: none;
text-align: center;