diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index ecbf2c6..3ceb2e5 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -11,5 +11,6 @@ module.exports = {
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': 'warn',
+ 'react/prop-types': 'off'
},
}
diff --git a/index.html b/index.html
index 79c4701..8a9e14f 100644
--- a/index.html
+++ b/index.html
@@ -4,6 +4,9 @@
+
+
+
Vite + React
diff --git a/package.json b/package.json
index 8e3cf39..1d7d74d 100644
--- a/package.json
+++ b/package.json
@@ -10,8 +10,11 @@
"preview": "vite preview"
},
"dependencies": {
+ "axios": "^1.4.0",
+ "axios-hooks": "^4.0.0",
"react": "^18.2.0",
- "react-dom": "^18.2.0"
+ "react-dom": "^18.2.0",
+ "swr": "^2.2.0"
},
"devDependencies": {
"@types/react": "^18.0.37",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fcc6e4c..dfab4da 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5,12 +5,21 @@ settings:
excludeLinksFromLockfile: false
dependencies:
+ axios:
+ specifier: ^1.4.0
+ version: 1.4.0
+ axios-hooks:
+ specifier: ^4.0.0
+ version: 4.0.0(axios@1.4.0)(react@18.2.0)
react:
specifier: ^18.2.0
version: 18.2.0
react-dom:
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
+ swr:
+ specifier: ^2.2.0
+ version: 2.2.0(react@18.2.0)
devDependencies:
'@types/react':
@@ -45,6 +54,13 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /@babel/runtime@7.19.0:
+ resolution: {integrity: sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.13.11
+ dev: false
+
/@esbuild/android-arm64@0.17.19:
resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==}
engines: {node: '>=12'}
@@ -553,11 +569,38 @@ packages:
get-intrinsic: 1.2.1
dev: true
+ /asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ dev: false
+
/available-typed-arrays@1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
dev: true
+ /axios-hooks@4.0.0(axios@1.4.0)(react@18.2.0):
+ resolution: {integrity: sha512-IYpVCh/3I99KA826+Qtms581EegvlUVzDkhljglo21Ugc6P9lQQVG6q22seZy0ieYuepjS3kvCtzUG7jAX7BTA==}
+ peerDependencies:
+ axios: '>=0.24.0'
+ react: ^16.8.0-0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ '@babel/runtime': 7.19.0
+ axios: 1.4.0
+ dequal: 2.0.3
+ lru-cache: 7.18.3
+ react: 18.2.0
+ dev: false
+
+ /axios@1.4.0:
+ resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
+ dependencies:
+ follow-redirects: 1.15.2
+ form-data: 4.0.0
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+ dev: false
+
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
@@ -600,6 +643,13 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
+ /combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ delayed-stream: 1.0.0
+ dev: false
+
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
@@ -641,6 +691,16 @@ packages:
object-keys: 1.1.1
dev: true
+ /delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+ dev: false
+
+ /dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+ dev: false
+
/doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
@@ -935,12 +995,31 @@ packages:
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
dev: true
+ /follow-redirects@1.15.2:
+ resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+ dev: false
+
/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
is-callable: 1.2.7
dev: true
+ /form-data@4.0.0:
+ resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+ engines: {node: '>= 6'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+ dev: false
+
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
@@ -1282,6 +1361,23 @@ packages:
dependencies:
js-tokens: 4.0.0
+ /lru-cache@7.18.3:
+ resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+ dev: false
+
+ /mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.52.0
+ dev: false
+
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
@@ -1444,6 +1540,10 @@ packages:
react-is: 16.13.1
dev: true
+ /proxy-from-env@1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+ dev: false
+
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
@@ -1474,6 +1574,10 @@ packages:
loose-envify: 1.4.0
dev: false
+ /regenerator-runtime@0.13.11:
+ resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+ dev: false
+
/regexp.prototype.flags@1.5.0:
resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
engines: {node: '>= 0.4'}
@@ -1629,6 +1733,15 @@ packages:
engines: {node: '>= 0.4'}
dev: true
+ /swr@2.2.0(react@18.2.0):
+ resolution: {integrity: sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==}
+ peerDependencies:
+ react: ^16.11.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ use-sync-external-store: 1.2.0(react@18.2.0)
+ dev: false
+
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: true
@@ -1668,6 +1781,14 @@ packages:
punycode: 2.3.0
dev: true
+ /use-sync-external-store@1.2.0(react@18.2.0):
+ resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.2.0
+ dev: false
+
/vite@4.3.9:
resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==}
engines: {node: ^14.18.0 || >=16.0.0}
diff --git a/public/vite.svg b/public/vite.svg
deleted file mode 100644
index e7b8dfb..0000000
--- a/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/App.jsx b/src/App.jsx
index 6702051..7141540 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,7 +1,11 @@
+import Posts, { PostsAxios } from "./components/posts";
+import Nav from "./components/navbar";
+
function App() {
return (
<>
- Hello, World!
+
+
>
)
}
diff --git a/src/components/navbar/Nav.jsx b/src/components/navbar/Nav.jsx
new file mode 100644
index 0000000..e0f9405
--- /dev/null
+++ b/src/components/navbar/Nav.jsx
@@ -0,0 +1,14 @@
+import NavTitle from "./NavTitle";
+import NavLinks from "./NavLinks";
+
+import "./nav.css"
+
+
+export default function Nav() {
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/navbar/NavLink.jsx b/src/components/navbar/NavLink.jsx
new file mode 100644
index 0000000..0faf2e9
--- /dev/null
+++ b/src/components/navbar/NavLink.jsx
@@ -0,0 +1,7 @@
+
+
+export default function NavLink({ title }) {
+ return (
+ {title}
+ )
+}
\ No newline at end of file
diff --git a/src/components/navbar/NavLinks.jsx b/src/components/navbar/NavLinks.jsx
new file mode 100644
index 0000000..b00a430
--- /dev/null
+++ b/src/components/navbar/NavLinks.jsx
@@ -0,0 +1,10 @@
+import NavLink from "./NavLink";
+
+
+export default function NavLinks() {
+ return (
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/navbar/NavTitle.jsx b/src/components/navbar/NavTitle.jsx
new file mode 100644
index 0000000..1ef14c4
--- /dev/null
+++ b/src/components/navbar/NavTitle.jsx
@@ -0,0 +1,10 @@
+
+
+export default function NavTitle({ title }) {
+ return (
+
+
{title}
+
+ )
+}
+
diff --git a/src/components/navbar/index.jsx b/src/components/navbar/index.jsx
new file mode 100644
index 0000000..53d0843
--- /dev/null
+++ b/src/components/navbar/index.jsx
@@ -0,0 +1,3 @@
+import Nav from "./Nav";
+
+export default Nav;
\ No newline at end of file
diff --git a/src/components/navbar/nav.css b/src/components/navbar/nav.css
new file mode 100644
index 0000000..79b2121
--- /dev/null
+++ b/src/components/navbar/nav.css
@@ -0,0 +1,36 @@
+
+.nav {
+ display: flex;
+ color: white;
+ background-color: #0078FB;
+ padding: 0 20px;
+}
+
+.nav-title {
+ font-size: 22px;
+ padding: 10px;
+}
+
+.nav-links-container {
+ flex: 1;
+ display: flex;
+ justify-content: end;
+ align-items: center;
+}
+
+.nav-link {
+ padding: 10px;
+ font-size: 14px;
+ font-weight: 500;
+ border-radius: 5px;
+ color: white;
+ border: 1px solid white;
+ margin: 5px;
+ text-transform: uppercase;
+}
+
+.nav-link:hover {
+ color: #0078FB;
+ background-color: white;
+ transition-delay: 0.1s;
+}
\ No newline at end of file
diff --git a/src/components/posts/Post.jsx b/src/components/posts/Post.jsx
new file mode 100644
index 0000000..226550b
--- /dev/null
+++ b/src/components/posts/Post.jsx
@@ -0,0 +1,17 @@
+
+
+function Post({ title, body }) {
+ return (
+
+
+ {title}
+
+
+ {body}
+
+
+ )
+}
+
+
+export default Post;
\ No newline at end of file
diff --git a/src/components/posts/Posts.jsx b/src/components/posts/Posts.jsx
new file mode 100644
index 0000000..2abfbe8
--- /dev/null
+++ b/src/components/posts/Posts.jsx
@@ -0,0 +1,22 @@
+import Post from "./Post";
+import "./posts.css";
+
+import usePosts from "./utils";
+
+
+function Posts({ totalPosts }) {
+ const { posts, error, isLoading } = usePosts();
+
+ if (isLoading) return ...Loading
+ if (error) return {error}
+ return (
+
+ {posts.data.slice(0, totalPosts).map(post =>
+
+ )}
+
+ )
+}
+
+
+export default Posts;
\ No newline at end of file
diff --git a/src/components/posts/PostsAxios.jsx b/src/components/posts/PostsAxios.jsx
new file mode 100644
index 0000000..da67b63
--- /dev/null
+++ b/src/components/posts/PostsAxios.jsx
@@ -0,0 +1,18 @@
+import useAxios from "axios-hooks";
+
+import Post from "./Post";
+
+
+export default function PostsAxios({ totalPosts }) {
+
+ const [{ data, loading }] = useAxios("https://jsonplaceholder.typicode.com/posts")
+
+ if (loading) return ...Loading
+ return (
+
+ {data.slice(0, totalPosts).map(post =>
+
+ )}
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/posts/index.jsx b/src/components/posts/index.jsx
new file mode 100644
index 0000000..ace5f66
--- /dev/null
+++ b/src/components/posts/index.jsx
@@ -0,0 +1,5 @@
+import Posts from "./Posts";
+import PostsAxios from "./PostsAxios";
+
+export default Posts;
+export { PostsAxios };
\ No newline at end of file
diff --git a/src/components/posts/posts.css b/src/components/posts/posts.css
new file mode 100644
index 0000000..183e4b7
--- /dev/null
+++ b/src/components/posts/posts.css
@@ -0,0 +1,26 @@
+
+
+.posts {
+ padding: 20px;
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+.post {
+ width: 450px;
+ border-radius: 5px;
+ padding: 20px;
+ margin: 20px;
+ text-align: justify;
+ box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
+}
+
+.post-title {
+ font-size: 20px;
+ margin-bottom: 20px;
+}
+
+.post-body {
+ line-height: 1.2;
+}
\ No newline at end of file
diff --git a/src/components/posts/utils.js b/src/components/posts/utils.js
new file mode 100644
index 0000000..75f64d1
--- /dev/null
+++ b/src/components/posts/utils.js
@@ -0,0 +1,13 @@
+import useSwr from "swr";
+import fetcher from "../../utils/fetcher";
+
+
+export default function usePosts() {
+ const { data, error, isLoading } = useSwr("https://jsonplaceholder.typicode.com/posts", fetcher);
+
+ return {
+ posts: data,
+ error,
+ isLoading
+ }
+}
diff --git a/src/main.css b/src/main.css
new file mode 100644
index 0000000..200a274
--- /dev/null
+++ b/src/main.css
@@ -0,0 +1,9 @@
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: 'Roboto', sans-serif;
+}
\ No newline at end of file
diff --git a/src/main.jsx b/src/main.jsx
index 51a8c58..ca3c2b1 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,6 +1,8 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
+import "./main.css";
+
ReactDOM.createRoot(document.getElementById('root')).render(
diff --git a/src/utils/fetcher.js b/src/utils/fetcher.js
new file mode 100644
index 0000000..f6d41e8
--- /dev/null
+++ b/src/utils/fetcher.js
@@ -0,0 +1,3 @@
+import axios from "axios";
+
+export default async (url) => await axios.get(url);
\ No newline at end of file