diff --git a/package-lock.json b/package-lock.json
index 65cf981c..674ffe66 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -162,6 +162,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
"integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.22.13",
@@ -553,6 +554,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18"
},
@@ -599,6 +601,7 @@
}
],
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=18"
}
@@ -1636,8 +1639,7 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@types/babel__core": {
"version": "7.20.3",
@@ -1716,6 +1718,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.31.tgz",
"integrity": "sha512-c2UnPv548q+5DFh03y8lEDeMfDwBn9G3dRwfkrxQMo/dOtRHUUO57k6pHvBIfH/VF4Nh+98mZ5aaSe+2echD5g==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -1727,6 +1730,7 @@
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz",
"integrity": "sha512-V835xgdSVmyQmI1KLV2BEIUgqEuinxp9O4G6g3FqO/SqLac049E53aysv0oEFD2kHfejeKU+ZqL2bcFWj9gLAQ==",
"dev": true,
+ "peer": true,
"dependencies": {
"@types/react": "*"
}
@@ -1838,6 +1842,7 @@
"integrity": "sha512-HURRrgGVzz2GQ2Imurp55FA+majHXgCXMzcwtojUZeRsAXyHNgEvxGRJf4QQY4kJeVakiugusGYeUqBgZ/xylg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vitest/utils": "4.0.3",
"fflate": "^0.8.2",
@@ -1873,6 +1878,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"dev": true,
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -1930,7 +1936,6 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=10"
},
@@ -2217,6 +2222,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001541",
"electron-to-chromium": "^1.4.535",
@@ -2536,8 +2542,7 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.4.563",
@@ -2731,6 +2736,7 @@
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz",
"integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==",
"dev": true,
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -3960,6 +3966,7 @@
"integrity": "sha512-SNSQteBL1IlV2zqhwwolaG9CwhIhTvVHWg3kTss/cLE7H/X4644mtPQqYvCfsSrGQWt9hSZcgOXX8bOZaMN+kA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@asamuzakjp/dom-selector": "^6.7.2",
"cssstyle": "^5.3.1",
@@ -4135,7 +4142,6 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -4572,6 +4578,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -4716,7 +4723,6 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -4731,8 +4737,7 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/prop-types": {
"version": "15.8.1",
@@ -4779,6 +4784,7 @@
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -4790,6 +4796,7 @@
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
@@ -5510,6 +5517,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -5756,6 +5764,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz",
"integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==",
"dev": true,
+ "peer": true,
"dependencies": {
"esbuild": "^0.18.10",
"postcss": "^8.4.27",
@@ -5812,6 +5821,7 @@
"integrity": "sha512-IUSop8jgaT7w0g1yOM/35qVtKjr/8Va4PrjzH1OUb0YH4c3OXB2lCZDkMAB6glA8T5w8S164oJGsbcmAecr4sA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@vitest/expect": "4.0.3",
"@vitest/mocker": "4.0.3",
@@ -6345,24 +6355,13 @@
}
}
},
- "node_modules/vitest/node_modules/jiti": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
- "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "bin": {
- "jiti": "lib/jiti-cli.mjs"
- }
- },
"node_modules/vitest/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -6418,6 +6417,7 @@
"integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
diff --git a/src/App.jsx b/src/App.jsx
index 3fd27dc8..0614b64f 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,27 +1,36 @@
/* eslint-disable no-unused-vars */
// App.jsx
-import React from "react";
+import React, { useState } from "react";
import { Route, Routes } from "react-router-dom";
import { ThemeProvider } from "./ThemeContext";
import Home from "./components/Home";
import "./style.css";
+import "./theme.css";
import About from "./components/About";
import History from "./components/History";
+import MemeHistory from "./components/MemeHistory";
+import Favorites from "./components/Favorites";
import Dynamicmeme from "./components/Dynamicmeme";
import NewMeme from "./components/NewMeme";
const App = () => {
+ const [meme, setMeme] = useState(null);
+
return (
-
- } />
+
+
+ } />
} />
} />
+ } />
+ } />
} />
} />
{/* Define other routes here */}
-
+
+
);
};
diff --git a/src/Meme.jsx b/src/Meme.jsx
index 69a94e9d..aa73489f 100644
--- a/src/Meme.jsx
+++ b/src/Meme.jsx
@@ -1,5 +1,5 @@
/* eslint-disable react/prop-types */
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { useToast } from "./contexts/ToastContext";
import {
shareToTwitter,
@@ -22,6 +22,32 @@ const Meme = ({ meme, setMeme }) => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState('');
const [showError, setShowError] = useState(false);
+
+ // Keyboard shortcuts
+ useEffect(() => {
+ const handleKeyPress = (e) => {
+ if (e.ctrlKey || e.metaKey) {
+ switch (e.key) {
+ case 's':
+ e.preventDefault();
+ downloadMeme(meme.url, "meme");
+ break;
+ case 'Enter':
+ e.preventDefault();
+ if (!isLoading) {
+ document.querySelector('form').requestSubmit();
+ }
+ break;
+ }
+ }
+ if (e.key === 'Escape') {
+ setMeme(null);
+ }
+ };
+
+ window.addEventListener('keydown', handleKeyPress);
+ return () => window.removeEventListener('keydown', handleKeyPress);
+ }, [meme.url, isLoading, setMeme]);
const saveMemeToHistory = (memeData) => {
const savedMemes = JSON.parse(localStorage.getItem('memeHistory') || '[]');
@@ -29,10 +55,18 @@ const Meme = ({ meme, setMeme }) => {
id: Date.now(),
url: memeData.url,
template_name: meme.name || 'Unknown Template',
+ template_id: meme.id,
texts: form.boxes.map(box => box.text || ''),
- created_at: new Date().toISOString()
+ created_at: new Date().toISOString(),
+ thumbnail: meme.url
};
+
+ // Keep only last 50 memes to avoid storage issues
savedMemes.unshift(newMeme);
+ if (savedMemes.length > 50) {
+ savedMemes.splice(50);
+ }
+
localStorage.setItem('memeHistory', JSON.stringify(savedMemes));
};
@@ -98,31 +132,82 @@ const Meme = ({ meme, setMeme }) => {
{/* Left Section - Image */}
-
-

+
+
+

+ {/* Meme Info Overlay */}
+
+ {meme.width}x{meme.height}px
+
+
+
+ {/* Meme Stats */}
+
+
{meme.name}
+
+ 📝 {meme.box_count} text boxes
+ 📈 {meme.width}x{meme.height}
+
+
{/* Right Section - Caption Inputs */}
-
Add Your Captions
-
+
+
Add Your Captions
+
+
📝 Fill in the text boxes below
+
⌨️ Shortcuts: Ctrl+S (Save), Ctrl+Enter (Generate), Esc (Back)
+
+
+
{[...Array(meme.box_count)].map((_, index) => (
-
{
- const newBox = form.boxes;
- newBox[index] = { text: e.target.value };
- setForm({ ...form, boxes: newBox });
- }}
- />
+
+
{
+ const newBox = form.boxes;
+ newBox[index] = { text: e.target.value };
+ setForm({ ...form, boxes: newBox });
+ }}
+ />
+ {/* Quick Text Options */}
+
+
+
+
+
))}
@@ -158,11 +243,11 @@ const Meme = ({ meme, setMeme }) => {
>
) : showError ? (
<>
- ❌ Error
+ ❌ Failed - Try Again
>
) : showSuccessNote ? (
<>
- ✅ Success!
+ ✅ Meme Created!
>
) : (
<>
@@ -174,10 +259,52 @@ const Meme = ({ meme, setMeme }) => {
type="button"
className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg transition-colors font-medium"
onClick={() => downloadMeme(meme.url, "meme")}
+ title="Save meme (Ctrl+S)"
>
💾 Save
+ {/* Quick Actions */}
+
+
+
+
{/* Success Note */}
{showSuccessNote && (
@@ -187,8 +314,13 @@ const Meme = ({ meme, setMeme }) => {
{/* Error Message */}
{showError && (
-
- ❌ {error}
+
+
⚠️
+
+
Generation Failed
+
{error}
+
Check your connection and try again
+
)}
@@ -235,6 +367,36 @@ const Meme = ({ meme, setMeme }) => {
>
📋 Copy Link
+
+ {/* Additional Share Options */}
+
+
+
)}
diff --git a/src/Temp.jsx b/src/Temp.jsx
index 6b82b1fe..7d5bbeeb 100644
--- a/src/Temp.jsx
+++ b/src/Temp.jsx
@@ -2,11 +2,13 @@
import React, { useRef, useLayoutEffect } from "react";
import gsap from "gsap";
import memesMeta from "./memesMeta";
+import { useFavorites } from "./hooks/useFavorites";
const Temp = ({ temp, setMeme }) => {
const row1 = useRef(null);
const row2 = useRef(null);
const row3 = useRef(null);
+ const { toggleFavorite, isFavorite } = useFavorites();
useLayoutEffect(() => {
const ctx1 = gsap.context(() => {
@@ -45,21 +47,33 @@ const Temp = ({ temp, setMeme }) => {
const renderTemplate = (temps) => (
setMeme(temps)}
- // 1. Add aria-label to the clickable container
aria-label={`Select meme template: ${temps.name}`}
- role="button" // Indicates it is an interactive element
+ role="button"
>
+ {/* Heart button */}
+
+
{/* Caption overlay */}
{memesMeta[temps.name]?.captions?.join(", ")}
diff --git a/src/components/Favorites.jsx b/src/components/Favorites.jsx
new file mode 100644
index 00000000..2f84bd01
--- /dev/null
+++ b/src/components/Favorites.jsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { useFavorites } from '../hooks/useFavorites';
+
+const Favorites = ({ setMeme }) => {
+ const { favorites, toggleFavorite } = useFavorites();
+
+ if (favorites.length === 0) {
+ return (
+
+
+
Your Favorite Templates
+
+
+
❤️
+
No Favorites Yet
+
+ Heart your favorite meme templates to see them here
+
+
+ Browse Templates
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
Your Favorite Templates
+
+
+ {favorites.length} favorite template{favorites.length !== 1 ? 's' : ''}
+
+
+
+ {favorites.map((template) => (
+
setMeme(template)}
+ >
+
+

+
+
+
+ {/* Heart button */}
+
+
+ {/* Play icon on hover */}
+
+
+
+
+
{template.name}
+
+ 📝 {template.box_count} texts
+
+
+
+ ))}
+
+
+
+ );
+};
+
+export default Favorites;
\ No newline at end of file
diff --git a/src/components/Home.jsx b/src/components/Home.jsx
index c4aa2fe5..6a3e16d7 100644
--- a/src/components/Home.jsx
+++ b/src/components/Home.jsx
@@ -7,28 +7,68 @@ import Footer from "./Footer";
import "../style.css";
import "../index.css";
+
const Home = () => {
const [temp, setTemp] = useState([]);
const [meme, setMeme] = useState(null);
const [searchQuery, setSearchQuery] = useState("");
const [currentPage, setCurrentPage] = useState(1);
+ const [selectedCategory, setSelectedCategory] = useState('all');
+ const [isLoading, setIsLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [isDark, setIsDark] = useState(() => {
+ const saved = localStorage.getItem('theme');
+ return saved ? saved === 'dark' : true;
+ });
+
+ const toggleTheme = () => {
+ const newTheme = !isDark;
+ setIsDark(newTheme);
+ localStorage.setItem('theme', newTheme ? 'dark' : 'light');
+ };
const [itemsPerPage] = useState(18); // Fixed 18 items per page
useEffect(() => {
+ setIsLoading(true);
fetch("https://api.imgflip.com/get_memes")
- .then((res) => res.json())
+ .then((res) => {
+ if (!res.ok) throw new Error('Failed to load memes');
+ return res.json();
+ })
.then((data) => {
setTemp(data.data.memes);
+ setIsLoading(false);
+ })
+ .catch((err) => {
+ setError(err.message);
+ setIsLoading(false);
});
}, []);
- // Function to filter memes based on the search query
- const filteredMemes = temp.filter((meme) =>
- meme.name.toLowerCase().includes(searchQuery.toLowerCase())
- );
+ // Enhanced filtering with categories
+ const filteredMemes = temp.filter((meme) => {
+ const matchesSearch = meme.name.toLowerCase().includes(searchQuery.toLowerCase());
+
+ if (selectedCategory === 'all') return matchesSearch;
+
+ const categoryKeywords = {
+ reaction: ['surprised', 'pikachu', 'yelling', 'woman', 'cat'],
+ funny: ['spongebob', 'mocking', 'fine', 'dog'],
+ choice: ['drake', 'buttons', 'two buttons', 'exit'],
+ success: ['cheers', 'dicaprio', 'handshake'],
+ programming: ['debugging', 'brain', 'expanding']
+ };
+
+ const keywords = categoryKeywords[selectedCategory] || [];
+ const matchesCategory = keywords.some(keyword =>
+ meme.name.toLowerCase().includes(keyword)
+ );
+
+ return matchesSearch && matchesCategory;
+ });
// Calculate the index of the last and first item on the current page
const indexOfLastItem = currentPage * itemsPerPage;
@@ -87,20 +127,109 @@ const Home = () => {
};
return (
-
+
+
-
+
{meme === null ? (
<>
-
-
+ {/* Categories */}
+
+
+ {[
+ { id: 'all', name: 'All', icon: '🎭' },
+ { id: 'reaction', name: 'Reaction', icon: '😱' },
+ { id: 'funny', name: 'Funny', icon: '😂' },
+ { id: 'choice', name: 'Choice', icon: '🤔' },
+ { id: 'success', name: 'Success', icon: '🎉' },
+ { id: 'programming', name: 'Code', icon: '💻' }
+ ].map(category => (
+
+ ))}
+
+
+ {filteredMemes.length} memes found
+ {selectedCategory !== 'all' && ` in ${selectedCategory}`}
+
+
+
+ {/* Error Message */}
+ {error && (
+
+
+
⚠️
+
+
{error}
+
+
+
+
+ )}
+
+ {/* Loading State */}
+ {isLoading ? (
+
+ {[...Array(18)].map((_, i) => (
+
+ ))}
+
+ ) : filteredMemes.length === 0 ? (
+
+
😅
+
No memes found
+
+ {searchQuery ? `No results for "${searchQuery}"` : 'No memes in this category'}
+
+
+
+ ) : (
+
+ )}
+ {/* Pagination - Only show if has results */}
+ {!isLoading && filteredMemes.length > 0 && (
+
+
+ )}
>
) : (
<>
diff --git a/src/components/MemeHistory.jsx b/src/components/MemeHistory.jsx
new file mode 100644
index 00000000..93efa172
--- /dev/null
+++ b/src/components/MemeHistory.jsx
@@ -0,0 +1,139 @@
+import React, { useState, useEffect } from 'react';
+import { downloadMeme } from '../utils/socialShare';
+
+const MemeHistory = () => {
+ const [history, setHistory] = useState([]);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ const saved = JSON.parse(localStorage.getItem('memeHistory') || '[]');
+ setHistory(saved);
+ setLoading(false);
+ }, []);
+
+ const clearHistory = () => {
+ if (window.confirm('Are you sure you want to clear all history?')) {
+ localStorage.removeItem('memeHistory');
+ setHistory([]);
+ }
+ };
+
+ const deleteMeme = (id) => {
+ const updated = history.filter(meme => meme.id !== id);
+ localStorage.setItem('memeHistory', JSON.stringify(updated));
+ setHistory(updated);
+ };
+
+ if (loading) {
+ return (
+
+
+
+
+ {[...Array(8)].map((_, i) => (
+
+ ))}
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
Your Meme History
+ {history.length > 0 && (
+
+ 🗑️ Clear All
+
+ )}
+
+
+ {history.length === 0 ? (
+
+ ) : (
+ <>
+
+ {history.length} meme{history.length !== 1 ? 's' : ''} in your history
+
+
+
+ {history.map((meme) => (
+
+
+

+
+
+ {/* Action buttons */}
+
+ deleteMeme(meme.id)}
+ className="bg-red-600 hover:bg-red-700 text-white p-1 rounded text-xs mr-1"
+ title="Delete"
+ >
+ 🗑️
+
+ downloadMeme(meme.url, `meme-${meme.id}`)}
+ className="bg-blue-600 hover:bg-blue-700 text-white p-1 rounded text-xs"
+ title="Download"
+ >
+ 💾
+
+
+
+
+
+
+ {meme.template_name}
+
+
+ {new Date(meme.created_at).toLocaleDateString('en-US', {
+ month: 'short',
+ day: 'numeric',
+ year: 'numeric'
+ })}
+
+
+ {/* Show meme texts */}
+ {meme.texts && meme.texts.length > 0 && (
+
+ {meme.texts.slice(0, 2).map((text, i) => (
+
"{text}"
+ ))}
+
+ )}
+
+
+ ))}
+
+ >
+ )}
+
+
+ );
+};
+
+export default MemeHistory;
\ No newline at end of file
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index a6892b91..11cb1494 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -1,19 +1,17 @@
import React, { useState, useEffect, useRef } from "react";
-import { Link, useLocation } from "react-router-dom";
-import { useTheme } from "../ThemeContext";
+import { Link, useLocation, useNavigate } from "react-router-dom";
import { FaSearch, FaTimes, FaGithub } from "react-icons/fa";
import "../index.css";
-import { useNavigate } from "react-router-dom";
-const Navbar = ({ setMeme, searchQuery, setSearchQuery }) => {
+
+const Navbar = ({ setMeme, searchQuery, setSearchQuery, isDark, toggleTheme }) => {
const searchInputRef = useRef(null);
const location = useLocation();
+ const navigate = useNavigate();
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isMobileSearchOpen, setIsMobileSearchOpen] = useState(false);
const [isScrolled, setIsScrolled] = useState(false);
const isHomePage = location.pathname === "/";
- const { isDarkTheme, toggleTheme } = useTheme();
- const navigate = useNavigate();
- // Handle scroll effect for navbar and scroll-to-top button
+
useEffect(() => {
const handleScroll = () => {
const scrolled = window.scrollY > 20;
@@ -24,13 +22,9 @@ const Navbar = ({ setMeme, searchQuery, setSearchQuery }) => {
return () => window.removeEventListener('scroll', handleScroll);
}, []);
- // no-op
-
- // Toggle mobile search
const toggleMobileSearch = () => {
setIsMobileSearchOpen(!isMobileSearchOpen);
if (!isMobileSearchOpen && searchInputRef.current) {
- // Focus search input when opening
setTimeout(() => searchInputRef.current.focus(), 100);
}
};
@@ -41,24 +35,20 @@ const Navbar = ({ setMeme, searchQuery, setSearchQuery }) => {
}
};
- // Close mobile menu and reset search
const closeMobileMenu = () => {
setIsMobileMenuOpen(false);
setIsMobileSearchOpen(false);
};
- //Handle navigation for back button
- const handleBackClick= () => {
- setMeme && setMeme(null);
- //go back in history if possible, otherwise go to Home
+ const handleBackClick = () => {
+ setMeme && setMeme(null);
if(window.history.length > 1){
navigate(-1);
- }
- else{
+ } else {
navigate("/");
}
};
- // Handle navigation and close mobile menu
+
const handleNavigation = (path) => {
if (path === "/") {
setMeme && setMeme(null);
@@ -69,44 +59,30 @@ const Navbar = ({ setMeme, searchQuery, setSearchQuery }) => {
return (
<>
- {/* Skip to content for accessibility */}
-
- Skip to content
-