Add ability to filter menu links

pull/4176/head
Chocobozzz 2021-06-07 13:16:50 +02:00
parent 9cc4b9c61f
commit 8beea2d37d
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
7 changed files with 135 additions and 100 deletions

View File

@ -82,6 +82,7 @@ export class EditBasicConfigurationComponent implements OnInit, OnChanges {
buildLandingPageOptions () {
this.defaultLandingPageOptions = this.menuService.buildCommonLinks(this.serverConfig)
.links
.map(o => ({
id: o.path,
label: o.label,

View File

@ -2,16 +2,23 @@ import { fromEvent } from 'rxjs'
import { debounceTime } from 'rxjs/operators'
import { Injectable } from '@angular/core'
import { GlobalIconName } from '@app/shared/shared-icons'
import { sortObjectComparator } from '@shared/core-utils/miscs/miscs'
import { HTMLServerConfig } from '@shared/models/server'
import { ScreenService } from '../wrappers'
export type MenuLink = {
icon: GlobalIconName
label: string
menuLabel: string
// Used by the left menu for example
shortLabel: string
path: string
priority: number
}
export type MenuSection = {
key: string
title: string
links: MenuLink[]
}
@Injectable()
@ -59,51 +66,90 @@ export class MenuService {
this.isMenuDisplayed = window.innerWidth >= 800 && !this.isMenuChangedByUser
}
buildCommonLinks (config: HTMLServerConfig) {
let entries: MenuLink[] = [
buildLibraryLinks (userCanSeeVideosLink: boolean): MenuSection {
let links: MenuLink[] = []
if (userCanSeeVideosLink) {
links.push({
path: '/my-library/videos',
icon: 'videos' as GlobalIconName,
shortLabel: $localize`Videos`,
label: $localize`My videos`
})
}
links = links.concat([
{
path: '/my-library/video-playlists',
icon: 'playlists' as GlobalIconName,
shortLabel: $localize`Playlists`,
label: $localize`My playlists`
},
{
path: '/videos/subscriptions',
icon: 'subscriptions' as GlobalIconName,
shortLabel: $localize`Subscriptions`,
label: $localize`My subscriptions`
},
{
path: '/my-library/history/videos',
icon: 'history' as GlobalIconName,
shortLabel: $localize`History`,
label: $localize`My history`
}
])
return {
key: 'in-my-library',
title: 'In my library',
links
}
}
buildCommonLinks (config: HTMLServerConfig): MenuSection {
let links: MenuLink[] = []
if (config.homepage.enabled) {
links.push({
icon: 'home' as 'home',
label: $localize`Home`,
shortLabel: $localize`Home`,
path: '/home'
})
}
links = links.concat([
{
icon: 'globe' as 'globe',
label: $localize`Discover videos`,
menuLabel: $localize`Discover`,
path: '/videos/overview',
priority: 150
shortLabel: $localize`Discover`,
path: '/videos/overview'
},
{
icon: 'trending' as 'trending',
label: $localize`Trending videos`,
menuLabel: $localize`Trending`,
path: '/videos/trending',
priority: 140
shortLabel: $localize`Trending`,
path: '/videos/trending'
},
{
icon: 'recently-added' as 'recently-added',
label: $localize`Recently added videos`,
menuLabel: $localize`Recently added`,
path: '/videos/recently-added',
priority: 130
shortLabel: $localize`Recently added`,
path: '/videos/recently-added'
},
{
icon: 'local' as 'local',
label: $localize`Local videos`,
menuLabel: $localize`Local videos`,
path: '/videos/local',
priority: 120
shortLabel: $localize`Local videos`,
path: '/videos/local'
}
]
])
if (config.homepage.enabled) {
entries.push({
icon: 'home' as 'home',
label: $localize`Home`,
menuLabel: $localize`Home`,
path: '/home',
priority: 160
})
return {
key: 'on-instance',
title: $localize`ON ${config.instance.name}`,
links
}
entries = entries.sort(sortObjectComparator('priority', 'desc'))
return entries
}
private handleWindowResize () {

View File

@ -95,39 +95,16 @@
<a i18n *ngIf="isRegistrationAllowed()" routerLink="/signup" class="peertube-button-link create-account-button">Create an account</a>
</div>
<div *ngIf="isLoggedIn" class="in-my-library">
<div i18n class="block-title">IN MY LIBRARY</div>
<ng-container *ngFor="let menuSection of menuSections" >
<div [ngClass]="[ menuSection.key, 'menu-block' ]">
<div i18n class="block-title">{{ menuSection.title }}</div>
<a *ngIf="user.canSeeVideosLink" class="menu-link" routerLink="/my-library/videos" routerLinkActive="active">
<my-global-icon iconName="videos" aria-hidden="true"></my-global-icon>
<ng-container i18n>Videos</ng-container>
</a>
<a class="menu-link" routerLink="/my-library/video-playlists" routerLinkActive="active">
<my-global-icon iconName="playlists" aria-hidden="true"></my-global-icon>
<ng-container i18n>Playlists</ng-container>
</a>
<a class="menu-link" routerLink="/videos/subscriptions" routerLinkActive="active">
<my-global-icon iconName="subscriptions" aria-hidden="true"></my-global-icon>
<ng-container i18n>Subscriptions</ng-container>
</a>
<a class="menu-link" routerLink="/my-library/history/videos" routerLinkActive="active">
<my-global-icon iconName="history" aria-hidden="true"></my-global-icon>
<ng-container i18n>History</ng-container>
</a>
</div>
<div class="on-instance">
<div i18n class="block-title">ON {{instanceName}}</div>
<a class="menu-link" *ngFor="let commonLink of commonMenuLinks" [routerLink]="commonLink.path" routerLinkActive="active">
<my-global-icon [iconName]="commonLink.icon" aria-hidden="true"></my-global-icon>
<ng-container>{{ commonLink.menuLabel }}</ng-container>
</a>
</div>
<a class="menu-link" *ngFor="let link of menuSection.links" [routerLink]="link.path" routerLinkActive="active">
<my-global-icon [iconName]="link.icon" aria-hidden="true"></my-global-icon>
<ng-container>{{ link.shortLabel }}</ng-container>
</a>
</div>
</ng-container>
</div>
<div class="footer">

View File

@ -274,8 +274,7 @@ my-actor-avatar {
}
}
.in-my-library,
.on-instance,
.menu-block,
.footer-block {
margin-bottom: 15px;

View File

@ -8,7 +8,8 @@ import {
AuthService,
AuthStatus,
AuthUser,
MenuLink,
HooksService,
MenuSection,
MenuService,
RedirectService,
ScreenService,
@ -45,7 +46,7 @@ export class MenuComponent implements OnInit {
currentInterfaceLanguage: string
commonMenuLinks: MenuLink[] = []
menuSections: MenuSection[] = []
private languages: VideoConstant<string>[] = []
@ -71,7 +72,8 @@ export class MenuComponent implements OnInit {
private screenService: ScreenService,
private menuService: MenuService,
private modalService: PeertubeModalService,
private router: Router
private router: Router,
private hooks: HooksService
) { }
get isInMobileView () {
@ -88,46 +90,23 @@ export class MenuComponent implements OnInit {
return this.languageChooserModal.getCurrentLanguage()
}
get instanceName () {
return this.htmlServerConfig.instance.name
}
ngOnInit () {
this.htmlServerConfig = this.serverService.getHTMLConfig()
this.buildMenuLinks()
this.isLoggedIn = this.authService.isLoggedIn()
if (this.isLoggedIn === true) {
this.user = this.authService.getUser()
this.computeNSFWPolicy()
this.computeVideosLink()
}
this.computeAdminAccess()
this.currentInterfaceLanguage = this.languageChooserModal.getCurrentLanguage()
this.updateUserState()
this.buildMenuSections()
this.authService.loginChangedSource.subscribe(
status => {
if (status === AuthStatus.LoggedIn) {
this.isLoggedIn = true
this.user = this.authService.getUser()
this.computeAdminAccess()
this.computeVideosLink()
logger('Logged in.')
} else if (status === AuthStatus.LoggedOut) {
this.isLoggedIn = false
this.user = undefined
this.computeAdminAccess()
logger('Logged out.')
} else {
console.error('Unknown auth status: ' + status)
}
this.updateUserState()
this.buildMenuSections()
}
)
@ -257,8 +236,20 @@ export class MenuComponent implements OnInit {
}
}
private buildMenuLinks () {
this.commonMenuLinks = this.menuService.buildCommonLinks(this.htmlServerConfig)
private async buildMenuSections () {
const menuSections = []
if (this.isLoggedIn) {
menuSections.push(
this.menuService.buildLibraryLinks(this.user?.canSeeVideosLink)
)
}
menuSections.push(
this.menuService.buildCommonLinks(this.htmlServerConfig)
)
this.menuSections = await this.hooks.wrapObject(menuSections, 'common', 'filter:left-menu.links.create.result')
}
private buildUserLanguages () {
@ -268,7 +259,7 @@ export class MenuComponent implements OnInit {
}
if (!this.user.videoLanguages) {
this.videoLanguages = [$localize`any language`]
this.videoLanguages = [ $localize`any language` ]
return
}
@ -284,6 +275,8 @@ export class MenuComponent implements OnInit {
}
private computeVideosLink () {
if (!this.isLoggedIn) return
this.authService.userInformationLoaded
.pipe(
switchMap(() => this.user.computeCanSeeVideosLink(this.userService.getMyVideoQuotaUsed()))
@ -313,4 +306,14 @@ export class MenuComponent implements OnInit {
break
}
}
private updateUserState () {
this.user = this.isLoggedIn
? this.authService.getUser()
: undefined
this.computeAdminAccess()
this.computeNSFWPolicy()
this.computeVideosLink()
}
}

View File

@ -50,7 +50,10 @@ export const clientFilterHookObject = {
// Filter our SVG icons content
'filter:internal.common.svg-icons.get-content.params': true,
'filter:internal.common.svg-icons.get-content.result': true
'filter:internal.common.svg-icons.get-content.result': true,
// Filter left menu links
'filter:left-menu.links.create.result': true
}
export type ClientFilterHookName = keyof typeof clientFilterHookObject

View File

@ -29,6 +29,7 @@
- [Add custom fields to video form](#add-custom-fields-to-video-form)
- [Register settings script](#register-settings-script)
- [HTML placeholder elements](#html-placeholder-elements)
- [Add/remove left menu links](#addremove-left-menu-links)
- [Publishing](#publishing)
- [Write a plugin/theme](#write-a-plugintheme)
- [Clone the quickstart repository](#clone-the-quickstart-repository)
@ -744,6 +745,11 @@ async function register (...) {
See the complete list on https://docs.joinpeertube.org/api-plugins
#### Add/remove left menu links
Left menu links can be filtered (add/remove a section or add/remove links) using the `filter:left-menu.links.create.result` client hook.
### Publishing
PeerTube plugins and themes should be published on [NPM](https://www.npmjs.com/) so that PeerTube indexes