diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/.eslintrc.json b/Next-JS-Projects/Advanced/Breaking-News-App/.eslintrc.json
new file mode 100644
index 00000000..bffb357a
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "next/core-web-vitals"
+}
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/README.md b/Next-JS-Projects/Advanced/Breaking-News-App/README.md
new file mode 100644
index 00000000..7bd86c58
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/README.md
@@ -0,0 +1,72 @@
+
đĨ Breaking News đĨ
+
+
+
+Tech Stack Used đŽ
+
+
+
+
+ ![HTML5](https://img.shields.io/badge/html5-%23E34F26.svg?style=for-the-badge&logo=html5&logoColor=white)
+ ![CSS3](https://img.shields.io/badge/css3-%231572B6.svg?style=for-the-badge&logo=css3&logoColor=white)
+ ![JavaScript](https://img.shields.io/badge/javascript-%23323330.svg?style=for-the-badge&logo=javascript&logoColor=%23F7DF1E)
+ ![Nextjs](https://img.shields.io/badge/Nextjs-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB)
+
+
+
+![Line](https://github.com/Avdhesh-Varshney/WebMasterLog/assets/114330097/4b78510f-a941-45f8-a9d5-80ed0705e847)
+
+
+
+## :zap: Description đ
+
+
+
+
+ A news app is a mobile or web application designed to provide users with up-to-date news and information from various sources. The app aggregates news articles, videos, and other content, presenting it in an organized and easily accessible format.
+
+
+
+
+
+
+
+## :zap: How to run it? đšī¸
+
+
+Steps to run this website in your local machine is as follows :
+1. Fork this repository
+2. Save the code on your local machine you can also clone the repository
+3. Open terminal
+4. Run following commands in the terminal :
+5. npm install
+6. npm run dev
+7. Browse the website by hitting `localhost:3000` on a web browser.
+8. Make sure you have installed node js before entering these code in the terminal
+
+
+
+
+## :zap: Screenshots đ¸
+
+
+
+
+
+![Line](https://github.com/Avdhesh-Varshney/WebMasterLog/assets/114330097/4b78510f-a941-45f8-a9d5-80ed0705e847)
+
+
+
+Developed By Maheshwari Love đĻ
+
+
+
+
+
+
+
+
+
+Happy Coding đ§âđģ
+
+Show some â¤ī¸ by đ this repository!
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/assets/images/newsarticle_placeholder.png b/Next-JS-Projects/Advanced/Breaking-News-App/assets/images/newsarticle_placeholder.png
new file mode 100644
index 00000000..013e0e5d
Binary files /dev/null and b/Next-JS-Projects/Advanced/Breaking-News-App/assets/images/newsarticle_placeholder.png differ
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/components/NavBar.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/components/NavBar.tsx
new file mode 100644
index 00000000..62f3738d
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/components/NavBar.tsx
@@ -0,0 +1,47 @@
+import Link from "next/link";
+import { Navbar, Container, Nav, NavDropdown } from "react-bootstrap";
+
+const NavBar = () => {
+ return (
+
+
+
+
+
+
+ Breaking
+
+
+ Search
+
+
+
+ Business
+
+
+ Entertainment
+
+
+ General
+
+
+ Health
+
+
+ Science
+
+
+ Sports
+
+
+ Technology
+
+
+
+
+
+
+ );
+};
+
+export default NavBar;
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/components/NewsArticleEntry.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/components/NewsArticleEntry.tsx
new file mode 100644
index 00000000..33339bbc
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/components/NewsArticleEntry.tsx
@@ -0,0 +1,37 @@
+import placeholderImage from "@/assets/images/newsarticle_placeholder.jpg";
+import { Card } from "react-bootstrap";
+import Image from "next/image";
+import styles from "@/styles/NewsArticleEntry.module.css";
+
+type NewsArticleEntryProps = {
+ article: INewsArticle;
+};
+const NewsArticleEntry = ({
+ article: { title, description, author, url, urlToImage },
+}: NewsArticleEntryProps) => {
+ const validImageUrl =
+ urlToImage?.startsWith("http://") || urlToImage?.startsWith("https://")
+ ? urlToImage
+ : undefined;
+
+ return (
+
+
+ {/* */}
+
+
+ {title}
+ {description}
+
+
+
+ );
+};
+
+export default NewsArticleEntry;
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/components/NewsArticlesGrid.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/components/NewsArticlesGrid.tsx
new file mode 100644
index 00000000..85d58db4
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/components/NewsArticlesGrid.tsx
@@ -0,0 +1,19 @@
+import { Col, Row } from "react-bootstrap";
+import NewsArticleEntry from "./NewsArticleEntry";
+
+type NewsArticlesGridProps = {
+ articles: INewsArticle[];
+};
+const NewsArticlesGrid = ({ articles }: NewsArticlesGridProps) => {
+ return (
+
+ {articles.map((article) => (
+
+
+
+ ))}
+
+ );
+};
+
+export default NewsArticlesGrid;
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/models/NewsArticles.d.ts b/Next-JS-Projects/Advanced/Breaking-News-App/models/NewsArticles.d.ts
new file mode 100644
index 00000000..648e9a3a
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/models/NewsArticles.d.ts
@@ -0,0 +1,15 @@
+interface INewsArticlesResponse {
+ status: string,
+ totalResults: number,
+ articles: INewsArticle[]
+}
+
+interface INewsArticle {
+ author: string,
+ title: string,
+ description: string,
+ url: string,
+ urlToImage?: string,
+ publishedAt: string,
+ content: string,
+}
\ No newline at end of file
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/next.config.js b/Next-JS-Projects/Advanced/Breaking-News-App/next.config.js
new file mode 100644
index 00000000..d68bbaad
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/next.config.js
@@ -0,0 +1,19 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+ reactStrictMode: true,
+ images: {
+ domains: ["www.si.com", "fashionista.com"],
+ remotePatterns: [
+ {
+ protocol: "https",
+ hostname: '**'
+ },
+ {
+ protocol: "http",
+ hostname: '**'
+ },
+ ]
+ }
+}
+
+module.exports = nextConfig
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/package.json b/Next-JS-Projects/Advanced/Breaking-News-App/package.json
new file mode 100644
index 00000000..34c32d2a
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "news-website",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "dev": "next dev",
+ "build": "next build",
+ "start": "next start",
+ "lint": "next lint"
+ },
+ "dependencies": {
+ "@types/node": "18.15.11",
+ "@types/react": "18.0.33",
+ "@types/react-dom": "18.0.11",
+ "bootstrap": "^5.2.3",
+ "eslint": "8.37.0",
+ "eslint-config-next": "13.3.0",
+ "next": "13.3.0",
+ "nextjs-progressbar": "^0.0.16",
+ "react": "18.2.0",
+ "react-bootstrap": "^2.7.2",
+ "react-dom": "18.2.0",
+ "typescript": "5.0.3"
+ }
+}
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/404.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/pages/404.tsx
new file mode 100644
index 00000000..270dbeb6
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/404.tsx
@@ -0,0 +1,10 @@
+const NotFoundPage = () => {
+ return (
+
+
Not Found
+
Looks like this page is not exists
+
+ );
+};
+
+export default NotFoundPage;
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/500.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/pages/500.tsx
new file mode 100644
index 00000000..5ff52573
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/500.tsx
@@ -0,0 +1,13 @@
+const ErrorPage = () => {
+ return (
+
+
Error đĩ
+
+ Looks like something went wrong. Please refresh the page or contact
+ support.
+
+
+ );
+};
+
+export default ErrorPage;
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/_app.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/pages/_app.tsx
new file mode 100644
index 00000000..9c4e7f60
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/_app.tsx
@@ -0,0 +1,34 @@
+import "bootstrap/dist/css/bootstrap.min.css";
+import "@/styles/globals.css";
+import styles from "@/styles/app.module.css";
+import Head from "next/head";
+import NextNProgress from "nextjs-progressbar";
+import type { AppProps } from "next/app";
+import { Inter } from "next/font/google";
+import { Container } from "react-bootstrap";
+import NavBar from "@/components/NavBar";
+const inter = Inter({ subsets: ["latin"] });
+
+export default function App({ Component, pageProps }: AppProps) {
+ return (
+ <>
+
+
+
Nextjs News App
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/_document.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/pages/_document.tsx
new file mode 100644
index 00000000..54e8bf3e
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/_document.tsx
@@ -0,0 +1,13 @@
+import { Html, Head, Main, NextScript } from 'next/document'
+
+export default function Document() {
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/api/search-news.ts b/Next-JS-Projects/Advanced/Breaking-News-App/pages/api/search-news.ts
new file mode 100644
index 00000000..2a16da68
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/api/search-news.ts
@@ -0,0 +1,24 @@
+// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
+import type { NextApiRequest, NextApiResponse } from 'next'
+
+type ErrRes = {
+ error: any
+}
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse
+) {
+ const searchQuery = req.query.q?.toString();
+
+ if (!searchQuery) {
+ return res.status(400).json({ error: "Please provide a search query" })
+ }
+ try {
+ const response = await fetch(`https://newsapi.org/v2/everything?q=${searchQuery}&apiKey=${process.env.NEWS_API_KEY}`)
+ const newsResponse: INewsArticlesResponse = await response.json()
+ res.status(200).json(newsResponse.articles)
+ } catch (error) {
+ res.status(400).json({ error: error })
+ }
+}
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/categories/[category].tsx b/Next-JS-Projects/Advanced/Breaking-News-App/pages/categories/[category].tsx
new file mode 100644
index 00000000..732e6e0c
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/categories/[category].tsx
@@ -0,0 +1,69 @@
+import Head from "next/head";
+import { useRouter } from "next/router";
+import NewsArticlesGrid from "@/components/NewsArticlesGrid";
+import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next";
+import { Alert } from "react-bootstrap";
+
+type CategoryNewsPageProps = {
+ articles: INewsArticle[];
+};
+const CategoryNewsPage = ({ articles }: CategoryNewsPageProps) => {
+ const router = useRouter();
+ const categoryName = router.query.category?.toString();
+ const title = `Category: ${categoryName}`;
+ return (
+ <>
+
+ {`${title} - NextJS News App`}
+
+
+ {title}
+
+ This page is uses getStaticProps for very high page
+ loading speed and incremental static regeneration to
+ show data not older then 5 minutes.
+
+
+
+ >
+ );
+};
+
+export const getStaticPaths: GetStaticPaths = async () => {
+ const categorySlugs = [
+ "business",
+ "entertainment",
+ "general",
+ "health",
+ "science",
+ "sports",
+ "technology",
+ ];
+
+ const paths = categorySlugs.map((slug) => ({
+ params: { category: slug },
+ }));
+ return {
+ paths,
+ fallback: false,
+ };
+};
+
+export const getStaticProps: GetStaticProps = async ({
+ params,
+}: GetStaticPropsContext) => {
+ const category = params?.category?.toString();
+ const response = await fetch(
+ `https://newsapi.org/v2/top-headlines?country=us&category=${category}&apiKey=${process.env.NEWS_API_KEY}`
+ );
+ const newsResponse: INewsArticlesResponse = await response.json();
+ return {
+ props: { articles: newsResponse.articles },
+ //? Incremantal static regeneration.
+ //? It means revalidate page content every (5 * 60 = 5 minutes).
+ revalidate: 5 * 60,
+ };
+ // Let error go to 500 page
+};
+
+export default CategoryNewsPage;
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/index.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/pages/index.tsx
new file mode 100644
index 00000000..7a0a41c8
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/index.tsx
@@ -0,0 +1,52 @@
+import NewsArticlesGrid from "@/components/NewsArticlesGrid";
+import { GetServerSideProps } from "next";
+import Head from "next/head";
+import { Alert } from "react-bootstrap";
+
+type BreakingNewsPageProps = {
+ newsArticles?: INewsArticle[];
+};
+export default function BreakingNewsPage({
+ newsArticles,
+}: BreakingNewsPageProps) {
+ return (
+ <>
+
+ Breaking news - Nextjs News App
+
+
+ Breaking News
+
+
+ This page uses getServerSideProps to fetch data
+ server-side on every request.
+
+ This allows to search engines to crawl the page content and{" "}
+ improves SEO .
+
+ {newsArticles !== undefined ? (
+ <>
+
+ >
+ ) : (
+ Error
+ )}
+
+ >
+ );
+}
+
+export const getServerSideProps: GetServerSideProps<
+ BreakingNewsPageProps
+> = async () => {
+ const response = await fetch(
+ `https://newsapi.org/v2/top-headlines?country=us&apiKey=${process.env.NEWS_API_KEY}`
+ );
+ const newsResponse: INewsArticlesResponse = await response.json();
+ return {
+ props: {
+ newsArticles: newsResponse.articles,
+ },
+ };
+ // Let error go to 500 page
+};
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/pages/search.tsx b/Next-JS-Projects/Advanced/Breaking-News-App/pages/search.tsx
new file mode 100644
index 00000000..bc0630a3
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/pages/search.tsx
@@ -0,0 +1,80 @@
+import NewsArticlesGrid from "@/components/NewsArticlesGrid";
+import Head from "next/head";
+import { FormEvent, useState } from "react";
+import { Alert, Button, Form, Spinner } from "react-bootstrap";
+
+const SearchPage = () => {
+ const [searchQuery, setSearchQuery] = useState();
+ const [searchResults, setSearchResults] = useState(
+ null
+ );
+ const [searchResultsLoading, setSearchResultsLoading] = useState(false);
+ const [searchResultsLoadingIsError, setSearchResultsLoadingIsError] =
+ useState(false);
+
+ const handleSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ if (searchQuery) {
+ try {
+ setSearchResults(null);
+ setSearchResultsLoadingIsError(false);
+ setSearchResultsLoading(true);
+ const response = await fetch(`/api/search-news?q=${searchQuery}`);
+ const articles: INewsArticle[] = await response.json();
+ setSearchResults(articles);
+ } catch (error) {
+ console.error(error);
+ setSearchResultsLoadingIsError(true);
+ } finally {
+ setSearchResultsLoading(false);
+ }
+ }
+ };
+
+ return (
+ <>
+
+ Search News | NextJS News App
+
+
+ Search News
+
+ This page uses client-side data fetching to show
+ fresh data for every search.
+
+ Requests are handled by our backend via API routes.
+
+
+ Search query
+ setSearchQuery(e.target.value)}
+ />
+
+
+ Search
+
+
+
+
+ {searchResultsLoading &&
}
+ {searchResultsLoadingIsError && (
+
Something went wrong please try again!
+ )}
+ {searchResults?.length === 0 && (
+
Nothing found. Try a differet query
+ )}
+ {searchResults &&
}
+
+
+ >
+ );
+};
+
+export default SearchPage;
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/public/favicon.ico b/Next-JS-Projects/Advanced/Breaking-News-App/public/favicon.ico
new file mode 100644
index 00000000..718d6fea
Binary files /dev/null and b/Next-JS-Projects/Advanced/Breaking-News-App/public/favicon.ico differ
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/public/next.svg b/Next-JS-Projects/Advanced/Breaking-News-App/public/next.svg
new file mode 100644
index 00000000..5174b28c
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/public/next.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/public/vercel.svg b/Next-JS-Projects/Advanced/Breaking-News-App/public/vercel.svg
new file mode 100644
index 00000000..d2f84222
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/public/vercel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/screenshot.webp b/Next-JS-Projects/Advanced/Breaking-News-App/screenshot.webp
new file mode 100644
index 00000000..01eb10c3
Binary files /dev/null and b/Next-JS-Projects/Advanced/Breaking-News-App/screenshot.webp differ
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/styles/NewsArticleEntry.module.css b/Next-JS-Projects/Advanced/Breaking-News-App/styles/NewsArticleEntry.module.css
new file mode 100644
index 00000000..0763164b
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/styles/NewsArticleEntry.module.css
@@ -0,0 +1,4 @@
+.image {
+ object-fit: cover;
+ height: 100%;
+}
\ No newline at end of file
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/styles/app.module.css b/Next-JS-Projects/Advanced/Breaking-News-App/styles/app.module.css
new file mode 100644
index 00000000..7ba3db9c
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/styles/app.module.css
@@ -0,0 +1,3 @@
+.pageContainer {
+ margin: 2rem auto;
+}
\ No newline at end of file
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/styles/globals.css b/Next-JS-Projects/Advanced/Breaking-News-App/styles/globals.css
new file mode 100644
index 00000000..d071795b
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/styles/globals.css
@@ -0,0 +1,33 @@
+:root {
+ --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
+ 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
+ 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
+
+ --foreground-rgb: 0, 0, 0;
+ --background-start-rgb: 214, 219, 220;
+ --background-end-rgb: 255, 255, 255;
+}
+
+* {
+ box-sizing: border-box;
+ padding: 0;
+ margin: 0;
+}
+
+html,
+body {
+ max-width: 100vw;
+ min-height: 100vh;
+}
+
+body {
+ color: rgb(var(--foreground-rgb));
+ background: linear-gradient(to bottom,
+ transparent,
+ rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb));
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
\ No newline at end of file
diff --git a/Next-JS-Projects/Advanced/Breaking-News-App/tsconfig.json b/Next-JS-Projects/Advanced/Breaking-News-App/tsconfig.json
new file mode 100644
index 00000000..5950e225
--- /dev/null
+++ b/Next-JS-Projects/Advanced/Breaking-News-App/tsconfig.json
@@ -0,0 +1,36 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "paths": {
+ "@/*": [
+ "./*"
+ ]
+ }
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ "models"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/Next-JS-Projects/README.md b/Next-JS-Projects/README.md
index 588ca56d..95e86213 100644
--- a/Next-JS-Projects/README.md
+++ b/Next-JS-Projects/README.md
@@ -27,8 +27,7 @@
|------|--------------|----------|
| 1 | [Weather-Website](./Basic/Weather-Website) | ![Basic](https://img.shields.io/badge/Basic-00FF00?style=for-the-badge) |
| 2 | [Quiz-App](./Intermediate/Quiz-App) | ![Intermediate](https://img.shields.io/badge/Intermediate-FFD700?style=for-the-badge) |
-
-
+| 3 | [Breaking-News-App](./Advanced/Breaking-News-App/) | ![Advanced](https://img.shields.io/badge/Advanced-FF0000?style=for-the-badge) |