From 010d0c094622857c956690a0d554b6bd80f5d98f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B0=D1=82=D1=8C=D1=8F=D0=BD=D0=B0=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B4=D1=80=D0=B5=D0=B5=D0=B2=D0=B0?= Date: Sat, 8 Jun 2024 16:40:04 +0300 Subject: [PATCH] add view --- src/app.js | 1 - src/locales/ru.js | 4 +++ src/parser.js | 5 +-- src/view.js | 84 +++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/app.js b/src/app.js index fd15719..00863f6 100644 --- a/src/app.js +++ b/src/app.js @@ -66,7 +66,6 @@ export default () => { const { feed, posts } = parseData; const id = uniqueId(); watchedState.feeds.push({ ...feed, feedId: id, url }); - console.log(watchedState.feeds); posts.forEach((post) => watchedState.posts.push({ ...post, id })); watchedState.loadingProcess.status = 'finished'; watchedState.loadingProcess.error = ''; diff --git a/src/locales/ru.js b/src/locales/ru.js index c313446..13e89e1 100644 --- a/src/locales/ru.js +++ b/src/locales/ru.js @@ -5,6 +5,10 @@ export default { label: 'Ссылка RSS', example: 'Пример: https://ru.hexlet.io/lessons.rss', button: 'Добавить', + feedback: 'RSS успешно загружен', + feedTitle: 'Фиды', + postsTitle: 'Посты', + postsButton: 'Просмотр', errors: { existsRss: 'RSS уже существует', invalidUrl: 'Ссылка должна быть валидным URL', diff --git a/src/parser.js b/src/parser.js index 575751a..57a71b6 100644 --- a/src/parser.js +++ b/src/parser.js @@ -9,11 +9,12 @@ export default (data) => { const feedTitle = doc.querySelector('channel > title').textContent; const feedDescription = doc.querySelector('description').textContent; const feed = { title: feedTitle, description: feedDescription }; - const items = doc.querySelectorAll('items'); + const items = doc.querySelectorAll('item'); const posts = Array.from(items).map((post) => { const title = post.querySelector('title').textContent; const description = post.querySelector('description').textContent; - return { title, description }; + const url = post.querySelector('link').textContent; + return { title, description, url }; }); return { feed, posts }; }; diff --git a/src/view.js b/src/view.js index 7186d98..4f2c9e9 100644 --- a/src/view.js +++ b/src/view.js @@ -4,37 +4,107 @@ export default (elements, i18n, state) => { const { t } = i18n; const renderForm = () => { - // eslint-disable-next-line no-restricted-globals - focus(); + const { input } = elements; + input.focus(); Object.entries(elements.staticEl).forEach(([key, el]) => { const element = el; element.textContent = t(`${key}`); }); }; - const renderFeedsAndPosts = () => { + const renderBlock = (title) => { + const card = document.createElement('div'); + const cardBody = document.createElement('div'); + const cardTitle = document.createElement('h2'); + card.classList.add('card', 'border-0'); + cardBody.classList.add('card-body'); + cardTitle.classList.add('card-title', 'h4'); + cardTitle.textContent = title; + + card.append(cardBody); + cardBody.append(cardTitle); + return card; + }; + + const renderFeeds = () => { + const feedContainer = document.querySelector('.feeds'); + const cardFeed = renderBlock(t('feedTitle')); + const lists = document.createElement('ul'); + lists.classList.add('list-group', 'border-0', 'rounded-0'); + + state.feeds.forEach(({ title, description }) => { + const li = document.createElement('li'); + const h3 = document.createElement('h3'); + const p = document.createElement('p'); + li.classList.add('list-group-item', 'border-0', 'border-end-0'); + h3.classList.add('h6', 'm-0'); + p.classList.add('m-0', 'small', 'text-black-50'); + h3.textContent = title; + p.textContent = description; + + li.append(h3, p); + lists.append(li); + cardFeed.append(lists); + feedContainer.append(cardFeed); + }); + }; + + const renderPosts = () => { + const postsContainer = document.querySelector('.posts'); + const cardPosts = renderBlock(t('postsTitle')); + const lists = document.createElement('ul'); + lists.classList.add('list-group', 'border-0', 'rounded-0'); + + state.posts.forEach(({ title, id, url }) => { + const li = document.createElement('li'); + const link = document.createElement('a'); + const button = document.createElement('button'); + li.classList.add('list-group-item', 'border-0', 'border-end-0', 'd-flex', 'justify-content-between', 'align-items-start'); + link.classList.add('fw-bold'); + link.setAttribute('href', url); + link.setAttribute('id', id); + link.textContent = title; + + button.classList.add('btn', 'btn-outline-primary', 'btn-sm'); + button.setAttribute('type', 'button'); + button.textContent = t('postsButton'); + + li.append(link, button); + lists.append(li); + cardPosts.append(lists); + postsContainer.append(cardPosts); + }); }; const watchedState = onChange(state, (path, value) => { - const { errorElement, input, button } = elements; + const { + errorElement, input, form, staticEl, + } = elements; switch (path) { case 'form.status': if (value === 'pending') { renderForm(); } else if (value === 'invalid') { - console.log(value); input.classList.add('is-invalid'); errorElement.classList.remove('text-success'); errorElement.classList.add('text-danger'); errorElement.textContent = t('errors.invalidUrl'); } - renderFeedsAndPosts(); break; case 'loadingProcess.status': if (value === 'sending') { + staticEl.button.disabled = true; errorElement.textContent = ''; + } else if (value === 'finished') { + staticEl.button.disabled = false; input.classList.remove('is-invalid'); - button.disabled = true; + errorElement.classList.remove('text-danger'); + errorElement.classList.add('text-success'); + errorElement.textContent = t('feedback'); + form.reset(); + input.focus(); + renderFeeds(); + renderPosts(); } break; case 'loadingProcess.error':