├── .eslintrc.cjs
├── .gitignore
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
└── vite.svg
├── src
├── App.css
├── App.jsx
├── Components
│ ├── Blogs.jsx
│ ├── Footer.jsx
│ ├── Header.jsx
│ ├── IntroPost.jsx
│ └── Search.jsx
├── Pages
│ ├── BlogDetail.jsx
│ └── Home.jsx
├── Services
│ └── GlobalApi.jsx
├── assets
│ ├── Images
│ │ ├── banner.jpg
│ │ └── logo.png
│ └── react.svg
├── index.css
└── main.jsx
├── tailwind.config.js
└── vite.config.js
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: { browser: true, es2020: true },
3 | extends: [
4 | 'eslint:recommended',
5 | 'plugin:react/recommended',
6 | 'plugin:react/jsx-runtime',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
10 | settings: { react: { version: '18.2' } },
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': 'warn',
14 | },
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blog-yt",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.4.0",
14 | "localforage": "^1.10.0",
15 | "match-sorter": "^6.3.1",
16 | "react": "^18.2.0",
17 | "react-dom": "^18.2.0",
18 | "react-icons": "^4.8.0",
19 | "react-markdown": "^8.0.7",
20 | "react-router-dom": "^6.11.2",
21 | "sort-by": "^1.2.0"
22 | },
23 | "devDependencies": {
24 | "@types/react": "^18.0.28",
25 | "@types/react-dom": "^18.0.11",
26 | "@vitejs/plugin-react": "^4.0.0",
27 | "autoprefixer": "^10.4.14",
28 | "eslint": "^8.38.0",
29 | "eslint-plugin-react": "^7.32.2",
30 | "eslint-plugin-react-hooks": "^4.6.0",
31 | "eslint-plugin-react-refresh": "^0.3.4",
32 | "postcss": "^8.4.23",
33 | "tailwindcss": "^3.3.2",
34 | "vite": "^4.3.2"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 |
5 | }
6 |
7 | .logo {
8 | height: 6em;
9 | padding: 1.5em;
10 | will-change: filter;
11 | transition: filter 300ms;
12 | }
13 | .logo:hover {
14 | filter: drop-shadow(0 0 2em #646cffaa);
15 | }
16 | .logo.react:hover {
17 | filter: drop-shadow(0 0 2em #61dafbaa);
18 | }
19 |
20 | @keyframes logo-spin {
21 | from {
22 | transform: rotate(0deg);
23 | }
24 | to {
25 | transform: rotate(360deg);
26 | }
27 | }
28 |
29 | @media (prefers-reduced-motion: no-preference) {
30 | a:nth-of-type(2) .logo {
31 | animation: logo-spin infinite 20s linear;
32 | }
33 | }
34 |
35 | .card {
36 | padding: 2em;
37 | }
38 |
39 | .read-the-docs {
40 | color: #888;
41 | }
42 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import reactLogo from './assets/react.svg'
3 | import viteLogo from '/vite.svg'
4 | import './App.css'
5 | import Home from './Pages/Home'
6 | import { Route, Routes } from 'react-router-dom'
7 | import BlogDetail from './Pages/BlogDetail'
8 | import Header from './Components/Header'
9 | import Footer from './Components/Footer'
10 |
11 | function App() {
12 | const [count, setCount] = useState(0)
13 |
14 | return (
15 | <>
16 |
17 | {/* Header */}
18 |
19 |
20 | }>
21 | }>
22 |
23 |
24 |
25 |
26 | {/* Footer */}
27 |
28 | >
29 | )
30 | }
31 |
32 | export default App
33 |
--------------------------------------------------------------------------------
/src/Components/Blogs.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useNavigate } from 'react-router-dom'
3 |
4 | function Blogs({posts}) {
5 | const navigate=useNavigate();
6 | return (
7 |
9 | {posts.map((item)=>(
10 |
navigate('blog-detail/'+item.id)} >
11 |

13 |
{item.tag}
14 |
{item.title}
15 |
{item.desc}
16 |
17 |

19 |
20 |
Tubeguruji
21 | 24 Sept 2024
22 |
23 |
24 |
25 | ))}
26 |
27 |
28 | )
29 | }
30 |
31 | export default Blogs
--------------------------------------------------------------------------------
/src/Components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | function Footer() {
4 | return (
5 |
6 |
Need help? Email hello@tubeguruji.com
7 | Copyright © 2023 Tubeguruji
8 |
9 | )
10 | }
11 |
12 | export default Footer
--------------------------------------------------------------------------------
/src/Components/Header.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from './../assets/Images/logo.png'
3 | import { IoLogoYoutube } from "react-icons/io5";
4 | import { useNavigate } from 'react-router-dom';
5 | function Header() {
6 | const navigate=useNavigate();
7 | return (
8 |
9 |

10 |
11 | - navigate('/')}>Home
12 | - About Us
13 | - Contact Us
14 |
15 |
17 |
18 | )
19 | }
20 |
21 | export default Header
--------------------------------------------------------------------------------
/src/Components/IntroPost.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { useNavigate } from 'react-router-dom'
3 |
4 |
5 | function IntroPost({post}) {
6 | const navigate=useNavigate();
7 | return (
8 | navigate('blog-detail/'+post.id)}>
11 |

13 |
14 |
{post.tag}
15 |
{post.title}
16 |
{post.desc}
17 |
18 |

20 |
21 |
Tubeguruji
22 | 24 Sept 2024
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
30 | export default IntroPost
--------------------------------------------------------------------------------
/src/Components/Search.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import banner from './../assets/Images/banner.jpg'
3 | import { IoSearchOutline } from "react-icons/io5";
4 | import GlobalApi from '../Services/GlobalApi';
5 | function Search({selectedTag}) {
6 | const tags=[
7 | {
8 | id:1,
9 | name:'All',
10 | },
11 | {
12 | id:2,
13 | name:'React',
14 | },
15 | {
16 | id:3,
17 | name:'React Native',
18 | },
19 | {
20 | id:4,
21 | name:'Angular',
22 | },
23 | {
24 | id:5,
25 | name:'UI/UX',
26 | },
27 | ]
28 |
29 |
30 |
31 |
32 | const [activeIndex,setActiveIndex]=useState(0);
33 | return (
34 |
36 |

37 |
39 |
41 |
43 |
44 |
46 | {tags.map((item,index)=>(
47 |
{setActiveIndex(index);selectedTag(item.name)}}
48 | className={`${index==activeIndex?
49 | 'bg-red-500 text-white':null} p-1 pb-2 rounded-sm
50 | md:rounded-full cursor-pointer md:px-4
51 | hover:scale-110 hover:border-[1px]
52 | border-red-500 transition-all duration-100 ease-in-out`}>
53 | - {item.name}
54 |
55 | ))}
56 |
57 |
58 |
59 | )
60 | }
61 |
62 | export default Search
--------------------------------------------------------------------------------
/src/Pages/BlogDetail.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { useParams } from 'react-router-dom'
3 | import GlobalApi from '../Services/GlobalApi';
4 | import { ReactMarkdown } from 'react-markdown/lib/react-markdown';
5 |
6 | function BlogDetail() {
7 | const {id}=useParams();
8 | const [post,setPost]=useState([])
9 | useEffect(()=>{
10 | console.log("Id",id)
11 | getBlogById();
12 | },[])
13 |
14 | const getBlogById=()=>{
15 | GlobalApi.getPostById(id).then(resp=>{
16 |
17 | const item=resp.data.data;
18 | const result={
19 | id:item.id,
20 | title:item.attributes.title,
21 | desc:item.attributes.description,
22 | tag:item.attributes.tag,
23 | coverImage:item.attributes.coverImage.data.attributes.url,
24 | };
25 | setPost(result);
26 | console.log("Result",result);
27 | })
28 | }
29 | return (
30 |
31 |
{post.tag}
32 |
{post.title}
33 |
34 |

36 |
37 |
Tubeguruji
38 | 24 Sept 2024
39 |
40 |
41 |

42 | {/*
{post.desc}
*/}
43 |
45 |
46 | )
47 | }
48 |
49 | export default BlogDetail
--------------------------------------------------------------------------------
/src/Pages/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import Header from '../Components/Header'
3 | import Search from '../Components/Search'
4 | import IntroPost from '../Components/IntroPost'
5 | import Blogs from '../Components/Blogs'
6 | import Footer from '../Components/Footer'
7 | import GlobalApi from '../Services/GlobalApi'
8 |
9 | function Home() {
10 | const [post,setPost]=useState([])
11 | const [orgPost,setOrgPost]=useState([])
12 |
13 | useEffect(()=>{
14 | getPost();
15 | },[])
16 | const getPost=()=>{
17 | GlobalApi.getPost.then(resp=>{
18 | const result=resp.data.data.map(item=>({
19 | id:item.id,
20 | title:item.attributes.title,
21 | desc:item.attributes.description,
22 | tag:item.attributes.tag,
23 | coverImage:item.attributes.coverImage.data.attributes.url,
24 | }));
25 | setPost(result);
26 | setOrgPost(result);
27 | })
28 | }
29 |
30 | const filterPost=(tag)=>{
31 | if(tag=='All')
32 | {
33 | setPost(orgPost);
34 | return ;
35 | }
36 | const result=orgPost.filter(item=>item.tag==tag);
37 | setPost(result);
38 | }
39 | return (
40 |
41 |
42 | {/* Search */}
43 | filterPost(tag)} />
44 | {/* IntroPost */}
45 | {post.length>0? :null}
46 | {/* Blogs */}
47 | {post.length>0? :null}
48 |
49 |
50 | )
51 | }
52 |
53 | export default Home
--------------------------------------------------------------------------------
/src/Services/GlobalApi.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 |
4 | // const BASE_URL='http://localhost:1337/api';
5 | const BASE_URL='https://tubeguruji-admin.herokuapp.com/api'
6 |
7 | const getPost=axios.get(BASE_URL+'/blogs?populate=*');
8 | const getPostById=(id)=>axios.get(BASE_URL+'/blogs/'+id+'?populate=*');
9 |
10 | export default{
11 | getPost,
12 | getPostById
13 | }
14 |
--------------------------------------------------------------------------------
/src/assets/Images/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrs301/personal-blog-react/7d6dc083ff57bada4c45ad562b1349c32873ce48/src/assets/Images/banner.jpg
--------------------------------------------------------------------------------
/src/assets/Images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rrs301/personal-blog-react/7d6dc083ff57bada4c45ad562b1349c32873ce48/src/assets/Images/logo.png
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 | :root {
5 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
6 | line-height: 1.5;
7 | font-weight: 400;
8 |
9 | color-scheme: light dark;
10 | color: rgba(255, 255, 255, 0.87);
11 | background-color: #242424;
12 |
13 | font-synthesis: none;
14 | text-rendering: optimizeLegibility;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | -webkit-text-size-adjust: 100%;
18 | }
19 |
20 | a {
21 | font-weight: 500;
22 | color: #646cff;
23 | text-decoration: inherit;
24 | }
25 | a:hover {
26 | color: #535bf2;
27 | }
28 |
29 | body {
30 | margin: 0;
31 |
32 | }
33 |
34 | h1 {
35 | font-size: 3.2em;
36 | line-height: 1.1;
37 | }
38 |
39 | button {
40 | border-radius: 8px;
41 | border: 1px solid transparent;
42 | padding: 0.6em 1.2em;
43 | font-size: 1em;
44 | font-weight: 500;
45 | font-family: inherit;
46 | background-color: #1a1a1a;
47 | cursor: pointer;
48 | transition: border-color 0.25s;
49 | }
50 | button:hover {
51 | border-color: #646cff;
52 | }
53 | button:focus,
54 | button:focus-visible {
55 | outline: 4px auto -webkit-focus-ring-color;
56 | }
57 |
58 | @media (prefers-color-scheme: light) {
59 | :root {
60 | color: #213547;
61 | background-color: #ffffff;
62 | }
63 | a:hover {
64 | color: #747bff;
65 | }
66 | button {
67 | background-color: #f9f9f9;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 | import { BrowserRouter } from 'react-router-dom'
6 |
7 | ReactDOM.createRoot(document.getElementById('root')).render(
8 |
9 |
10 | ,
11 | )
12 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: [
4 | "./index.html",
5 | "./src/**/*.{js,ts,jsx,tsx}",
6 | ],
7 | theme: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | }
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------