diff options
Diffstat (limited to 'client/src/app')
-rw-r--r-- | client/src/app/about/about-routing.module.ts | 23 | ||||
-rw-r--r-- | client/src/app/about/about.component.html | 17 | ||||
-rw-r--r-- | client/src/app/about/about.component.scss | 12 | ||||
-rw-r--r-- | client/src/app/about/about.component.ts | 38 | ||||
-rw-r--r-- | client/src/app/about/about.module.ts | 24 | ||||
-rw-r--r-- | client/src/app/about/index.ts | 3 | ||||
-rw-r--r-- | client/src/app/app.component.html | 2 | ||||
-rw-r--r-- | client/src/app/app.component.ts | 4 | ||||
-rw-r--r-- | client/src/app/app.module.ts | 2 | ||||
-rw-r--r-- | client/src/app/core/server/server.service.ts | 33 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.html | 9 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.scss | 7 | ||||
-rw-r--r-- | client/src/app/shared/forms/form-validators/custom-config.ts | 2 | ||||
-rw-r--r-- | client/src/app/videos/shared/markdown.service.ts | 3 |
14 files changed, 172 insertions, 7 deletions
diff --git a/client/src/app/about/about-routing.module.ts b/client/src/app/about/about-routing.module.ts new file mode 100644 index 000000000..11a650c80 --- /dev/null +++ b/client/src/app/about/about-routing.module.ts | |||
@@ -0,0 +1,23 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { RouterModule, Routes } from '@angular/router' | ||
3 | import { MetaGuard } from '@ngx-meta/core' | ||
4 | import { AboutComponent } from './about.component' | ||
5 | |||
6 | const aboutRoutes: Routes = [ | ||
7 | { | ||
8 | path: 'about', | ||
9 | component: AboutComponent, | ||
10 | canActivate: [ MetaGuard ], | ||
11 | data: { | ||
12 | meta: { | ||
13 | title: 'About' | ||
14 | } | ||
15 | } | ||
16 | } | ||
17 | ] | ||
18 | |||
19 | @NgModule({ | ||
20 | imports: [ RouterModule.forChild(aboutRoutes) ], | ||
21 | exports: [ RouterModule ] | ||
22 | }) | ||
23 | export class AboutRoutingModule {} | ||
diff --git a/client/src/app/about/about.component.html b/client/src/app/about/about.component.html new file mode 100644 index 000000000..c0be53581 --- /dev/null +++ b/client/src/app/about/about.component.html | |||
@@ -0,0 +1,17 @@ | |||
1 | <div class="margin-content"> | ||
2 | <div class="title-page title-page-single"> | ||
3 | Welcome to the {{ instanceName }} instance | ||
4 | </div> | ||
5 | |||
6 | <div class="description"> | ||
7 | <div class="section-title">Description</div> | ||
8 | |||
9 | <div [innerHTML]="descriptionHTML"></div> | ||
10 | </div> | ||
11 | |||
12 | <div class="terms"> | ||
13 | <div class="section-title">Terms</div> | ||
14 | |||
15 | <div [innerHTML]="termsHTML"></div> | ||
16 | </div> | ||
17 | </div> | ||
diff --git a/client/src/app/about/about.component.scss b/client/src/app/about/about.component.scss new file mode 100644 index 000000000..dba4df729 --- /dev/null +++ b/client/src/app/about/about.component.scss | |||
@@ -0,0 +1,12 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .section-title { | ||
5 | font-weight: $font-semibold; | ||
6 | font-size: 20px; | ||
7 | margin-bottom: 5px; | ||
8 | } | ||
9 | |||
10 | .description { | ||
11 | margin-bottom: 30px; | ||
12 | } | ||
diff --git a/client/src/app/about/about.component.ts b/client/src/app/about/about.component.ts new file mode 100644 index 000000000..6a2e59be1 --- /dev/null +++ b/client/src/app/about/about.component.ts | |||
@@ -0,0 +1,38 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { ServerService } from '@app/core' | ||
3 | import { MarkdownService } from '@app/videos/shared' | ||
4 | import { NotificationsService } from 'angular2-notifications' | ||
5 | |||
6 | @Component({ | ||
7 | selector: 'my-about', | ||
8 | templateUrl: './about.component.html', | ||
9 | styleUrls: [ './about.component.scss' ] | ||
10 | }) | ||
11 | |||
12 | export class AboutComponent implements OnInit { | ||
13 | descriptionHTML = '' | ||
14 | termsHTML = '' | ||
15 | |||
16 | constructor ( | ||
17 | private notificationsService: NotificationsService, | ||
18 | private serverService: ServerService, | ||
19 | private markdownService: MarkdownService | ||
20 | ) {} | ||
21 | |||
22 | get instanceName () { | ||
23 | return this.serverService.getConfig().instance.name | ||
24 | } | ||
25 | |||
26 | ngOnInit () { | ||
27 | this.serverService.getAbout() | ||
28 | .subscribe( | ||
29 | res => { | ||
30 | this.descriptionHTML = this.markdownService.markdownToHTML(res.instance.description) | ||
31 | this.termsHTML = this.markdownService.markdownToHTML(res.instance.terms) | ||
32 | }, | ||
33 | |||
34 | err => this.notificationsService.error('Error', err) | ||
35 | ) | ||
36 | } | ||
37 | |||
38 | } | ||
diff --git a/client/src/app/about/about.module.ts b/client/src/app/about/about.module.ts new file mode 100644 index 000000000..da3163f43 --- /dev/null +++ b/client/src/app/about/about.module.ts | |||
@@ -0,0 +1,24 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | |||
3 | import { AboutRoutingModule } from './about-routing.module' | ||
4 | import { AboutComponent } from './about.component' | ||
5 | import { SharedModule } from '../shared' | ||
6 | |||
7 | @NgModule({ | ||
8 | imports: [ | ||
9 | AboutRoutingModule, | ||
10 | SharedModule | ||
11 | ], | ||
12 | |||
13 | declarations: [ | ||
14 | AboutComponent | ||
15 | ], | ||
16 | |||
17 | exports: [ | ||
18 | AboutComponent | ||
19 | ], | ||
20 | |||
21 | providers: [ | ||
22 | ] | ||
23 | }) | ||
24 | export class AboutModule { } | ||
diff --git a/client/src/app/about/index.ts b/client/src/app/about/index.ts new file mode 100644 index 000000000..218d09801 --- /dev/null +++ b/client/src/app/about/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './about-routing.module' | ||
2 | export * from './about.component' | ||
3 | export * from './about.module' | ||
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index ba7debc71..3a7aedac6 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | <a id="peertube-title" [routerLink]="['/videos/list']" title="Homepage"> | 7 | <a id="peertube-title" [routerLink]="['/videos/list']" title="Homepage"> |
8 | <span class="icon icon-logo"></span> | 8 | <span class="icon icon-logo"></span> |
9 | PeerTube | 9 | {{ instanceName }} |
10 | </a> | 10 | </a> |
11 | </div> | 11 | </div> |
12 | 12 | ||
diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 55c7bbf99..121e60ffc 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts | |||
@@ -34,6 +34,10 @@ export class AppComponent implements OnInit { | |||
34 | return this.serverService.getConfig().serverVersion | 34 | return this.serverService.getConfig().serverVersion |
35 | } | 35 | } |
36 | 36 | ||
37 | get instanceName () { | ||
38 | return this.serverService.getConfig().instance.name | ||
39 | } | ||
40 | |||
37 | ngOnInit () { | 41 | ngOnInit () { |
38 | this.authService.loadClientCredentials() | 42 | this.authService.loadClientCredentials() |
39 | 43 | ||
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index ddcaf3f48..1134d061b 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { BrowserModule } from '@angular/platform-browser' | 2 | import { BrowserModule } from '@angular/platform-browser' |
3 | import { AboutModule } from '@app/about' | ||
3 | import { ResetPasswordModule } from '@app/reset-password' | 4 | import { ResetPasswordModule } from '@app/reset-password' |
4 | 5 | ||
5 | import { MetaLoader, MetaModule, MetaStaticLoader, PageTitlePositioning } from '@ngx-meta/core' | 6 | import { MetaLoader, MetaModule, MetaStaticLoader, PageTitlePositioning } from '@ngx-meta/core' |
@@ -51,6 +52,7 @@ export function metaFactory (): MetaLoader { | |||
51 | SignupModule, | 52 | SignupModule, |
52 | SharedModule, | 53 | SharedModule, |
53 | VideosModule, | 54 | VideosModule, |
55 | AboutModule, | ||
54 | 56 | ||
55 | MetaModule.forRoot({ | 57 | MetaModule.forRoot({ |
56 | provide: MetaLoader, | 58 | provide: MetaLoader, |
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 6df449018..65714fd05 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts | |||
@@ -3,12 +3,14 @@ import { Injectable } from '@angular/core' | |||
3 | import 'rxjs/add/operator/do' | 3 | import 'rxjs/add/operator/do' |
4 | import { ReplaySubject } from 'rxjs/ReplaySubject' | 4 | import { ReplaySubject } from 'rxjs/ReplaySubject' |
5 | import { ServerConfig } from '../../../../../shared' | 5 | import { ServerConfig } from '../../../../../shared' |
6 | import { About } from '../../../../../shared/models/config/about.model' | ||
6 | import { environment } from '../../../environments/environment' | 7 | import { environment } from '../../../environments/environment' |
7 | 8 | ||
8 | @Injectable() | 9 | @Injectable() |
9 | export class ServerService { | 10 | export class ServerService { |
10 | private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/' | 11 | private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/' |
11 | private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' | 12 | private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' |
13 | private static CONFIG_LOCAL_STORAGE_KEY = 'server-config' | ||
12 | 14 | ||
13 | videoPrivaciesLoaded = new ReplaySubject<boolean>(1) | 15 | videoPrivaciesLoaded = new ReplaySubject<boolean>(1) |
14 | videoCategoriesLoaded = new ReplaySubject<boolean>(1) | 16 | videoCategoriesLoaded = new ReplaySubject<boolean>(1) |
@@ -16,6 +18,9 @@ export class ServerService { | |||
16 | videoLanguagesLoaded = new ReplaySubject<boolean>(1) | 18 | videoLanguagesLoaded = new ReplaySubject<boolean>(1) |
17 | 19 | ||
18 | private config: ServerConfig = { | 20 | private config: ServerConfig = { |
21 | instance: { | ||
22 | name: 'PeerTube' | ||
23 | }, | ||
19 | serverVersion: 'Unknown', | 24 | serverVersion: 'Unknown', |
20 | signup: { | 25 | signup: { |
21 | allowed: false | 26 | allowed: false |
@@ -40,11 +45,14 @@ export class ServerService { | |||
40 | private videoLanguages: Array<{ id: number, label: string }> = [] | 45 | private videoLanguages: Array<{ id: number, label: string }> = [] |
41 | private videoPrivacies: Array<{ id: number, label: string }> = [] | 46 | private videoPrivacies: Array<{ id: number, label: string }> = [] |
42 | 47 | ||
43 | constructor (private http: HttpClient) {} | 48 | constructor (private http: HttpClient) { |
49 | this.loadConfigLocally() | ||
50 | } | ||
44 | 51 | ||
45 | loadConfig () { | 52 | loadConfig () { |
46 | this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL) | 53 | this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL) |
47 | .subscribe(data => this.config = data) | 54 | .do(this.saveConfigLocally) |
55 | .subscribe(data => this.config = data) | ||
48 | } | 56 | } |
49 | 57 | ||
50 | loadVideoCategories () { | 58 | loadVideoCategories () { |
@@ -83,6 +91,10 @@ export class ServerService { | |||
83 | return this.videoPrivacies | 91 | return this.videoPrivacies |
84 | } | 92 | } |
85 | 93 | ||
94 | getAbout () { | ||
95 | return this.http.get<About>(ServerService.BASE_CONFIG_URL + '/about') | ||
96 | } | ||
97 | |||
86 | private loadVideoAttributeEnum ( | 98 | private loadVideoAttributeEnum ( |
87 | attributeName: 'categories' | 'licences' | 'languages' | 'privacies', | 99 | attributeName: 'categories' | 'licences' | 'languages' | 'privacies', |
88 | hashToPopulate: { id: number, label: string }[], | 100 | hashToPopulate: { id: number, label: string }[], |
@@ -101,4 +113,21 @@ export class ServerService { | |||
101 | notifier.next(true) | 113 | notifier.next(true) |
102 | }) | 114 | }) |
103 | } | 115 | } |
116 | |||
117 | private saveConfigLocally (config: ServerConfig) { | ||
118 | localStorage.setItem(ServerService.CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config)) | ||
119 | } | ||
120 | |||
121 | private loadConfigLocally () { | ||
122 | const configString = localStorage.getItem(ServerService.CONFIG_LOCAL_STORAGE_KEY) | ||
123 | |||
124 | if (configString) { | ||
125 | try { | ||
126 | const parsed = JSON.parse(configString) | ||
127 | Object.assign(this.config, parsed) | ||
128 | } catch (err) { | ||
129 | console.error('Cannot parse config saved in local storage.', err) | ||
130 | } | ||
131 | } | ||
132 | } | ||
104 | } | 133 | } |
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index 94f82e352..d174c76ba 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -45,12 +45,17 @@ | |||
45 | </a> | 45 | </a> |
46 | </div> | 46 | </div> |
47 | 47 | ||
48 | <div *ngIf="userHasAdminAccess" class="panel-block"> | 48 | <div class="panel-block"> |
49 | <div class="block-title">More</div> | 49 | <div class="block-title">More</div> |
50 | 50 | ||
51 | <a [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active"> | 51 | <a *ngIf="userHasAdminAccess" [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active"> |
52 | <span class="icon icon-administration"></span> | 52 | <span class="icon icon-administration"></span> |
53 | Administration | 53 | Administration |
54 | </a> | 54 | </a> |
55 | |||
56 | <a routerLink="/about" routerLinkActive="active"> | ||
57 | <span class="icon icon-about"></span> | ||
58 | About | ||
59 | </a> | ||
55 | </div> | 60 | </div> |
56 | </menu> | 61 | </menu> |
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss index 4714a9e87..1f3c889cf 100644 --- a/client/src/app/menu/menu.component.scss +++ b/client/src/app/menu/menu.component.scss | |||
@@ -132,6 +132,13 @@ menu { | |||
132 | 132 | ||
133 | background-image: url('../../assets/images/menu/administration.svg'); | 133 | background-image: url('../../assets/images/menu/administration.svg'); |
134 | } | 134 | } |
135 | |||
136 | &.icon-about { | ||
137 | width: 23px; | ||
138 | height: 23px; | ||
139 | |||
140 | background-image: url('../../assets/images/menu/about.svg'); | ||
141 | } | ||
135 | } | 142 | } |
136 | } | 143 | } |
137 | } | 144 | } |
diff --git a/client/src/app/shared/forms/form-validators/custom-config.ts b/client/src/app/shared/forms/form-validators/custom-config.ts index 9e3fa98d8..a0966a9a7 100644 --- a/client/src/app/shared/forms/form-validators/custom-config.ts +++ b/client/src/app/shared/forms/form-validators/custom-config.ts | |||
@@ -3,7 +3,7 @@ import { Validators } from '@angular/forms' | |||
3 | export const INSTANCE_NAME = { | 3 | export const INSTANCE_NAME = { |
4 | VALIDATORS: [ Validators.required ], | 4 | VALIDATORS: [ Validators.required ], |
5 | MESSAGES: { | 5 | MESSAGES: { |
6 | 'required': 'Instance name is required.', | 6 | 'required': 'Instance name is required.' |
7 | } | 7 | } |
8 | } | 8 | } |
9 | 9 | ||
diff --git a/client/src/app/videos/shared/markdown.service.ts b/client/src/app/videos/shared/markdown.service.ts index fd0330f9b..3f51a82ce 100644 --- a/client/src/app/videos/shared/markdown.service.ts +++ b/client/src/app/videos/shared/markdown.service.ts | |||
@@ -7,12 +7,13 @@ export class MarkdownService { | |||
7 | private markdownIt: MarkdownIt.MarkdownIt | 7 | private markdownIt: MarkdownIt.MarkdownIt |
8 | 8 | ||
9 | constructor () { | 9 | constructor () { |
10 | this.markdownIt = new MarkdownIt('zero', { linkify: true }) | 10 | this.markdownIt = new MarkdownIt('zero', { linkify: true, breaks: true }) |
11 | .enable('linkify') | 11 | .enable('linkify') |
12 | .enable('autolink') | 12 | .enable('autolink') |
13 | .enable('emphasis') | 13 | .enable('emphasis') |
14 | .enable('link') | 14 | .enable('link') |
15 | .enable('newline') | 15 | .enable('newline') |
16 | .enable('list') | ||
16 | 17 | ||
17 | this.setTargetToLinks() | 18 | this.setTargetToLinks() |
18 | } | 19 | } |