diff --git a/public/215697_small.mp4 b/public/215697_small.mp4
new file mode 100644
index 0000000..b8139d5
Binary files /dev/null and b/public/215697_small.mp4 differ
diff --git a/src/App.css b/src/App.css
index 683a976..b2256f7 100644
--- a/src/App.css
+++ b/src/App.css
@@ -14,10 +14,17 @@ body {
}
.header img {
- width: 200px;
- height: 200px;
+ width: 150px;
+ height: auto;
+}
+
+.header-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ max-width: 1200px;
margin: auto;
- animation: fadeIn 2s ease-in-out;
+ flex-wrap: wrap;
}
.character-container {
@@ -43,19 +50,14 @@ body {
box-shadow: 0 5px 15px rgba(255, 204, 0, 0.5);
}
-.character-image {
- width: 100%;
- height: auto;
- border-radius: 10px;
-}
-
.character-details p {
margin: 10px 0;
- color: #ffcc00;
+ color: #fff;
}
-
-.changePage {
- margin-top: 20px;
+.character-details p strong {
+ color: #ffcc00;
+ text-transform: capitalize;
+ padding-right: 5px;
}
.button {
@@ -66,7 +68,7 @@ body {
font-size: 16px;
border-radius: 5px;
cursor: pointer;
- margin: 0 10px;
+ margin: 30px 10px;
transition: background-color 0.3s;
}
@@ -74,33 +76,6 @@ body {
background-color: #ffb103;
}
-.loading {
- font-size: 24px;
- color: #ffcc00;
- animation: pulse 1.5s infinite;
-}
-
-@keyframes fadeIn {
- from {
- opacity: 0;
- transform: translateY(-20px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-@keyframes pulse {
- 0%,
- 100% {
- opacity: 0.8;
- }
- 50% {
- opacity: 1;
- }
-}
-
@media (max-width: 768px) {
.character-card {
width: 100%;
@@ -111,3 +86,113 @@ body {
font-size: 14px;
}
}
+
+/* Search Functionality */
+
+.search-container {
+ position: relative;
+ margin: 50px auto;
+ width: 300px;
+}
+
+.search-input {
+ width: 100%;
+ padding: 10px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ outline: none;
+ color: #000;
+}
+
+.suggestions {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ background: #333;
+ border: 1px solid #ccc;
+ border-top: none;
+ height: auto;
+ overflow-y: auto;
+ position: absolute;
+ width: 100%;
+ z-index: 10;
+}
+
+.suggestion-item {
+ padding: 10px;
+ cursor: pointer;
+}
+
+.suggestion-item:hover {
+ background-color: #222;
+}
+
+@media (max-width: 768px) {
+ .header-container {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .search-container {
+ margin-top: 20px;
+ width: 100%;
+ max-width: none;
+ }
+
+ .header img {
+ width: 120px;
+ }
+}
+
+/* SKELETON */
+.skeleton-character-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+ list-style: none;
+ padding: 0;
+ justify-content: center;
+}
+
+.skeleton-character-card {
+ display: flex;
+ justify-content: center;
+ background: #fff;
+ border: 1px solid #ccc;
+ border-radius: 8px;
+ padding: 20px;
+ width: 250px;
+ height: 225px;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+.skeleton-character-details p {
+ margin: 10px 0;
+}
+
+.skeleton-line {
+ text-align: center;
+ background: linear-gradient(to right, #666 8%, #999 18%, #666 33%);
+ background-size: 1000px 100%;
+ animation: shimmer 3s infinite;
+ border-radius: 4px;
+ width: 120px;
+ height: 16px;
+ margin: 15px 0;
+}
+
+@keyframes shimmer {
+ 0% {
+ background-position: -1000px;
+ }
+ 100% {
+ background-position: 1000px;
+ }
+}
+
+@media (max-width: 768px) {
+ .character-card {
+ width: 100%;
+ max-width: 300px;
+ }
+}
diff --git a/src/App.jsx b/src/App.jsx
index 0284122..199bfdc 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,33 +1,19 @@
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import "./App.css";
import Home from "./pages/Home";
-import About from "./pages/About";
-import Contact from "./pages/Contact";
-import Layout from "./components/layout/Layout";
import Error from "./components/Error";
-import CharacterDetails from "./components/CharacterDetails";
+import CharacterDetails from "./components/characterDetail/CharacterDetails";
function App() {
const router = createBrowserRouter([
{
- path: "/",
- element: ,
errorElement: ,
children: [
- {
- path: "/about",
- element: ,
- },
- {
- path: "/contact",
- element: ,
- },
{
path: "/",
element: ,
},
{
path: "/characterDetails/:id",
-
element: ,
},
],
diff --git a/src/components/CharacterCard.jsx b/src/components/CharacterCard.jsx
index 99a4f40..5d9de96 100644
--- a/src/components/CharacterCard.jsx
+++ b/src/components/CharacterCard.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useEffect, useState } from "react";
import "../App.css";
import { Link } from "react-router-dom";
@@ -6,18 +6,27 @@ const CharacterCard = (props) => {
return (
{props.data.map((character, index) => {
- // Extract ID from character's URL
const id = character.url.split("/").filter(Boolean).pop();
return (
-
-
Name: {character.name}
-
Gender: {character.gender}
-
Height: {character.height} cm
-
Hair Color: {character.hair_color}
-
Birth Year: {character.birth_year}
-
+
+ Name {character.name}
+
+
+ Gender {character.gender}
+
+
+ Height {character.height} cm
+
+
+ Hair Color {character.hair_color}
+
+
+ Birth Year {character.birth_year}
+
+
);
diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx
deleted file mode 100644
index c76c39e..0000000
--- a/src/components/Footer.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-
-const Footer = () => {
- return (
-
-footer
-
- )
-}
-
-export default Footer
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
deleted file mode 100644
index f756582..0000000
--- a/src/components/Navbar.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from "react";
-
-const Navbar = () => {
- return navbar
;
-};
-
-export default Navbar;
diff --git a/src/components/characterDetail/CharacterDetails.css b/src/components/characterDetail/CharacterDetails.css
new file mode 100644
index 0000000..9b98dbe
--- /dev/null
+++ b/src/components/characterDetail/CharacterDetails.css
@@ -0,0 +1,47 @@
+@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");
+
+.character-detail-page {
+ background-color: #000;
+ font-family: "Poppins", sans-serif;
+ color: #ffffff;
+ padding: 20px;
+ border-radius: 10px;
+ max-width: 700px;
+ margin: 40px auto;
+ box-shadow: 0px 5px 10px rgba(255, 255, 255, 0.3);
+ border: 2px solid #ffd700;
+}
+
+.character-detail-page p {
+ margin: 12px 0;
+ font-size: 18px;
+}
+
+.character-detail-page p strong {
+ color: #ffd700;
+ text-transform: uppercase;
+ font-weight: bold;
+ padding-right: 10px;
+}
+
+.character-detail-page:hover {
+ box-shadow: 0 5px 15px 2px rgba(255, 204, 0, 0.9);
+
+}
+
+.character-detail-page p:first-child {
+ margin-top: 0;
+}
+
+.character-detail-page p:last-child {
+ margin-bottom: 0;
+}
+
+.character-detail-page h2 {
+ font-size: 3rem;
+ font-family: "Poppins", serif;
+ text-align: center;
+ color: #ffd700;
+ font-weight: bold;
+ text-transform: capitalize;
+}
diff --git a/src/components/CharacterDetails.jsx b/src/components/characterDetail/CharacterDetails.jsx
similarity index 64%
rename from src/components/CharacterDetails.jsx
rename to src/components/characterDetail/CharacterDetails.jsx
index 528d083..4c814bf 100644
--- a/src/components/CharacterDetails.jsx
+++ b/src/components/characterDetail/CharacterDetails.jsx
@@ -1,6 +1,8 @@
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router";
+import Film from "../Film";
+import "../characterDetail/CharacterDetails.css";
const CharacterDetails = () => {
const { id } = useParams();
console.log(id);
@@ -30,29 +32,32 @@ const CharacterDetails = () => {
return (
-
{character.name}
+
Character Info
- Gender:
+ Name {character.name}
+
+
+ Gender
{character.gender}
- Home World:
- {character.homeworld}
+ Height {character.height} cm
- Species: {character.species}
+ Hair Color {character.hair_color}
- Films: {character.films}
+ Skin Color {character.skin_color}
- Height: {character.height} cm
+ Eye Color {character.eye_color}
- Hair Color: {character.hair_color}
+ Birth Year {character.birth_year}
+
- Birth Year: {character.birth_year}
+ Films
);
diff --git a/src/components/layout/Layout.jsx b/src/components/layout/Layout.jsx
deleted file mode 100644
index b385c6b..0000000
--- a/src/components/layout/Layout.jsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react'
-import { Outlet } from 'react-router'
-import Navbar from '../Navbar'
-import Footer from '../Footer'
-const Layout = () => {
- return (
- <>
-
-
-
- >
- )
-}
-
-export default Layout;
diff --git a/src/pages/About.jsx b/src/pages/About.jsx
deleted file mode 100644
index bfdc716..0000000
--- a/src/pages/About.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-
-const About = () => {
- return (
-
- about page
-
- )
-}
-
-export default About
diff --git a/src/pages/Contact.jsx b/src/pages/Contact.jsx
deleted file mode 100644
index 98a3491..0000000
--- a/src/pages/Contact.jsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-
-const Contact = () => {
- return (
-
- contact page
-
- )
-}
-
-export default Contact
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
index 7ecd677..5daeb40 100644
--- a/src/pages/Home.jsx
+++ b/src/pages/Home.jsx
@@ -5,7 +5,10 @@ import CharacterCard from "../components/CharacterCard";
const Home = () => {
const [page, setPage] = useState(1);
const [data, setData] = useState([]);
- const [loading, setLoading] = useState(false);
+ const [filteredData, setFilteredData] = useState([]);
+ const [searchQuery, setSearchQuery] = useState("");
+ const [loading, setLoading] = useState(true);
+ const [suggestions, setSuggestions] = useState([]);
const increment = () => {
setPage(page + 1);
@@ -16,21 +19,108 @@ const Home = () => {
};
useEffect(() => {
- setLoading(true);
axios.get(`https://swapi.py4e.com/api/people/?page=${page}`).then((res) => {
setData(res.data.results);
- setLoading(false);
+ setFilteredData(res.data.results);
});
}, [page]);
+
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ setLoading(false);
+ }, 1500);
+
+ return () => clearTimeout(timer);
+ }, []);
+
+
+
+
+ const handleSearch = (e) => {
+ const query = e.target.value.toLowerCase();
+ setSearchQuery(query);
+
+ if (query === "") {
+ setFilteredData(data);
+ setSuggestions([]);
+ return;
+ }
+
+ // FILTERING DATA TO LOWERCASE
+ const filtered = data.filter((character) =>
+ character.name.toLowerCase().includes(query)
+ );
+ setFilteredData(filtered);
+
+ // AUTOCOMPLETE SUGGESTION
+ const autoSuggestions = data
+ .map((character) => character.name)
+ .filter((name) => name.toLowerCase().includes(query))
+ .slice(0, 5);
+ setSuggestions(autoSuggestions);
+ };
+
+ // HANDLING SUGGESTION ONCLICK EVENT
+ const handleSuggestionClick = (suggestion) => {
+ setSearchQuery(suggestion);
+ setFilteredData(
+ data.filter(
+ (character) => character.name.toLowerCase() === suggestion.toLowerCase()
+ )
+ );
+ setSuggestions([]);
+ };
+
return (
-
-
![Logo](/images/logo.png)
+
+
+
![Logo](/images/logo.png)
+
+
+
+
+ {suggestions.length > 0 && (
+
+ {suggestions.map((suggestion, index) => (
+ - handleSuggestionClick(suggestion)}
+ >
+ {suggestion}
+
+ ))}
+
+ )}
+
- {loading ?
Loading...
:
}
- {!loading &&
Page: {page}
}
+ {loading ? (
+
+ {[...(data || Array(5))].map((_, index) => (
+ -
+
+
+ ))}
+
+ ) : (
+
+ )}
+
);
};