From 063caa8c579f154b774a4e1ae6bb7ff1a38ef655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=A7=D0=B5=D1=87=D1=83=D0=BB=D0=B8=D0=BD?= Date: Fri, 13 Dec 2024 22:33:13 +0300 Subject: [PATCH 1/4] =?UTF-8?q?=D1=80=D0=B5=D1=88=D0=B8=D1=82=D1=8C=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC=D0=B0=D1=88=D0=BA=D0=B8=20dom1-2-3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 149 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 38 deletions(-) diff --git a/index.html b/index.html index 6f14ae14aa..dabde05f09 100644 --- a/index.html +++ b/index.html @@ -8,53 +8,20 @@
- +
@@ -65,7 +32,113 @@ From 857e026d569896e46240348438d79bbd5af41ed7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=A7=D0=B5=D1=87=D1=83=D0=BB=D0=B8=D0=BD?= Date: Sun, 22 Dec 2024 15:39:01 +0300 Subject: [PATCH 2/4] =?UTF-8?q?=D1=80=D0=B5=D1=88=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20dom1-2-3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .prettierrc.yaml | 3 ++ eslint.config.mjs | 13 ++++++++ index.html | 5 ++-- index.js | 5 ++++ modules/comments.js | 16 ++++++++++ modules/initListeners.js | 63 +++++++++++++++++++++++++++++++++++++++ modules/renderComments.js | 35 ++++++++++++++++++++++ modules/sanitizeHtml.js | 3 ++ 9 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 .prettierrc.yaml create mode 100644 eslint.config.mjs create mode 100644 index.js create mode 100644 modules/comments.js create mode 100644 modules/initListeners.js create mode 100644 modules/renderComments.js create mode 100644 modules/sanitizeHtml.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..b512c09d47 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000000..0c03d914b1 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,3 @@ +tabWidth: 4 +semi: false +singleQuote: true diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..641d47197f --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,13 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; +import config from "eslint-config-prettier"; +import plugin from "eslint-plugin-prettier/recommended"; + + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + {languageOptions: { globals: globals.browser }}, + pluginJs.configs.recommended, + config, + plugin +]; \ No newline at end of file diff --git a/index.html b/index.html index dabde05f09..e7b24c3ead 100644 --- a/index.html +++ b/index.html @@ -28,9 +28,10 @@
+ - --> diff --git a/index.js b/index.js new file mode 100644 index 0000000000..fd148cf26d --- /dev/null +++ b/index.js @@ -0,0 +1,5 @@ +import { initAddCommentListener } from './modules/initListeners.js' +import { renderComments } from './modules/renderComments.js' + +renderComments() +initAddCommentListener(renderComments) diff --git a/modules/comments.js b/modules/comments.js new file mode 100644 index 0000000000..76ee49cd96 --- /dev/null +++ b/modules/comments.js @@ -0,0 +1,16 @@ +export let comments = [ + { + name: "Глеб Фокин", + date: new Date(), + text: "Это будет первый комментарий на этой странице", + likes: 3, + isLiked: false, + }, + { + name: "Варвара Н.", + date: new Date(), + text: "Мне нравится как оформлена эта страница! ❤", + likes: 75, + isLiked: true, + }, + ]; \ No newline at end of file diff --git a/modules/initListeners.js b/modules/initListeners.js new file mode 100644 index 0000000000..5e2f081883 --- /dev/null +++ b/modules/initListeners.js @@ -0,0 +1,63 @@ +import { comments } from "./comments.js"; +import { sanitizeHtml } from "./sanitizeHtml.js"; + +export const initLikeListeners = (renderComments) => { + const likeButtons = document.querySelectorAll(".like-button"); + + for (const likeButton of likeButtons) { + likeButton.addEventListener("click", (event) => { + event.stopPropagation(); + + const index = likeButton.dataset.index; + const comment = comments[index]; + + comment.likes = comment.isLiked + ? comment.likes - 1 + : comment.likes + 1; + + comment.isLiked = !comment.isLiked; + + renderComments(); + }); + } +} + +export const initReplyListeners = () => { + const text = document.getElementById("text-input"); + const commentsElements = document.querySelectorAll(".comment"); + + for (const commentElement of commentsElements) { + commentElement.addEventListener("click", () => { + const currentComment = comments[commentElement.dataset.index]; + text.value = `${currentComment.name}: ${currentComment.text}`; + }); + } +} + +export const initAddCommentListener = (renderComments) => { + const name = document.getElementById("name-input"); + const text = document.getElementById("text-input"); + const addButton = document.querySelector(".add-form-button"); + + addButton.addEventListener("click", () => { + if (!name.value || !text.value) { + console.error("заполните форму"); + return; + } + + const newComment = { + name: sanitizeHtml(name.value), + date: new Date(), + text: sanitizeHtml(text.value), + likes: 0, + isLiked: false, + }; + + comments.push(newComment); + + renderComments(); + + name.value = ""; + text.value = ""; + }); +} \ No newline at end of file diff --git a/modules/renderComments.js b/modules/renderComments.js new file mode 100644 index 0000000000..062f004c92 --- /dev/null +++ b/modules/renderComments.js @@ -0,0 +1,35 @@ +import { comments } from "./comments.js"; +import { initLikeListeners, initReplyListeners } from "./initListeners.js"; + +export const renderComments = () => { + const list = document.querySelector(".comments"); + + list.innerHTML = comments + .map((comment, index) => { + return ` +
  • +
    +
    ${comment.name}
    +
    ${comment.date.toLocaleDateString()}
    +
    +
    +
    + ${comment.text} +
    +
    + +
  • + `; + }) + .join(""); + + initLikeListeners(renderComments); + initReplyListeners(); + }; \ No newline at end of file diff --git a/modules/sanitizeHtml.js b/modules/sanitizeHtml.js new file mode 100644 index 0000000000..7e9db7acd6 --- /dev/null +++ b/modules/sanitizeHtml.js @@ -0,0 +1,3 @@ +export const sanitizeHtml = (value) => { + return value.replaceAll("<", "<").replaceAll(">", ">"); +}; \ No newline at end of file From 06ba8356ce67e83610c0adcf16c7c787467fcaf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=A7=D0=B5=D1=87=D1=83=D0=BB=D0=B8=D0=BD?= Date: Sun, 22 Dec 2024 18:15:02 +0300 Subject: [PATCH 3/4] =?UTF-8?q?=D1=80=D0=B5=D1=88=D0=B5=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D0=B4=D0=BE=D0=BC=D0=B0=D1=88=D0=B5=D0=BA=201-2-3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eslint.config.mjs | 19 +- index.html | 173 ++---- index.js | 15 +- modules/api.js | 41 ++ modules/comments.js | 34 +- modules/initListeners.js | 114 ++-- modules/renderComments.js | 26 +- package-lock.json | 1102 +++++++++++++++++++++++++++++++++++++ package.json | 19 + styles.css | 102 ++-- 10 files changed, 1370 insertions(+), 275 deletions(-) create mode 100644 modules/api.js create mode 100644 package-lock.json create mode 100644 package.json diff --git a/eslint.config.mjs b/eslint.config.mjs index 641d47197f..a5dc7820be 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,13 +1,12 @@ -import globals from "globals"; -import pluginJs from "@eslint/js"; -import config from "eslint-config-prettier"; -import plugin from "eslint-plugin-prettier/recommended"; - +import globals from 'globals' +import pluginJs from '@eslint/js' +import config from 'eslint-config-prettier' +import plugin from 'eslint-plugin-prettier/recommended' /** @type {import('eslint').Linter.Config[]} */ export default [ - {languageOptions: { globals: globals.browser }}, - pluginJs.configs.recommended, - config, - plugin -]; \ No newline at end of file + { languageOptions: { globals: globals.browser } }, + pluginJs.configs.recommended, + config, + plugin, +] diff --git a/index.html b/index.html index e7b24c3ead..b17b81df3f 100644 --- a/index.html +++ b/index.html @@ -1,145 +1,36 @@ - + - - Проект "Комменты" - - - - - -
    -
      -
      - - -
      - -
      -
      -
      - - - - + + + diff --git a/index.js b/index.js index fd148cf26d..d5f2949379 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,18 @@ +import { fetchComments } from './modules/api.js' +import { updateComments } from './modules/comments.js' import { initAddCommentListener } from './modules/initListeners.js' import { renderComments } from './modules/renderComments.js' -renderComments() +document.querySelector('.comments').innerHTML = + 'Пожалуйста подождите, загружаю комментарии...' + +const fetchAndRenderComments = () => { + fetchComments().then((data) => { + updateComments(data) + + renderComments() + }) +} + +fetchAndRenderComments() initAddCommentListener(renderComments) diff --git a/modules/api.js b/modules/api.js new file mode 100644 index 0000000000..b4d3e97353 --- /dev/null +++ b/modules/api.js @@ -0,0 +1,41 @@ +const host = 'https://webdev-hw-api.vercel.app/api/v1/vladislav-chechulin' + +export const fetchComments = () => { + return fetch(host + '/comments') + .then((res) => res.json()) + .then((responseData) => { + const appComments = responseData.comments.map((comment) => { + return { + name: comment.author.name, + date: new Date(comment.date), + text: comment.text, + likes: comment.likes, + isLiked: false, + } + }) + + return appComments + }) +} + +export const postComment = (text, name) => { + return fetch(host + '/comments', { + method: 'POST', + body: JSON.stringify({ + text, + name, + }), + }) + .then((response) => { + if (response.status === 500) { + throw new Error('Ошибка сервера') + } + + if (response.status === 400) { + throw new Error('Неверный запрос') + } + }) + .then(() => { + return fetchComments() + }) +} diff --git a/modules/comments.js b/modules/comments.js index 76ee49cd96..2893d2aacb 100644 --- a/modules/comments.js +++ b/modules/comments.js @@ -1,16 +1,20 @@ export let comments = [ - { - name: "Глеб Фокин", - date: new Date(), - text: "Это будет первый комментарий на этой странице", - likes: 3, - isLiked: false, - }, - { - name: "Варвара Н.", - date: new Date(), - text: "Мне нравится как оформлена эта страница! ❤", - likes: 75, - isLiked: true, - }, - ]; \ No newline at end of file + // { + // name: 'Глеб Фокин', + // date: new Date(), + // text: 'Это будет первый комментарий на этой странице', + // likes: 3, + // isLiked: false, + // }, + // { + // name: 'Варвара Н.', + // date: new Date(), + // text: 'Мне нравится как оформлена эта страница! ❤', + // likes: 75, + // isLiked: true, + // }, +] + +export const updateComments = (newComments) => { + comments = newComments +} diff --git a/modules/initListeners.js b/modules/initListeners.js index 5e2f081883..3489c99c94 100644 --- a/modules/initListeners.js +++ b/modules/initListeners.js @@ -1,63 +1,85 @@ -import { comments } from "./comments.js"; -import { sanitizeHtml } from "./sanitizeHtml.js"; +import { postComment } from './api.js' +import { comments, updateComments } from './comments.js' +import { sanitizeHtml } from './sanitizeHtml.js' export const initLikeListeners = (renderComments) => { - const likeButtons = document.querySelectorAll(".like-button"); - + const likeButtons = document.querySelectorAll('.like-button') + for (const likeButton of likeButtons) { - likeButton.addEventListener("click", (event) => { - event.stopPropagation(); + likeButton.addEventListener('click', (event) => { + event.stopPropagation() - const index = likeButton.dataset.index; - const comment = comments[index]; + const index = likeButton.dataset.index + const comment = comments[index] - comment.likes = comment.isLiked - ? comment.likes - 1 - : comment.likes + 1; + comment.likes = comment.isLiked + ? comment.likes - 1 + : comment.likes + 1 - comment.isLiked = !comment.isLiked; + comment.isLiked = !comment.isLiked - renderComments(); - }); + renderComments() + }) } } export const initReplyListeners = () => { - const text = document.getElementById("text-input"); - const commentsElements = document.querySelectorAll(".comment"); + const text = document.getElementById('text-input') + const commentsElements = document.querySelectorAll('.comment') for (const commentElement of commentsElements) { - commentElement.addEventListener("click", () => { - const currentComment = comments[commentElement.dataset.index]; - text.value = `${currentComment.name}: ${currentComment.text}`; - }); + commentElement.addEventListener('click', () => { + const currentComment = comments[commentElement.dataset.index] + text.value = `${currentComment.name}: ${currentComment.text}` + }) } } export const initAddCommentListener = (renderComments) => { - const name = document.getElementById("name-input"); - const text = document.getElementById("text-input"); - const addButton = document.querySelector(".add-form-button"); - - addButton.addEventListener("click", () => { - if (!name.value || !text.value) { - console.error("заполните форму"); - return; - } - - const newComment = { - name: sanitizeHtml(name.value), - date: new Date(), - text: sanitizeHtml(text.value), - likes: 0, - isLiked: false, - }; - - comments.push(newComment); - - renderComments(); - - name.value = ""; - text.value = ""; - }); -} \ No newline at end of file + const name = document.getElementById('name-input') + const text = document.getElementById('text-input') + const addButton = document.querySelector('.add-form-button') + + addButton.addEventListener('click', () => { + if (!name.value || !text.value) { + console.error('заполните форму') + return + } + + document.querySelector('.form-loading').style.display = 'block' + document.querySelector('.add-form').style.display = 'none' + + postComment(sanitizeHtml(text.value), sanitizeHtml(name.value)) + .then((data) => { + updateComments(data) + renderComments() + + name.value = '' + text.value = '' + }) + .catch((error) => { + document.querySelector('.form-loading').style.display = 'none' + document.querySelector('.add-form').style.display = 'flex' + + if (error.message === 'Ошибка сервера') { + alert('Сервер сломался, попробуй позже') + } + + if (error.message === 'Failed to fetch') { + alert('Нет интернета, попробуй позже') + } + + if (error.message === 'Неверный запрос') { + alert('Имя и комментарий должны быть не короче 3х символов') + + name.classList.add('-error') + text.classList.add('-error') + + setTimeout(() => { + name.classList.remove('-error') + text.classList.remove('-error') + }, 2000) + } + }) + }) +} diff --git a/modules/renderComments.js b/modules/renderComments.js index 062f004c92..63d9f09e27 100644 --- a/modules/renderComments.js +++ b/modules/renderComments.js @@ -1,12 +1,12 @@ -import { comments } from "./comments.js"; -import { initLikeListeners, initReplyListeners } from "./initListeners.js"; +import { comments } from './comments.js' +import { initLikeListeners, initReplyListeners } from './initListeners.js' export const renderComments = () => { - const list = document.querySelector(".comments"); + const list = document.querySelector('.comments') list.innerHTML = comments - .map((comment, index) => { - return ` + .map((comment, index) => { + return `
    • ${comment.name}
      @@ -21,15 +21,15 @@ export const renderComments = () => {
    • - `; - }) - .join(""); + ` + }) + .join('') - initLikeListeners(renderComments); - initReplyListeners(); - }; \ No newline at end of file + initLikeListeners(renderComments) + initReplyListeners() +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000..1721cfabf3 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1102 @@ +{ + "name": "comments-tempalte", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "comments-tempalte", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@eslint/js": "^9.17.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "globals": "^15.14.0", + "prettier": "^3.4.2" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "peer": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "peer": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", + "peer": true, + "dependencies": { + "@eslint/object-schema": "^2.1.5", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", + "peer": true, + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "peer": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "peer": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "peer": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "peer": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "peer": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "peer": true + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "peer": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "peer": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "peer": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "peer": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "peer": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "peer": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "peer": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "peer": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", + "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "peer": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "peer": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "peer": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "peer": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "peer": true + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "peer": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "peer": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "peer": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "peer": true + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "peer": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "peer": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "peer": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "peer": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "peer": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "peer": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "peer": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "peer": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "peer": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "peer": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "peer": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "peer": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "peer": true + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "peer": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "peer": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "peer": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "peer": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "peer": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "peer": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "peer": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000..a69809246b --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "comments-tempalte", + "version": "1.0.0", + "description": "https://glebkaf.github.io/webdev-dom-homework/", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@eslint/js": "^9.17.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", + "globals": "^15.14.0", + "prettier": "^3.4.2" + } +} diff --git a/styles.css b/styles.css index edc120f8cd..57b9642db9 100644 --- a/styles.css +++ b/styles.css @@ -1,8 +1,8 @@ body { margin: 0; - } +} - .container { +.container { font-family: Helvetica; color: #ffffff; display: flex; @@ -12,117 +12,117 @@ body { padding-bottom: 200px; background: #202020; min-height: 100vh; - } +} - .comments, - .comment { +.comments, +.comment { margin: 0; padding: 0; list-style: none; - } +} - .comment, - .add-form { +.comment, +.add-form { width: 596px; box-sizing: border-box; background: radial-gradient( - 75.42% 75.42% at 50% 42.37%, - rgba(53, 53, 53, 0) 22.92%, - #7334ea 100% + 75.42% 75.42% at 50% 42.37%, + rgba(53, 53, 53, 0) 22.92%, + #7334ea 100% ); filter: drop-shadow(0px 20px 67px rgba(0, 0, 0, 0.08)); border-radius: 20px; - } +} - .comments { +.comments { display: flex; flex-direction: column; gap: 24px; - } +} - .comment { +.comment { padding: 48px; - } +} - .comment-header { +.comment-header { font-size: 16px; display: flex; justify-content: space-between; - } +} - .comment-footer { +.comment-footer { display: flex; justify-content: flex-end; - } +} - .comment-body { +.comment-body { margin-top: 32px; margin-bottom: 32px; - } +} - .comment-text { +.comment-text { font-size: 32px; - } +} - .likes { +.likes { display: flex; align-items: center; - } +} - .like-button { +.like-button { all: unset; cursor: pointer; - } +} - .likes-counter { +.likes-counter { font-size: 26px; margin-right: 8px; - } +} - .like-button { +.like-button { margin-left: 10px; background-image: url("data:image/svg+xml,%3Csvg width='22' height='20' viewBox='0 0 22 20' fill='none' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath d='M11.11 16.9482L11 17.0572L10.879 16.9482C5.654 12.2507 2.2 9.14441 2.2 5.99455C2.2 3.81471 3.85 2.17984 6.05 2.17984C7.744 2.17984 9.394 3.26975 9.977 4.75204H12.023C12.606 3.26975 14.256 2.17984 15.95 2.17984C18.15 2.17984 19.8 3.81471 19.8 5.99455C19.8 9.14441 16.346 12.2507 11.11 16.9482ZM15.95 0C14.036 0 12.199 0.882834 11 2.26703C9.801 0.882834 7.964 0 6.05 0C2.662 0 0 2.6267 0 5.99455C0 10.1035 3.74 13.4714 9.405 18.5613L11 20L12.595 18.5613C18.26 13.4714 22 10.1035 22 5.99455C22 2.6267 19.338 0 15.95 0Z' fill='%23BCEC30' /%3E%3C/svg%3E"); background-repeat: no-repeat; width: 22px; height: 22px; - } +} - .-active-like { +.-active-like { background-image: url("data:image/svg+xml,%3Csvg width='22' height='20' viewBox='0 0 22 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.95 0C14.036 0 12.199 0.882834 11 2.26703C9.801 0.882834 7.964 0 6.05 0C2.662 0 0 2.6267 0 5.99455C0 10.1035 3.74 13.4714 9.405 18.5613L11 20L12.595 18.5613C18.26 13.4714 22 10.1035 22 5.99455C22 2.6267 19.338 0 15.95 0Z' fill='%23BCEC30'/%3E%3C/svg%3E"); - } +} - .add-form { +.add-form { padding: 20px; margin-top: 48px; display: flex; flex-direction: column; - } +} - .add-form-name, - .add-form-text { +.add-form-name, +.add-form-text { font-size: 16px; font-family: Helvetica; border-radius: 8px; border: none; - } +} - .add-form-name { +.add-form-name { width: 300px; padding: 11px 22px; - } +} - .add-form-text { +.add-form-text { margin-top: 12px; padding: 22px; resize: none; - } +} - .add-form-row { +.add-form-row { display: flex; justify-content: flex-end; - } +} - .add-form-button { +.add-form-button { margin-top: 24px; font-size: 24px; padding: 10px 20px; @@ -130,8 +130,12 @@ body { border: none; border-radius: 18px; cursor: pointer; - } +} - .add-form-button:hover { +.add-form-button:hover { opacity: 0.9; - } \ No newline at end of file +} + +.-error { + border: 1px solid red; +} From 83f4cbe57e2bfc47ce282df3d782e67dcc27b616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=A7=D0=B5=D1=87=D1=83=D0=BB=D0=B8=D0=BD?= Date: Mon, 27 Jan 2025 13:34:58 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 +- index.js | 14 ++++--- modules/api.js | 36 +++++++++++++++++- modules/renderComments.js | 55 +++++++++++++++++++++++++-- modules/renderLogin.js | 56 ++++++++++++++++++++++++++++ modules/renderRegistration.js | 59 +++++++++++++++++++++++++++++ modules/sanitizeHtml.js | 4 +- styles.css | 70 +++++++++++++++++++++++++++++++++++ 8 files changed, 283 insertions(+), 15 deletions(-) create mode 100644 modules/renderLogin.js create mode 100644 modules/renderRegistration.js diff --git a/index.html b/index.html index b17b81df3f..9ba0007d6f 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,7 @@
      -
        +
        diff --git a/index.js b/index.js index d5f2949379..2db746f118 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,15 @@ import { fetchComments } from './modules/api.js' import { updateComments } from './modules/comments.js' -import { initAddCommentListener } from './modules/initListeners.js' import { renderComments } from './modules/renderComments.js' -document.querySelector('.comments').innerHTML = - 'Пожалуйста подождите, загружаю комментарии...' +export const fetchAndRenderComments = (isFirstLoading) => { + const container = document.querySelector('.container') + + if (isFirstLoading) { + container.innerHTML = + '

        Пожалуйста подождите, загружаю комментарии...

        ' + } -const fetchAndRenderComments = () => { fetchComments().then((data) => { updateComments(data) @@ -14,5 +17,4 @@ const fetchAndRenderComments = () => { }) } -fetchAndRenderComments() -initAddCommentListener(renderComments) +fetchAndRenderComments(true) diff --git a/modules/api.js b/modules/api.js index b4d3e97353..6ce2c1d11d 100644 --- a/modules/api.js +++ b/modules/api.js @@ -1,4 +1,31 @@ -const host = 'https://webdev-hw-api.vercel.app/api/v1/vladislav-chechulin' +// const host = 'https://webdev-hw-api.vercel.app/api/v1/vladislav-chechulin' +const host = ' https://wedev-api.sky.pro/api/v2/vladislav-chechulin' +const authHost = 'https://wedev-api.sky.pro/api/user' + +export let token = '' +export let name = '' + +export const setToken = (newToken) => { + token = newToken +} + +export const setName = (newName) => { + name = newName +} + +export const login = (login, password) => { + return fetch(authHost + '/login', { + method: 'POST', + body: JSON.stringify({ login: login, password: password }), + }) +} + +export const registration = (name, login, password) => { + return fetch(authHost, { + method: 'POST', + body: JSON.stringify({ name: name, login: login, password: password }), + }) +} export const fetchComments = () => { return fetch(host + '/comments') @@ -21,6 +48,9 @@ export const fetchComments = () => { export const postComment = (text, name) => { return fetch(host + '/comments', { method: 'POST', + headers: { + Authorization: `Bearer ${token}`, + }, body: JSON.stringify({ text, name, @@ -31,6 +61,10 @@ export const postComment = (text, name) => { throw new Error('Ошибка сервера') } + if (response.status === 401) { + throw new Error('Пользователь не авторизован') + } + if (response.status === 400) { throw new Error('Неверный запрос') } diff --git a/modules/renderComments.js b/modules/renderComments.js index 63d9f09e27..3ba6f6acc4 100644 --- a/modules/renderComments.js +++ b/modules/renderComments.js @@ -1,10 +1,16 @@ +import { name, token } from './api.js' import { comments } from './comments.js' -import { initLikeListeners, initReplyListeners } from './initListeners.js' +import { + initAddCommentListener, + initLikeListeners, + initReplyListeners, +} from './initListeners.js' +import { renderLogin } from './renderLogin.js' export const renderComments = () => { - const list = document.querySelector('.comments') + const container = document.querySelector('.container') - list.innerHTML = comments + const commentsHtml = comments .map((comment, index) => { return `
      • @@ -30,6 +36,47 @@ export const renderComments = () => { }) .join('') + const addCommentHtml = `
        + + +
        + +
        +
        + ` + + const linkToLoginText = `

        чтобы отправить комментарий,

        ` + + const baseHtml = ` +
          ${commentsHtml}
        + ${token ? addCommentHtml : linkToLoginText} + ` + + container.innerHTML = baseHtml + initLikeListeners(renderComments) - initReplyListeners() + + if (token) { + initReplyListeners() + initAddCommentListener(renderComments) + } else { + document.querySelector('.link-login').addEventListener('click', () => { + renderLogin() + }) + } } diff --git a/modules/renderLogin.js b/modules/renderLogin.js new file mode 100644 index 0000000000..9022f830c4 --- /dev/null +++ b/modules/renderLogin.js @@ -0,0 +1,56 @@ +import { fetchAndRenderComments } from '../index.js' +import { login, setName, setToken } from './api.js' +import { renderRegistration } from './renderRegistration.js' + +export const renderLogin = () => { + const container = document.querySelector('.container') + + const loginHtml = ` +
        +

        Форма входа

        + + +
        + + + Зарегистрироваться + +
        +
        + ` + + container.innerHTML = loginHtml + + const loginEl = document.querySelector('#login') + const passwordEl = document.querySelector('#password') + const submitButtonEl = document.querySelector('.button-main') + + submitButtonEl.addEventListener('click', () => { + login(loginEl.value, passwordEl.value) + .then((response) => { + return response.json() + }) + .then((data) => { + setToken(data.user.token) + setName(data.user.name) + fetchAndRenderComments() + }) + }) + + document.querySelector('.registry').addEventListener('click', () => { + renderRegistration() + }) +} diff --git a/modules/renderRegistration.js b/modules/renderRegistration.js new file mode 100644 index 0000000000..c6e2580796 --- /dev/null +++ b/modules/renderRegistration.js @@ -0,0 +1,59 @@ +import { fetchAndRenderComments } from '../index.js' +import { registration, setName, setToken } from './api.js' + +export const renderRegistration = () => { + const container = document.querySelector('.container') + + const registryHtml = ` +
        +

        Форма регистрации

        + + + +
        + + + Войти + +
        +
        + ` + + container.innerHTML = registryHtml + + const loginEl = document.querySelector('#login') + const passwordEl = document.querySelector('#password') + const nameEl = document.querySelector('#name') + const submitButtonEl = document.querySelector('.button-main') + + submitButtonEl.addEventListener('click', () => { + registration(nameEl.value, loginEl.value, passwordEl.value) + .then((response) => { + return response.json() + }) + .then((data) => { + setToken(data.user.token) + setName(data.user.name) + fetchAndRenderComments() + }) + }) +} diff --git a/modules/sanitizeHtml.js b/modules/sanitizeHtml.js index 7e9db7acd6..d4c65c332f 100644 --- a/modules/sanitizeHtml.js +++ b/modules/sanitizeHtml.js @@ -1,3 +1,3 @@ export const sanitizeHtml = (value) => { - return value.replaceAll("<", "<").replaceAll(">", ">"); -}; \ No newline at end of file + return value.replaceAll('<', '<').replaceAll('>', '>') +} diff --git a/styles.css b/styles.css index 57b9642db9..e35e866d25 100644 --- a/styles.css +++ b/styles.css @@ -2,6 +2,10 @@ body { margin: 0; } +* { + box-sizing: border-box; +} + .container { font-family: Helvetica; color: #ffffff; @@ -139,3 +143,69 @@ body { .-error { border: 1px solid red; } + +.link-login { + text-decoration: underline; +} + +.add-form { + padding: 20px; + margin-top: 48px; + display: flex; + flex-direction: column; +} +.add-form-name, +.add-form-text { + font-size: 16px; + font-family: Helvetica; + border-radius: 8px; + border: none; +} +.add-form-name { + width: 540px; + padding: 11px 22px; + margin-bottom: 12px; +} + +.add-form-name:read-only { + background-color: #d2ddd2; + color: #363636; + font-weight: bold; +} + +.add-form-registry { + display: flex; + flex-direction: column; + justify-content: flex-end; + border: none; + padding-left: 0; +} + +.add-form-button-main { + width: 100%; + margin-top: 24px; + font-size: 24px; + padding: 10px 20px; + background-color: #bcec30; + border: none; + border-radius: 18px; + cursor: pointer; +} + +.add-form-button-link { + text-align: center; + padding-top: 22px; + color: white; + cursor: pointer; + border-bottom: inherit; +} + +.add-form-button-exit { + width: 50px; + margin-left: auto; + font-size: 12px; + background-color: #acb78b; + border: none; + border-radius: 18px; + cursor: pointer; +}