HoroScope / src /App.js
ntphuc149's picture
Update src/App.js
0be8258 verified
raw
history blame
17.9 kB
import React, { useState } from "react";
const HoroscopeApp = () => {
const [selectedSign, setSelectedSign] = useState("taurus");
const [selectedGender, setSelectedGender] = useState("female");
const [selectedPeriod, setSelectedPeriod] = useState("today");
const [selectedCategory, setSelectedCategory] = useState("love");
const [isDarkMode, setIsDarkMode] = useState(false);
const zodiacSigns = [
{
id: "taurus",
name: "Taurus",
dates: "April 20 - May 20",
emoji: "🐂",
imageFile: "TAURUS.png",
},
{
id: "sagittarius",
name: "Sagittarius",
dates: "Nov 22 - Dec 21",
emoji: "🏹",
imageFile: "SAGITTARIUS.png",
},
{
id: "pisces",
name: "Pisces",
dates: "Feb 19 - Mar 20",
emoji: "🐠",
imageFile: "PISCES.png",
},
{
id: "libra",
name: "Libra",
dates: "Sep 23 - Oct 22",
emoji: "⚖️",
imageFile: "LIBRA.png",
},
{
id: "gemini",
name: "Gemini",
dates: "May 21 - Jun 20",
emoji: "👯",
imageFile: "GEMINI.png",
},
{
id: "leo",
name: "Leo",
dates: "Jul 23 - Aug 22",
emoji: "🦁",
imageFile: "LEO.png",
},
{
id: "virgo",
name: "Virgo",
dates: "Aug 23 - Sep 22",
emoji: "👸",
imageFile: "VIRGO.png",
},
{
id: "aquarius",
name: "Aquarius",
dates: "Jan 20 - Feb 18",
emoji: "🏺",
imageFile: "AQUARIUS.png",
},
{
id: "aries",
name: "Aries",
dates: "Mar 21 - Apr 19",
emoji: "🐏",
imageFile: "ARIES.png",
},
{
id: "cancer",
name: "Cancer",
dates: "Jun 21 - Jul 22",
emoji: "🦀",
imageFile: "CANCER.png",
},
{
id: "scorpio",
name: "Scorpio",
dates: "Oct 23 - Nov 21",
emoji: "🦂",
imageFile: "SCORPIO.png",
},
{
id: "capricorn",
name: "Capricorn",
dates: "Dec 22 - Jan 19",
emoji: "🐐",
imageFile: "CAPRICORN.png",
},
];
const periods = [
{ id: "today", name: "Today" },
{ id: "week", name: "Week" },
{ id: "month", name: "Month" },
{ id: "year", name: "Year" },
];
const categories = [
{ id: "love", name: "Love", icon: "💖" },
{ id: "health", name: "Health", icon: "🌟" },
{ id: "relationship", name: "Relationship", icon: "👥" },
{ id: "finance", name: "Finance", icon: "💰" },
];
const horoscopeContent = {
love: {
today:
"Love is in the air today! Your romantic side is highlighted, making it a perfect day for expressing your feelings.",
week: "This week brings romantic opportunities and deepening connections with your loved ones.",
month:
"A month of passionate encounters and meaningful relationships awaits you.",
year: "This year will be transformative for your love life, bringing lasting happiness.",
},
health: {
today:
"Your energy levels are high today. Focus on maintaining balance between work and rest.",
week: "Pay attention to your physical wellbeing this week. Small changes can make big differences.",
month:
"This month emphasizes the importance of mental and physical health harmony.",
year: "A year of wellness and vitality lies ahead. Make health your priority.",
},
relationship: {
today:
"Relationships flourish under today's cosmic energy. Communication is key to success.",
week: "Strengthen your bonds with family and friends through meaningful conversations.",
month:
"Social connections expand this month, bringing new friendships and opportunities.",
year: "Your social circle will grow significantly, enriching your life in unexpected ways.",
},
finance: {
today:
"Financial opportunities present themselves today. Stay alert for new possibilities.",
week: "This week favors careful financial planning and smart investments.",
month:
"Money matters require attention this month. Budget wisely for future security.",
year: "Financial growth and stability are highlighted throughout this year.",
},
};
const luckyData = {
colors: [
"Green",
"Blue",
"Purple",
"Gold",
"Silver",
"Red",
"Pink",
"Orange",
"Yellow",
"Turquoise",
"Violet",
"Indigo",
],
numbers: [1, 3, 7, 9, 11, 13, 21, 23, 27, 33, 42, 77],
stones: [
"Emerald",
"Sapphire",
"Ruby",
"Diamond",
"Amethyst",
"Topaz",
"Opal",
"Pearl",
"Garnet",
"Aquamarine",
"Citrine",
"Turquoise",
],
moods: [
"Optimistic",
"Energetic",
"Peaceful",
"Confident",
"Creative",
"Adventurous",
"Romantic",
"Focused",
"Joyful",
"Balanced",
"Inspired",
"Harmonious",
],
};
const getImagePath = (sign) => {
if (!sign.imageFile) return null;
return `/img/${selectedGender}/${sign.imageFile}`;
};
const getCurrentSign = () => {
return zodiacSigns.find((sign) => sign.id === selectedSign);
};
const getHoroscopeText = () => {
return horoscopeContent[selectedCategory][selectedPeriod];
};
const getLuckyElement = (type) => {
const data = luckyData[type];
return data[Math.floor(Math.random() * data.length)];
};
const getPeriodTitle = () => {
const titles = {
today: "Horoscope for Today",
week: "Horoscope for This Week",
month: "Horoscope for This Month",
year: "Horoscope for This Year",
};
return titles[selectedPeriod];
};
const toggleTheme = () => {
setIsDarkMode(!isDarkMode);
};
return (
<div
className={`min-h-screen transition-all duration-500 ${
isDarkMode
? "bg-gradient-to-br from-gray-900 via-blue-900 to-purple-900 text-white"
: "bg-gradient-to-br from-blue-50 via-purple-50 to-pink-50 text-gray-800"
}`}
>
<div className="max-w-6xl mx-auto p-5">
{/* Header Controls */}
<div className="flex justify-between items-center mb-6 md:mb-8">
{/* Theme Toggle */}
<button
onClick={toggleTheme}
className={`flex items-center gap-2 px-3 md:px-4 py-2 rounded-full font-medium transition-all duration-300 ${
isDarkMode
? "bg-white bg-opacity-10 text-white hover:bg-opacity-20"
: "bg-white bg-opacity-90 text-gray-700 hover:bg-opacity-100"
} shadow-lg hover:scale-105`}
>
<span className="text-xl">{isDarkMode ? "☀️" : "🌙"}</span>
<span className="hidden sm:inline">
{isDarkMode ? "Light Mode" : "Dark Mode"}
</span>
</button>
{/* App Icon - Visible on mobile */}
<div className="sm:hidden">
<div className="inline-flex items-center justify-center w-12 h-12 bg-gradient-to-r from-blue-400 to-purple-500 rounded-full shadow-lg">
<span className="text-xl text-white">🔮</span>
</div>
</div>
{/* Gender Selection */}
<div
className={`flex rounded-full p-1 shadow-lg ${
isDarkMode ? "bg-white bg-opacity-10" : "bg-white bg-opacity-90"
}`}
>
<button
onClick={() => setSelectedGender("female")}
className={`px-3 md:px-6 py-2 rounded-full font-medium transition-all ${
selectedGender === "female"
? "bg-pink-400 text-white shadow-md"
: isDarkMode
? "text-white hover:text-pink-300"
: "text-gray-600 hover:text-pink-400"
}`}
>
<span className="hidden sm:inline">Female</span>
<span className="sm:hidden"></span>
</button>
<button
onClick={() => setSelectedGender("male")}
className={`px-3 md:px-6 py-2 rounded-full font-medium transition-all ${
selectedGender === "male"
? "bg-blue-400 text-white shadow-md"
: isDarkMode
? "text-white hover:text-blue-300"
: "text-gray-600 hover:text-blue-400"
}`}
>
<span className="hidden sm:inline">Male</span>
<span className="sm:hidden"></span>
</button>
</div>
</div>
{/* App Title - Hidden on mobile */}
<div className="text-center mb-6 md:mb-10 hidden sm:block">
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-r from-blue-400 to-purple-500 rounded-full mb-4 shadow-lg">
<span className="text-2xl text-white">🔮</span>
</div>
<h1 className="text-4xl font-bold mb-2">Horoscope App</h1>
</div>
{/* Zodiac Signs Grid - Single Row */}
<div className="w-full overflow-x-auto mb-6 md:mb-10">
<div className="flex justify-start md:justify-center gap-2 md:gap-3 pb-4 px-4 min-w-max py-2">
{zodiacSigns.map((sign) => (
<div
key={sign.id}
onClick={() => setSelectedSign(sign.id)}
className="flex flex-col items-center cursor-pointer transition-all duration-300 hover:scale-105 flex-shrink-0 py-1"
>
<div
className={`w-20 h-20 md:w-24 md:h-24 rounded-full p-0.5 transition-all ${
selectedSign === sign.id ? "shadow-lg" : ""
}`}
style={{
background:
selectedSign === sign.id
? "linear-gradient(135deg, #1D3249 0%, #96D1E2 100%)"
: "linear-gradient(135deg, #07090A 0%, #979999 100%)",
}}
>
<div
className={`w-full h-full rounded-full flex items-center justify-center text-xl overflow-hidden ${
isDarkMode ? "bg-gray-800" : "bg-gray-100"
}`}
>
{getImagePath(sign) ? (
<img
src={getImagePath(sign)}
alt={sign.name}
className="w-full h-full object-cover rounded-full"
onError={(e) => {
e.target.style.display = "none";
e.target.nextSibling.style.display = "block";
}}
/>
) : null}
<span
style={{ display: getImagePath(sign) ? "none" : "block" }}
>
{sign.emoji}
</span>
</div>
</div>
<p className="text-xs font-medium mt-3 text-center">
{sign.name}
</p>
</div>
))}
</div>
</div>
{/* Period Selection */}
<div className="flex justify-center mb-6 md:mb-8">
<div
className={`flex rounded-full p-1 shadow-lg ${
isDarkMode ? "bg-white bg-opacity-10" : "bg-white bg-opacity-90"
}`}
>
{periods.map((period) => (
<button
key={period.id}
onClick={() => setSelectedPeriod(period.id)}
className={`px-4 md:px-6 py-2 md:py-3 rounded-full font-medium transition-all text-sm md:text-base ${
selectedPeriod === period.id
? "bg-blue-400 text-white shadow-md"
: isDarkMode
? "text-white hover:text-blue-300"
: "text-gray-600 hover:text-blue-400"
}`}
>
{period.name}
</button>
))}
</div>
</div>
{/* Category Selection */}
<div className="flex justify-center flex-wrap gap-2 md:gap-3 mb-6 md:mb-10">
{categories.map((category) => (
<button
key={category.id}
onClick={() => setSelectedCategory(category.id)}
className={`flex items-center gap-2 px-3 md:px-4 py-2 rounded-full font-medium transition-all duration-300 shadow-lg hover:scale-105 text-sm md:text-base ${
selectedCategory === category.id
? "bg-purple-400 text-white shadow-lg"
: isDarkMode
? "bg-white bg-opacity-10 text-white hover:bg-opacity-20"
: "bg-white bg-opacity-90 text-gray-600 hover:bg-opacity-100"
}`}
>
<span>{category.icon}</span>
{category.name}
</button>
))}
</div>
{/* Horoscope Content */}
<div
className={`rounded-3xl p-8 mb-4 shadow-2xl backdrop-blur-lg transition-all ${
isDarkMode
? "bg-white bg-opacity-10 border border-white border-opacity-20"
: "bg-white bg-opacity-95"
}`}
>
<div className="flex items-center gap-6 mb-8">
<div
className="w-20 h-20 rounded-full p-0.5 shadow-lg"
style={{
background: "linear-gradient(135deg, #1D3249 0%, #96D1E2 100%)",
}}
>
<div
className={`w-full h-full rounded-full flex items-center justify-center text-2xl overflow-hidden ${
isDarkMode ? "bg-gray-800" : "bg-gray-100"
}`}
>
{getImagePath(getCurrentSign()) ? (
<img
src={getImagePath(getCurrentSign())}
alt={getCurrentSign()?.name}
className="w-full h-full object-cover rounded-full"
onError={(e) => {
e.target.style.display = "none";
e.target.nextSibling.style.display = "block";
}}
/>
) : null}
<span
style={{
display: getImagePath(getCurrentSign()) ? "none" : "block",
}}
>
{getCurrentSign()?.emoji}
</span>
</div>
</div>
<div className="flex-1">
<h2 className="text-3xl font-bold text-blue-400 flex items-center gap-2 mb-2">
{getPeriodTitle()}
<span className="text-xl">📈</span>
</h2>
<div className="flex items-center gap-2">
<span className="text-xl">{getCurrentSign()?.emoji}</span>
<span className="font-semibold">{getCurrentSign()?.name}</span>
</div>
</div>
</div>
<p
className={`font-medium mb-6 ${
isDarkMode ? "text-gray-300" : "text-gray-600"
}`}
>
{getCurrentSign()?.name} ({getCurrentSign()?.dates})
</p>
<p className="text-lg leading-relaxed mb-8">{getHoroscopeText()}</p>
{/* Lucky Elements */}
<div
className={`grid grid-cols-2 md:grid-cols-4 gap-6 pt-6 border-t ${
isDarkMode ? "border-gray-700" : "border-gray-200"
}`}
>
<div className="text-center">
<div className="text-3xl mb-3">🍀</div>
<p
className={`text-xs uppercase tracking-wider mb-2 ${
isDarkMode ? "text-gray-400" : "text-gray-500"
}`}
>
Lucky Color
</p>
<p className="font-bold text-green-500">
{getLuckyElement("colors")}
</p>
</div>
<div className="text-center">
<div className="text-3xl mb-3">🔢</div>
<p
className={`text-xs uppercase tracking-wider mb-2 ${
isDarkMode ? "text-gray-400" : "text-gray-500"
}`}
>
Lucky Number
</p>
<p className="font-bold text-blue-500">
{getLuckyElement("numbers")}
</p>
</div>
<div className="text-center">
<div className="text-3xl mb-3">💎</div>
<p
className={`text-xs uppercase tracking-wider mb-2 ${
isDarkMode ? "text-gray-400" : "text-gray-500"
}`}
>
Lucky Stone
</p>
<p className="font-bold text-purple-500">
{getLuckyElement("stones")}
</p>
</div>
<div className="text-center">
<div className="text-3xl mb-3"></div>
<p
className={`text-xs uppercase tracking-wider mb-2 ${
isDarkMode ? "text-gray-400" : "text-gray-500"
}`}
>
Mood
</p>
<p className="font-bold text-yellow-500">
{getLuckyElement("moods")}
</p>
</div>
</div>
</div>
{/* Footer */}
<div className="text-center text-sm opacity-70 mt-4">
<p>
✨ Discover your daily horoscope and unlock the secrets of the stars
</p>
</div>
</div>
</div>
);
};
export default HoroscopeApp;