Spaces:
Running
Running
| import React, { useState } from "react"; | |
| // Zodiac Icon Components using Tabler Icons SVGs | |
| const ZodiacIcon = ({ sign, size = 24, className = "" }) => { | |
| const iconPaths = { | |
| taurus: [ | |
| "M6 3a6 6 0 0 0 12 0", | |
| "M12 15m-6 0a6 6 0 1 0 12 0a6 6 0 1 0 -12 0", | |
| ], | |
| sagittarius: ["M4 20l16 -16", "M13 4h7v7", "M6.5 12.5l5 5"], | |
| pisces: ["M5 3a21 21 0 0 1 0 18", "M19 3a21 21 0 0 0 0 18", "M5 12l14 0"], | |
| libra: ["M5 20l14 0", "M5 17h5v-.3a7 7 0 1 1 4 0v.3h5"], | |
| gemini: [ | |
| "M3 3a21 21 0 0 0 18 0", | |
| "M3 21a21 21 0 0 1 18 0", | |
| "M7 4.5l0 15", | |
| "M17 4.5l0 15", | |
| ], | |
| leo: [ | |
| "M13 17a4 4 0 1 0 8 0", | |
| "M6 16m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0", | |
| "M11 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0", | |
| "M7 7c0 3 2 5 2 9", | |
| "M15 7c0 4 -2 6 -2 10", | |
| ], | |
| virgo: [ | |
| "M3 4a2 2 0 0 1 2 2v9", | |
| "M5 6a2 2 0 0 1 4 0v9", | |
| "M9 6a2 2 0 0 1 4 0v10a7 5 0 0 0 7 5", | |
| "M12 21a7 5 0 0 0 7 -5v-2a3 3 0 0 0 -6 0", | |
| ], | |
| aquarius: [ | |
| "M3 10l3 -3l3 3l3 -3l3 3l3 -3l3 3", | |
| "M3 17l3 -3l3 3l3 -3l3 3l3 -3l3 3", | |
| ], | |
| aries: ["M12 5a5 5 0 1 0 -4 8", "M16 13a5 5 0 1 0 -4 -8", "M12 21l0 -16"], | |
| cancer: [ | |
| "M6 12m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0", | |
| "M18 12m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0", | |
| "M3 12a10 6.5 0 0 1 14 -6.5", | |
| "M21 12a10 6.5 0 0 1 -14 6.5", | |
| ], | |
| scorpio: [ | |
| "M3 4a2 2 0 0 1 2 2v9", | |
| "M5 6a2 2 0 0 1 4 0v9", | |
| "M9 6a2 2 0 0 1 4 0v10a3 3 0 0 0 3 3h5l-3 -3m0 6l3 -3", | |
| ], | |
| capricorn: [ | |
| "M4 4a3 3 0 0 1 3 3v9", | |
| "M7 7a3 3 0 0 1 6 0v11a3 3 0 0 1 -3 3", | |
| "M16 17m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0", | |
| ], | |
| }; | |
| const paths = iconPaths[sign] || []; | |
| return ( | |
| <svg | |
| width={size} | |
| height={size} | |
| viewBox="0 0 24 24" | |
| fill="none" | |
| stroke="currentColor" | |
| strokeWidth="2" | |
| strokeLinecap="round" | |
| strokeLinejoin="round" | |
| className={className} | |
| > | |
| <path stroke="none" d="M0 0h24v24H0z" fill="none" /> | |
| {paths.map((path, index) => ( | |
| <path key={index} d={path} /> | |
| ))} | |
| </svg> | |
| ); | |
| }; | |
| 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: "π", | |
| symbol: "β", | |
| imageFile: "TAURUS.png", | |
| }, | |
| { | |
| id: "sagittarius", | |
| name: "Sagittarius", | |
| dates: "Nov 22 - Dec 21", | |
| emoji: "πΉ", | |
| symbol: "β", | |
| imageFile: "SAGITTARIUS.png", | |
| }, | |
| { | |
| id: "pisces", | |
| name: "Pisces", | |
| dates: "Feb 19 - Mar 20", | |
| emoji: "π ", | |
| symbol: "β", | |
| imageFile: "PISCES.png", | |
| }, | |
| { | |
| id: "libra", | |
| name: "Libra", | |
| dates: "Sep 23 - Oct 22", | |
| emoji: "βοΈ", | |
| symbol: "β", | |
| imageFile: "LIBRA.png", | |
| }, | |
| { | |
| id: "gemini", | |
| name: "Gemini", | |
| dates: "May 21 - Jun 20", | |
| emoji: "π―", | |
| symbol: "β", | |
| imageFile: "GEMINI.png", | |
| }, | |
| { | |
| id: "leo", | |
| name: "Leo", | |
| dates: "Jul 23 - Aug 22", | |
| emoji: "π¦", | |
| symbol: "β", | |
| imageFile: "LEO.png", | |
| }, | |
| { | |
| id: "virgo", | |
| name: "Virgo", | |
| dates: "Aug 23 - Sep 22", | |
| emoji: "πΈ", | |
| symbol: "β", | |
| imageFile: "VIRGO.png", | |
| }, | |
| { | |
| id: "aquarius", | |
| name: "Aquarius", | |
| dates: "Jan 20 - Feb 18", | |
| emoji: "πΊ", | |
| symbol: "β", | |
| imageFile: "AQUARIUS.png", | |
| }, | |
| { | |
| id: "aries", | |
| name: "Aries", | |
| dates: "Mar 21 - Apr 19", | |
| emoji: "π", | |
| symbol: "β", | |
| imageFile: "ARIES.png", | |
| }, | |
| { | |
| id: "cancer", | |
| name: "Cancer", | |
| dates: "Jun 21 - Jul 22", | |
| emoji: "π¦", | |
| symbol: "β", | |
| imageFile: "CANCER.png", | |
| }, | |
| { | |
| id: "scorpio", | |
| name: "Scorpio", | |
| dates: "Oct 23 - Nov 21", | |
| emoji: "π¦", | |
| symbol: "β", | |
| imageFile: "SCORPIO.png", | |
| }, | |
| { | |
| id: "capricorn", | |
| name: "Capricorn", | |
| dates: "Dec 22 - Jan 19", | |
| emoji: "π", | |
| symbol: "β", | |
| 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: <i className="ri-hearts-line"></i> }, | |
| { | |
| id: "health", | |
| name: "Health", | |
| icon: <i className="ri-open-arm-line"></i>, | |
| }, | |
| { | |
| id: "relationship", | |
| name: "Relationship", | |
| icon: <i className="ri-team-line"></i>, | |
| }, | |
| { | |
| id: "finance", | |
| name: "Finance", | |
| icon: <i className="ri-wallet-3-line"></i>, | |
| }, | |
| ]; | |
| 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", | |
| ], | |
| }; | |
| // Function to get image path based on gender | |
| 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`} | |
| > | |
| <i | |
| className={`text-xl ${ | |
| isDarkMode ? "ri-sun-line" : "ri-moon-line" | |
| }`} | |
| ></i> | |
| <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"> | |
| <i className="ri-magic-line text-xl text-white"></i> | |
| </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> | |
| <i className="ri-women-line sm:hidden"></i> | |
| </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> | |
| <i className="ri-men-line sm:hidden"></i> | |
| </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"> | |
| <i className="ri-magic-line text-2xl text-white"></i> | |
| </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%)", | |
| }} | |
| > | |
| {/* Background layer for separation */} | |
| <div | |
| className={`w-full h-full rounded-full p-0.5 ${ | |
| isDarkMode ? "bg-gray-900" : "bg-gray-50" | |
| }`} | |
| > | |
| <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"; | |
| }} | |
| /> | |
| ) : ( | |
| <ZodiacIcon | |
| sign={sign.id} | |
| size={28} | |
| className="text-gray-600" | |
| /> | |
| )} | |
| <span | |
| style={{ | |
| display: getImagePath(sign) ? "none" : "none", | |
| }} | |
| > | |
| {sign.emoji} | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| <p className="text-xs font-medium mt-3 text-center flex items-center justify-center gap-1"> | |
| <ZodiacIcon | |
| sign={sign.id} | |
| size={16} | |
| className="text-current" | |
| /> | |
| {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" | |
| }`} | |
| > | |
| {category.icon} | |
| {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%)", | |
| }} | |
| > | |
| {/* Background layer for separation */} | |
| <div | |
| className={`w-full h-full rounded-full p-0.5 ${ | |
| isDarkMode ? "bg-gray-900" : "bg-gray-50" | |
| }`} | |
| > | |
| <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"; | |
| }} | |
| /> | |
| ) : ( | |
| <ZodiacIcon | |
| sign={getCurrentSign()?.id} | |
| size={32} | |
| className="text-gray-600" | |
| /> | |
| )} | |
| <span | |
| style={{ | |
| display: getImagePath(getCurrentSign()) ? "none" : "none", | |
| }} | |
| > | |
| {getCurrentSign()?.emoji} | |
| </span> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="flex-1"> | |
| <h2 className="text-3xl font-bold text-blue-400 flex items-center gap-2 mb-2"> | |
| {getPeriodTitle()} | |
| <i className="ri-pulse-line text-xl"></i> | |
| </h2> | |
| <div className="flex items-center gap-2"> | |
| <ZodiacIcon | |
| sign={getCurrentSign()?.id} | |
| size={20} | |
| className="text-current" | |
| /> | |
| <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"> | |
| <i className="ri-palette-line text-3xl mb-3 text-green-500"></i> | |
| <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"> | |
| <i className="ri-hashtag text-3xl mb-3 text-blue-500"></i> | |
| <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"> | |
| <i className="ri-vip-diamond-line text-3xl mb-3 text-purple-500"></i> | |
| <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"> | |
| <i className="ri-star-line text-3xl mb-3 text-yellow-500"></i> | |
| <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 className="flex items-center justify-center gap-2"> | |
| <i className="ri-sparkling-line"></i> | |
| Discover your daily horoscope and unlock the secrets of the stars | |
| <i className="ri-sparkling-line"></i> | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default HoroscopeApp; | |