Skip to content

Commit 563ee4f

Browse files
committed
Merge branch 'master' into features-backlog
2 parents 5d114df + 07cc6ea commit 563ee4f

304 files changed

Lines changed: 5494 additions & 11080 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"build:skills:prod": "ng build skills --configuration=production",
1111
"build:skills:dev": "ng build skills --configuration=development",
1212
"build:prod": "npm run build:social:prod && npm run build:skills:prod",
13-
"build:pr": "npm run build:social:dev && npm run build:skills:dev",
13+
"build:pr": "npm run build:social:dev",
1414
"watch": "ng build --watch social_platform --configuration=development",
1515
"build:sprite-social": "svg-sprite -s --dest=projects/social_platform/src/assets/icons 'projects/social_platform/src/assets/icons/svg/**/*.svg'",
1616
"build:sprite-skills": "svg-sprite -s --dest=projects/skills/src/assets/icons 'projects/skills/src/assets/icons/svg/**/*.svg'",
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/** @format */
2+
3+
import { Pipe, PipeTransform } from "@angular/core";
4+
import { DomSanitizer, SafeHtml } from "@angular/platform-browser";
5+
6+
@Pipe({ name: "truncateHtml", standalone: true })
7+
export class TruncateHtmlPipe implements PipeTransform {
8+
constructor(private sanitizer: DomSanitizer) {}
9+
10+
transform(value: string, limit: number): SafeHtml {
11+
if (!value) return "";
12+
13+
// Сначала убираем все HTML теги чтобы считать только текст
14+
const plainText = value.replace(/<[^>]*>/g, "");
15+
16+
if (plainText.length <= limit) {
17+
return this.sanitizer.bypassSecurityTrustHtml(value);
18+
}
19+
20+
// Обрезаем по тексту, сохраняя теги
21+
let charCount = 0;
22+
let result = "";
23+
let inTag = false;
24+
let currentTag = "";
25+
const openTags: string[] = [];
26+
const selfClosingTags = ["br", "hr", "img", "input", "meta", "link"];
27+
28+
for (let i = 0; i < value.length; i++) {
29+
const char = value[i];
30+
31+
if (char === "<") {
32+
inTag = true;
33+
currentTag = "";
34+
}
35+
36+
if (inTag) {
37+
result += char;
38+
currentTag += char;
39+
40+
if (char === ">") {
41+
// Закончился тег, анализируем его
42+
const tagContent = currentTag.slice(1, -1).trim(); // убираем < и >
43+
44+
if (tagContent.startsWith("/")) {
45+
// Закрывающий тег
46+
openTags.pop();
47+
} else if (!tagContent.startsWith("!")) {
48+
// Открывающий тег (не комментарий)
49+
const tagNameMatch = tagContent.match(/^(\w+)/i);
50+
if (tagNameMatch) {
51+
const tagName = tagNameMatch[1].toLowerCase();
52+
// Проверяем, что это не самозакрывающийся тег
53+
if (!selfClosingTags.includes(tagName) && !tagContent.endsWith("/")) {
54+
openTags.push(tagName);
55+
}
56+
}
57+
}
58+
59+
inTag = false;
60+
currentTag = "";
61+
}
62+
} else {
63+
if (charCount >= limit) break;
64+
result += char;
65+
charCount++;
66+
}
67+
}
68+
69+
// Закрываем все открытые теги
70+
let closedTags = result;
71+
for (let i = openTags.length - 1; i >= 0; i--) {
72+
closedTags += `</${openTags[i]}>`;
73+
}
74+
75+
return this.sanitizer.bypassSecurityTrustHtml(closedTags + "...");
76+
}
77+
}

projects/skills/src/app/app.component.html

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
<!-- @format -->
22

33
<div class="app">
4-
<ui-sidebar class="app__sidebar" [navItems]="navItems" logoSrc="/assets/images/shared/logo.svg">
5-
@if(userData()){
6-
<app-sidebar-profile></app-sidebar-profile>
7-
}
8-
</ui-sidebar>
9-
104
<div class="app__wrapper">
115
<div class="app__top">
126
<div class="nav-bar__toggle">
@@ -63,7 +57,34 @@
6357

6458
<div class="app__body">
6559
<div class="app__inner">
66-
<router-outlet></router-outlet>
60+
<div class="app__inner--wrapper">
61+
<ui-sidebar
62+
class="app__sidebar"
63+
[navItems]="navItems"
64+
logoSrc="/assets/images/shared/logo.svg"
65+
style="align-self: flex-start"
66+
>
67+
<div class="app__sidebar--text">
68+
<p class="text-body-6">Платформа создана компанией ООО «Молодежный форсайт»</p>
69+
<p class="text-body-6">Политика обработки персональных данных</p>
70+
<p class="text-body-6">2022</p>
71+
</div>
72+
</ui-sidebar>
73+
74+
<div class="app__inner--content">
75+
@if (userData() !== undefined) {
76+
<app-profile-control-panel
77+
[invites]="[]"
78+
[hasNotifications]="false"
79+
[hasUnreads]="false"
80+
[user]="userData()"
81+
(logout)="onLogout()"
82+
></app-profile-control-panel>
83+
}
84+
<router-outlet></router-outlet>
85+
<app-snackbar></app-snackbar>
86+
</div>
87+
</div>
6788
</div>
6889
</div>
6990
</div>

projects/skills/src/app/app.component.scss

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
@use "styles/typography";
33

44
.app {
5+
position: relative;
56
display: flex;
67
height: 100%;
7-
padding: 20px;
8-
background-color: var(--light-gray);
8+
background-color: var(--white);
99

1010
&__wrapper {
1111
display: flex;
@@ -22,6 +22,20 @@
2222
flex-shrink: 0;
2323
width: 234px;
2424
height: 100vh;
25+
26+
::ng-deep {
27+
.sidebar__logo {
28+
margin-bottom: 17px;
29+
}
30+
}
31+
}
32+
33+
&--text {
34+
display: flex;
35+
flex-direction: column;
36+
gap: 2px;
37+
margin-top: 17px;
38+
color: var(--dark-grey);
2539
}
2640
}
2741

@@ -116,12 +130,30 @@
116130
}
117131

118132
&__body {
133+
display: flex;
119134
flex-grow: 1;
120-
padding: 10px 10px 0;
135+
justify-content: center;
136+
padding: 0 200px;
121137
overflow-y: auto;
122138

123-
@include responsive.apply-desktop {
124-
padding: 20px 20px 0;
139+
@media (max-width: 1600px) {
140+
padding: 0 150px;
141+
}
142+
143+
@media (max-width: 1400px) {
144+
padding: 0 100px;
145+
}
146+
147+
@media (max-width: 1200px) {
148+
padding: 0 50px;
149+
}
150+
151+
@media (max-width: 992px) {
152+
padding: 0 20px;
153+
}
154+
155+
@media (max-width: 768px) {
156+
padding: 0 15px;
125157
}
126158
}
127159

@@ -135,12 +167,23 @@
135167
}
136168

137169
&__inner {
170+
display: flex;
171+
width: 100%;
138172
height: 100%;
139-
max-height: 100%;
140173

141-
@include responsive.apply-desktop {
142-
max-width: responsive.$container-md;
143-
margin: 0 auto;
174+
&--wrapper {
175+
display: grid;
176+
grid-template-columns: 2fr 10fr;
177+
width: 100%;
178+
179+
@media (max-width: 992px) {
180+
grid-template-columns: 1fr;
181+
}
182+
}
183+
184+
&--content {
185+
flex-grow: 1;
186+
min-width: 0;
144187
}
145188
}
146189
}

projects/skills/src/app/app.component.ts

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import { Component, inject, type OnInit, signal } from "@angular/core";
44
import { CommonModule } from "@angular/common";
55
import { Router, RouterLink, RouterOutlet } from "@angular/router";
6-
import { IconComponent, SidebarComponent } from "@uilib";
6+
import { IconComponent, ProfileControlPanelComponent, SidebarComponent } from "@uilib";
77
import { SidebarProfileComponent } from "./shared/sidebar-profile/sidebar-profile.component";
8-
import { ProfileService } from "./profile/services/profile.service";
98
import type { UserData } from "../models/profile.model";
109
import { AuthService } from "@auth/services";
10+
import { SnackbarComponent } from "@ui/components/snackbar/snackbar.component";
1111

1212
/**
1313
* Корневой компонент приложения, который служит основным контейнером макета
@@ -32,13 +32,14 @@ import { AuthService } from "@auth/services";
3232
SidebarComponent,
3333
SidebarProfileComponent,
3434
IconComponent,
35+
ProfileControlPanelComponent,
36+
SnackbarComponent,
3537
],
3638
templateUrl: "./app.component.html",
3739
styleUrl: "./app.component.scss",
3840
})
3941
export class AppComponent implements OnInit {
4042
// Внедренные сервисы для управления профилем и аутентификацией
41-
profileService = inject(ProfileService);
4243
authService = inject(AuthService);
4344
router = inject(Router);
4445

@@ -54,12 +55,9 @@ export class AppComponent implements OnInit {
5455
* Каждый элемент представляет основной раздел приложения
5556
*/
5657
navItems = [
57-
// { name: "Навыки", icon: "lib", link: "skills" }, // Временно отключено
58-
{ name: "Детский Форсайт", icon: "trackcar", link: "trackCar" },
59-
// { name: "Траектории", icon: "receipt", link: "subscription" },
60-
// { name: "Рейтинг", icon: "growth", link: "rating" },
61-
// { name: "Траектория бизнеса", icon: "trackbuss", link: "trackBuss" }, // Временно отключено
62-
// { name: "Вебинары", icon: "webinars", link: "webinars" }, // Временно отключено
58+
{ name: "Мой профиль", icon: "person", link: "profile" },
59+
{ name: "Рейтинг", icon: "growth", link: "rating" },
60+
// { name: "Траектории", icon: "receipt", link: "trackCar" },
6361
];
6462

6563
// Реактивное состояние с использованием Angular signals
@@ -71,23 +69,11 @@ export class AppComponent implements OnInit {
7169
* Получает данные пользователя и синхронизирует профиль при запуске
7270
* Перенаправляет на страницу входа при ошибке аутентификации
7371
*/
74-
ngOnInit(): void {
75-
// Получение текущих данных пользователя
76-
this.profileService.getUserData().subscribe({
77-
next: data => this.userData.set(data as UserData),
78-
error: () => {
79-
// Перенаправление на основное приложение для входа при ошибке получения данных пользователя
80-
location.href = "https://app.procollab.ru/auth/login";
81-
},
82-
});
72+
ngOnInit(): void {}
8373

84-
// Синхронизация данных профиля с бэкендом
85-
this.profileService.syncProfile().subscribe({
74+
onLogout() {
75+
this.authService.logout().subscribe({
8676
next: () => {
87-
// Синхронизация профиля успешна - никаких действий не требуется
88-
},
89-
error: () => {
90-
// Перенаправление на основное приложение для входа при ошибке синхронизации профиля
9177
location.href = "https://app.procollab.ru/auth/login";
9278
},
9379
});

projects/skills/src/app/app.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { ApplicationConfig } from "@angular/core";
44
import { provideRouter } from "@angular/router";
5+
import { provideAnimations } from "@angular/platform-browser/animations";
56
import { routes } from "./app.routes";
67
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from "@angular/common/http";
78
import {
@@ -22,5 +23,6 @@ export const appConfig: ApplicationConfig = {
2223
{ provide: SKILLS_API_URL, useValue: environment.skillsApiUrl },
2324
{ provide: PRODUCTION, useValue: environment.production },
2425
provideHttpClient(withInterceptorsFromDi()),
26+
provideAnimations(),
2527
],
2628
};

projects/skills/src/app/app.routes.ts

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,43 +23,11 @@ export const routes: Routes = [
2323
{
2424
path: "",
2525
pathMatch: "full",
26-
redirectTo: "profile", // Маршрут по умолчанию перенаправляет на профиль пользователя
26+
redirectTo: "trackCar", // Маршрут по умолчанию перенаправляет на профиль пользователя
2727
},
28-
{
29-
path: "profile",
30-
loadChildren: () => import("./profile/profile.routes").then(c => c.PROFILE_ROUTES),
31-
},
32-
{
33-
path: "skills",
34-
loadChildren: () => import("./skills/skills.routes").then(c => c.SKILLS_ROUTES),
35-
},
36-
// {
37-
// path: "rating",
38-
// loadChildren: () => import("./rating/rating.routes").then(c => c.RATING_ROUTES),
39-
// },
40-
{
41-
path: "task",
42-
loadChildren: () => import("./task/task.routes").then(c => c.TASK_ROUTES),
43-
},
44-
// {
45-
// path: "trackBuss",
46-
// loadChildren: () =>
47-
// import("./trajectories/track-bussiness/track-bussiness.routes").then(
48-
// c => c.TRACK_BUSSINESS_ROUTES
49-
// ),
50-
// },
5128
{
5229
path: "trackCar",
5330
loadChildren: () =>
5431
import("./trajectories/track-career/track-career.routes").then(c => c.TRACK_CAREER_ROUTES),
5532
},
56-
{
57-
path: "subscription",
58-
loadChildren: () =>
59-
import("./subscription/subscription.routes").then(c => c.SUBSCRIPTION_ROUTES),
60-
},
61-
// {
62-
// path: "webinars",
63-
// loadChildren: () => import("./webinars/webinars.routes").then(c => c.WEBINARS_ROUTES),
64-
// },
6533
];

projects/skills/src/app/profile/home/profile-home.component.html

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)