diff --git a/public/data/quotes.json b/public/data/quotes.json new file mode 100644 index 00000000..a3f6dfe4 --- /dev/null +++ b/public/data/quotes.json @@ -0,0 +1,12 @@ +[ + { "text": "Programs must be written for people to read, and only incidentally for machines to execute.", "author": "Harold Abelson" }, + { "text": "Talk is cheap. Show me the code.", "author": "Linus Torvalds" }, + { "text": "First, solve the problem. Then, write the code.", "author": "John Johnson" }, + { "text": "Experience is the name everyone gives to their mistakes.", "author": "Oscar Wilde" }, + { "text": "In order to be irreplaceable, one must always be different.", "author": "Coco Chanel" }, + { "text": "Java is to JavaScript what car is to Carpet.", "author": "Chris Heilmann" }, + { "text": "Code is like humor. When you have to explain it, it’s bad.", "author": "Cory House" }, + { "text": "Fix the cause, not the symptom.", "author": "Steve Maguire" }, + { "text": "Optimism is an occupational hazard of programming: feedback is the treatment.", "author": "Kent Beck" }, + { "text": "Simplicity is the soul of efficiency.", "author": "Austin Freeman" } +] diff --git a/src/Homepage.jsx b/src/Homepage.jsx index f1257678..419f3aee 100644 --- a/src/Homepage.jsx +++ b/src/Homepage.jsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef } from 'react'; import Profile from './components/Profile/Profile'; +import RandomQuote from './components/RandomQuote'; import ProfileSkeleton from './components/ProfileSkeleton/ProfileSkeleton'; import Search from './components/Search/Search'; import Sidebar from './components/Sidebar/Sidebar'; @@ -31,10 +32,9 @@ function App() { } catch (error) { console.error('Error fetching data:', error); return []; - } - }; + } - const combineData = async () => { + export default App; setLoadingProfiles(true); try { const promises = filenames.map((file, index) => @@ -146,26 +146,34 @@ function App() { return paginatedData.map((currentRecord, index) => ); }; - return currentUrl === '/' ? ( -
- -
- - {profiles.length === 0 && searching ? : renderProfiles()} - {combinedData.length > 0 && ( - - )} + if (currentUrl === '/') { + return ( +
+ +
+ + + {searching ? ( + + ) : ( + + )} +
+ {/* */}
- {/* */} -
- ) : ( - - ); -} - -export default App; + ); + } else { + return ; + } +} \ No newline at end of file diff --git a/src/components/RandomQuote.jsx b/src/components/RandomQuote.jsx new file mode 100644 index 00000000..0f72c017 --- /dev/null +++ b/src/components/RandomQuote.jsx @@ -0,0 +1,136 @@ +import React from 'react'; + + + +const RandomQuote = () => { + const [quotes, setQuotes] = React.useState([]); + const [quoteIdx, setQuoteIdx] = React.useState(0); + const [fade, setFade] = React.useState(true); + + React.useEffect(() => { + fetch('/data/quotes.json') + .then(res => res.json()) + .then(data => { + setQuotes(data); + setQuoteIdx(Math.floor(Math.random() * data.length)); + }); + }, []); + + function getRandomQuoteIdx(excludeIdx) { + if (!quotes.length) return 0; + let idx; + do { + idx = Math.floor(Math.random() * quotes.length); + } while (idx === excludeIdx && quotes.length > 1); + return idx; + } + + const handleNewQuote = () => { + setFade(false); + setTimeout(() => { + setQuoteIdx(getRandomQuoteIdx(quoteIdx)); + setFade(true); + }, 250); + }; + + if (!quotes.length) return null; + const quote = quotes[quoteIdx]; + + // Share/copy handlers + const [copied, setCopied] = React.useState(false); + const quoteText = `"${quote.text}" β€” ${quote.author}`; + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(quoteText); + setCopied(true); + setTimeout(() => setCopied(false), 1200); + } catch (e) { + setCopied(false); + } + }; + + const handleShareTwitter = () => { + const url = `https://twitter.com/intent/tweet?text=${encodeURIComponent(quoteText)}`; + window.open(url, '_blank'); + }; + + return ( +
+
+ πŸ’‘ + {quote.text} +
+
+ β€” {quote.author} +
+
+ + +
+ +
+ ); +}; + +export default RandomQuote;