diff --git a/README.md b/README.md
index 9751a3a..71f9887 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,5 @@
-# React TypeScript Starter Pack
+Description:
+ - News page with ability to search articles and choose categories.
-To use this template click `Use this template`
-### Available Scripts
-
-`Deploy` - available to deploy your application to gh-pages
-
-`SCSS Preprocessor` - available to write your styles with modern style language
+- [DEMO](https://uran-web.github.io/react-typescript-starter-pack/);
diff --git a/package-lock.json b/package-lock.json
index a3d5e77..bc2dcf5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4556,6 +4556,11 @@
}
}
},
+ "classnames": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
+ "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+ },
"clean-css": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
diff --git a/package.json b/package.json
index aae404f..8169a66 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"@types/node": "^12.20.10",
"@types/react": "^17.0.4",
"@types/react-dom": "^17.0.3",
+ "classnames": "^2.3.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
diff --git a/public/images/header.jpg b/public/images/header.jpg
new file mode 100644
index 0000000..f43051d
Binary files /dev/null and b/public/images/header.jpg differ
diff --git a/public/index.html b/public/index.html
index aa069f2..9f82a10 100644
--- a/public/index.html
+++ b/public/index.html
@@ -24,6 +24,12 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
+
React App
diff --git a/public/search.svg b/public/search.svg
new file mode 100644
index 0000000..ae4687e
--- /dev/null
+++ b/public/search.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/App.scss b/src/App.scss
index 8f4cd9f..0358dde 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -1,3 +1,155 @@
.starter {
font-size: 18px;
}
+
+.menu {
+ position: sticky;
+ top: 0;
+ width: 100%;
+ z-index: 1020;
+}
+
+.container {
+ padding: 14px 60px 0;
+ background-color: #fff;
+}
+
+.card-body--head-article {
+ padding: 41px 82px 43px 57px;
+}
+
+.card-title {
+ font-family: Inter;
+ font-style: normal;
+ font-weight: bold;
+ font-size: 20px;
+ line-height: 24px;
+
+ &--head-title {
+ font-size: 30px;
+ line-height: 36px;
+ }
+}
+
+.mb-27 {
+ margin-bottom: 27px;
+}
+
+.mb-30 {
+ margin-bottom: 30px;
+}
+
+.h-100 {
+ height: 382px;
+}
+
+.card-inner {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.element {
+ margin: 0;
+}
+
+.gu-image {
+ width: 100%;
+ height: 179px;
+
+ object-fit: fill;
+}
+
+.element-image__caption, .element-image__credit {
+ display: none;
+}
+
+.card-text {
+ font-family: Inter;
+ font-style: normal;
+ font-weight: normal;
+ font-size: 14px;
+ line-height: 17px;
+
+ color: #718096;
+
+ &--bot {
+ margin: 0;
+
+ font-size: 12px;
+ line-height: 15px;
+ }
+
+ &--small-card {
+ height: 85px;
+ overflow: hidden;
+ }
+}
+
+.card-date {
+ margin: 0;
+
+ font-family: Inter;
+ font-style: normal;
+ font-weight: bold;
+ font-size: 12px;
+ line-height: 15px;
+
+ color: #2D3748;
+}
+
+.article-details {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ &__text {
+ margin: 0;
+ }
+}
+
+.article-link {
+ color: black;
+ font-weight: bold;
+ text-decoration: none;
+
+ &__text {
+ margin: 0;
+ }
+}
+
+.article-link:hover {
+ text-decoration: underline;
+}
+
+.footer {
+ padding-bottom: 50px;
+}
+
+.footer-copyright {
+ margin: 0;
+ padding-bottom: 1px;
+
+ font-family: Inter;
+ font-style: normal;
+ font-weight: normal;
+ font-size: 16px;
+ line-height: 19px;
+}
+
+.logo-footer {
+ display: flex;
+ margin-right: 50px;
+
+ font-family: Inter;
+ font-style: normal;
+ font-weight: bold;
+ font-size: 16px;
+ line-height: 19px;
+}
+
+.logo-bar--rights {
+ align-items: flex-end;
+ font-size: 16px;
+ line-height: 19px;
+}
diff --git a/src/App.tsx b/src/App.tsx
index 7bd15e8..4fe1ca4 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,27 +1,129 @@
-import React from 'react';
+import React, { useState, useEffect } from 'react';
import './App.scss';
-
-interface Props {
- onClick: () => void;
-}
-
-export const Provider: React.FC = React.memo(
- ({ onClick, children }) => (
-
- ),
-);
+import { SearchBar } from './components/SearchBar/SearchBar';
+import { getData } from './api/api';
export const App: React.FC = () => {
+ const [articleData, setArticleData] = useState([]);
+ const [currentCategory, setCurrentCategory] = useState('');
+ const [query, setQuery] = useState('');
+ const [articles, setArticles] = useState();
+
+ useEffect(() => {
+ getData(currentCategory).then(response => {
+ setArticleData(response.response.results);
+ setArticles(response.response.results);
+ });
+ }, [currentCategory]);
+
+ const sortedByDate = () => {
+ const sorted = [...articleData].sort((article1: Article, article2: Article) => {
+ return (
+ article1.webPublicationDate.localeCompare(article2.webPublicationDate)
+ );
+ });
+
+ return sorted;
+ };
+
+ const sortedArticles = sortedByDate();
+
+ useEffect(() => {
+ const filtered = sortedArticles.filter(article => {
+ if (query.length === 0) {
+ return (
+ article.webTitle?.includes(' ')
+ );
+ }
+
+ return (
+ article.webTitle?.includes(query)
+ );
+ });
+
+ setArticles(filtered);
+ }, [query]);
+
+ const renderArticleCard = (article: Article) => {
+ const createdDateYear = new Date(article.webPublicationDate);
+ const dateToday = new Date();
+ const oneDay = 1000 * 60 * 60 * 24;
+ const daysAgo = Math.floor(+(dateToday.getTime() - +createdDateYear.getTime()) / oneDay);
+
+ return (
+
+
+
+
+
{article.webTitle}
+
{article.fields?.bodyText}
+
+
+
+
+ );
+ };
+
return (
-
+ <>
+
+
+
+
+
+
+
+
+
Always intreating news!
+
Look at these amazing world actions!
+
+
Last updated 3 mins ago
+
Last updated 3 mins ago
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+ {articles?.map(renderArticleCard)}
+
+
+
+
+
+
+
+ >
);
};
diff --git a/src/api/api.tsx b/src/api/api.tsx
new file mode 100644
index 0000000..f520219
--- /dev/null
+++ b/src/api/api.tsx
@@ -0,0 +1,11 @@
+export const BASE_URL = 'https://content.guardianapis.com/search?q=';
+
+export const getData = async (query: string) => {
+ const response = await fetch(`${BASE_URL}${query}&show-tags=all&page-size=20&show-fields=all&order-by=relevance&api-key=141f90d4-5cce-4f13-8f4e-2b6cf69cd8cb`);
+
+ if (!response.ok) {
+ throw new Error(`${response.status} - ${response.statusText}`);
+ }
+
+ return response.json();
+};
diff --git a/src/components/BurgerMenu/BurgerMenu.scss b/src/components/BurgerMenu/BurgerMenu.scss
new file mode 100644
index 0000000..c5e3d49
--- /dev/null
+++ b/src/components/BurgerMenu/BurgerMenu.scss
@@ -0,0 +1,80 @@
+.burger-menu {
+ display: flex;
+ position: relative;
+
+ &__catagories {
+ margin-right: 60px;
+ }
+
+ &__trend {
+ margin-right: 141px;
+ cursor: pointer;
+ border: none;
+ background-color: #fff;
+ align-self: flex-start;
+ }
+
+ &__trend:hover {
+ color: #2F80ED;
+ }
+}
+
+.drop {
+ font-family: Inter;
+ font-size: 14px;
+ line-height: 17px;
+ border: none;
+ color: #000000;
+}
+
+.dropdown-content {
+ display: none;
+ position: absolute;
+ margin-top: 5px;
+ background-color: #f1f1f1;
+ min-width: 160px;
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
+ z-index: 1000;
+}
+
+.category {
+ color: #000000;
+ padding: 12px 16px;
+ text-decoration: none;
+ display: block;
+ cursor: pointer;
+ border: none;
+ z-index: 1000;
+}
+
+.burger-menu__catagories:hover .drop {
+ color: #2F80ED;
+}
+
+.burger-menu__catagories:hover .dropdown-content {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+}
+
+.category:hover {
+ background-color: #ddd;
+ color: #2F80ED;
+}
+
+.bar1, .bar2, .bar3 {
+ width: 18px;
+ height: 2px;
+ background-color: #333;
+ margin: 6px 0;
+ transition: 0.4s;
+}
+
+.change .bar1 {
+ transform: rotate(-45deg) translate(-5px, 4px);
+}
+
+.change .bar2 {opacity: 0;}
+
+.change .bar3 {
+ transform: rotate(45deg) translate(-7px, -7px);
+}
diff --git a/src/components/BurgerMenu/BurgerMenu.tsx b/src/components/BurgerMenu/BurgerMenu.tsx
new file mode 100644
index 0000000..a75594a
--- /dev/null
+++ b/src/components/BurgerMenu/BurgerMenu.tsx
@@ -0,0 +1,138 @@
+import React, { useState } from 'react';
+import './BurgerMenu.scss';
+import classNames from 'classnames';
+
+type Props = {
+ setCurrentCategory: (category: string) => void;
+};
+
+export const BurgerMenu: React.FC = (props) => {
+ const { setCurrentCategory } = props;
+
+ const [clicked, setClicked] = useState(false);
+ const [selectedCategory, setSelectedCategory] = useState('trending');
+
+ const showMenu = () => {
+ setClicked(!clicked);
+ };
+
+ const handleClick = (event: React.MouseEvent) => {
+ const { id } = event.currentTarget;
+
+ setSelectedCategory(id);
+ };
+
+ setCurrentCategory(selectedCategory);
+
+ const handleKeyPress = () => {
+
+ };
+
+ return (
+
+
+ {!clicked || (
+ <>
+
+
Categories
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+
+ );
+};
diff --git a/src/components/SearchBar/SearchBar.scss b/src/components/SearchBar/SearchBar.scss
new file mode 100644
index 0000000..199aeb9
--- /dev/null
+++ b/src/components/SearchBar/SearchBar.scss
@@ -0,0 +1,69 @@
+.input-bar {
+ display: flex;
+ align-items: center;
+ position: relative;
+ width: 100%;
+
+ background-color: #fff;
+ z-index: 1;
+}
+
+.logo-bar {
+ display: flex;
+ margin-right: 50px;
+
+ font-family: Inter;
+ font-weight: bold;
+ font-size: 20px;
+ line-height: 24px;
+
+ &__article {
+ color: #000000;
+ text-decoration: none;
+ }
+}
+
+.input-group {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ width: 350px;
+ border: 1px solid transparent;
+ border-radius: 4px;
+ background-color: #f2f2f2;
+
+}
+
+.btn--bar {
+ padding: 7px 12px 7px 19px;
+ display: flex;
+ align-items: center;
+
+ cursor: pointer;
+ border: none;
+}
+
+.magnifier {
+ width: 18px;
+ height: 18px;
+}
+
+.form-control {
+ background: #f2f2f2;
+ border-radius: 4px;
+ width: 100%;
+
+ border: none;
+ outline: none;
+}
+
+.form-control {
+ outline: none;
+}
+
+.burger {
+ display: flex;
+ position: absolute;
+ right: 0;
+}
diff --git a/src/components/SearchBar/SearchBar.tsx b/src/components/SearchBar/SearchBar.tsx
new file mode 100644
index 0000000..63ec204
--- /dev/null
+++ b/src/components/SearchBar/SearchBar.tsx
@@ -0,0 +1,53 @@
+import React, { useState } from 'react';
+import './SearchBar.scss';
+import { BurgerMenu } from '../BurgerMenu/BurgerMenu';
+
+type Props = {
+ setCurrentCategory: (gotCategory: string) => void;
+ setQueryFromBar: (gotCategory: string) => void;
+};
+
+export const SearchBar: React.FC = (props) => {
+ const { setCurrentCategory, setQueryFromBar } = props;
+
+ const [query, setQuery] = useState('');
+
+ const handleChange = (event: React.ChangeEvent) => {
+ const { value } = event.target;
+
+ setQuery(value);
+ };
+
+ setQueryFromBar(query.toLowerCase());
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index 6431bc5..72fe492 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -1 +1,13 @@
///
+
+interface Article {
+ id?: string;
+ webPublicationDate: string;
+ webTitle?: string;
+ fields?: Fields;
+}
+
+interface Fields {
+ bodyText?: string;
+ main?: string;
+}