From acd2626f3dbd4d6ebed165c6fbbd7b2bd81b1ea0 Mon Sep 17 00:00:00 2001 From: Stanislav Gavrilov Date: Mon, 19 Feb 2024 20:08:44 +0300 Subject: [PATCH 1/3] docs: add ru translations --- .../ru/challenges/angular/1-projection.md | 43 +++++++++++++++++++ .../challenges/angular/21-achor-scrolling.md | 18 ++++++++ .../angular/4-context-outlet-typed.md | 40 +++++++++++++++++ .../docs/ru/challenges/angular/8-pipe-pure.md | 36 ++++++++++++++++ .../forms/41-control-value-accessor.md | 41 ++++++++++++++++++ docs/src/content/i18n/ru.json | 18 ++++---- 6 files changed, 187 insertions(+), 9 deletions(-) create mode 100644 docs/src/content/docs/ru/challenges/angular/1-projection.md create mode 100644 docs/src/content/docs/ru/challenges/angular/21-achor-scrolling.md create mode 100644 docs/src/content/docs/ru/challenges/angular/4-context-outlet-typed.md create mode 100644 docs/src/content/docs/ru/challenges/angular/8-pipe-pure.md create mode 100644 docs/src/content/docs/ru/challenges/forms/41-control-value-accessor.md diff --git a/docs/src/content/docs/ru/challenges/angular/1-projection.md b/docs/src/content/docs/ru/challenges/angular/1-projection.md new file mode 100644 index 000000000..a08f04671 --- /dev/null +++ b/docs/src/content/docs/ru/challenges/angular/1-projection.md @@ -0,0 +1,43 @@ +--- +title: 🟢 Проекция контента +description: Challenge 1 заключается в изучении проекции элементов DOM через компоненты +author: thomas-laforge +challengeNumber: 1 +command: angular-projection +blogLink: https://medium.com/@thomas.laforge/create-a-highly-customizable-component-cc3a9805e4c5 +videoLink: + link: https://www.youtube.com/watch?v=npyEyUZxoIw&ab_channel=ArthurLannelucq + alt: Projection video by Arthur Lannelucq + flag: FR +sidebar: + order: 1 +--- + +## Информация + +Проекция контента в Angular - это мощная техника для создания компонентов с гибко настраиваемым внешним видом. Понимание и использование концепций ng-content и ngTemplateOutlet может значительно вам помочь создавать компоненты, предназначенные для повторного использования. + +[Здесь](https://angular.io/guide/content-projection#projecting-content-in-more-complex-environments) вы можете изучить все о ng-content, начиная с простых примеров и до более сложных. + +Документацию ngTemplateOutlett, вместе с базовыми примерами, можно найти [тут](https://angular.io/api/common/NgTemplateOutlet). + +Имея эти два инструмента в своем распоряжении, вы теперь готовы пройти испытание. + +## Пояснение + +Вы начнете с полностью работающего приложения, которое включает панель с карточкой учителя и карточкой студента. Цель состоит в том, чтобы реализовать карточку города. + +Хотя приложение работает, его внутреннее устройство далеко от идеала. Каждый раз, когда вам нужно реализовать новую карточку, вам придется изменять `card.component.ts`. В реальных проектах этот компонент может использоваться во многих приложениях. Цель этого упражнения создать `CardComponent`, внешний вид которого можно настроить без каких-либо изменений. После того как вы создадите этот компонент, вы можете создать `CityCardComponent` без модификации `CardComponent`. + +## Ограничения + +- Вы должны провести рефакторинг `CardComponent` и `ListItemComponent`. +- Директива `NgFor` должна быть определена и должна оставаться внутри `CardComponent`, несмотря на возможное желание перенести её в `ParentCardComponent`,как это сделано в `TeacherCardComponent`. +- `CardComponent` не должен содержать `NgIf` или `NgSwitch`. +- CSS: избегайте использования `::ng-deep`. Ищите альтернативные способы стилизации с помощью CSS. + +## Дополнительные задачи + +- Попробуйте использовать новый синтаксис для циклов и условий (документация [тут](https://angular.dev/guide/templates/control-flow)). +- Используйте signal API для управления состоянием компонентов (документация [тут](https://angular.dev/guide/signals)). +- Для ссылки на шаблон используйте директивы вместо магических строк ([What is wrong with magic strings?](https://softwareengineering.stackexchange.com/a/365344)). diff --git a/docs/src/content/docs/ru/challenges/angular/21-achor-scrolling.md b/docs/src/content/docs/ru/challenges/angular/21-achor-scrolling.md new file mode 100644 index 000000000..716f18b8b --- /dev/null +++ b/docs/src/content/docs/ru/challenges/angular/21-achor-scrolling.md @@ -0,0 +1,18 @@ +--- +title: 🟢Навигация по якорю +description: Испытание 21 про навигацию на странице с помощью якоря +author: thomas-laforge +challengeNumber: 21 +command: angular-anchor-scrolling +sidebar: + order: 4 +--- + +## Информация + +Вы начинаете с приложения, которое имеет базовую навигацию и навигацию с использованием якорей в `HomeComponent`. Однако, использование `href` каждый раз создает новый путь и обновляет страницу. + +## Пояснение + +- Ваша задача - рефакторинг этого приложения для использования встроенного инструмента навигации, для более эффективной работы в рамках фреймворка Angular. Вы можете использовать router, но лучше остаться в шаблоне и использовать `RouterLink` директиву. +- Для улучшения пользовательского опыта, добавьте плавную прокрутку. diff --git a/docs/src/content/docs/ru/challenges/angular/4-context-outlet-typed.md b/docs/src/content/docs/ru/challenges/angular/4-context-outlet-typed.md new file mode 100644 index 000000000..053897d78 --- /dev/null +++ b/docs/src/content/docs/ru/challenges/angular/4-context-outlet-typed.md @@ -0,0 +1,40 @@ +--- +title: 🔴 Типизация ContextOutlet +description: Испытание 4 про строгую типизацию ngContextOutlet директивы +author: thomas-laforge +challengeNumber: 4 +command: angular-context-outlet-type +blogLink: https://medium.com/@thomas.laforge/ngtemplateoutlet-type-checking-5d2dcb07a2c6 +sidebar: + order: 201 +--- + +## Информация + +В Angular есть статическая функция [`ngTemplateContextGuard`](https://angular.io/guide/structural-directives#typing-the-directives-context) для строгой типизации структурных директив. + +Однако, контекстом **NgTemplateOutlet** является **Object**. Но с помощью вышеупомянутой гарда, мы можем улучшить это поведение. + +## Пояснение + +В этом испытании, мы хотим научиться строго типизировать ng-template в AppComponent. + +Это упражнение имеет два уровня сложности: + +### Уровень 1: Известный интерфейс + +Сейчас код выглядит следующим образом. + +![Unkown Person](../../../../../assets/4/unknown-person.png 'Unkown Person') + +Как мы видим, у переменной name тип "any". Мы хотим вывести правильный тип. + +### Уровень 2: Обобщённый интерфейс + +Сейчас код выглядит следующим образом. + +![Unkown Student](../../../../../assets/4/unknown-student.png 'Unkown Student') + +Как мы видим, у переменной student тип "any". Мы хотим вывести правильный тип. + +Но на этот раз, мы хотим передавать в `ListComponent` список из любых объектов. И мы все равно хотим, чтобы был выведен правильный тип. diff --git a/docs/src/content/docs/ru/challenges/angular/8-pipe-pure.md b/docs/src/content/docs/ru/challenges/angular/8-pipe-pure.md new file mode 100644 index 000000000..7d8067abb --- /dev/null +++ b/docs/src/content/docs/ru/challenges/angular/8-pipe-pure.md @@ -0,0 +1,36 @@ +--- +title: 🟢Чистый пайп +description: Испытание 8 про создание чистого пайпа +author: thomas-laforge +challengeNumber: 8 +command: angular-pipe-easy +blogLink: https://medium.com/ngconf/deep-dive-into-angular-pipes-c040588cd15d +sidebar: + order: 3 +--- + +## Информация + +This is the first of three `@Pipe()` challenges, the goal of this series is to master **pipes** in Angular. +Это первое испытание про `@Pipe()` из трех, цель этой серии испытаний - освоить работу с **pipes** в Angular. + +Пайпы - удобный способ трансформации данных в вашем шаблоне. Разница между вызовом функции и пайпом заключается в том, что результат, возвращаемый чистыми пайпами, кэшируется. Таким образом, они не будут пересчитываться при каждом цикле обнаружения изменений, если их входные значения не изменились. + +Pipes разработаны так, чтобы быть эффективными и оптимизированными для производительности. Они используют механизмы обнаружения изменений, чтобы пересчитывать значение только в случае изменения входных данных, минимизируя ненужные вычисления и улучшая производительность рендеринга. + +По умолчанию пайпы чистые, но вы должны знать, что установка `pure` в false может привести к неэффективности, поскольку это увеличивает количество перерисовок. + +:::note[Примечание] +**Чистые** пайп вызывается только когда изменяется входное значение.\ +**Нечистый** пайп вызывается на каждый цикл обнаружения изменений. +::: + +Существуют несколько полезных предопределенных пайпов, таких как DatePipe, UpperCasePipe и CurrencyPipe. Чтобы узнать больше о пайпах в Angular, ознакомьтесь с документацией API [здесь](https://angular.io/guide/pipes). + +## Пояснение + +В этом упражнении необходимо превратить вызов функции в шаблоне в использование пайпа. + +## Ограничение + +- Пайп должен быть типизирован. diff --git a/docs/src/content/docs/ru/challenges/forms/41-control-value-accessor.md b/docs/src/content/docs/ru/challenges/forms/41-control-value-accessor.md new file mode 100644 index 000000000..98659a936 --- /dev/null +++ b/docs/src/content/docs/ru/challenges/forms/41-control-value-accessor.md @@ -0,0 +1,41 @@ +--- +title: 🟠 Control Value Accessor +description: Испытание 41 про создание пользовательское поле формы которое использует интерфейс ControlValueAccessor. +author: stanislav-gavrilov +challengeNumber: 41 +command: forms-control-value-accessor +sidebar: + order: 1 +--- + +## Информация + +Цель этого испытания создать пользовательское поле формы, которое использует API формы Angular через `ControlValueAccessor`. Документацию можно посмотреть [здесь](https://angular.io/api/forms/ControlValueAccessor). Этот интерфейс критически важен для создания пользовательских элементов управления формами, которые могут беспрепятственно взаимодействовать с API форм Angular. + +## Пояснение + +Задача - использовать контрол в `feedbackForm` напрямую, чтобы убрать необходимость в использовании `@Output` для получения значения из `app-rating-control` и установки его в `FormGroup`. +Кроме того, вы должны добавить валидацию для нового элемента управления, чтобы гарантировать наличие данных о рейтинге. (Кнопка отправки формы должна быть отключена, если форма недействительна). + +Сейчас компонент рейтинга используется следующим образом: + +```html + +``` + +```ts +rating: string | null = null; + +onFormSubmit(): void { + this.feedBackSubmit.emit({ + ...this.feedbackForm.value, + rating: this.rating, // not inside the FormGroup and no validation + }); +} +``` + +Необходимо, чтобы компонент можно было использовать так: + +```html + +``` diff --git a/docs/src/content/i18n/ru.json b/docs/src/content/i18n/ru.json index 9595ba21d..0e8155756 100644 --- a/docs/src/content/i18n/ru.json +++ b/docs/src/content/i18n/ru.json @@ -1,10 +1,10 @@ { "page.title.challenge": "Испытание", "author.createdBy": "Создано", - "buttons.email": "Email subscription", - "buttons.star": "Дать звезду", - "buttons.sponsor": "Спонсор", - "buttons.clipboardCopy": "Copied!", + "buttons.email": "Подписаться на email рассылку", + "buttons.star": "Добавить звезду", + "buttons.sponsor": "Спонсировать", + "buttons.clipboardCopy": "Скопировано!", "404.text": "Страница не найдена. Проверьте URL-адрес или воспользуйтесь строкой поиска.", "challenge.footer.note": "Примечание", "challenge.footer.running": "Запустите проект, выполнив команду:", @@ -13,12 +13,12 @@ "challenge.footer.communityAnswers": "Решения сообщества", "challenge.footer.authorAnswer": "Решение автора", "challenge.footer.blogPost": "Статья", - "challenge.footer.video": "Video", + "challenge.footer.video": "Видео", "challenge.footer.gettingStarted.title": "Чтобы пройти это испытание, прочитайте:", "challenge.footer.gettingStarted.link": "Первые шаги", - "challenge.footer.upvoteAnswer": "You can upvote an answer with a 👍 if you like it", - "subscription.button": "Subscribe", + "challenge.footer.upvoteAnswer": "Вы можете проголосовать за этот ответ 👍 если он вам понравился", + "subscription.button": "Подписаться", "subscription.email": "username@gmail.com", - "subscription.note.title": "Notes", - "subscription.note.description": "This email will only be used for sending new challenges updates" + "subscription.note.title": "Примечание", + "subscription.note.description": "Этот email будет использоваться только для о новых испытаниях" } From cc4d34fce040753e78bb1e185626ba070b5cd222 Mon Sep 17 00:00:00 2001 From: Stanislav Gavrilov Date: Mon, 19 Feb 2024 20:16:40 +0300 Subject: [PATCH 2/3] docs: fix typo --- docs/src/content/i18n/ru.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/content/i18n/ru.json b/docs/src/content/i18n/ru.json index 0e8155756..be1716a4c 100644 --- a/docs/src/content/i18n/ru.json +++ b/docs/src/content/i18n/ru.json @@ -20,5 +20,5 @@ "subscription.button": "Подписаться", "subscription.email": "username@gmail.com", "subscription.note.title": "Примечание", - "subscription.note.description": "Этот email будет использоваться только для о новых испытаниях" + "subscription.note.description": "Этот email будет использоваться только для сообщений о новых испытаниях" } From 595c6f39a7351858e6b3cbb96d5cebda252aa919 Mon Sep 17 00:00:00 2001 From: Stanislav Gavrilov Date: Tue, 20 Feb 2024 21:24:21 +0300 Subject: [PATCH 3/3] docs(ru): 40-christmas-web-worker.md translation --- .../performance/40-christmas-web-worker.md | 33 +++++++++++++++++++ docs/src/content/i18n/ru.json | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 docs/src/content/docs/ru/challenges/performance/40-christmas-web-worker.md diff --git a/docs/src/content/docs/ru/challenges/performance/40-christmas-web-worker.md b/docs/src/content/docs/ru/challenges/performance/40-christmas-web-worker.md new file mode 100644 index 000000000..674ceed2b --- /dev/null +++ b/docs/src/content/docs/ru/challenges/performance/40-christmas-web-worker.md @@ -0,0 +1,33 @@ +--- +title: 🟠 Веб-воркеры +description: Испытание 40 о том как создать и использовать веб-воркер +author: thomas-laforge +challengeNumber: 40 +command: performance-christmas-web-worker +sidebar: + order: 119 +--- + +## Информация + +Это испытание было создано для [Angular Advent Calendar](https://angularchristmascalendar.com) 2023. + +Это простое приложение, где нужно нажать на кнопку **Discover**, чтобы увидеть сюрприз, скрывающийся за черным экраном. Тем не менее, взаимодействие с приложением оставляет желать лучшего. При нажатии на кнопку происходит зависание страницы, а затем, после краткой задержки, секрет раскрывается мгновенно и без какой-либо плавности в анимации. + +> Пояснение: Для того, чтобы вызвать зависание приложения, загрузчик использует функцию, выполняющую очень сложные вычисления. Хотя возможно было бы использовать обычный таймер, но это не суть данного испытания. + +Так как JavaScript работает в однопоточном режиме, выполнение ресурсоемких задач препятствует обновлению пользовательского интерфейса браузера и реагированию на клики мыши или другие действия. Задача этого испытания - разгрузить основной поток, перенеся сложные вычисления в отдельный поток. Для этой цели мы будем использовать веб-воркеры. Веб-воркеры способны запускать скрипты в фоне, не влияя на основной поток, что позволяет браузеру сохранять высокое качество пользовательского взаимодействия. + +В Angular использование этой технологии не так распространено, но внедрить её довольно легко. Есть схематик, который вы можете найти [здесь](https://angular.io/guide/web-worker) чтобы начать. + +## Пояснение + +Это испытание направлено на создание плавной анимации за счет перемещения функции, выполняющей сложные вычисления, в веб-воркер. + +Для начала, используя схематик, создайте веб-воркер и перенесите в него функцию, вызывающую проблемы. После этих шагов анимация должна стать плавной, а отображение процента выполнения — обновляться, тем самым значительно улучшив пользовательский опыт. + +:::note[Пояснение] +Поскольку мы находимся в рабочем пространстве Nx, просто замените команду `ng` на `nx` при запуске схематика. + +Если `nx` не установлен глобально на вашем компьютере, добавьте префикс `npx` к вашей команде. +::: diff --git a/docs/src/content/i18n/ru.json b/docs/src/content/i18n/ru.json index be1716a4c..4e58543ad 100644 --- a/docs/src/content/i18n/ru.json +++ b/docs/src/content/i18n/ru.json @@ -16,7 +16,7 @@ "challenge.footer.video": "Видео", "challenge.footer.gettingStarted.title": "Чтобы пройти это испытание, прочитайте:", "challenge.footer.gettingStarted.link": "Первые шаги", - "challenge.footer.upvoteAnswer": "Вы можете проголосовать за этот ответ 👍 если он вам понравился", + "challenge.footer.upvoteAnswer": "Вы можете проголосовать за ответ 👍 если он вам понравился", "subscription.button": "Подписаться", "subscription.email": "username@gmail.com", "subscription.note.title": "Примечание",