autowp/autowp-frontend

View on GitHub
src/app/about/about.component.ts

Summary

Maintainability
A
0 mins
Test Coverage
import {AsyncPipe, DecimalPipe} from '@angular/common';
import {Component, inject, OnInit} from '@angular/core';
import {Router, RouterLink} from '@angular/router';
import {APIUser} from '@grpc/spec.pb';
import {StatisticsClient} from '@grpc/spec.pbsc';
import {Empty} from '@ngx-grpc/well-known-types';
import {PageEnvService} from '@services/page-env.service';
import {UserService} from '@services/user';
import escapeStringRegexp from 'escape-string-regexp';
import {BytesPipe} from 'ngx-pipes';
import {map, switchMap} from 'rxjs/operators';
import showdown from 'showdown';
 
import * as versionJson from '../../version.json';
 
function replaceAll(str: string, find: string, replace: string): string {
return str.replace(new RegExp(escapeStringRegexp(find), 'g'), replace);
}
 
function replacePairs(str: string, pairs: {[key: string]: string}): string {
for (const key in pairs) {
str = replaceAll(str, String(key), pairs[key]);
}
return str;
}
 
const aboutText = $localize`### People
 
Π‘Π²ΠΎΠΈΠΌ сущСствованиСм наш ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ обязан людям, приходящим сюда ΠΈ Π²ΠΊΠ»Π°Π΄Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΌ своё врСмя ΠΈ знания.
 
ΠšΡ‚ΠΎ-Ρ‚ΠΎ добавляСт ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹, Π° ΠΊΡ‚ΠΎ-Ρ‚ΠΎ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ Π½Π°ΠΉΡ‚ΠΈ ошибки Π² ΡƒΠΆΠ΅ ΠΈΠΌΠ΅ΡŽΡ‰ΠΈΡ…ΡΡ. ΠšΡ‚ΠΎ-Ρ‚ΠΎ спСциализируСтся Π½Π° ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ ΠΌΠ°Ρ€ΠΊΠ΅, Π° ΠΊΡ‚ΠΎ-Ρ‚ΠΎ успСваСт Π·Π° всСм. ΠšΡ‚ΠΎ-Ρ‚ΠΎ Π±Π΅Π· лишнСго внимания со стороны наполняСт сайт шаг Π·Π° шагом, Π° ΠΊΡ‚ΠΎ-Ρ‚ΠΎ собираСт ΠΎΠ²Π°Ρ†ΠΈΠΈ Ρ€Π΅Π΄ΠΊΠΈΠΌΠΈ, Π½ΠΎ ΠΆΠ³ΡƒΡ‡ΠΈΠΌΠΈ Ρ„ΠΎΡ‚ΠΎ.
 
Нас ΠΌΠ½ΠΎΠ³ΠΎ ΠΈ ΠΌΡ‹ Ρ€Π°Π·Π½Ρ‹Π΅, ΠΈ это прСкрасно. Π’ΠΎΡ‚ лишь Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠ· нас:
 
%users%
 
#### "ЦвСтовая диффСрСнциация ΡˆΡ‚Π°Π½ΠΎΠ²"
 
Π’Π°ΠΊ завСлось, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ выдСляСм Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π½Π°ΡˆΠΈΡ… людСй особым Ρ†Π²Π΅Ρ‚ΠΎΠΌ - Π·Π΅Π»Π΅Π½Ρ‹ΠΌ. НС просто Ρ‚Π°ΠΊ - это особая ΠΌΠ΅Ρ‚ΠΊΠ°. Π—Π½Π°ΠΉΡ‚Π΅, Ссли Π²Ρ‹ Π²ΠΈΠ΄ΠΈΡ‚Π΅ ΠΊΠΎΠ³ΠΎ-Ρ‚ΠΎ ΠΈΠ· "Π·Π΅Π»Π΅Π½Ρ‹Ρ…", Π²Ρ‹ всСгда ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΡ…Π²Π°Ρ‚ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΈ ΡΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ ΠΎ Ρ‡Π΅ΠΌ ΡƒΠ³ΠΎΠ΄Π½ΠΎ Π²ΠΎΠΊΡ€ΡƒΠ³ нашСго ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ "Π·Π΅Π»Π΅Π½Ρ‹Π΅" - это самыС ΠΎΡ‚Π·Ρ‹Π²Ρ‡ΠΈΠ²Ρ‹Π΅ ΠΈ заинтСрСсованныС Π² ΠΆΠΈΠ·Π½ΠΈ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° люди.
 
НСкоторая Ρ‡Π°ΡΡ‚ΡŒ "Π·Π΅Π»Π΅Π½Ρ‹Ρ…" Π½Π°Π΄Π΅Π»Π΅Π½Π° модСраторскими функциями.
 
### Feedback
 
Если Ρƒ вас Π΅ΡΡ‚ΡŒ ΠΊΠ°ΠΊΠΈΠ΅-Ρ‚ΠΎ замСчания, прСдлоТСния ΠΈΠ»ΠΈ ΠΈΠ½Ρ‹Π΅ мысли, Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΠ·Π²ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΈΡ… Π½Π° [Ρ„ΠΎΡ€ΡƒΠΌΠ΅](/forums/), Π·Π°Π΄Π°Ρ‚ΡŒ Π»ΠΈΡ‡Π½ΠΎ Ρ‡Π΅Ρ€Π΅Π· систСму ΠΎΠ±ΠΌΠ΅Π½Π° сообщСниями ΠΈΠ»ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Π² "[ΠΎΠ±Ρ€Π°Ρ‚Π½ΡƒΡŽ связь](/feedback)" администрации сайта.
 
Если Ρƒ вас Π΅ΡΡ‚ΡŒ вопросы ΠΎ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠΈ Ρ€Π΅ΠΊΠ»Π°ΠΌΡ‹, ΠΎΠ±ΠΌΠ΅Π½Π° ссылками ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠ΄Π²ΠΈΠΆΠ΅Π½ΠΈΠΈ вашСго ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚Π° ΠΈΠ½Ρ‹ΠΌΠΈ способами, всС ΠΎΠ½ΠΈ ΠΈΠΌΠ΅ΡŽΡ‚ СдинствСнный ΠΎΡ‚Π²Π΅Ρ‚: ΠΌΡ‹ Π½Π΅ Ρ€Π°Π·ΠΌΠ΅Ρ‰Π°Π΅ΠΌ Ρ€Π΅ΠΊΠ»Π°ΠΌΡƒ.
 
### Numbers
 
Π’Π°ΠΊ слоТилось, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ любим Ρ‚Π΅ΡˆΠΈΡ‚ΡŒ своё тщСславиС большими Ρ†ΠΈΡ„Ρ€Π°ΠΌΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ всСм ΠΈΡ… ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ. Π’Π°ΡˆΠ΅ΠΌΡƒ вниманию Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠ· Π½ΠΈΡ…:
 
* Π½Π° сайтС Π±ΠΎΠ»Π΅Π΅ %total-pictures% ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ, %total-vehicles% Π°Π²Ρ‚ΠΎΠΌΠΎΠ±ΠΈΠ»Π΅ΠΉ, Ρ‡Ρ‚ΠΎ составляСт порядка %total-size% Π΄Π°Π½Π½Ρ‹Ρ…
* зарСгистрировано ΠΎΠΊΠΎΠ»ΠΎ %total-users% ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ, ΠΎΡΡ‚Π°Π²ΠΈΠ²ΡˆΠΈΡ… Π±ΠΎΠ»Π΅Π΅ %total-comments% сообщСний
 
### Development
 
Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° вСдСтся Π² основном силами %developer% ([contributors](https://github.com/autowp/autowp/graphs/contributors))
 
French site translation: %fr-translator%
 
Chinese site translation: %zh-translator%
 
Belarusian site translation: %be-translator%
 
Brazilian portuguese site translation: %pt-br-translator%
 
Π‘Π°ΠΉΡ‚ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½Π° [Zend Framework](http://framework.zend.com/), [jQuery](http://jquery.com/), [Twitter bootstrap](http://getbootstrap.com/), Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΌΠ½ΠΎΠ³ΠΈΡ… Π΄Ρ€ΡƒΠ³ΠΈΡ… "ΡƒΠΌΠ½Ρ‹Ρ… словах".
 
Π˜ΡΡ…ΠΎΠ΄Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ сайта являСтся ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΆΠ΅Π»Π°ΡŽΡ‰ΠΈΠΉ ΠΈΠΌΠ΅Π» Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π²Π»ΠΈΡΡ‚ΡŒ Π½Π° ΡΡƒΡ‚ΡŒ ΠΈ качСство ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°.
 
%github%
 
[![Build Status](https://travis-ci.org/autowp/autowp.svg?branch=master)](https://travis-ci.org/autowp/autowp)
[![Code Climate](https://codeclimate.com/github/autowp/autowp/badges/gpa.svg)](https://codeclimate.com/github/autowp/autowp)
[![Coverage Status](https://coveralls.io/repos/github/autowp/autowp/badge.svg?branch=master)](https://coveralls.io/github/autowp/autowp?branch=master)
 
### ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚
 
You can support our project by [finances](/donate) or [moral](/feedback).
Take part in [the translation of the site](https://github.com/autowp/autowp-frontend/tree/master/src/locale) into other languages.`;
 
@Component({
imports: [RouterLink, AsyncPipe],
providers: [BytesPipe],
selector: 'app-about',
templateUrl: './about.component.html',
})
export class AboutComponent implements OnInit {
readonly #userService = inject(UserService);
readonly #router = inject(Router);
readonly #decimalPipe = inject(DecimalPipe);
readonly #bytesPipe = inject(BytesPipe);
readonly #pageEnv = inject(PageEnvService);
readonly #statGrpc = inject(StatisticsClient);
 
protected readonly version = versionJson;
 
protected readonly html$ = this.#statGrpc
.getAboutData(new Empty())
.pipe(
switchMap((about) => {
const ids: string[] = about.contributors;
ids.push(about.developer);
ids.push(about.frTranslator);
ids.push(about.zhTranslator);
ids.push(about.beTranslator);
ids.push(about.ptBrTranslator);
 
return this.#userService.getUserMap$(ids).pipe(
map((users) => ({
about,
aboutText,
users,
})),
);
}),
)
.pipe(
map((data) => {
const contributorsHtml: string[] = [];
for (const id of data.about.contributors) {
contributorsHtml.push(this.userHtml(data.users.get(id)));
}
 
const markdownConverter = new showdown.Converter({});
return replacePairs(markdownConverter.makeHtml(data.aboutText), {
'%be-translator%': this.userHtml(data.users.get(data.about.beTranslator)),
'%developer%': this.userHtml(data.users.get(data.about.developer)),
'%fr-translator%': this.userHtml(data.users.get(data.about.frTranslator)),
'%github%':
'<i class="bi bi-github" aria-hidden="true"></i> ' +
'<a href="https://github.com/autowp/autowp">https://github.com/autowp/autowp</a>',
'%pt-br-translator%': this.userHtml(data.users.get(data.about.ptBrTranslator)),
'%total-comments%': data.about.totalComments.toString(),
'%total-pictures%': this.#decimalPipe.transform(data.about.totalPictures) ?? '',
'%total-size%': this.#bytesPipe.transform(data.about.picturesSize * 1024 * 1024, 1).toString(),
'%total-users%': data.about.totalUsers.toString(),
'%total-vehicles%': data.about.totalItems.toString(),
'%users%': contributorsHtml.join(' '),
'%zh-translator%': this.userHtml(data.users.get(data.about.zhTranslator)),
});
}),
);
 
ngOnInit(): void {
setTimeout(() => this.#pageEnv.set({pageId: 136}), 0);
}
 
private userHtml(user: APIUser | null | undefined): string {
if (!user) {
return '';
}
const span = document.createElement('span');
const classes = ['user'];
if (user.deleted) {
classes.push('muted');
}
if (user.longAway) {
classes.push('long-away');
}
if (user.green) {
classes.push('green-man');
}
span.setAttribute('class', classes.join(' '));
const a = document.createElement('a');
a.setAttribute(
'href',
this.#router.createUrlTree(['/users', user.identity ? user.identity : 'user' + user.id]).toString(),
);
a.innerText = user.name;
 
return '<i class="bi bi-person-fill" aria-hidden="true"></i> ' + span.appendChild(a).outerHTML;
}
}