Skip to content

Commit

Permalink
Redesign about pages
Browse files Browse the repository at this point in the history
  • Loading branch information
Chocobozzz committed Jan 9, 2025
1 parent fa7d8c0 commit f4d6cec
Show file tree
Hide file tree
Showing 81 changed files with 1,814 additions and 930 deletions.
56 changes: 56 additions & 0 deletions client/src/app/+about/about-contact/about-contact.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<div class="margin-content mt-4">
<h3 class="fs-3 fw-semibold mb-3" i18n>Contact {{ instanceName }} administrators</h3>

@if (isContactFormEnabled()) {
@if (!success) {
<form novalidate [formGroup]="form" (ngSubmit)="sendForm()">
<div class="form-group">
<label i18n for="fromName">Your name</label>
<input
type="text" id="fromName" class="form-control"
formControlName="fromName" [ngClass]="{ 'input-error': formErrors.fromName }"
autocomplete="name"
>

<div *ngIf="formErrors.fromName" class="form-error" role="alert">{{ formErrors.fromName }}</div>
</div>

<div class="form-group">
<label i18n for="fromEmail">Your email</label>
<input
type="text" id="fromEmail" class="form-control"
formControlName="fromEmail" [ngClass]="{ 'input-error': formErrors['fromEmail'] }"
i18n-placeholder placeholder="Example: [email protected]" autocomplete="email"
>

<div *ngIf="formErrors.fromEmail" class="form-error" role="alert">{{ formErrors.fromEmail }}</div>
</div>

<div class="form-group">
<label i18n for="subject">Subject</label>
<input
type="text" id="subject" class="form-control"
formControlName="subject" [ngClass]="{ 'input-error': formErrors['subject'] }"
>

<div *ngIf="formErrors.subject" class="form-error" role="alert">{{ formErrors.subject }}</div>
</div>

<div class="form-group">
<label i18n for="body">Your message</label>
<textarea id="body" formControlName="body" class="form-control" [ngClass]="{ 'input-error': formErrors['body'] }"></textarea>

<div *ngIf="formErrors.body" class="form-error" role="alert">{{ formErrors.body }}</div>
</div>

<my-alert *ngIf="error" type="danger">{{ error }}</my-alert>

<input type="submit" i18n-value value="Submit" class="peertube-button primary-button" [disabled]="!form.valid" />
</form>
} @else {
<my-alert type="success">{{ success }}</my-alert>
}
} @else {
<my-alert type="danger" i18n>The contact form is not enabled on this instance.</my-alert>
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,10 @@
@use '_mixins' as *;
@use '_form-mixins' as *;

.modal-subtitle {
line-height: 1rem;
margin-bottom: 0;
}

.modal-body {
text-align: left;
}

input[type=text] {
@include peertube-input-text(340px);
}

textarea {
@include peertube-textarea(100%, 200px);
@include peertube-textarea(500px, 200px);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { NgClass, NgIf } from '@angular/common'
import { Component, OnInit, ViewChild } from '@angular/core'
import { Component, OnInit } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { Router } from '@angular/router'
import { Notifier, ServerService } from '@app/core'
import { ActivatedRoute } from '@angular/router'
import { ServerService } from '@app/core'
import {
BODY_VALIDATOR,
FROM_EMAIL_VALIDATOR,
Expand All @@ -13,38 +13,30 @@ import { FormReactive } from '@app/shared/shared-forms/form-reactive'
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
import { InstanceService } from '@app/shared/shared-main/instance/instance.service'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { HTMLServerConfig, HttpStatusCode } from '@peertube/peertube-models'
import { GlobalIconComponent } from '../../shared/shared-icons/global-icon.component'

type Prefill = {
subject?: string
body?: string
}

@Component({
selector: 'my-contact-admin-modal',
templateUrl: './contact-admin-modal.component.html',
styleUrls: [ './contact-admin-modal.component.scss' ],
templateUrl: './about-contact.component.html',
styleUrls: [ './about-contact.component.scss' ],
standalone: true,
imports: [ GlobalIconComponent, NgIf, FormsModule, ReactiveFormsModule, NgClass, AlertComponent ]
imports: [ NgIf, FormsModule, ReactiveFormsModule, NgClass, AlertComponent ]
})
export class ContactAdminModalComponent extends FormReactive implements OnInit {
@ViewChild('modal', { static: true }) modal: NgbModal

export class AboutContactComponent extends FormReactive implements OnInit {
error: string
success: string

private openedModal: NgbModalRef
private serverConfig: HTMLServerConfig

constructor (
protected formReactiveService: FormReactiveService,
private router: Router,
private modalService: NgbModal,
private route: ActivatedRoute,
private instanceService: InstanceService,
private serverService: ServerService,
private notifier: Notifier
private serverService: ServerService
) {
super()
}
Expand All @@ -62,27 +54,14 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
subject: SUBJECT_VALIDATOR,
body: BODY_VALIDATOR
})

this.prefillForm(this.route.snapshot.queryParams)
}

isContactFormEnabled () {
return this.serverConfig.email.enabled && this.serverConfig.contactForm.enabled
}

show (prefill: Prefill = {}) {
this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false })

this.openedModal.shown.subscribe(() => this.prefillForm(prefill))
this.openedModal.result.finally(() => this.router.navigateByUrl('/about/instance'))
}

hide () {
this.form.reset()
this.error = undefined

this.openedModal.close()
this.openedModal = null
}

sendForm () {
const fromName = this.form.value['fromName']
const fromEmail = this.form.value['fromEmail']
Expand All @@ -92,8 +71,7 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
this.instanceService.contactAdministrator(fromEmail, fromName, subject, body)
.subscribe({
next: () => {
this.notifier.success($localize`Your message has been sent.`)
this.hide()
this.success = $localize`Your message has been sent.`
},

error: err => {
Expand Down
85 changes: 68 additions & 17 deletions client/src/app/+about/about-follows/about-follows.component.html
Original file line number Diff line number Diff line change
@@ -1,30 +1,81 @@
<div class="margin-content mt-4">
<div class="row">
<h1 class="visually-hidden" i18n>Follows</h1>
<div class="margin-content mt-5">

<div class="col-xl-6 col-md-12">
<h2 i18n class="fs-5-5 mb-4 fw-semibold">Followers of {{ instanceName }} ({{ followersPagination.totalItems }})</h2>
<div class="subscriptions me-3 mb-3">
<div class="block-header mb-4 d-flex">
<div class="flex-grow-1 me-2">
<h3 i18n>{{ subscriptionsPagination.totalItems }} {subscriptionsPagination.totalItems, plural, =1 {subscription} other {subscriptions}}</h3>

<div i18n class="no-results" *ngIf="followersPagination.totalItems === 0">{{ instanceName }} does not have followers.</div>
<div i18n class="text-content">
This is content to which we have subscribed. This allows us to display their videos directly on {{ instanceName }}.
</div>
</div>

<my-subscription-image></my-subscription-image>
</div>

<div class="follows">
<div i18n class="no-results" *ngIf="subscriptionsPagination.totalItems === 0">{{ instanceName }} does not have subscriptions.</div>

<a *ngFor="let follower of followers" [href]="follower.url" target="_blank" rel="noopener noreferrer">
{{ follower.name }}
</a>
<div *ngFor="let subscription of subscriptions" class="follow-block">
<my-actor-avatar [actor]="subscription" actorType="channel" size="32"></my-actor-avatar>

<button i18n class="peertube-button-link secondary-button mt-1" *ngIf="!loadedAllFollowers && canLoadMoreFollowers()" (click)="loadAllFollowers()">Show full list</button>
<div>
<a class="follow-name" [href]="subscription.url" target="_blank" rel="noopener noreferrer">{{ subscription.name }}</a>
</div>
</div>

</div>

<div class="text-center">
<my-button *ngIf="canLoadMoreSubscriptions()" class="mt-3 mx-auto" (click)="loadMoreSubscriptions()" theme="secondary" i18n>Show more subscriptions</my-button>
</div>

<div class="col-xl-6 col-md-12">
<h2 i18n class="fs-5-5 mb-4 fw-semibold">Subscriptions of {{ instanceName }} ({{ followingsPagination.totalItems }})</h2>
<div *ngIf="serverStats" class="stats mt-4">
<h4 i18n>Our network in figures</h4>

<div myPluginSelector pluginSelectorId="about-instance-network-statistics">
<div class="stat">
<strong>{{ serverStats.totalVideos | number }}</strong>
<a routerLink="/videos/browse" [queryParams]="{ scope: 'federated' }" i18n>total videos</a>
<my-global-icon iconName="videos"></my-global-icon>
</div>

<div i18n class="no-results" *ngIf="followingsPagination.totalItems === 0">{{ instanceName }} does not have subscriptions.</div>
<div class="stat">
<strong>{{ serverStats.totalVideoComments | number }}</strong>
<div i18n>total comments</div>
<my-global-icon iconName="message-circle"></my-global-icon>
</div>
</div>
</div>
</div>

<a *ngFor="let following of followings" [href]="following.url" target="_blank" rel="noopener noreferrer">
{{ following.name }}
</a>
<div class="followers">
<div class="block-header mb-4 d-flex">
<div class="flex-grow-1 me-2">
<h3 i18n>{{ followersPagination.totalItems }} {followersPagination.totalItems, plural, =1 {follower} other {followers}}</h3>

<button i18n class="peertube-button-link secondary-button mt-1" *ngIf="!loadedAllFollowings && canLoadMoreFollowings()" (click)="loadAllFollowings()">Show full list</button>
<div i18n class="text-content">
Our subscribers automatically display videos of {{ instanceName }} on their platforms.
</div>
</div>

<my-follower-image></my-follower-image>
</div>

<div class="follows">
<div i18n class="no-results" *ngIf="followersPagination.totalItems === 0">{{ instanceName }} does not have followers.</div>

<div *ngFor="let follower of followers" class="follow-block">
<my-actor-avatar [actor]="follower" actorType="channel" size="32"></my-actor-avatar>

<div>
<a class="follow-name" [href]="follower.url" target="_blank" rel="noopener noreferrer">{{ follower.name }}</a>
</div>
</div>

<div class="text-center">
<my-button *ngIf="canLoadMoreFollowers()" class="mt-3 mx-auto" (click)="loadMoreFollowers()" theme="secondary" i18n>Show more followers</my-button>
</div>
</div>
</div>
</div>
86 changes: 79 additions & 7 deletions client/src/app/+about/about-follows/about-follows.component.scss
Original file line number Diff line number Diff line change
@@ -1,13 +1,85 @@
@use '_variables' as *;
@use '_mixins' as *;
@use '_bootstrap-variables' as *;
@use '_components' as *;

a {
display: block;
width: fit-content;
margin-top: 3px;
.margin-content {
display: flex;
}

.no-results {
justify-content: flex-start;
align-items: flex-start;
.text-content {
color: pvar(--fg-300);
}

.stat {
@include stats-card;
}

.stats > div {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}

.followers,
.subscriptions {
flex-basis: 50%;
background-color: pvar(--bg-secondary-400);
padding: 1.5rem;
border-radius: 14px;

h3 {
font-weight: $font-bold;
color: pvar(--fg-400);

@include font-size(2rem);
}

h4 {
color: pvar(--fg-300);
font-weight: $font-bold;

@include font-size(1.25rem);
}
}

.follows {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}

.follow-block {
width: calc(50% - 1rem);
padding: 1rem;
border-radius: 8px;
background-color: pvar(--bg-secondary-450);
display: flex;
align-items: center;

my-actor-avatar {
@include margin-right(1rem);
}
}

.follow-name {
font-weight: $font-bold;
color: pvar(--fg-400);
}

@media screen and (max-width: #{breakpoint(xl)}) {
.margin-content {
flex-wrap: wrap;
}

.followers,
.subscriptions {
flex-basis: 100%;
}
}

@include on-small-main-col {
.follow-block {
width: 100%;
}
}
Loading

0 comments on commit f4d6cec

Please sign in to comment.