diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..c85804c96
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/node_modules/
+/dist/
\ No newline at end of file
diff --git a/.prettierrc.yaml b/.prettierrc.yaml
new file mode 100644
index 000000000..0fe5deb5b
--- /dev/null
+++ b/.prettierrc.yaml
@@ -0,0 +1,2 @@
+tabWidth: 4
+singleQuote: true
diff --git a/README.md b/README.md
index 34719e139..1fffa0b83 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,16 @@
MVP социальной сети для обмена фотографиями
+1. Добавить функионал удаления собственных постов.
+
+ Удалять можно как в общей ленте постов, так и при просмотре конкретного пользователя.
+
+ Удалять посты другого пользователя нельзя, кнопка удалить не активна.
+
## Первоначальная оценка
-ХХХХ часов
+72 часа
## Фактически затраченное время
-YYYY часов
+40 часов
diff --git a/api.js b/api.js
index 123a9e3b6..abd7d3855 100644
--- a/api.js
+++ b/api.js
@@ -1,69 +1,138 @@
// Замени на свой, чтобы получить независимый от других набор данных.
// "боевая" версия инстапро лежит в ключе prod
-const personalKey = "prod";
-const baseHost = "https://webdev-hw-api.vercel.app";
+const personalKey = 'avrusskov';
+const baseHost = 'https://webdev-hw-api.vercel.app';
const postsHost = `${baseHost}/api/v1/${personalKey}/instapro`;
export function getPosts({ token }) {
- return fetch(postsHost, {
- method: "GET",
- headers: {
- Authorization: token,
- },
- })
- .then((response) => {
- if (response.status === 401) {
- throw new Error("Нет авторизации");
- }
+ return fetch(postsHost, {
+ method: 'GET',
+ headers: {
+ Authorization: token,
+ },
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ throw new Error('Нет авторизации');
+ }
+
+ return response.json();
+ })
+ .then((data) => {
+ return data.posts;
+ });
+}
- return response.json();
+export function getUserPosts({ token }, userId) {
+ return fetch(`${postsHost}/user-posts/${userId}`, {
+ method: 'GET',
+ headers: {
+ Authorization: token,
+ },
})
- .then((data) => {
- return data.posts;
+ .then((response) => {
+ if (response.status === 401) {
+ throw new Error('Нет авторизации');
+ }
+
+ return response.json();
+ })
+ .then((data) => {
+ return data.posts;
+ });
+}
+
+export function addPost({ token }, description, imageUrl) {
+ return fetch(postsHost, {
+ method: 'POST',
+ headers: {
+ Authorization: token,
+ },
+ body: JSON.stringify({ description, imageUrl }),
+ }).then((response) => {
+ if (response.status === 401) {
+ throw new Error('Нет авторизации');
+ }
+
+ return;
+ });
+}
+
+export function deletePost({ token }, postId) {
+ return fetch(`${postsHost}/${postId}`, {
+ method: 'DELETE',
+ headers: { Authorization: token },
+ }).then((response) => {
+ if (response.status === 401) {
+ throw new Error('Нет авторизации');
+ }
+
+ return;
});
}
export function registerUser({ login, password, name, imageUrl }) {
- return fetch(baseHost + "/api/user", {
- method: "POST",
- body: JSON.stringify({
- login,
- password,
- name,
- imageUrl,
- }),
- }).then((response) => {
- if (response.status === 400) {
- throw new Error("Такой пользователь уже существует");
- }
- return response.json();
- });
+ return fetch(baseHost + '/api/user', {
+ method: 'POST',
+ body: JSON.stringify({
+ login,
+ password,
+ name,
+ imageUrl,
+ }),
+ }).then((response) => {
+ if (response.status === 400) {
+ throw new Error('Такой пользователь уже существует');
+ }
+ return response.json();
+ });
}
export function loginUser({ login, password }) {
- return fetch(baseHost + "/api/user/login", {
- method: "POST",
- body: JSON.stringify({
- login,
- password,
- }),
- }).then((response) => {
- if (response.status === 400) {
- throw new Error("Неверный логин или пароль");
- }
- return response.json();
- });
+ return fetch(baseHost + '/api/user/login', {
+ method: 'POST',
+ body: JSON.stringify({
+ login,
+ password,
+ }),
+ }).then((response) => {
+ if (response.status === 400) {
+ throw new Error('Неверный логин или пароль');
+ }
+ return response.json();
+ });
}
// Загружает картинку в облако, возвращает url загруженной картинки
export function uploadImage({ file }) {
- const data = new FormData();
- data.append("file", file);
+ const data = new FormData();
+ data.append('file', file);
+
+ return fetch(baseHost + '/api/upload/image', {
+ method: 'POST',
+ body: data,
+ }).then((response) => {
+ return response.json();
+ });
+}
+
+export function likePost({ token }, postId, isLiked) {
+ const flag = isLiked ? 'dislike' : 'like';
+
+ return fetch(`${postsHost}/${postId}/${flag}`, {
+ method: 'POST',
+ headers: {
+ Authorization: token,
+ },
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ throw new Error('Нет авторизации');
+ }
- return fetch(baseHost + "/api/upload/image", {
- method: "POST",
- body: data,
- }).then((response) => {
- return response.json();
- });
+ return response.json();
+ })
+ .then((data) => {
+ return data.post;
+ });
}
diff --git a/assets/images/3dots.png b/assets/images/3dots.png
new file mode 100644
index 000000000..bdfc310fa
Binary files /dev/null and b/assets/images/3dots.png differ
diff --git a/components/add-post-page-component.js b/components/add-post-page-component.js
index 8277f093b..838d2de91 100644
--- a/components/add-post-page-component.js
+++ b/components/add-post-page-component.js
@@ -1,23 +1,71 @@
+import { replaceHtmlTags } from '../helpers.js';
+import { renderHeaderComponent } from './header-component.js';
+import { renderUploadImageComponent } from './upload-image-component.js';
+
export function renderAddPostPageComponent({ appEl, onAddPostClick }) {
- const render = () => {
- // @TODO: Реализовать страницу добавления поста
- const appHtml = `
-
-
- Cтраница добавления поста
-
-
- `;
-
- appEl.innerHTML = appHtml;
-
- document.getElementById("add-button").addEventListener("click", () => {
- onAddPostClick({
- description: "Описание картинки",
- imageUrl: "https://image.png",
- });
- });
- };
-
- render();
+ let imageUrl = '';
+
+ const render = () => {
+ const appHtml = `
+
+ `;
+
+ appEl.innerHTML = appHtml;
+
+ renderHeaderComponent({
+ element: document.querySelector('.header-container'),
+ });
+
+ const uploadImageContainer = appEl.querySelector(
+ '.upload-image-container',
+ );
+ if (uploadImageContainer) {
+ renderUploadImageComponent({
+ element: uploadImageContainer,
+ onImageUrlChange(newImageUrl) {
+ imageUrl = newImageUrl;
+ },
+ });
+ }
+
+ document.getElementById('add-button').addEventListener('click', () => {
+ const description = document.getElementById('description-input');
+
+ if (!description.value) {
+ alert('Введите комментарий');
+ return;
+ }
+
+ if (!imageUrl) {
+ alert('Выберите фото');
+ return;
+ }
+ onAddPostClick({
+ description: description.value,
+ imageUrl: imageUrl,
+ });
+ });
+ };
+
+ render();
}
diff --git a/components/auth-page-component.js b/components/auth-page-component.js
index 0e93530ec..4405a450d 100644
--- a/components/auth-page-component.js
+++ b/components/auth-page-component.js
@@ -1,6 +1,7 @@
-import { loginUser, registerUser } from "../api.js";
-import { renderHeaderComponent } from "./header-component.js";
-import { renderUploadImageComponent } from "./upload-image-component.js";
+import { loginUser, registerUser } from '../api.js';
+import { renderHeaderComponent } from './header-component.js';
+import { renderUploadImageComponent } from './upload-image-component.js';
+import { replaceHtmlTags } from '../helpers.js';
/**
* Компонент страницы авторизации.
@@ -12,57 +13,57 @@ import { renderUploadImageComponent } from "./upload-image-component.js";
* Принимает объект пользователя в качестве аргумента.
*/
export function renderAuthPageComponent({ appEl, setUser }) {
- /**
- * Флаг, указывающий текущий режим формы.
- * Если `true`, форма находится в режиме входа. Если `false`, в режиме регистрации.
- * @type {boolean}
- */
- let isLoginMode = true;
-
- /**
- * URL изображения, загруженного пользователем при регистрации.
- * Используется только в режиме регистрации.
- * @type {string}
- */
- let imageUrl = "";
-
- /**
- * Рендерит форму авторизации или регистрации.
- * В зависимости от значения `isLoginMode` отображает соответствующий интерфейс.
- */
- const renderForm = () => {
- const appHtml = `
+ /**
+ * Флаг, указывающий текущий режим формы.
+ * Если `true`, форма находится в режиме входа. Если `false`, в режиме регистрации.
+ * @type {boolean}
+ */
+ let isLoginMode = true;
+
+ /**
+ * URL изображения, загруженного пользователем при регистрации.
+ * Используется только в режиме регистрации.
+ * @type {string}
+ */
+ let imageUrl = '';
+
+ /**
+ * Рендерит форму авторизации или регистрации.
+ * В зависимости от значения `isLoginMode` отображает соответствующий интерфейс.
+ */
+ const renderForm = () => {
+ const appHtml = `
`;
- appEl.innerHTML = appHtml;
-
- /**
- * Устанавливает сообщение об ошибке в форме.
- * @param {string} message - Текст сообщения об ошибке.
- */
- const setError = (message) => {
- appEl.querySelector(".form-error").textContent = message;
- };
-
- // Рендерим заголовок страницы
- renderHeaderComponent({
- element: document.querySelector(".header-container"),
- });
-
- // Если режим регистрации, рендерим компонент загрузки изображения
- const uploadImageContainer = appEl.querySelector(".upload-image-container");
- if (uploadImageContainer) {
- renderUploadImageComponent({
- element: uploadImageContainer,
- onImageUrlChange(newImageUrl) {
- imageUrl = newImageUrl;
- },
- });
- }
-
- // Обработка клика на кнопку входа/регистрации
- document.getElementById("login-button").addEventListener("click", () => {
- setError("");
-
- if (isLoginMode) {
- // Обработка входа
- const login = document.getElementById("login-input").value;
- const password = document.getElementById("password-input").value;
-
- if (!login) {
- alert("Введите логин");
- return;
- }
-
- if (!password) {
- alert("Введите пароль");
- return;
- }
-
- loginUser({ login, password })
- .then((user) => {
- setUser(user.user);
- })
- .catch((error) => {
- console.warn(error);
- setError(error.message);
- });
- } else {
- // Обработка регистрации
- const login = document.getElementById("login-input").value;
- const name = document.getElementById("name-input").value;
- const password = document.getElementById("password-input").value;
-
- if (!name) {
- alert("Введите имя");
- return;
- }
-
- if (!login) {
- alert("Введите логин");
- return;
- }
-
- if (!password) {
- alert("Введите пароль");
- return;
+ appEl.innerHTML = appHtml;
+
+ /**
+ * Устанавливает сообщение об ошибке в форме.
+ * @param {string} message - Текст сообщения об ошибке.
+ */
+ const setError = (message) => {
+ appEl.querySelector('.form-error').textContent = message;
+ };
+
+ // Рендерим заголовок страницы
+ renderHeaderComponent({
+ element: document.querySelector('.header-container'),
+ });
+
+ // Если режим регистрации, рендерим компонент загрузки изображения
+ const uploadImageContainer = appEl.querySelector(
+ '.upload-image-container',
+ );
+ if (uploadImageContainer) {
+ renderUploadImageComponent({
+ element: uploadImageContainer,
+ onImageUrlChange(newImageUrl) {
+ imageUrl = newImageUrl;
+ },
+ });
}
- if (!imageUrl) {
- alert("Не выбрана фотография");
- return;
- }
+ // Обработка клика на кнопку входа/регистрации
+ document
+ .getElementById('login-button')
+ .addEventListener('click', () => {
+ setError('');
+
+ if (isLoginMode) {
+ // Обработка входа
+ const login = document.getElementById('login-input').value;
+ const password =
+ document.getElementById('password-input').value;
+
+ if (!login) {
+ alert('Введите логин');
+ return;
+ }
+
+ if (!password) {
+ alert('Введите пароль');
+ return;
+ }
+ console.log(replaceHtmlTags(login));
+ loginUser({ login, password })
+ .then((user) => {
+ setUser(user.user);
+ })
+ .catch((error) => {
+ console.warn(error);
+ setError(error.message);
+ });
+ } else {
+ // Обработка регистрации
+ const login = document.getElementById('login-input').value;
+ const name = document.getElementById('name-input').value;
+ const password =
+ document.getElementById('password-input').value;
+
+ if (!name) {
+ alert('Введите имя');
+ return;
+ }
+
+ if (!login) {
+ alert('Введите логин');
+ return;
+ }
+
+ if (!password) {
+ alert('Введите пароль');
+ return;
+ }
+
+ if (!imageUrl) {
+ alert('Не выбрана фотография');
+ return;
+ }
+
+ registerUser({ login, password, name, imageUrl })
+ .then((user) => {
+ setUser(user.user);
+ })
+ .catch((error) => {
+ console.warn(error);
+ setError(error.message);
+ });
+ }
+ });
+
+ // Обработка переключения режима (вход ↔ регистрация)
+ document
+ .getElementById('toggle-button')
+ .addEventListener('click', () => {
+ isLoginMode = !isLoginMode;
+ renderForm(); // Перерисовываем форму с новым режимом
+ });
+ };
- registerUser({ login, password, name, imageUrl })
- .then((user) => {
- setUser(user.user);
- })
- .catch((error) => {
- console.warn(error);
- setError(error.message);
- });
- }
- });
-
- // Обработка переключения режима (вход ↔ регистрация)
- document.getElementById("toggle-button").addEventListener("click", () => {
- isLoginMode = !isLoginMode;
- renderForm(); // Перерисовываем форму с новым режимом
- });
- };
-
- // Инициализация формы
- renderForm();
+ // Инициализация формы
+ renderForm();
}
diff --git a/components/header-component.js b/components/header-component.js
index e733a39dc..f1be6e440 100644
--- a/components/header-component.js
+++ b/components/header-component.js
@@ -1,63 +1,67 @@
-import { goToPage, logout, user } from "../index.js";
-import { ADD_POSTS_PAGE, AUTH_PAGE, POSTS_PAGE } from "../routes.js";
+import { replaceHtmlTags } from '../helpers.js';
+import { goToPage, logout, user } from '../index.js';
+import { ADD_POSTS_PAGE, AUTH_PAGE, POSTS_PAGE } from '../routes.js';
/**
* Компонент заголовка страницы.
* Этот компонент отображает шапку страницы с логотипом, кнопкой добавления постов/входа и кнопкой выхода (если пользователь авторизован).
- *
+ *
* @param {HTMLElement} params.element - HTML-элемент, в который будет рендериться заголовок.
* @returns {HTMLElement} Возвращает элемент заголовка после рендеринга.
*/
export function renderHeaderComponent({ element }) {
- /**
- * Рендерит содержимое заголовка.
- */
- element.innerHTML = `
+ /**
+ * Рендерит содержимое заголовка.
+ */
+ element.innerHTML = `
`;
- /**
- * Обработчик клика по кнопке "Добавить пост"/"Войти".
- * Если пользователь авторизован, перенаправляет на страницу добавления постов.
- * Если пользователь не авторизован, перенаправляет на страницу авторизации.
- */
- element
- .querySelector(".add-or-login-button")
- .addEventListener("click", () => {
- if (user) {
- goToPage(ADD_POSTS_PAGE);
- } else {
- goToPage(AUTH_PAGE);
- }
- });
+ /**
+ * Обработчик клика по кнопке "Добавить пост"/"Войти".
+ * Если пользователь авторизован, перенаправляет на страницу добавления постов.
+ * Если пользователь не авторизован, перенаправляет на страницу авторизации.
+ */
+ element
+ .querySelector('.add-or-login-button')
+ .addEventListener('click', () => {
+ if (user) {
+ goToPage(ADD_POSTS_PAGE);
+ } else {
+ goToPage(AUTH_PAGE);
+ }
+ });
- /**
- * Обработчик клика по логотипу.
- * Перенаправляет на страницу с постами.
- */
- element.querySelector(".logo").addEventListener("click", () => {
- goToPage(POSTS_PAGE);
- });
+ /**
+ * Обработчик клика по логотипу.
+ * Перенаправляет на страницу с постами.
+ */
+ element.querySelector('.logo').addEventListener('click', () => {
+ goToPage(POSTS_PAGE);
+ });
- /**
- * Обработчик клика по кнопке "Выйти".
- * Если кнопка существует (т.е. пользователь авторизован), вызывает функцию `logout`.
- */
- element.querySelector(".logout-button")?.addEventListener("click", logout);
+ /**
+ * Обработчик клика по кнопке "Выйти".
+ * Если кнопка существует (т.е. пользователь авторизован), вызывает функцию `logout`.
+ */
+ element.querySelector('.logout-button')?.addEventListener('click', logout);
- return element;
+ return element;
}
diff --git a/components/loading-page-component.js b/components/loading-page-component.js
index c93522573..f42f40748 100644
--- a/components/loading-page-component.js
+++ b/components/loading-page-component.js
@@ -1,20 +1,20 @@
-import { renderHeaderComponent } from "./header-component.js";
+import { renderHeaderComponent } from './header-component.js';
/**
* Компонент страницы загрузки.
* Этот компонент отображает страницу с индикатором загрузки и заголовком.
* Используется для отображения промежуточного состояния, пока выполняется загрузка данных или другой процесс.
- *
+ *
* @param {HTMLElement} params.appEl - Корневой элемент приложения, в который будет рендериться страница загрузки.
* @param {Object} params.user - Объект пользователя, содержащий данные о текущем авторизованном пользователе (если он есть).
* @param {Function} params.goToPage - Функция для навигации по страницам.
*/
export function renderLoadingPageComponent({ appEl, user, goToPage }) {
- /**
- * HTML-разметка страницы загрузки.
- * Содержит контейнер заголовка и индикатор загрузки.
- */
- const appHtml = `
+ /**
+ * HTML-разметка страницы загрузки.
+ * Содержит контейнер заголовка и индикатор загрузки.
+ */
+ const appHtml = `
@@ -22,16 +22,16 @@ export function renderLoadingPageComponent({ appEl, user, goToPage }) {
`;
- // Устанавливаем разметку в корневой элемент приложения
- appEl.innerHTML = appHtml;
+ // Устанавливаем разметку в корневой элемент приложения
+ appEl.innerHTML = appHtml;
- /**
- * Рендеринг заголовка с использованием компонента `renderHeaderComponent`.
- * Передаются данные пользователя и функция навигации.
- */
- renderHeaderComponent({
- user,
- element: document.querySelector(".header-container"),
- goToPage,
- });
+ /**
+ * Рендеринг заголовка с использованием компонента `renderHeaderComponent`.
+ * Передаются данные пользователя и функция навигации.
+ */
+ renderHeaderComponent({
+ user,
+ element: document.querySelector('.header-container'),
+ goToPage,
+ });
}
diff --git a/components/posts-page-component.js b/components/posts-page-component.js
index 662ccdbdc..2485839be 100644
--- a/components/posts-page-component.js
+++ b/components/posts-page-component.js
@@ -1,109 +1,133 @@
-import { USER_POSTS_PAGE } from "../routes.js";
-import { renderHeaderComponent } from "./header-component.js";
-import { posts, goToPage } from "../index.js";
-
-export function renderPostsPageComponent({ appEl }) {
- // @TODO: реализовать рендер постов из api
- console.log("Актуальный список постов:", posts);
-
- /**
- * @TODO: чтобы отформатировать дату создания поста в виде "19 минут назад"
- * можно использовать https://date-fns.org/v2.29.3/docs/formatDistanceToNow
- */
- const appHtml = `
-
-
-
- -
-
-
-

-
-
-
-
- Нравится: 2
-
-
-
- Иван Иваныч
- Ромашка, ромашка...
-
-
- 19 минут назад
-
-
- -
-
-
-
-
-

-
-
-
-
- Нравится: 35
-
-
-
- Варварва Н.
- Нарисовала картину, посмотрите какая красивая
-
-
- 3 часа назад
-
-
- -
-
-
-
-
-

+import { DELETE_POST_PAGE, USER_POSTS_PAGE } from '../routes.js';
+import { renderHeaderComponent } from './header-component.js';
+import { posts, goToPage, user } from '../index.js';
+import { formatDistanceToNow } from 'date-fns';
+import { ru } from 'date-fns/locale';
+import { likePost } from '../api.js';
+import { replaceHtmlTags } from '../helpers.js';
+
+export function renderPostsPageComponent({ appEl }, token) {
+ let appHtml = '';
+
+ if (posts.length > 0) {
+ appHtml = posts
+ .map((post, index) => {
+ return `
+
+
+
+
+ -
+
+
+ ${replaceHtmlTags(post.user.name)}
+ ${replaceHtmlTags(post.description)}
+
+
+ ${formatDistanceToNow(post.createdAt, { locale: ru })}
+
+
- appEl.innerHTML = appHtml;
+
+
+ `;
+ })
+ .join('');
+ } else {
+ appHtml = `
+
+
+
+ `;
+ }
- renderHeaderComponent({
- element: document.querySelector(".header-container"),
- });
+ appEl.innerHTML = appHtml;
- for (let userEl of document.querySelectorAll(".post-header")) {
- userEl.addEventListener("click", () => {
- goToPage(USER_POSTS_PAGE, {
- userId: userEl.dataset.userId,
- });
+ renderHeaderComponent({
+ element: document.querySelector('.header-container'),
});
- }
+
+ for (let userEl of document.querySelectorAll('.post-header')) {
+ userEl.addEventListener('click', () => {
+ goToPage(USER_POSTS_PAGE, {
+ userId: userEl.dataset.userId,
+ });
+ });
+ }
+
+ for (let btnElem of document.querySelectorAll('.like-button')) {
+ btnElem.addEventListener('click', () => {
+ const index = btnElem.dataset.postIndex;
+ const img = btnElem.querySelector('img');
+ const countLikesElem =
+ document.querySelectorAll('.post-likes-text')[index];
+
+ likePost({ token }, posts[index].id, posts[index].isLiked).then(
+ (data) => {
+ posts[index].likes = data.likes;
+ posts[index].isLiked = data.isLiked;
+
+ if (posts[index].isLiked) {
+ img.src = './assets/images/like-active.svg';
+ } else {
+ img.src = './assets/images/like-not-active.svg';
+ }
+
+ countLikesElem.innerHTML = `Нравится:
${posts[index].likes.length}`;
+ },
+ );
+ });
+ }
+
+ for (let btnMenu of document.querySelectorAll('.post-header__menu-btn')) {
+ btnMenu.addEventListener('click', (event) => {
+ event.stopPropagation();
+
+ const index = btnMenu.dataset.index;
+
+ if (posts[index].user.id === user._id) {
+ const menu = document.getElementById(`menu-${index}`);
+ menu.style.display =
+ menu.style.display === 'none' ? 'flex' : 'none';
+ }
+ });
+ }
+
+ for (let btnDelete of document.querySelectorAll(
+ '.post-header__btn-delete',
+ )) {
+ btnDelete.addEventListener('click', (event) => {
+ event.stopPropagation();
+
+ if (user) {
+ const index = btnDelete.dataset.index;
+ const isConfirm = confirm('Вы подтверждаете удаление?');
+ if (isConfirm) {
+ goToPage(DELETE_POST_PAGE, { postId: posts[index].id });
+ }
+ }
+ });
+ }
}
diff --git a/components/upload-image-component.js b/components/upload-image-component.js
index e2cdf2018..f5df68c02 100644
--- a/components/upload-image-component.js
+++ b/components/upload-image-component.js
@@ -1,4 +1,4 @@
-import { uploadImage } from "../api.js";
+import { uploadImage } from '../api.js';
/**
* Компонент загрузки изображения.
@@ -10,30 +10,30 @@ import { uploadImage } from "../api.js";
* Принимает один аргумент - новый URL изображения или пустую строку.
*/
export function renderUploadImageComponent({ element, onImageUrlChange }) {
- /**
- * URL текущего изображения.
- * Изначально пуст, пока пользователь не загрузит изображение.
- * @type {string}
- */
- let imageUrl = "";
+ /**
+ * URL текущего изображения.
+ * Изначально пуст, пока пользователь не загрузит изображение.
+ * @type {string}
+ */
+ let imageUrl = '';
- /**
- * Функция рендеринга компонента.
- * Отображает интерфейс компонента в зависимости от состояния:
- * либо форма выбора файла, либо превью загруженного изображения с кнопкой замены.
- */
- const render = () => {
- element.innerHTML = `
+ /**
+ * Функция рендеринга компонента.
+ * Отображает интерфейс компонента в зависимости от состояния:
+ * либо форма выбора файла, либо превью загруженного изображения с кнопкой замены.
+ */
+ const render = () => {
+ element.innerHTML = `
${
- imageUrl
- ? `
+ imageUrl
+ ? `
`
- : `
+ : `