Weather widgets are essential tools for providing real-time weather updates directly on your website or application. They enhance user experience by offering quick and accessible weather information.
In this article, we will explore 10 exemplary weather widgets that stand out for their design, functionality, and ease of integration. These examples will inspire you to choose or create the perfect weather widget for your needs.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Designers and developers, elevate your weather widget creation with Subframe's drag-and-drop interface. Its intuitive, responsive canvas ensures pixel-perfect UI every time, making it a favorite among professionals.
Join the community that loves Subframe. Start for free today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI design game? With Subframe, you can create pixel-perfect weather widgets and other stunning UIs in minutes. Its drag-and-drop interface ensures efficiency and precision.
Don't wait! Start for free and begin designing immediately. Join the community of professionals who trust Subframe for their UI needs.
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CityPulse Weather</title> <style> :root { --day-primary: #f2f7ff; --day-secondary: #e0eafc; --day-accent: #5e81ac; --day-text: #2e3440; --night-primary: #2e3440; --night-secondary: #3b4252; --night-accent: #88c0d0; --night-text: #eceff4; --alert-low: #ebcb8b; --alert-medium: #d08770; --alert-high: #bf616a; --transition-speed: 0.6s; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #f5f5f5; transition: background-color var(--transition-speed); } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; border-radius: 24px; overflow: hidden; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1); transition: all var(--transition-speed); } .day-mode { background-color: var(--day-primary); color: var(--day-text); } .night-mode { background-color: var(--night-primary); color: var(--night-text); } .header { padding: 32px; display: flex; justify-content: space-between; align-items: center; transition: all var(--transition-speed); } .day-mode .header { background-color: var(--day-secondary); } .night-mode .header { background-color: var(--night-secondary); } .city-info { display: flex; flex-direction: column; } .city-name { font-size: 2.4rem; font-weight: 700; margin-bottom: 4px; } .date-time { font-size: 1rem; opacity: 0.8; } .mode-toggle { position: relative; width: 60px; height: 30px; background-color: rgba(125, 125, 125, 0.2); border-radius: 15px; cursor: pointer; display: flex; align-items: center; padding: 0 4px; } .toggle-thumb { position: absolute; width: 24px; height: 24px; border-radius: 50%; transition: transform var(--transition-speed), background-color var(--transition-speed); display: flex; justify-content: center; align-items: center; color: transparent; } .day-mode .toggle-thumb { transform: translateX(0); background-color: var(--day-accent); } .night-mode .toggle-thumb { transform: translateX(30px); background-color: var(--night-accent); } .main-content { flex: 1; padding: 32px; display: grid; grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; gap: 24px; transition: all var(--transition-speed); } .current-weather { display: flex; align-items: center; justify-content: space-between; } .temperature { font-size: 4.5rem; font-weight: 300; display: flex; align-items: start; } .degree { font-size: 2.5rem; margin-top: 8px; } .weather-icon { width: 100px; height: 100px; transition: all var(--transition-speed); } .weather-details { display: flex; gap: 24px; flex-wrap: wrap; } .detail-card { flex: 1; min-width: 120px; padding: 16px; border-radius: 16px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; transition: all var(--transition-speed); } .day-mode .detail-card { background-color: var(--day-secondary); } .night-mode .detail-card { background-color: var(--night-secondary); } .detail-icon { width: 24px; height: 24px; opacity: 0.8; } .detail-value { font-size: 1.5rem; font-weight: 600; } .detail-label { font-size: 0.9rem; opacity: 0.7; } .forecast { margin-top: 16px; } .section-title { font-size: 1.2rem; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; } .forecast-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 16px; } .forecast-card { padding: 16px; border-radius: 16px; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; transition: all var(--transition-speed); } .day-mode .forecast-card { background-color: var(--day-secondary); } .night-mode .forecast-card { background-color: var(--night-secondary); } .forecast-day { font-size: 0.9rem; font-weight: 600; } .forecast-icon { width: 42px; height: 42px; margin: 8px 0; } .forecast-temp { font-size: 1.2rem; font-weight: 600; } .alert-section { margin-top: 24px; overflow: hidden; border-radius: 16px; transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out; } .alert-header { padding: 16px; display: flex; justify-content: space-between; align-items: center; cursor: pointer; } .alert-content { padding: 0 16px 16px; font-size: 0.95rem; line-height: 1.5; } .alert-low { background-color: var(--alert-low); color: #4c4000; } .alert-medium { background-color: var(--alert-medium); color: #4c2000; } .alert-high { background-color: var(--alert-high); color: #4c0000; } .location-selector { display: flex; align-items: center; gap: 12px; margin-top: 24px; } .location-dropdown { flex: 1; padding: 12px 16px; border-radius: 12px; border: none; outline: none; font-size: 1rem; appearance: none; background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; background-size: 16px; transition: all var(--transition-speed); } .day-mode .location-dropdown { background-color: var(--day-secondary); color: var(--day-text); } .night-mode .location-dropdown { background-color: var(--night-secondary); color: var(--night-text); } .refresh-button { display: flex; justify-content: center; align-items: center; width: 42px; height: 42px; border-radius: 12px; border: none; cursor: pointer; transition: all var(--transition-speed); } .day-mode .refresh-button { background-color: var(--day-accent); color: white; } .night-mode .refresh-button { background-color: var(--night-accent); color: var(--night-primary); } .refresh-button:hover { transform: scale(1.05); } .refresh-button:active { transform: scale(0.95); } .refresh-icon { width: 20px; height: 20px; } .loading-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); display: flex; justify-content: center; align-items: center; z-index: 100; opacity: 0; pointer-events: none; transition: opacity 0.3s ease; border-radius: 24px; } .loading-overlay.active { opacity: 1; pointer-events: all; } .loader { width: 48px; height: 48px; border: 5px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top-color: white; animation: spin 1s ease-in-out infinite; } @keyframes spin { to { transform: rotate(360deg); } } .animated-icon { animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.1); opacity: 0.8; } 100% { transform: scale(1); opacity: 1; } } /* Custom scrollbar */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background-color: rgba(125, 125, 125, 0.5); border-radius: 20px; } /* Weather condition visual effects */ .weather-condition-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 5; border-radius: 24px; overflow: hidden; } /* Rain effect */ .rain-drop { position: absolute; width: 2px; background: linear-gradient(transparent, rgba(255, 255, 255, 0.7)); border-radius: 50%; animation: rain-fall linear infinite; } @keyframes rain-fall { to { transform: translateY(120vh); } } /* Snow effect */ .snow-flake { position: absolute; opacity: 0.8; border-radius: 50%; background-color: white; animation: snow-fall linear infinite; } @keyframes snow-fall { to { transform: translateY(120vh) rotate(360deg); } } /* City selector animation */ @keyframes highlight { 0% { box-shadow: 0 0 0 0 rgba(94, 129, 172, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(94, 129, 172, 0); } 100% { box-shadow: 0 0 0 0 rgba(94, 129, 172, 0); } } .highlight { animation: highlight 1.5s ease-out; } /* Responsive design for smaller screens */ @media (max-width: 600px) { .container { height: auto; min-height: 600px; } .header { padding: 20px; } .city-name { font-size: 2rem; } .main-content { padding: 20px; } .temperature { font-size: 3.5rem; } .degree { font-size: 2rem; } .weather-details { gap: 12px; } .detail-card { min-width: calc(50% - 6px); padding: 12px; } .forecast-grid { grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); gap: 12px; } .forecast-card { padding: 12px; } } </style> </head> <body> <div class="container day-mode"> <div class="weather-condition-overlay"></div> <div class="loading-overlay"> <div class="loader"></div> </div> <div class="header"> <div class="city-info"> <h1 class="city-name">San Francisco</h1> <p class="date-time">Monday, 10:30 AM</p> </div> <div class="mode-toggle"> <div class="toggle-thumb"> <svg class="mode-icon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor"> <path d="M12 2.25a.75.75 0 01.75.75v2.25a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.591 1.59a.75.75 0 101.06 1.061l1.591-1.59zM21.75 12a.75.75 0 01-.75.75h-2.25a.75.75 0 010-1.5H21a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 10-1.061 1.06l1.59 1.591zM12 18a.75.75 0 01.75.75V21a.75.75 0 01-1.5 0v-2.25A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.591 1.59a.75.75 0 001.06 1.061l1.591-1.59zM6 12a.75.75 0 01-.75.75H3a.75.75 0 010-1.5h2.25A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 00-1.061 1.06l1.59 1.591z"/> </svg> </div> </div> </div> <div class="main-content"> <div class="current-weather"> <div class="temperature"> 64<span class="degree">°F</span> </div> <div class="weather-condition"> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNWU4MWFjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9ImZlYXRoZXIgZmVhdGhlci1jbG91ZCI+PHBhdGggZD0iTTE4IDEwaC0xLjI2QTggOCAwIDEgMCA5IDIwaDlhNSA1IDAgMCAwIDAtMTB6Ij48L3BhdGg+PC9zdmc+" class="weather-icon" alt="Partly Cloudy"> <p>Partly Cloudy</p> </div> </div> <div class="weather-details"> <div class="detail-card"> <svg class="detail-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3"></path> </svg> <div class="detail-value">74%</div> <div class="detail-label">Humidity</div> </div> <div class="detail-card"> <svg class="detail-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M11 1L1 11m0 0l10 10m-10-10h22"></path> </svg> <div class="detail-value">12mph</div> <div class="detail-label">Wind</div> </div> <div class="detail-card"> <svg class="detail-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <path d="M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72l1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"></path> </svg> <div class="detail-value">6</div> <div class="detail-label">UV Index</div> </div> </div> <div class="forecast"> <h2 class="section-title"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="12" y1="2" x2="12" y2="6"></line> <line x1="12" y1="18" x2="12" y2="22"></line> <line x1="4.93" y1="4.93" x2="7.76" y2="7.76"></line> <line x1="16.24" y1="16.24" x2="19.07" y2="19.07"></line> <line x1="2" y1="12" x2="6" y2="12"></line> <line x1="18" y1="12" x2="22" y2="12"></line> <line x1="4.93" y1="19.07" x2="7.76" y2="16.24"></line> <line x1="16.24" y1="7.76" x2="19.07" y2="4.93"></line> </svg> 5-Day Forecast </h2> <div class="forecast-grid"> <div class="forecast-card"> <div class="forecast-day">Tue</div> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNWU4MWFjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9ImZlYXRoZXIgZmVhdGhlci1zdW4iPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjUiPjwvY2lyY2xlPjxsaW5lIHgxPSIxMiIgeTE9IjEiIHgyPSIxMiIgeTI9IjMiPjwvbGluZT48bGluZSB4MT0iMTIiIHkxPSIyMSIgeDI9IjEyIiB5Mj0iMjMiPjwvbGluZT48bGluZSB4MT0iNC4yMiIgeTE9IjQuMjIiIHgyPSI1LjY0IiB5Mj0iNS42NCI+PC9saW5lPjxsaW5lIHgxPSIxOC4zNiIgeTE9IjE4LjM2IiB4Mj0iMTkuNzgiIHkyPSIxOS43OCI+PC9saW5lPjxsaW5lIHgxPSIxIiB5MT0iMTIiIHgyPSIzIiB5Mj0iMTIiPjwvbGluZT48bGluZSB4MT0iMjEiIHkxPSIxMiIgeDI9IjIzIiB5Mj0iMTIiPjwvbGluZT48bGluZSB4MT0iNC4yMiIgeTE9IjE5Ljc4IiB4Mj0iNS42NCIgeTI9IjE4LjM2Ij48L2xpbmU+PGxpbmUgeDE9IjE4LjM2IiB5MT0iNS42NCIgeDI9IjE5Ljc4IiB5Mj0iNC4yMiI+PC9saW5lPjwvc3ZnPg==" alt="Sunny" class="forecast-icon"> <div class="forecast-temp">68°</div> </div> <div class="forecast-card"> <div class="forecast-day">Wed</div> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNWU4MWFjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9ImZlYXRoZXIgZmVhdGhlci1jbG91ZC1yYWluIj48bGluZSB4MT0iMTYiIHkxPSIxMyIgeDI9IjE2IiB5Mj0iMjEiPjwvbGluZT48bGluZSB4MT0iOCIgeTE9IjEzIiB4Mj0iOCIgeTI9IjIxIj48L2xpbmU+PGxpbmUgeDE9IjEyIiB5MT0iMTUiIHgyPSIxMiIgeTI9IjIzIj48L2xpbmU+PHBhdGggZD0iTTIwIDE2LjU4QTUgNSAwIDAgMCAxOCA3aC0xLjI2QTggOCAwIDEgMCA0IDE1LjI1Ij48L3BhdGg+PC9zdmc+" alt="Rainy" class="forecast-icon"> <div class="forecast-temp">59°</div> </div> <div class="forecast-card"> <div class="forecast-day">Thu</div> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNWU4MWFjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9ImZlYXRoZXIgZmVhdGhlci1jbG91ZC1kcml6emxlIj48bGluZSB4MT0iOCIgeTE9IjE5IiB4Mj0iOCIgeTI9IjIxIj48L2xpbmU+PGxpbmUgeDE9IjgiIHkxPSIxMyIgeDI9IjgiIHkyPSIxNSI+PC9saW5lPjxsaW5lIHgxPSIxNiIgeTE9IjE5IiB4Mj0iMTYiIHkyPSIyMSI+PC9saW5lPjxsaW5lIHgxPSIxNiIgeTE9IjEzIiB4Mj0iMTYiIHkyPSIxNSI+PC9saW5lPjxsaW5lIHgxPSIxMiIgeTE9IjIxIiB4Mj0iMTIiIHkyPSIyMyI+PC9saW5lPjxsaW5lIHgxPSIxMiIgeTE9IjE1IiB4Mj0iMTIiIHkyPSIxNyI+PC9saW5lPjxwYXRoIGQ9Ik0yMCAxNi41OEE1IDUgMCAwIDAgMTggN2gtMS4yNkE4IDggMCAxIDAgNCAxNS4yNSI+PC9wYXRoPjwvc3ZnPg==" alt="Drizzle" class="forecast-icon"> <div class="forecast-temp">61°</div> </div> <div class="forecast-card"> <div class="forecast-day">Fri</div> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNWU4MWFjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9ImZlYXRoZXIgZmVhdGhlci1jbG91ZCI+PHBhdGggZD0iTTE4IDEwaC0xLjI2QTggOCAwIDEgMCA5IDIwaDlhNSA1IDAgMCAwIDAtMTB6Ij48L3BhdGg+PC9zdmc+" alt="Cloudy" class="forecast-icon"> <div class="forecast-temp">63°</div> </div> <div class="forecast-card"> <div class="forecast-day">Sat</div> <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNWU4MWFjIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgY2xhc3M9ImZlYXRoZXIgZmVhdGhlci1zdW4iPjxjaXJjbGUgY3g9IjEyIiBjeT0iMTIiIHI9IjUiPjwvY2lyY2xlPjxsaW5lIHgxPSIxMiIgeTE9IjEiIHgyPSIxMiIgeTI9IjMiPjwvbGluZT48bGluZSB4MT0iMTIiIHkxPSIyMSIgeDI9IjEyIiB5Mj0iMjMiPjwvbGluZT48bGluZSB4MT0iNC4yMiIgeTE9IjQuMjIiIHgyPSI1LjY0IiB5Mj0iNS42NCI+PC9saW5lPjxsaW5lIHgxPSIxOC4zNiIgeTE9IjE4LjM2IiB4Mj0iMTkuNzgiIHkyPSIxOS43OCI+PC9saW5lPjxsaW5lIHgxPSIxIiB5MT0iMTIiIHgyPSIzIiB5Mj0iMTIiPjwvbGluZT48bGluZSB4MT0iMjEiIHkxPSIxMiIgeDI9IjIzIiB5Mj0iMTIiPjwvbGluZT48bGluZSB4MT0iNC4yMiIgeTE9IjE5Ljc4IiB4Mj0iNS42NCIgeTI9IjE4LjM2Ij48L2xpbmU+PGxpbmUgeDE9IjE4LjM2IiB5MT0iNS42NCIgeDI9IjE5Ljc4IiB5Mj0iNC4yMiI+PC9saW5lPjwvc3ZnPg==" alt="Sunny" class="forecast-icon"> <div class="forecast-temp">67°</div> </div> </div> </div> <div class="alert-section alert-medium"> <div class="alert-header"> <strong>ALERT: Flash Flood Watch</strong> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="6 9 12 15 18 9"></polyline> </svg> </div> <div class="alert-content"> A flash flood watch is in effect from Wednesday, 6 AM through Thursday, 11 PM for the Bay Area. Heavy rainfall of 2-4 inches expected. Allow extra time for your commute and avoid areas prone to flooding. </div> </div> <div class="location-selector"> <select class="location-dropdown"> <option value="sf">San Francisco</option> <option value="nyc">New York City</option> <option value="chicago">Chicago</option> <option value="la">Los Angeles</option> <option value="seattle">Seattle</option> </select> <button class="refresh-button"> <svg class="refresh-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M23 4v6h-6"></path> <path d="M1 20v-6h6"></path> <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10"></path> <path d="M20.49 15a9 9 0 0 1-14.85 3.36L1 14"></path> </svg> </button> </div> </div> </div> <script> // DOM elements const container = document.querySelector('.container'); const toggleBtn = document.querySelector('.mode-toggle'); const dateTimeEl = document.querySelector('.date-time'); const cityNameEl = document.querySelector('.city-name'); const temperatureEl = document.querySelector('.temperature'); const weatherIconEl = document.querySelector('.weather-icon'); const weatherConditionEl = document.querySelector('.weather-condition p'); const weatherConditionOverlay = document.querySelector('.weather-condition-overlay'); const alertSection = document.querySelector('.alert-section'); const alertHeader = document.querySelector('.alert-header'); const alertContent = document.querySelector('.alert-content'); const locationDropdown = document.querySelector('.location-dropdown'); const refreshButton = document.querySelector('.refresh-button');
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Smart Home Weather Widget</title> <style> :root { --primary-color: #8ab6d6; --secondary-color: #f0dab1; --tertiary-color: #e2c2c6; --quaternary-color: #b5d8cc; --text-color: #2c3e50; --shadow-color: rgba(0, 0, 0, 0.1); --bg-color: #f9f9fb; --card-color: #ffffff; --slider-track: #e0e0e0; --slider-fill: var(--primary-color); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--bg-color); display: flex; align-items: center; justify-content: center; min-height: 100vh; color: var(--text-color); padding: 20px; overflow: hidden; } .container { width: 100%; max-width: 680px; height: 680px; background-color: var(--card-color); border-radius: 24px; box-shadow: 0 10px 30px var(--shadow-color); padding: 24px; display: flex; flex-direction: column; overflow: hidden; position: relative; transition: all 0.3s ease; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .time-display { font-size: 1.6rem; font-weight: 500; transition: all 0.3s ease; } .date-display { font-size: 0.9rem; opacity: 0.8; } .profile { display: flex; align-items: center; gap: 10px; } .profile-avatar { width: 40px; height: 40px; border-radius: 50%; background-color: var(--tertiary-color); display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 1.2rem; color: white; box-shadow: 0 4px 6px var(--shadow-color); } .main-content { display: flex; flex-direction: column; gap: 20px; flex: 1; } .weather-section { display: flex; flex-direction: column; gap: 20px; padding: 24px; background: linear-gradient(to right, var(--primary-color), var(--quaternary-color)); border-radius: 16px; color: white; box-shadow: 0 6px 12px var(--shadow-color); transition: transform 0.3s ease, box-shadow 0.3s ease; overflow: hidden; position: relative; } .weather-section:hover { transform: translateY(-5px); box-shadow: 0 12px 20px var(--shadow-color); } .weather-bubbles { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; z-index: 0; overflow: hidden; } .bubble { position: absolute; background-color: rgba(255, 255, 255, 0.2); border-radius: 50%; animation: float 8s infinite ease-in-out; } @keyframes float { 0%, 100% { transform: translateY(0) translateX(0); } 50% { transform: translateY(-20px) translateX(10px); } } .weather-header { display: flex; justify-content: space-between; z-index: 1; } .temperature { font-size: 3.5rem; font-weight: 300; z-index: 1; } .temp-details { display: flex; gap: 24px; z-index: 1; } .weather-detail { display: flex; flex-direction: column; align-items: center; gap: 8px; } .weather-detail i { font-size: 1.5rem; margin-bottom: 5px; } .weather-detail-value { font-size: 1.2rem; font-weight: 500; } .weather-detail-label { font-size: 0.8rem; opacity: 0.8; } .smart-controls { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin-top: 10px; } .control-card { background-color: var(--card-color); border-radius: 16px; padding: 20px; box-shadow: 0 4px 8px var(--shadow-color); display: flex; flex-direction: column; gap: 15px; transition: all 0.3s ease; cursor: pointer; position: relative; overflow: hidden; } .control-card:hover { transform: translateY(-5px); box-shadow: 0 8px 16px var(--shadow-color); } .control-card.active { border: 2px solid var(--primary-color); } .control-header { display: flex; justify-content: space-between; align-items: center; } .control-title { font-weight: 500; font-size: 1.1rem; transition: color 0.3s ease; } .control-card:hover .control-title { color: var(--primary-color); } .control-icon { width: 40px; height: 40px; border-radius: 50%; background-color: var(--quaternary-color); display: flex; align-items: center; justify-content: center; transition: all 0.3s ease; } .control-card:hover .control-icon { background-color: var(--primary-color); transform: scale(1.1); } .control-icon i { font-size: 1.3rem; color: white; } .control-value { font-size: 2rem; font-weight: 300; } .control-slider { -webkit-appearance: none; width: 100%; height: 6px; border-radius: 5px; background: var(--slider-track); outline: none; position: relative; } .control-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 20px; height: 20px; border-radius: 50%; background: var(--primary-color); cursor: pointer; transition: all 0.2s ease; box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); } .control-slider::-webkit-slider-thumb:hover { transform: scale(1.2); } .control-slider-fill { position: absolute; height: 6px; border-radius: 5px; background: var(--slider-fill); pointer-events: none; } .scenes-section { margin-top: 5px; } .section-title { font-size: 1.2rem; font-weight: 500; margin-bottom: 15px; } .scene-tabs { display: flex; gap: 10px; margin-bottom: 20px; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 5px; } .scene-tabs::-webkit-scrollbar { display: none; } .scene-tab { padding: 10px 18px; border-radius: 30px; font-size: 0.9rem; background-color: #f0f0f0; transition: all 0.3s ease; white-space: nowrap; cursor: pointer; } .scene-tab.active { background-color: var(--primary-color); color: white; box-shadow: 0 4px 8px var(--shadow-color); } .weather-forecast { display: flex; gap: 15px; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; padding: 10px 0; } .weather-forecast::-webkit-scrollbar { display: none; } .forecast-item { display: flex; flex-direction: column; align-items: center; min-width: 80px; padding: 15px 10px; border-radius: 16px; background-color: var(--card-color); box-shadow: 0 4px 8px var(--shadow-color); transition: all 0.3s ease; } .forecast-item:hover { transform: translateY(-5px); box-shadow: 0 8px 16px var(--shadow-color); } .forecast-day { font-size: 0.8rem; opacity: 0.7; margin-bottom: 8px; } .forecast-icon { font-size: 1.5rem; margin-bottom: 8px; color: var(--primary-color); } .forecast-temp { font-size: 1.1rem; font-weight: 500; } .mode-toggle { position: absolute; bottom: 24px; right: 24px; width: 60px; height: 30px; background-color: var(--card-color); border-radius: 30px; display: flex; align-items: center; padding: 5px; box-shadow: 0 4px 8px var(--shadow-color); cursor: pointer; z-index: 10; } .toggle-thumb { width: 22px; height: 22px; background-color: var(--primary-color); border-radius: 50%; transition: transform 0.3s ease; } .toggle-thumb.night { transform: translateX(30px); background-color: #34495e; } .mode-toggle i { position: absolute; font-size: 0.8rem; transition: opacity 0.3s ease; } .mode-toggle .sun-icon { left: 10px; opacity: 1; } .mode-toggle .moon-icon { right: 10px; opacity: 0.5; } .night-mode .mode-toggle .sun-icon { opacity: 0.5; } .night-mode .mode-toggle .moon-icon { opacity: 1; } .night-mode { --bg-color: #1a1a2e; --card-color: #16213e; --text-color: #e1e1e1; --shadow-color: rgba(0, 0, 0, 0.3); --primary-color: #4a6fa5; --slider-track: #2c2c44; } .gesture-hint { position: absolute; bottom: 24px; left: 24px; font-size: 0.8rem; opacity: 0.7; display: flex; align-items: center; gap: 5px; padding: 8px 15px; background-color: rgba(255, 255, 255, 0.1); border-radius: 20px; backdrop-filter: blur(5px); box-shadow: 0 4px 6px var(--shadow-color); transition: all 0.3s ease; z-index: 5; } .gesture-hint:hover { opacity: 1; transform: translateY(-5px); } .voice-control { position: absolute; top: 24px; right: 24px; width: 40px; height: 40px; border-radius: 50%; background-color: var(--primary-color); display: flex; align-items: center; justify-content: center; color: white; cursor: pointer; box-shadow: 0 4px 8px var(--shadow-color); transition: all 0.3s ease; z-index: 10; } .voice-control:hover { transform: scale(1.1); } .voice-waves { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 50%; pointer-events: none; } .wave { position: absolute; border: 2px solid rgba(255, 255, 255, 0.5); width: 100%; height: 100%; border-radius: 50%; opacity: 0; animation: wave 2s infinite ease-out; } .wave:nth-child(2) { animation-delay: 0.5s; } .wave:nth-child(3) { animation-delay: 1s; } @keyframes wave { 0% { transform: scale(1); opacity: 0.5; } 100% { transform: scale(2); opacity: 0; } } .voice-active .wave { animation-play-state: running; } .voice-inactive .wave { animation-play-state: paused; } @media (max-width: 600px) { .container { padding: 16px; border-radius: 20px; } .smart-controls { grid-template-columns: 1fr; } .time-display { font-size: 1.3rem; } .temperature { font-size: 2.8rem; } .temp-details { gap: 15px; } .weather-detail-value { font-size: 1rem; } .gesture-hint, .voice-control { display: none; } } /* Animation for notifications */ @keyframes notification { 0% { opacity: 0; transform: translateY(20px); } 10% { opacity: 1; transform: translateY(0); } 90% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-20px); } } .notification { position: absolute; bottom: 80px; left: 50%; transform: translateX(-50%); padding: 12px 20px; background-color: var(--primary-color); color: white; border-radius: 10px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); display: flex; align-items: center; gap: 10px; opacity: 0; pointer-events: none; z-index: 100; animation: notification 4s forwards; } .notification i { font-size: 1.2rem; } </style> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> </head> <body> <div class="container"> <div class="header"> <div class="time-info"> <div class="time-display" id="time">12:30 PM</div> <div class="date-display" id="date">Monday, May 15</div> </div> <div class="profile"> <div class="profile-avatar">J</div> </div> </div> <div class="main-content"> <div class="weather-section" id="weatherSection"> <div class="weather-bubbles" id="bubbles"></div> <div class="weather-header"> <div> <div>Currently Outside</div> <div class="temperature" id="outside-temp">23°C</div> <div>Partly Cloudy</div> </div> <div class="temp-details"> <div class="weather-detail"> <i class="fas fa-wind"></i> <div class="weather-detail-value">12 km/h</div> <div class="weather-detail-label">Wind</div> </div> <div class="weather-detail"> <i class="fas fa-tint"></i> <div class="weather-detail-value">45%</div> <div class="weather-detail-label">Humidity</div> </div> </div> </div> </div> <div class="smart-controls"> <div class="control-card" id="temperatureControl"> <div class="control-header"> <div class="control-title">Indoor Temperature</div> <div class="control-icon"> <i class="fas fa-thermometer-half"></i> </div> </div> <div class="control-value" id="indoor-temp">22°C</div> <div class="control-slider-container"> <div class="control-slider-fill" id="temp-slider-fill"></div> <input type="range" min="16" max="30" value="22" class="control-slider" id="temp-slider"> </div> </div> <div class="control-card" id="humidityControl"> <div class="control-header"> <div class="control-title">Indoor Humidity</div> <div class="control-icon"> <i class="fas fa-water"></i> </div> </div> <div class="control-value" id="indoor-humidity">40%</div> <div class="control-slider-container"> <div class="control-slider-fill" id="humidity-slider-fill"></div> <input type="range" min="30" max="70" value="40" class="control-slider" id="humidity-slider"> </div> </div> <div class="control-card" id="lightingControl"> <div class="control-header"> <div class="control-title">Lighting</div> <div class="control-icon"> <i class="fas fa-lightbulb"></i> </div> </div> <div class="control-value" id="lighting-value">60%</div> <div class="control-slider-container"> <div class="control-slider-fill" id="lighting-slider-fill"></div> <input type="range" min="0" max="100" value="60" class="control-slider" id="lighting-slider"> </div> </div> <div class="control-card" id="airQualityControl"> <div class="control-header"> <div class="control-title">Air Quality</div> <div class="control-icon"> <i class="fas fa-wind"></i> </div> </div> <div class="control-value" id="air-quality">Good</div> <div style="font-size: 0.9rem; opacity: 0.8;"> PM2.5: 10μg/m³ • CO₂: 450ppm </div> </div> </div> <div class="scenes-section"> <div class="section-title">Quick Scenes</div> <div class="scene-tabs"> <div class="scene-tab active">Comfort</div> <div class="scene-tab">Energy Saving</div> <div class="scene-tab">Night Mode</div> <div class="scene-tab">Away</div> <div class="scene-tab">Movie Night</div> </div> </div> <div class="forecast-section"> <div class="section-title">5-Day Forecast</div> <div class="weather-forecast"> <div class="forecast-item"> <div class="forecast-day">Tue</div> <i class="fas fa-sun forecast-icon"></i> <div class="forecast-temp">25°C</div> </div> <div class="forecast-item"> <div class="forecast-day">Wed</div> <i class="fas fa-cloud-sun forecast-icon"></i> <div class="forecast-temp">22°C</div> </div> <div class="forecast-item"> <div class="forecast-day">Thu</div> <i class="fas fa-cloud-rain forecast-icon"></i> <div class="forecast-temp">19°C</div> </div> <div class="forecast-item"> <div class="forecast-day">Fri</div> <i class="fas fa-cloud forecast-icon"></i> <div class="forecast-temp">20°C</div> </div> <div class="forecast-item"> <div class="forecast-day">Sat</div> <i class="fas fa-sun forecast-icon"></i> <div class="forecast-temp">24°C</div> </div> </div> </div> </div> <div class="mode-toggle" id="modeToggle"> <i class="fas fa-sun sun-icon"></i> <i class="fas fa-moon moon-icon"></i> <div class="toggle-thumb" id="toggleThumb"></div> </div> <div class="gesture-hint"> <i class="fas fa-hand-point-up"></i> <span>Swipe up for more controls</span> </div> <div class="voice-control voice-inactive" id="voiceControl"> <i class="fas fa-microphone"></i> <div class="voice-waves"> <div class="wave"></div> <div class="wave"></div> <div class="wave"></div> </div> </div> </div> <script> // Initialize the widget document.addEventListener('DOMContentLoaded', function() { // Update time and date updateDateTime(); setInterval(updateDateTime, 60000); // Create bubbles for weather section createBubbles(); // Initialize sliders initSliders(); // Set up event listeners setupEventListeners(); // Random temperature fluctuation for demo setInterval(simulateTemperatureChange, 10000); }); function updateDateTime() { const now = new Date(); const timeElem = document.getElementById('time'); const dateElem = document.getElementById('date'); const timeString = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); const dateOptions = { weekday: 'long', month: 'long', day: 'numeric' }; const dateString = now.toLocaleDateString([], dateOptions); timeElem.textContent = timeString; dateElem.textContent = dateString; } function createBubbles() { const bubblesContainer = document.getElementById('bubbles'); const bubbleCount = 8; for (let i = 0; i < bubbleCount; i++) { const bubble = document.createElement('div'); bubble.classList.add('bubble'); // Random size between 20px and 80px const size = Math.floor(Math.random() * 60) + 20; bubble.style.width = `${size}px`; bubble.style.height = `${size}px`; // Random position const left = Math.floor(Math.random() * 90) + 5; const top = Math.floor(Math.random() * 90) + 5; bubble.style.left = `${left}%`; bubble.style.top = `${top}%`; // Random animation duration and delay const duration = Math.floor(Math.random() * 6) + 6; const delay = Math.floor(Math.random() * 5); bubble.style.animationDuration = `${duration}s`; bubble.style.animationDelay = `${delay}s`; bubblesContainer.appendChild(bubble); } } function initSliders() { // Temperature slider const tempSlider = document.getElementById('temp-slider'); const tempSliderFill = document.getElementById('temp-slider-fill'); const indoorTemp = document.getElementById('indoor-temp'); tempSliderFill.style.width = `${(tempSlider.value - tempSlider.min) / (tempSlider.max - tempSlider.min) * 100}%`; tempSlider.addEventListener('input', function() { tempSliderFill.style.width = `${(this.value - this.min) / (this.max - this.min) * 100}%`; indoorTemp.textContent = `${this.value}°C`; }); // Humidity slider const humiditySlider = document.getElementById('humidity-slider'); const humiditySliderFill = document.getElementById('humidity-slider-fill'); const indoorHumidity = document.getElementById('indoor-humidity'); humiditySliderFill.style.width = `${(humiditySlider.value - humiditySlider.min) / (humiditySlider.max - humiditySlider.min) * 100}%`; humiditySlider.addEventListener('input', function() { humiditySliderFill.style.width = `${(this.value - this.min) / (this.max - this.min) * 100}%`; indoorHumidity.textContent = `${this.value}%`; }); // Lighting slider const lightingSlider = document.getElementById('lighting-slider'); const lightingSliderFill = document.getElementById('lighting-slider-fill'); const lightingValue = document.getElementById('lighting-value'); lightingSliderFill.style.width = `${(lightingSlider.value - lightingSlider.min) / (lightingSlider.max - lightingSlider.min) * 100}%`; lightingSlider.addEventListener('input', function() { lightingSliderFill.style.width = `${(this.value - this.min) / (this.max - this.min) * 100}%`; lightingValue.textContent = `${this.value}%`; }); } function setupEventListeners() { // Mode toggle (day/night) const modeToggle = document.getElementById('modeToggle'); const toggleThumb = document.getElementById('toggleThumb'); modeToggle.addEventListener('click', function() { document.body.classList.toggle('night-mode'); toggleThumb.classList.toggle('night'); // Show a notification when mode changes const mode = document.body.classList.contains('night-mode') ? 'Night' : 'Day'; showNotification(`${mode} mode activated`, 'fas fa-moon'); }); // Scene tabs const sceneTabs = document.querySelectorAll('.scene-tab'); sceneTabs.forEach(tab => { tab.addEventListener('click', function() { // Remove active class from all tabs sceneTabs.forEach(t => t.classList.remove('active')); // Add active class to clicked tab this.classList.add('active'); // Update settings based on scene applyScene(this.textContent); }); }); // Voice control const voiceControl = document.getElementById('voiceControl'); voiceControl.addEventListener('click', function() { this.classList.toggle('voice-inactive'); this.classList.toggle('voice-active'); if (this.classList.contains('voice-active')) { showNotification('Voice control activated', 'fas fa-microphone'); // Simulate voice command after 3 seconds setTimeout(() => { showNotification('Setting temperature to 22°C', 'fas fa-thermometer-half'); document.getElementById('temp-slider').value = 22; document.getElementById('indoor-temp').textContent = '22°C'; document.getElementById('temp-slider-fill').style.width = `${(22 - 16) / (30 - 16) * 100}%`; // Deactivate voice control after command this.classList.remove('voice-active'); this.classList.add('voice-inactive'); }, 3000); } else { showNotification('Voice control deactivated', 'fas fa-microphone-slash'); } }); // Weather section gesture const weatherSection = document.getElementById('weatherSection'); let touchStartY; weatherSection.addEventListener('touchstart', function(e) { touchStartY = e.touches[0].clientY; }); weatherSection.addEventListener('touchmove', function(e) { if (touchStartY && (touchStartY - e.touches[0].clientY > 50)) { showNotification('Detailed weather view opened', 'fas fa-cloud-sun'); touchStartY = null; } }); // Simulate clicks for desktop weatherSection.addEventListener('click', function() { showNotification('Weather updated just now', 'fas fa-sync'); }); } function applyScene(sceneName) { const tempSlider = document.getElementById('temp-slider'); const humiditySlider = document.getElementById('humidity-slider'); const lightingSlider = document.getElementById('lighting-slider'); // Values for different scenes const sceneSettings = { 'Comfort': { temp: 23, humidity: 45, lighting: 70 }, 'Energy Saving': { temp: 20, humidity: 40, lighting: 40 }, 'Night Mode': { temp: 19, humidity: 45, lighting: 10 }, 'Away': { temp: 17, humidity: 35, lighting: 0 }, 'Movie Night': { temp: 22, humidity: 40, lighting: 20 } }; // Apply settings if scene exists if (sceneSettings[sceneName]) { const settings = sceneSettings[sceneName]; // Temperature tempSlider.value = settings.temp; document.getElementById('temp-slider-fill').style.width = `${(settings.temp - tempSlider.min) / (tempSlider.max - tempSlider.min) * 100}%`; document.getElementById('indoor-temp').textContent = `${settings.temp}°C`; // Humidity humiditySlider.value = settings.humidity; document.getElementById('humidity-slider-fill').style.width = `${(settings.humidity - humiditySlider.min) / (humiditySlider.max - humiditySlider.min) * 100}%`; document.getElementById('indoor-humidity').textContent = `${settings.humidity}%`; // Lighting lightingSlider.value = settings.lighting; document.getElementById('lighting-slider-fill').style.width = `${(settings.lighting - lightingSlider.min) / (lightingSlider.max - lightingSlider.min) * 100}%`; document.getElementById('lighting-value').textContent = `${settings.lighting}%`; showNotification(`${sceneName} scene activated`, 'fas fa-magic'); // If night mode scene, also toggle the theme if (sceneName === 'Night Mode' && !document.body.classList.contains('night-mode')) { document.body.classList.add('night-mode'); document.getElementById('toggleThumb').classList.add('night'); } else if (sceneName !== 'Night Mode' && document.body.classList.contains('night-mode')) { document.body.classList.remove('night-mode'); document.getElementById('toggleThumb').classList.remove('night'); } } } function simulateTemperatureChange() { const outsideTemp = document.getElementById('outside-temp'); const currentTemp = parseInt(outsideTemp.textContent); // Random fluctuation of ±1°C const fluctuation = Math.random() > 0.5 ? 1 : -1; const newTemp = currentTemp + fluctuation; if (newTemp >= 18 && newTemp <= 28) { outsideTemp.textContent = `${newTemp}°C`; } } function showNotification(message, iconClass) { // Remove existing notification const existingNotification = document.querySelector('.notification'); if (existingNotification) { existingNotification.remove(); } // Create new notification const notification = document.createElement('div'); notification.classList.add('notification'); const icon = document.createElement('i'); icon.className = iconClass; const text = document.createElement('span'); text.textContent = message; notification.appendChild(icon); notification.appendChild(text); document.querySelector('.container').appendChild(notification); // Automatically remove after animation completes setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 4000); } </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Agricultural Forecast Widget</title> <style> :root { --soil-brown: #8B5A2B; --wheat: #F5DEB3; --foliage-green: #556B2F; --sky-blue: #87CEEB; --rain-blue: #4682B4; --clay: #B87333; --harvest-gold: #DAA520; --earthy-red: #A52A2A; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Roboto Slab', serif; } body { width: 100%; height: 100%; background-color: #f9f7f2; color: #333; display: flex; justify-content: center; align-items: center; overflow: hidden; } .container { width: 650px; height: 650px; background: linear-gradient(135deg, #f9f7f2, #e8e4d8); border-radius: 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); padding: 20px; position: relative; overflow: hidden; display: flex; flex-direction: column; } .container::before { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23bdb49b' fill-opacity='0.1' fill-rule='evenodd'/%3E%3C/svg%3E"); opacity: 0.5; z-index: 0; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; position: relative; z-index: 1; } .logo { display: flex; align-items: center; } .logo-icon { width: 40px; height: 40px; background-color: var(--foliage-green); border-radius: 8px; display: flex; justify-content: center; align-items: center; margin-right: 10px; color: white; font-size: 20px; } .logo-text h1 { font-size: 1.5rem; font-weight: 700; color: var(--soil-brown); margin: 0; } .logo-text p { font-size: 0.8rem; color: var(--earthy-red); opacity: 0.8; font-weight: 500; } .location-selector { position: relative; z-index: 2; } .location-btn { background: var(--foliage-green); color: white; border: none; padding: 8px 15px; border-radius: 8px; display: flex; align-items: center; cursor: pointer; font-weight: 600; font-size: 14px; transition: all 0.3s; box-shadow: 0 3px 8px rgba(85, 107, 47, 0.2); } .location-btn:hover { background: #465a25; transform: translateY(-2px); } .location-btn i { margin-right: 5px; } .current-weather { display: flex; justify-content: space-between; margin: 15px 0; background: rgba(255, 255, 255, 0.6); padding: 15px; border-radius: 15px; border-left: 5px solid var(--harvest-gold); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); position: relative; z-index: 1; } .weather-main { display: flex; flex-direction: column; } .weather-main h2 { font-size: 2.5rem; font-weight: 700; margin: 0; color: var(--soil-brown); } .weather-main p { color: var(--earthy-red); font-size: 1rem; margin-top: 5px; } .weather-icon { width: 80px; height: 80px; background: linear-gradient(135deg, var(--sky-blue), var(--rain-blue)); border-radius: 50%; display: flex; justify-content: center; align-items: center; font-size: 30px; color: white; margin-right: 20px; } .weather-details { display: flex; gap: 15px; margin-top: 5px; } .weather-detail { display: flex; align-items: center; color: var(--soil-brown); font-size: 0.9rem; } .weather-detail i { margin-right: 5px; color: var(--foliage-green); } .agricultural-insights { background: rgba(255, 255, 255, 0.6); border-radius: 15px; padding: 15px; margin: 15px 0; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); border-left: 5px solid var(--clay); position: relative; z-index: 1; } .insights-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .insights-header h3 { font-size: 1.2rem; color: var(--soil-brown); font-weight: 700; margin: 0; } .insights-toggle { display: flex; gap: 10px; } .toggle-btn { background: #f0ece3; border: 2px solid var(--foliage-green); color: var(--foliage-green); padding: 5px 12px; border-radius: 20px; font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: all 0.3s; } .toggle-btn.active { background: var(--foliage-green); color: white; } .insights-content { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-top: 15px; } .insight-card { background: white; border-radius: 12px; padding: 15px; text-align: center; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05); transition: transform 0.3s; cursor: pointer; } .insight-card:hover { transform: translateY(-5px); box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1); } .insight-icon { font-size: 24px; color: var(--foliage-green); margin-bottom: 8px; } .insight-value { font-size: 1.2rem; font-weight: 700; color: var(--soil-brown); margin-bottom: 5px; } .insight-label { font-size: 0.8rem; color: var(--earthy-red); } .forecast-section { flex: 1; display: flex; flex-direction: column; position: relative; z-index: 1; } .forecast-tabs { display: flex; gap: 10px; margin-bottom: 15px; } .forecast-tab { padding: 8px 15px; border: none; background: none; font-size: 1rem; font-weight: 600; color: var(--soil-brown); opacity: 0.5; cursor: pointer; border-bottom: 3px solid transparent; transition: all 0.3s; } .forecast-tab.active { opacity: 1; border-bottom: 3px solid var(--foliage-green); } .forecast-content { flex: 1; position: relative; } .daily-forecast, .weekly-forecast, .seasonal-forecast { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; visibility: hidden; transition: opacity 0.3s, visibility 0.3s; display: flex; flex-direction: column; } .forecast-content .active { opacity: 1; visibility: visible; } .hourly-forecast { display: flex; overflow-x: auto; scrollbar-width: thin; scrollbar-color: var(--foliage-green) #f0ece3; padding: 10px 0; } .hourly-forecast::-webkit-scrollbar { height: 6px; } .hourly-forecast::-webkit-scrollbar-track { background: #f0ece3; border-radius: 3px; } .hourly-forecast::-webkit-scrollbar-thumb { background-color: var(--foliage-green); border-radius: 3px; } .hour-card { min-width: 80px; background: white; border-radius: 10px; padding: 10px; margin-right: 10px; text-align: center; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.05); transition: transform 0.3s; } .hour-card:hover { transform: translateY(-3px); } .hour-time { font-size: 0.8rem; color: var(--earthy-red); margin-bottom: 5px; } .hour-temp { font-size: 1.1rem; font-weight: 700; color: var(--soil-brown); margin-bottom: 5px; } .hour-icon { font-size: 20px; color: var(--foliage-green); margin-bottom: 5px; } .hour-precip { font-size: 0.8rem; color: var(--rain-blue); display: flex; align-items: center; justify-content: center; } .hour-precip i { margin-right: 3px; font-size: 12px; } .rainfall-chart { flex: 1; margin-top: 20px; background: white; border-radius: 15px; padding: 15px; position: relative; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); } .chart-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .chart-header h3 { font-size: 1.1rem; color: var(--soil-brown); font-weight: 700; margin: 0; } .chart-legend { display: flex; align-items: center; gap: 15px; } .legend-item { display: flex; align-items: center; font-size: 0.8rem; color: var(--soil-brown); } .legend-color { width: 12px; height: 12px; border-radius: 50%; margin-right: 5px; } .legend-rainfall .legend-color { background: linear-gradient(135deg, var(--rain-blue), #36648B); } .legend-average .legend-color { background: linear-gradient(135deg, var(--harvest-gold), #B8860B); } .chart-container { width: 100%; height: 150px; position: relative; } .chart-bg { position: absolute; width: 100%; height: 100%; display: flex; } .chart-column { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; padding: 0 5px; } .chart-bar { width: 100%; background: linear-gradient(135deg, var(--rain-blue), #36648B); border-radius: 5px 5px 0 0; position: relative; transition: height 1s cubic-bezier(0.23, 1, 0.32, 1); } .chart-average { width: 90%; height: 3px; background: linear-gradient(135deg, var(--harvest-gold), #B8860B); position: absolute; left: 5%; transition: bottom 1s cubic-bezier(0.23, 1, 0.32, 1); } .chart-labels { display: flex; justify-content: space-between; margin-top: 10px; } .chart-label { flex: 1; text-align: center; font-size: 0.8rem; color: var(--soil-brown); } .weekly-forecast { display: flex; flex-direction: column; } .week-row { display: flex; margin-bottom: 10px; background: white; border-radius: 10px; padding: 10px; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.05); align-items: center; transition: transform 0.3s; cursor: pointer; } .week-row:hover { transform: translateX(5px); box-shadow: 0 5px 12px rgba(0, 0, 0, 0.1); } .week-day { width: 80px; font-weight: 600; color: var(--soil-brown); } .week-icon { width: 60px; text-align: center; font-size: 20px; color: var(--foliage-green); } .week-temp { flex: 1; display: flex; align-items: center; } .temp-range { position: relative; height: 6px; background: #f0ece3; border-radius: 3px; flex: 1; margin: 0 15px; } .temp-fill { position: absolute; height: 100%; background: linear-gradient(to right, var(--foliage-green), var(--harvest-gold)); border-radius: 3px; } .temp-min, .temp-max { font-size: 0.9rem; font-weight: 600; } .temp-min { color: var(--sky-blue); } .temp-max { color: var(--earthy-red); } .week-precip { width: 70px; text-align: right; color: var(--rain-blue); font-weight: 600; font-size: 0.9rem; } .seasonal-forecast { flex-direction: column; } .season-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .season-header h3 { font-size: 1.1rem; color: var(--soil-brown); font-weight: 700; margin: 0; } .season-selector { display: flex; gap: 10px; } .season-btn { padding: 5px 12px; border: 2px solid var(--foliage-green); background: none; color: var(--foliage-green); border-radius: 20px; font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: all 0.3s; } .season-btn.active { background: var(--foliage-green); color: white; } .season-chart { flex: 1; background: white; border-radius: 15px; padding: 15px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); position: relative; } .season-grid { width: 100%; height: 200px; position: relative; margin-top: 20px; } .grid-lines { position: absolute; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: space-between; } .grid-line { width: 100%; height: 1px; background: #f0ece3; position: relative; } .grid-label { position: absolute; left: -40px; font-size: 0.7rem; color: var(--soil-brown); opacity: 0.7; top: -7px; } .data-line { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; } .data-points { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; } .data-point { position: absolute; width: 10px; height: 10px; background: var(--foliage-green); border-radius: 50%; transform: translate(-50%, 50%); cursor: pointer; transition: all 0.3s; } .data-point:hover { transform: translate(-50%, 50%) scale(1.5); box-shadow: 0 0 0 3px rgba(85, 107, 47, 0.2); } .data-tooltip { position: absolute; background: white; border-radius: 5px; padding: 5px 10px; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); font-size: 0.8rem; transform: translateY(-100%); pointer-events: none; opacity: 0; transition: opacity 0.3s; white-space: nowrap; z-index: 10; } .data-point:hover .data-tooltip { opacity: 1; } .x-labels { display: flex; justify-content: space-between; margin-top: 10px; } .x-label { flex: 1; text-align: center; font-size: 0.8rem; color: var(--soil-brown); } .seasonal-notes { margin-top: 20px; background: rgba(255, 255, 255, 0.6); border-radius: 10px; padding: 12px; font-size: 0.9rem; color: var(--earthy-red); border-left: 3px solid var(--harvest-gold); } .seasonal-notes p { margin: 0; line-height: 1.5; } .seasonal-notes strong { color: var(--soil-brown); } .footer { display: flex; justify-content: space-between; align-items: center; margin-top: 20px; padding-top: 15px; border-top: 1px solid rgba(139, 90, 43, 0.1); font-size: 0.8rem; color: var(--soil-brown); position: relative; z-index: 1; } .footer-links { display: flex; gap: 15px; } .footer-link { color: var(--foliage-green); text-decoration: none; transition: opacity 0.3s; } .footer-link:hover { opacity: 0.8; } /* Responsive adjustments */ @media (max-width: 700px) { .container { width: 100%; height: 100%; border-radius: 0; padding: 15px; } .insights-content { grid-template-columns: repeat(2, 1fr); } .logo-text h1 { font-size: 1.2rem; } .weather-main h2 { font-size: 2rem; } .forecast-tabs { overflow-x: auto; padding-bottom: 5px; } .forecast-tab { font-size: 0.9rem; white-space: nowrap; } .week-day { width: 60px; } .week-icon { width: 40px; } .chart-header { flex-direction: column; align-items: flex-start; } .chart-legend { margin-top: 10px; } } /* Animation styles */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes raindrop { 0% { transform: translateY(-5px); opacity: 0; } 50% { opacity: 1; } 100% { transform: translateY(5px); opacity: 0; } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .rain-animation { position: absolute; width: 100%; height: 100%; top: 0; left: 0; pointer-events: none; z-index: 0; } .raindrop { position: absolute; width: 2px; height: 10px; background: var(--rain-blue); border-radius: 50%; opacity: 0; animation: raindrop 2s linear infinite; } .fadeIn { animation: fadeIn 0.5s forwards; } .pulse { animation: pulse 2s infinite; } </style> </head> <body> <div class="container"> <div class="header fadeIn" style="animation-delay: 0.1s;"> <div class="logo"> <div class="logo-icon"> <i class="fas fa-seedling"></i> </div> <div class="logo-text"> <h1>FarmCast</h1> <p>Agricultural Weather Insights</p> </div> </div> <div class="location-selector"> <button class="location-btn"> <i class="fas fa-map-marker-alt"></i> Davis, CA </button> </div> </div> <div class="current-weather fadeIn" style="animation-delay: 0.2s;"> <div class="weather-icon"> <i class="fas fa-sun"></i> </div> <div class="weather-main"> <h2>78°F</h2> <p>Clear Sky, Optimal for Field Work</p> <div class="weather-details"> <div class="weather-detail"> <i class="fas fa-wind"></i> <span>8 mph NW</span> </div> <div class="weather-detail"> <i class="fas fa-tint"></i> <span>45%</span> </div> <div class="weather-detail"> <i class="fas fa-thermometer-half"></i> <span>70° / 82°</span> </div> </div> </div> </div> <div class="agricultural-insights fadeIn" style="animation-delay: 0.3s;"> <div class="insights-header"> <h3>Agricultural Conditions</h3> <div class="insights-toggle"> <button class="toggle-btn active" data-toggle="today">Today</button> <button class="toggle-btn" data-toggle="week">Week</button> </div> </div> <div class="insights-content"> <div class="insight-card"> <div class="insight-icon"> <i class="fas fa-leaf"></i> </div> <div class="insight-value">Excellent</div> <div class="insight-label">Crop Growth</div> </div> <div class="insight-card"> <div class="insight-icon"> <i class="fas fa-tractor"></i> </div> <div class="insight-value">Favorable</div> <div class="insight-label">Field Workability</div> </div> <div class="insight-card"> <div class="insight-icon"> <i class="fas fa-bug"></i> </div> <div class="insight-value">Moderate</div> <div class="insight-label">Pest Risk</div> </div> <div class="insight-card"> <div class="insight-icon"> <i class="fas fa-shower"></i> </div> <div class="insight-value">1.2 in</div> <div class="insight-label">Weekly Precip</div> </div> <div class="insight-card"> <div class="insight-icon"> <i class="fas fa-sun"></i> </div> <div class="insight-value">8.5 hrs</div> <div class="insight-label">Daily Sunlight</div> </div> <div class="insight-card"> <div class="insight-icon"> <i class="fas fa-seedling"></i> </div> <div class="insight-value">78%</div> <div class="insight-label">Soil Moisture</div> </div> </div> </div> <div class="forecast-section fadeIn" style="animation-delay: 0.4s;"> <div class="forecast-tabs"> <button class="forecast-tab active" data-tab="daily">Daily Forecast</button> <button class="forecast-tab" data-tab="weekly">7-Day Outlook</button> <button class="forecast-tab" data-tab="seasonal">Seasonal Trends</button> </div> <div class="forecast-content"> <div class="daily-forecast active"> <div class="hourly-forecast"> <div class="hour-card"> <div class="hour-time">Now</div> <div class="hour-temp">78°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>0%</span> </div> </div> <div class="hour-card"> <div class="hour-time">11 AM</div> <div class="hour-temp">80°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>0%</span> </div> </div> <div class="hour-card"> <div class="hour-time">12 PM</div> <div class="hour-temp">82°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>0%</span> </div> </div> <div class="hour-card"> <div class="hour-time">1 PM</div> <div class="hour-temp">82°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>0%</span> </div> </div> <div class="hour-card"> <div class="hour-time">2 PM</div> <div class="hour-temp">81°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>0%</span> </div> </div> <div class="hour-card"> <div class="hour-time">3 PM</div> <div class="hour-temp">80°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>0%</span> </div> </div> <div class="hour-card"> <div class="hour-time">4 PM</div> <div class="hour-temp">78°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>0%</span> </div> </div> <div class="hour-card"> <div class="hour-time">5 PM</div> <div class="hour-temp">75°</div> <div class="hour-icon"> <i class="fas fa-sun"></i> </div> <div class="hour-precip"> <i class="fas fa-tint"></i> <span>5%</span> </div> </div> </div> <div class="rainfall-chart"> <div class="chart-header"> <h3>Precipitation Forecast</h3> <div class="chart-legend"> <div class="legend-item legend-rainfall"> <div class="legend-color"></div> <span>Rainfall</span> </div> <div class="legend-item legend-average"> <div class="legend-color"></div> <span>Historic Avg</span> </div> </div> </div> <div class="chart-container"> <div class="chart-bg"> <div class="chart-column"> <div class="chart-bar" style="height: 10%;"></div> </div> <div class="chart-column"> <div class="chart-
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Weather Explorer Learning Portal</title> <style> :root { --primary: #4c9aff; --secondary: #ffbf47; --success: #5bd75b; --info: #b37cff; --warning: #ff8f59; --danger: #ff6b6b; --light: #f8f9fa; --dark: #343a40; --cloud: #e9f0fb; --rain: #a4caed; --sun: #ffcf5c; --snow: #ffffff; --thunder: #9059ff; --wind: #c5e0f5; --border-radius: 18px; --box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); --transition: all 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Nunito', sans-serif; } body { background: linear-gradient(135deg, #f5f7fa 0%, #e4eff9 100%); height: 100vh; display: flex; justify-content: center; align-items: center; color: var(--dark); overflow: hidden; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; background-color: white; border-radius: var(--border-radius); box-shadow: var(--box-shadow); overflow: hidden; position: relative; padding: 1.5rem; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; position: relative; z-index: 10; } .title { font-size: 1.8rem; font-weight: 800; color: var(--primary); display: flex; align-items: center; gap: 0.5rem; } .title span { background: linear-gradient(135deg, var(--primary), var(--info)); -webkit-background-clip: text; background-clip: text; color: transparent; } .search-bar { position: relative; width: 100%; max-width: 300px; } .search-bar input { width: 100%; padding: 0.8rem 1rem 0.8rem 3rem; border: 2px solid #e0e6ed; border-radius: 50px; font-size: 0.9rem; transition: var(--transition); background-color: var(--light); } .search-bar input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(76, 154, 255, 0.2); } .search-icon { position: absolute; left: 1rem; top: 50%; transform: translateY(-50%); color: #a0a9b8; } .main-content { display: flex; flex-direction: column; flex-grow: 1; gap: 1.5rem; position: relative; z-index: 5; } .weather-display { display: flex; background: linear-gradient(to right, var(--primary), #70b3ff); border-radius: var(--border-radius); padding: 1.5rem; color: white; box-shadow: 0 8px 16px rgba(76, 154, 255, 0.2); position: relative; overflow: hidden; height: 180px; transition: var(--transition); } .weather-details { flex: 1; display: flex; flex-direction: column; justify-content: center; } .location { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.5rem; } .date { font-size: 0.9rem; opacity: 0.9; margin-bottom: 1rem; } .temperature { font-size: 3rem; font-weight: 800; position: relative; display: inline-block; } .temperature::after { content: "°C"; position: absolute; top: 8px; right: -25px; font-size: 1.2rem; font-weight: 400; } .condition { margin-top: 0.5rem; font-size: 1.1rem; } .weather-icon { display: flex; justify-content: center; align-items: center; width: 120px; height: 120px; position: relative; } .svg-container { position: absolute; width: 100%; height: 100%; } .weather-forecast { display: flex; gap: 1rem; margin-top: 0.5rem; overflow-x: auto; padding-bottom: 0.5rem; scroll-behavior: smooth; } .weather-forecast::-webkit-scrollbar { height: 6px; } .weather-forecast::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; } .weather-forecast::-webkit-scrollbar-thumb { background: var(--primary); border-radius: 10px; } .forecast-item { display: flex; flex-direction: column; align-items: center; min-width: 80px; padding: 1rem 0.5rem; background-color: white; border-radius: var(--border-radius); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); transition: var(--transition); cursor: pointer; } .forecast-item:hover { transform: translateY(-5px); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); } .forecast-day { font-size: 0.9rem; font-weight: 600; margin-bottom: 0.5rem; } .forecast-icon { margin-bottom: 0.5rem; width: 40px; height: 40px; } .forecast-temp { font-size: 1.1rem; font-weight: 700; } .learning-modules { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; margin-top: 0.5rem; } .module-card { background: white; border-radius: var(--border-radius); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); padding: 1.2rem; display: flex; flex-direction: column; transition: var(--transition); border-left: 4px solid var(--primary); cursor: pointer; position: relative; overflow: hidden; } .module-card:hover { transform: translateY(-5px); box-shadow: 0 8px 18px rgba(0, 0, 0, 0.1); } .module-card:nth-child(2) { border-left-color: var(--secondary); } .module-card:nth-child(3) { border-left-color: var(--success); } .module-card:nth-child(4) { border-left-color: var(--info); } .module-icon { margin-bottom: 1rem; width: 50px; height: 50px; border-radius: 12px; display: flex; align-items: center; justify-content: center; background-color: var(--cloud); color: var(--primary); } .module-card:nth-child(2) .module-icon { background-color: #fff8e6; color: var(--secondary); } .module-card:nth-child(3) .module-icon { background-color: #e9f9e9; color: var(--success); } .module-card:nth-child(4) .module-icon { background-color: #f4eeff; color: var(--info); } .module-title { font-size: 1rem; font-weight: 700; margin-bottom: 0.5rem; } .module-description { font-size: 0.85rem; color: #6c757d; margin-bottom: 1rem; flex-grow: 1; } .module-action { font-size: 0.85rem; color: var(--primary); font-weight: 600; display: flex; align-items: center; gap: 0.5rem; } .badge { position: absolute; top: 1rem; right: 1rem; background-color: #ffebed; color: var(--danger); font-size: 0.7rem; font-weight: 600; padding: 0.25rem 0.5rem; border-radius: 50px; } .weather-badges { display: flex; gap: 0.5rem; margin-top: 1rem; } .weather-badge { background-color: rgba(255, 255, 255, 0.2); border-radius: 50px; padding: 0.3rem 0.8rem; font-size: 0.8rem; display: flex; align-items: center; gap: 0.3rem; } .tooltip { position: relative; cursor: pointer; } .tooltip .tooltiptext { visibility: hidden; width: 200px; background-color: var(--dark); color: white; text-align: center; border-radius: 6px; padding: 0.5rem; position: absolute; z-index: 1; bottom: 125%; left: 50%; transform: translateX(-50%); opacity: 0; transition: opacity 0.3s; font-size: 0.8rem; } .tooltip .tooltiptext::after { content: ""; position: absolute; top: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: var(--dark) transparent transparent transparent; } .tooltip:hover .tooltiptext { visibility: visible; opacity: 1; } .feedback-circle { position: absolute; width: 30px; height: 30px; border-radius: 50%; background-color: var(--primary); color: white; display: flex; align-items: center; justify-content: center; bottom: 1.5rem; right: 1.5rem; cursor: pointer; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); transition: var(--transition); z-index: 20; font-size: 1rem; } .feedback-circle:hover { transform: scale(1.1); } .quiz-button { position: absolute; bottom: 1.5rem; left: 1.5rem; background-color: var(--secondary); color: white; border: none; border-radius: 50px; padding: 0.5rem 1rem; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 0.5rem; box-shadow: 0 4px 8px rgba(255, 191, 71, 0.3); transition: var(--transition); z-index: 20; } .quiz-button:hover { transform: translateY(-3px); box-shadow: 0 6px 12px rgba(255, 191, 71, 0.4); } .animated-bg { position: absolute; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; z-index: 1; opacity: 0.03; } .animated-bg svg { position: absolute; width: 100%; height: auto; } .loading-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(255, 255, 255, 0.9); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 100; } .loading-spinner { width: 50px; height: 50px; border-radius: 50%; border: 4px solid rgba(76, 154, 255, 0.1); border-top-color: var(--primary); animation: spin 1s infinite linear; margin-bottom: 1rem; } .loading-text { font-weight: 600; color: var(--primary); } @keyframes spin { to { transform: rotate(360deg); } } .quiz-modal { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; z-index: 50; opacity: 0; visibility: hidden; transition: all 0.3s ease; } .quiz-modal.active { opacity: 1; visibility: visible; } .quiz-content { background-color: white; border-radius: var(--border-radius); width: 90%; max-width: 500px; max-height: 90%; overflow-y: auto; padding: 2rem; position: relative; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); transform: translateY(20px); transition: all 0.3s ease; } .quiz-modal.active .quiz-content { transform: translateY(0); } .close-quiz { position: absolute; top: 1rem; right: 1rem; background: none; border: none; font-size: 1.5rem; cursor: pointer; color: #ccc; transition: var(--transition); } .close-quiz:hover { color: var(--danger); } .quiz-header { text-align: center; margin-bottom: 1.5rem; } .quiz-title { font-size: 1.5rem; color: var(--primary); margin-bottom: 0.5rem; } .quiz-subtitle { color: #6c757d; font-size: 0.9rem; } .quiz-question { margin-bottom: 1.5rem; } .question-text { font-weight: 600; margin-bottom: 1rem; } .quiz-options { display: flex; flex-direction: column; gap: 0.8rem; } .quiz-option { padding: 1rem; border: 2px solid #e9ecef; border-radius: 10px; cursor: pointer; transition: var(--transition); } .quiz-option:hover { border-color: var(--primary); background-color: rgba(76, 154, 255, 0.05); } .quiz-option.selected { border-color: var(--primary); background-color: rgba(76, 154, 255, 0.1); } .quiz-option.correct { border-color: var(--success); background-color: rgba(91, 215, 91, 0.1); } .quiz-option.incorrect { border-color: var(--danger); background-color: rgba(255, 107, 107, 0.1); } .quiz-feedback { margin-top: 1rem; padding: 1rem; border-radius: 10px; display: none; } .quiz-feedback.correct { background-color: rgba(91, 215, 91, 0.1); color: var(--success); display: block; } .quiz-feedback.incorrect { background-color: rgba(255, 107, 107, 0.1); color: var(--danger); display: block; } .quiz-nav { display: flex; justify-content: space-between; margin-top: 1.5rem; } .quiz-nav button { background-color: var(--primary); color: white; border: none; padding: 0.7rem 1.5rem; border-radius: 50px; cursor: pointer; font-weight: 600; transition: var(--transition); } .quiz-nav button:hover { background-color: #3a8aed; } .quiz-nav button:disabled { background-color: #ccc; cursor: not-allowed; } .quiz-progress { display: flex; justify-content: space-between; margin-bottom: 1.5rem; } .progress-bar { flex-grow: 1; height: 8px; background-color: #e9ecef; border-radius: 10px; margin: 0 1rem; position: relative; overflow: hidden; } .progress-bar-fill { height: 100%; background-color: var(--primary); border-radius: 10px; width: 25%; transition: width 0.3s ease; } .progress-text { font-size: 0.9rem; color: #6c757d; font-weight: 600; } @media (max-width: 600px) { .container { border-radius: 0; padding: 1rem; height: 100vh; } .header { flex-direction: column; align-items: flex-start; gap: 1rem; } .search-bar { max-width: 100%; } .weather-display { height: auto; padding: 1.2rem; } .learning-modules { grid-template-columns: 1fr; } .weather-forecast { gap: 0.5rem; } .forecast-item { min-width: 70px; padding: 0.8rem 0.3rem; } } /* Animation for clouds */ @keyframes float { 0% { transform: translateY(0); } 50% { transform: translateY(-10px); } 100% { transform: translateY(0); } } .cloud { animation: float 5s ease-in-out infinite; } .cloud:nth-child(2) { animation-delay: 1s; } .cloud:nth-child(3) { animation-delay: 2s; } .pulse { animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .svg-sun { animation: rotate 20s linear infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .svg-rain { animation: fall 1.5s linear infinite; } @keyframes fall { from { transform: translateY(-10px); opacity: 0; } 50% { opacity: 1; } to { transform: translateY(10px); opacity: 0; } } .celebration { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 100; display: none; } .confetti { position: absolute; width: 10px; height: 10px; background-color: #f00; border-radius: 10px; animation: fall-rotate 5s linear infinite; } @keyframes fall-rotate { 0% { transform: translateY(-100px) rotate(0deg); opacity: 1; } 100% { transform: translateY(1000px) rotate(720deg); opacity: 0; } } </style> </head> <body> <div class="container"> <div class="animated-bg"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"> <path fill="#4c9aff" fill-opacity="0.1" d="M0,288L48,272C96,256,192,224,288,197.3C384,171,480,149,576,165.3C672,181,768,235,864,250.7C960,267,1056,245,1152,208C1248,171,1344,117,1392,90.7L1440,64L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z"></path> </svg> </div> <div class="header"> <div class="title"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path> </svg> <span>Weather Explorer</span> </div> <div class="search-bar"> <svg class="search-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="11" cy="11" r="8"></circle> <line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> <input type="text" placeholder="Search for a location..." id="search-input"> </div> </div> <div class="main-content"> <div class="weather-display"> <div class="weather-details"> <div class="location">New York City</div> <div class="date">Tuesday, May 16</div> <div class="temperature">23</div> <div class="condition">Partly Cloudy</div> <div class="weather-badges"> <div class="weather-badge tooltip"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M12 16a4 4 0 1 0 0-8 4 4 0 0 0 0 8z"></path> <path d="M12 8V3"></path> <path d="M12 21v-3"></path> <path d="M3.6 9.6L6 12"></path> <path d="M18 12l2.4 2.4"></path> <path d="M3.6 14.4L6 12"></path> <path d="M18 12l2.4-2.4"></path> </svg> UV: 5 <span class="tooltiptext">UV Index indicates the risk of harm from unprotected sun exposure.</span> </div> <div class="weather-badge tooltip"> <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M12 22V2"></path> <path d="M5 12H2"></path> <path d="M22 12h-3"></path> <path d="M12 5V2"></path> <path d="M12 22v-3"></path> </svg> Humidity: 65% <span class="tooltiptext">Humidity is the amount of water vapor in the air.</span> </div> </div> </div> <div class="weather-icon"> <div class="svg-container"> <svg id="weather-svg" width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle class="svg-sun" cx="60" cy="45" r="25" fill="#FFCF5C" /> <path class="cloud" d="M95 70C95 59 86 50 75 50C64 50 55 59 55 70C55 70 55 70 55 70C55 70 35 70 35 70C29.5 70 25 74.5 25 80C25 85.5 29.5 90 35 90H95C100.5 90 105 85.5 105 80C105 74.5 100.5 70 95 70Z" fill="#E9F0FB" /> </svg> </div> </div> </div> <div class="weather-forecast" id="forecast-container"> <div class="forecast-item"> <div class="forecast-day">Wed</div> <img class="forecast-icon" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSIyMCIgY3k9IjE1IiByPSI4IiBmaWxsPSIjRkZDRjVDIi8+PHBhdGggZD0iTTI1IDI1QzI1IDIyIDIyIDIwIDE5IDIwQzE2IDIwIDEzIDIyIDEzIDI1QzEzIDI1IDEzIDI1IDEzIDI1QzEzIDI1IDkgMjUgOSAyNUM3LjUgMjUgNiAyNi41IDYgMjhDNiAyOS41IDcuNSAzMSA5IDMxSDI2QzI3LjUgMzEgMjkgMjkuNSAyOSAyOEMyOSAyNi41IDI3LjUgMjUgMjYgMjVIMjVaIiBmaWxsPSIjRTlGMEZCIi8+PC9zdmc+" alt="Weather icon"> <div class="forecast-temp">24°</div> </div> <div class="forecast-item"> <div class="forecast-day">Thu</div> <img class="forecast-icon" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSIyMCIgY3k9IjE1IiByPSI4IiBmaWxsPSIjRkZDRjVDIi8+PC9zdmc+" alt="Weather icon"> <div class="forecast-temp">26°</div> </div> <div class="forecast-item"> <div class="forecast-day">Fri</div> <img class="forecast-icon" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzAgMTlDMzAgMTQgMjYgMTAgMjEgMTBDMTYgMTAgMTIgMTQgMTIgMTlDMTIgMTkgMTIgMTkgMTIgMTlDMTIgMTkgNiAxOSA2IDE5QzMuNSAxOSAxIDIxLjUgMSAyNEMxIDI2LjUgMy41IDI5IDYgMjlIMzBDMzIuNSAyOSAzNSAyNi41IDM1IDI0QzM1IDIxLjUgMzIuNSAxOSAzMCAxOVoiIGZpbGw9IiNFOUYwRkIiLz48cGF0aCBkPSJNMTUgMjlMMTIgMzUiIHN0cm9rZT0iI0E0Q0FFRCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjEgMjlMMTggMzUiIHN0cm9rZT0iI0E0Q0FFRCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjcgMjlMMjQgMzUiIHN0cm9rZT0iI0E0Q0FFRCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48L3N2Zz4=" alt="Weather icon"> <div class="forecast-temp">21°</div> </div> <div class="forecast-item"> <div class="forecast-day">Sat</div> <img class="forecast-icon" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMzAgMTlDMzAgMTQgMjYgMTAgMjEgMTBDMTYgMTAgMTIgMTQgMTIgMTlDMTIgMTkgMTIgMTkgMTIgMTlDMTIgMTkgNiAxOSA2IDE5QzMuNSAxOSAxIDIxLjUgMSAyNEMxIDI2LjUgMy41IDI5IDYgMjlIMzBDMzIuNSAyOSAzNSAyNi41IDM1IDI0QzM1IDIxLjUgMzIuNSAxOSAzMCAxOVoiIGZpbGw9IiNFOUYwRkIiLz48L3N2Zz4=" alt="Weather icon"> <div class="forecast-temp">19°</div> </div> <div class="forecast-item"> <div class="forecast-day">Sun</div> <img class="forecast-icon" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48Y2lyY2xlIGN4PSIyMCIgY3k9IjIwIiByPSIxMCIgZmlsbD0iI0ZGQ0Y1QyIvPjxwYXRoIGQ9Ik0yMCA1VjEwIiBzdHJva2U9IiNGRkNGNUMiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTIwIDMwVjM1IiBzdHJva2U9IiNGRkNGNUMiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTM1IDIwSDMwIiBzdHJva2U9IiNGRkNGNUMiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTEwIDIwSDUiIHN0cm9rZT0iI0ZGQ0Y1QyIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMzAgMTBMMjYgMTQiIHN0cm9rZT0iI0ZGQ0Y1QyIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMTQgMjZMMTAgMzAiIHN0cm9rZT0iI0ZGQ0Y1QyIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWN
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Enterprise Dashboard Widget</title> <style> :root { --primary: #2563eb; --primary-light: #3b82f6; --primary-dark: #1d4ed8; --success: #10b981; --warning: #f59e0b; --danger: #ef4444; --neutral: #64748b; --neutral-light: #94a3b8; --neutral-dark: #475569; --bg-main: #f8fafc; --bg-card: #ffffff; --text-main: #1e293b; --text-secondary: #64748b; --border: #e2e8f0; --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); --radius: 8px; } [data-theme="dark"] { --primary: #3b82f6; --primary-light: #60a5fa; --primary-dark: #2563eb; --success: #10b981; --warning: #f59e0b; --danger: #ef4444; --neutral: #94a3b8; --neutral-light: #cbd5e1; --neutral-dark: #64748b; --bg-main: #0f172a; --bg-card: #1e293b; --text-main: #f1f5f9; --text-secondary: #cbd5e1; --border: #334155; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', sans-serif; } body { background-color: var(--bg-main); color: var(--text-main); transition: all 0.3s ease; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; padding: 15px; } .dashboard-widget { width: 100%; max-width: 700px; height: 700px; background-color: var(--bg-card); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; display: grid; grid-template-rows: auto 1fr; position: relative; } .widget-header { padding: 1.25rem; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; } .header-title { font-weight: 600; font-size: 1.25rem; display: flex; align-items: center; } .header-title svg { margin-right: 8px; color: var(--primary); } .header-controls { display: flex; gap: 12px; } .header-controls button { background: none; border: none; cursor: pointer; color: var(--neutral); display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; padding: 6px; border-radius: 4px; } .header-controls button:hover { color: var(--primary); background-color: rgba(59, 130, 246, 0.1); } .widget-content { padding: 1.25rem; display: grid; grid-template-rows: auto 1fr; gap: 1.25rem; overflow: hidden; } .status-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; } .status-card { background-color: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem; display: flex; flex-direction: column; transition: all 0.3s ease; position: relative; overflow: hidden; } .status-card:hover { box-shadow: var(--shadow); transform: translateY(-2px); border-color: var(--primary-light); } .card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.75rem; } .card-icon { display: flex; align-items: center; justify-content: center; border-radius: 50%; width: 2.5rem; height: 2.5rem; background-color: rgba(59, 130, 246, 0.1); color: var(--primary); } .status-indicator { width: 10px; height: 10px; border-radius: 50%; background-color: var(--success); } .critical .status-indicator { background-color: var(--danger); } .warning .status-indicator { background-color: var(--warning); } .card-value { font-size: 1.5rem; font-weight: 700; margin-bottom: 0.25rem; } .card-label { font-size: 0.875rem; color: var(--text-secondary); } .card-metric { display: flex; align-items: center; font-size: 0.75rem; font-weight: 500; margin-top: 0.5rem; } .metric-positive { color: var(--success); } .metric-negative { color: var(--danger); } .status-card.critical { border-left: 3px solid var(--danger); } .status-card.critical .card-icon { background-color: rgba(239, 68, 68, 0.1); color: var(--danger); } .status-card.warning { border-left: 3px solid var(--warning); } .status-card.warning .card-icon { background-color: rgba(245, 158, 11, 0.1); color: var(--warning); } .detail-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; overflow: hidden; } .detail-panel { background-color: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.25rem; display: flex; flex-direction: column; overflow: hidden; position: relative; } .panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; } .panel-title { font-weight: 600; font-size: 1rem; display: flex; align-items: center; } .panel-title svg { margin-right: 8px; color: var(--primary); } .panel-controls { display: flex; gap: 8px; } .panel-controls button { background: none; border: none; cursor: pointer; color: var(--neutral); display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; padding: 4px; border-radius: 4px; } .panel-controls button:hover { color: var(--primary); background-color: rgba(59, 130, 246, 0.1); } .alerts-list { overflow-y: auto; max-height: 100%; display: flex; flex-direction: column; gap: 0.75rem; } .alert-item { display: flex; padding: 0.875rem; border-radius: var(--radius); border: 1px solid var(--border); background-color: var(--bg-card); transition: all 0.3s ease; cursor: pointer; position: relative; overflow: hidden; } .alert-item:hover { border-color: var(--primary-light); box-shadow: var(--shadow); } .alert-item.critical { border-left: 3px solid var(--danger); } .alert-item.warning { border-left: 3px solid var(--warning); } .alert-item.info { border-left: 3px solid var(--primary); } .alert-icon { margin-right: 12px; display: flex; align-items: flex-start; } .alert-icon svg { width: 1.25rem; height: 1.25rem; } .alert-item.critical .alert-icon { color: var(--danger); } .alert-item.warning .alert-icon { color: var(--warning); } .alert-item.info .alert-icon { color: var(--primary); } .alert-content { flex: 1; } .alert-title { font-weight: 500; margin-bottom: 4px; font-size: 0.9375rem; } .alert-message { color: var(--text-secondary); font-size: 0.8125rem; line-height: 1.4; } .alert-meta { font-size: 0.75rem; color: var(--neutral); margin-top: 6px; display: flex; align-items: center; } .alert-meta svg { width: 0.75rem; height: 0.75rem; margin-right: 4px; } .forecasts { overflow-y: auto; max-height: 100%; display: flex; flex-direction: column; gap: 1rem; } .forecast-chart { flex: 1; min-height: 180px; position: relative; margin-top: 0.5rem; } .chart-container { position: relative; width: 100%; height: 100%; } .forecast-segments { display: flex; gap: 1rem; margin-top: 0.75rem; } .forecast-segment { flex: 1; padding: 0.75rem; border-radius: var(--radius); border: 1px solid var(--border); background-color: var(--bg-card); display: flex; flex-direction: column; align-items: flex-start; transition: all 0.3s ease; } .forecast-segment:hover { border-color: var(--primary-light); box-shadow: var(--shadow); } .segment-label { font-size: 0.75rem; color: var(--text-secondary); margin-bottom: 4px; } .segment-value { font-weight: 600; font-size: 1.125rem; } .segment-growth { font-size: 0.75rem; display: flex; align-items: center; margin-top: 4px; } .segment-growth.positive { color: var(--success); } .segment-growth.negative { color: var(--danger); } .segment-growth svg { width: 0.875rem; height: 0.875rem; margin-right: 4px; } /* Tooltip */ .tooltip { position: absolute; background-color: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 0.75rem; box-shadow: var(--shadow-lg); max-width: 250px; z-index: 100; opacity: 0; visibility: hidden; transition: opacity 0.2s ease, visibility 0.2s ease; } .tooltip.visible { opacity: 1; visibility: visible; } .tooltip-title { font-weight: 600; margin-bottom: 0.5rem; font-size: 0.9375rem; } .tooltip-content { font-size: 0.8125rem; color: var(--text-secondary); line-height: 1.4; } .tooltip-data { margin-top: 0.5rem; display: flex; flex-direction: column; gap: 0.25rem; } .tooltip-data-item { display: flex; justify-content: space-between; font-size: 0.8125rem; } .tooltip-data-label { color: var(--text-secondary); } .tooltip-data-value { font-weight: 500; } /* Loading state */ .loading-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(255, 255, 255, 0.7); display: flex; align-items: center; justify-content: center; z-index: 50; opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease; } [data-theme="dark"] .loading-overlay { background-color: rgba(15, 23, 42, 0.7); } .loading-overlay.visible { opacity: 1; visibility: visible; } .spinner { width: 40px; height: 40px; border-radius: 50%; border: 3px solid rgba(59, 130, 246, 0.1); border-top-color: var(--primary); animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* Toggle switch */ .theme-switch { position: relative; width: 50px; height: 26px; } .theme-switch input { opacity: 0; width: 0; height: 0; } .switch-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--neutral-light); transition: .4s; border-radius: 34px; } .switch-slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .switch-slider { background-color: var(--primary); } input:checked + .switch-slider:before { transform: translateX(24px); } .switch-slider .sun-icon, .switch-slider .moon-icon { position: absolute; top: 6px; font-size: 14px; transition: .4s; } .switch-slider .sun-icon { left: 6px; color: #fff; opacity: 0; } .switch-slider .moon-icon { right: 6px; color: #fff; opacity: 1; } input:checked + .switch-slider .sun-icon { opacity: 1; } input:checked + .switch-slider .moon-icon { opacity: 0; } /* Pill filters */ .filter-pills { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; } .filter-pill { background-color: var(--bg-main); border: 1px solid var(--border); border-radius: 1rem; padding: 0.375rem 0.875rem; font-size: 0.8125rem; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; gap: 0.375rem; } .filter-pill:hover { border-color: var(--primary-light); } .filter-pill.active { background-color: var(--primary); color: white; border-color: var(--primary); } .filter-pill svg { width: 0.875rem; height: 0.875rem; } /* Responsive styles */ @media (max-width: 768px) { .status-cards { grid-template-columns: repeat(2, 1fr); } .detail-panels { grid-template-columns: 1fr; } } @media (max-width: 480px) { .status-cards { grid-template-columns: 1fr; } .header-title { font-size: 1rem; } .widget-header { padding: 1rem; flex-direction: column; align-items: flex-start; gap: 0.75rem; } .header-controls { width: 100%; justify-content: space-between; } .widget-content { padding: 1rem; } .forecast-segments { flex-direction: column; } } /* Animation keyframes */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } } .status-card.critical .status-indicator { animation: pulse 2s infinite; } .alert-item { animation: fadeIn 0.3s ease forwards; } .alert-item:nth-child(2) { animation-delay: 0.1s; } .alert-item:nth-child(3) { animation-delay: 0.2s; } .alert-item:nth-child(4) { animation-delay: 0.3s; } .alert-item:nth-child(5) { animation-delay: 0.4s; } /* Notification badge */ .notification-badge { position: absolute; top: -5px; right: -5px; width: 18px; height: 18px; border-radius: 50%; background-color: var(--danger); color: white; font-size: 0.6875rem; font-weight: 600; display: flex; align-items: center; justify-content: center; } /* Progress indicator */ .progress-indicator { position: absolute; bottom: 0; left: 0; height: 3px; background-color: var(--primary); transition: width 0.3s ease; z-index: 1; } </style> </head> <body> <div class="dashboard-widget"> <div class="widget-header"> <div class="header-title"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect> <line x1="8" y1="21" x2="16" y2="21"></line> <line x1="12" y1="17" x2="12" y2="21"></line> </svg> Operations Dashboard </div> <div class="header-controls"> <button id="refresh-btn" title="Refresh data"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="1 4 1 10 7 10"></polyline> <polyline points="23 20 23 14 17 14"></polyline> <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path> </svg> </button> <button id="expand-btn" title="Expand view"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="15 3 21 3 21 9"></polyline> <polyline points="9 21 3 21 3 15"></polyline> <line x1="21" y1="3" x2="14" y2="10"></line> <line x1="3" y1="21" x2="10" y2="14"></line> </svg> </button> <label class="theme-switch" title="Toggle dark mode"> <input type="checkbox" id="theme-toggle"> <span class="switch-slider"> <span class="sun-icon">☀️</span> <span class="moon-icon">🌙</span> </span> </label> </div> </div> <div class="widget-content"> <div class="status-cards"> <div class="status-card critical" data-id="server-load"> <div class="card-header"> <div class="card-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect> <rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect> <line x1="6" y1="6" x2="6.01" y2="6"></line> <line x1="6" y1="18" x2="6.01" y2="18"></line> </svg> </div> <div class="status-indicator"></div> </div> <div class="card-value">92%</div> <div class="card-label">Server Load</div> <div class="card-metric metric-negative"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="12" y1="5" x2="12" y2="19"></line> <polyline points="19 12 12 19 5 12"></polyline> </svg> +18% since yesterday </div> </div> <div class="status-card" data-id="response-time"> <div class="card-header"> <div class="card-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> </div> <div class="status-indicator"></div> </div> <div class="card-value">231ms</div> <div class="card-label">Response Time</div> <div class="card-metric metric-positive"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="12" y1="19" x2="12" y2="5"></line> <polyline points="5 12 12 5 19 12"></polyline> </svg> -12% since yesterday </div> </div> <div class="status-card warning" data-id="memory-usage"> <div class="card-header"> <div class="card-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M22 12H2"></path> <path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path> <line x1="6" y1="16" x2="6.01" y2="16"></line> <line x1="10" y1="16" x2="10.01" y2="16"></line> </svg> </div> <div class="status-indicator"></div> </div> <div class="card-value">76%</div> <div class="card-label">Memory Usage</div> <div class="card-metric metric-negative"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="12" y1="5" x2="12" y2="19"></line> <polyline points="19 12 12 19 5 12"></polyline> </svg> +8% since yesterday </div> </div> <div class="status-card" data-id="uptime"> <div class="card-header"> <div class="card-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M6 18h8"></path> <path d="M3 22h18"></path> <path d="M14 18a4 4 0 0 0 0-8H6"></path> <path d="M6 10V3"></path> <path d="M10 3h8"></path> <path d="M18 3a2 2 0 0 1 0 4"></path> </svg> </div> <div class="status-indicator"></div> </div> <div class="card-value">99.8%</div> <div class="card-label">Uptime</div> <div class="card-metric metric-positive"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="12" y1="19" x2="12" y2="5"></line> <polyline points="5 12 12 5 19 12"></polyline> </svg> +0.2% since yesterday </div> </div> </div> <div class="detail-panels"> <div class="detail-panel"> <div class="panel-header"> <div class="panel-title"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon> <line x1="12" y1="8" x2="12" y2="12"></line> <line x1="12" y1="16" x2="12.01" y2="16"></line> </svg> Critical Alerts </div> <div class="filter-pills"> <div class="filter-pill active" data-filter="all"> All </div> <div class="filter-pill" data-filter="critical"> Critical </div> <div class="filter-pill" data-filter="warning"> Warning </div> </div> </div> <div class="alerts-list"> <div class="alert-item critical" data-id="alert-1"> <div class="alert-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <line x1="12" y1="8" x2="12" y2="12"></line> <line x1="12" y1="16" x2="12.01" y2="16"></line> </svg> </div> <div class="alert-content"> <div class="alert-title">Database CPU exceeding threshold</div> <div class="alert-message">Primary database cluster CPU utilization at 92%. This may impact transaction processing times.</div> <div class="alert-meta"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> 15 minutes ago </div> </div> <div class="progress-indicator" style="width: 80%;"></div> </div> <div class="alert-item warning" data-id="alert-2"> <div class="alert-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path> <line x1="12" y1="9" x2="12" y2="13"></line> <line x1="12" y1="17" x2="12.01" y2="17"></line> </svg> </div> <div class="alert-content"> <div class="alert-title">API rate limit approaching</div> <div class="alert-message">The payments API is approaching its rate limit (85% utilized). Consider throttling requests.</div> <div class="alert-meta"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> 42 minutes ago </div> </div> <div class="progress-indicator" style="width: 60%;"></div> </div> <div class="alert-item info" data-id="alert-3"> <div class="alert-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <line x1="12" y1="16" x2="12" y2="12"></line> <line x1="12" y1="8" x2="12.01" y2="8"></line> </svg> </div> <div class="alert-content"> <div class="alert-title">Scheduled maintenance window</div> <div class="alert-message">Datacenter US-EAST-2 will undergo scheduled maintenance tonight, 2am-4am EDT.</div> <div class="alert-meta"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <polyline points="12 6 12 12 16 14"></polyline> </svg> 2 hours ago </div> </div> <div class="progress-indicator" style="width: 40%;"></div> </div> <div class="alert-item critical" data-id="alert-4"> <div class="alert-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Seasonal Forecast Widget</title> <style> :root { --spring-color: #7dce82; --spring-accent: #f9c0c7; --summer-color: #f8b04e; --summer-accent: #ff7e67; --fall-color: #e9764d; --fall-accent: #ffd465; --winter-color: #4baee8; --winter-accent: #c3e3f7; --main-color: var(--spring-color); --accent-color: var(--spring-accent); --text-color: #2c3e50; --light-text: #f8f9fa; --card-bg: #ffffff; --bg-color: #f8f9fa; --shadow: 0 4px 20px rgba(0, 0, 0, 0.08); --hover-shadow: 0 6px 25px rgba(0, 0, 0, 0.12); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Poppins', sans-serif; } body { background-color: var(--bg-color); color: var(--text-color); display: flex; justify-content: center; align-items: center; min-height: 700px; position: relative; overflow: hidden; } .widget-container { width: 100%; max-width: 650px; height: 650px; padding: 20px; position: relative; overflow: hidden; } .weather-widget { background-color: var(--card-bg); border-radius: 24px; box-shadow: var(--shadow); padding: 30px; width: 100%; height: 100%; display: flex; flex-direction: column; position: relative; overflow: hidden; transition: all 0.5s ease; } .bg-pattern { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.04; z-index: 0; background-size: cover; background-repeat: no-repeat; transition: opacity 0.5s ease; } .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; position: relative; z-index: 1; } .logo { font-size: 1.25rem; font-weight: 700; color: var(--main-color); display: flex; align-items: center; } .logo span { background: var(--main-color); color: white; padding: 4px 10px; border-radius: 50px; margin-right: 8px; font-size: 0.9rem; } .season-tabs { display: flex; gap: 10px; } .season-tab { background: transparent; border: none; padding: 6px 12px; border-radius: 50px; cursor: pointer; font-weight: 600; font-size: 0.85rem; color: var(--text-color); opacity: 0.5; transition: all 0.3s ease; } .season-tab.active { background-color: var(--main-color); color: white; opacity: 1; } .season-tab:hover:not(.active) { opacity: 0.8; } .content { flex: 1; display: flex; flex-direction: column; position: relative; z-index: 1; } .season-banner { background: linear-gradient(135deg, var(--main-color), var(--accent-color)); border-radius: 16px; padding: 25px; margin-bottom: 20px; color: white; position: relative; overflow: hidden; transition: all 0.5s ease; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.08); } .banner-content { position: relative; z-index: 2; } .banner-pattern { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.15; background-size: 20%; background-repeat: repeat; } .season-title { font-size: 2.2rem; font-weight: 800; margin-bottom: 10px; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); } .season-subtitle { font-size: 1rem; margin-bottom: 25px; line-height: 1.5; max-width: 80%; } .promotion-button { background-color: white; color: var(--main-color); border: none; padding: 10px 25px; border-radius: 50px; font-weight: 600; cursor: pointer; transition: transform 0.3s ease, box-shadow 0.3s ease; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } .promotion-button:hover { transform: translateY(-3px); box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15); } .forecast-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-bottom: 20px; } .forecast-card { background-color: #f8f9fa; border-radius: 16px; padding: 18px; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; display: flex; flex-direction: column; align-items: center; text-align: center; } .forecast-card::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 6px; background: var(--main-color); transition: height 0.3s ease; } .forecast-card:hover { box-shadow: var(--hover-shadow); transform: translateY(-5px); } .forecast-card:hover::before { height: 100%; opacity: 0.05; } .forecast-day { font-weight: 700; margin-bottom: 8px; font-size: 0.95rem; position: relative; z-index: 1; } .forecast-icon { font-size: 1.75rem; margin: 8px 0; color: var(--main-color); position: relative; z-index: 1; } .forecast-temp { font-size: 1.5rem; font-weight: 700; margin-bottom: 5px; position: relative; z-index: 1; } .forecast-desc { font-size: 0.8rem; color: #6c757d; position: relative; z-index: 1; } .forecast-detail { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: var(--card-bg); display: flex; flex-direction: column; justify-content: center; align-items: center; opacity: 0; transform: translateY(20px); transition: all 0.3s ease; padding: 20px; z-index: 2; } .forecast-card:hover .forecast-detail { opacity: 1; transform: translateY(0); } .detail-header { font-weight: 700; margin-bottom: 12px; color: var(--main-color); } .detail-item { margin-bottom: 8px; font-size: 0.85rem; } .product-suggestion { display: flex; align-items: center; padding: 12px 15px; border-radius: 12px; background-color: #f8f9fa; margin-top: 10px; transition: all 0.3s ease; } .product-suggestion:hover { background-color: var(--accent-color); color: white; } .product-icon { margin-right: 10px; font-size: 1.1rem; } .trend-chart { margin-top: auto; height: 100px; width: 100%; position: relative; } .trend-line { position: absolute; bottom: 25px; left: 0; width: 100%; height: 3px; background-color: #e9ecef; } .trend-data { position: absolute; bottom: 25px; left: 0; width: 100%; height: 40px; display: flex; align-items: flex-end; } .trend-bar { flex: 1; background-color: var(--main-color); margin: 0 3px; border-radius: 3px 3px 0 0; position: relative; transition: height 0.5s ease, background-color 0.5s ease; } .trend-bar:hover { background-color: var(--accent-color); } .trend-tooltip { position: absolute; bottom: calc(100% + 5px); left: 50%; transform: translateX(-50%); background-color: var(--text-color); color: white; padding: 4px 8px; border-radius: 4px; font-size: 0.75rem; opacity: 0; transition: opacity 0.3s ease; pointer-events: none; white-space: nowrap; } .trend-bar:hover .trend-tooltip { opacity: 1; } .trend-labels { position: absolute; bottom: 0; left: 0; width: 100%; display: flex; justify-content: space-around; } .trend-label { font-size: 0.75rem; color: #6c757d; text-align: center; } .current-weather { display: flex; align-items: center; margin-bottom: 25px; background-color: rgba(255, 255, 255, 0.9); border-radius: 12px; padding: 15px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); } .current-weather-icon { font-size: 2.5rem; margin-right: 15px; color: var(--main-color); } .current-weather-info { flex: 1; } .current-location { font-size: 0.85rem; color: #6c757d; display: flex; align-items: center; margin-bottom: 5px; } .location-icon { margin-right: 5px; font-size: 0.8rem; } .current-temp { font-size: 1.8rem; font-weight: 700; } .current-desc { color: #495057; font-size: 0.9rem; } .seasonal-hint { text-align: center; margin-top: 15px; color: #6c757d; font-size: 0.8rem; font-style: italic; } .seasonal-alert { background: rgba(255, 255, 255, 0.8); border-left: 4px solid var(--main-color); padding: 10px 15px; margin-top: 15px; border-radius: 6px; display: flex; align-items: center; } .alert-icon { margin-right: 10px; font-size: 1.2rem; color: var(--main-color); } .alert-message { font-size: 0.85rem; } @media (max-width: 600px) { .widget-container { padding: 10px; } .weather-widget { padding: 20px; } .header { flex-direction: column; align-items: flex-start; gap: 15px; } .season-tabs { width: 100%; justify-content: space-between; } .season-tab { padding: 5px 8px; font-size: 0.75rem; } .season-banner { padding: 20px; } .season-title { font-size: 1.8rem; } .season-subtitle { font-size: 0.9rem; max-width: 100%; } .forecast-grid { grid-template-columns: repeat(2, 1fr); } .current-weather { flex-direction: column; text-align: center; } .current-weather-icon { margin-right: 0; margin-bottom: 10px; } } /* Animation Classes */ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .animate-fadeIn { animation: fadeIn 0.5s ease forwards; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .pulse { animation: pulse 2s infinite; } /* Weather icons */ .wi { display: inline-block; font-family: 'weathericons'; font-style: normal; font-weight: normal; line-height: 1; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* Simple dot loading animation */ .dot-loading { display: inline-block; } .dot-loading:after { content: '.'; animation: dots 1.5s steps(5, end) infinite; } @keyframes dots { 0%, 20% { content: '.'; } 40% { content: '..'; } 60% { content: '...'; } 80%, 100% { content: ''; } } </style> <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> </head> <body> <div class="widget-container"> <div class="weather-widget"> <div class="bg-pattern"></div> <div class="header"> <div class="logo"> <span><i class="fas fa-cloud-sun"></i></span> SeasonSense </div> <div class="season-tabs"> <button class="season-tab" data-season="spring">Spring</button> <button class="season-tab" data-season="summer">Summer</button> <button class="season-tab active" data-season="fall">Fall</button> <button class="season-tab" data-season="winter">Winter</button> </div> </div> <div class="content"> <div class="season-banner"> <div class="banner-pattern"></div> <div class="banner-content"> <h1 class="season-title">Autumn Arrivals</h1> <p class="season-subtitle">Falling temperatures call for warmer wardrobes. Explore our new collection of fall essentials.</p> <button class="promotion-button">Shop Fall Collection</button> </div> </div> <div class="current-weather"> <div class="current-weather-icon"> <i class="fas fa-cloud-sun"></i> </div> <div class="current-weather-info"> <div class="current-location"> <i class="fas fa-map-marker-alt location-icon"></i> New York, NY </div> <div class="current-temp">62°F</div> <div class="current-desc">Partly Cloudy</div> </div> </div> <div class="forecast-grid"> <div class="forecast-card"> <div class="forecast-day">Today</div> <div class="forecast-icon"><i class="fas fa-cloud-sun"></i></div> <div class="forecast-temp">62°F</div> <div class="forecast-desc">Partly Cloudy</div> <div class="forecast-detail"> <div class="detail-header">Perfect For</div> <div class="detail-item"><i class="fas fa-tshirt"></i> Light layers</div> <div class="detail-item"><i class="fas fa-umbrella"></i> 10% chance of rain</div> <div class="product-suggestion"> <div class="product-icon"><i class="fas fa-vest"></i></div> <div>Shop Fall Vests</div> </div> </div> </div> <div class="forecast-card"> <div class="forecast-day">Tomorrow</div> <div class="forecast-icon"><i class="fas fa-cloud-rain"></i></div> <div class="forecast-temp">58°F</div> <div class="forecast-desc">Light Rain</div> <div class="forecast-detail"> <div class="detail-header">Perfect For</div> <div class="detail-item"><i class="fas fa-umbrella"></i> 80% chance of rain</div> <div class="detail-item"><i class="fas fa-wind"></i> Winds 8-12 mph</div> <div class="product-suggestion"> <div class="product-icon"><i class="fas fa-umbrella"></i></div> <div>Shop Rain Gear</div> </div> </div> </div> <div class="forecast-card"> <div class="forecast-day">Friday</div> <div class="forecast-icon"><i class="fas fa-sun"></i></div> <div class="forecast-temp">64°F</div> <div class="forecast-desc">Sunny</div> <div class="forecast-detail"> <div class="detail-header">Perfect For</div> <div class="detail-item"><i class="fas fa-sun"></i> UV Index: High</div> <div class="detail-item"><i class="fas fa-temperature-low"></i> Morning chill</div> <div class="product-suggestion"> <div class="product-icon"><i class="fas fa-hat-cowboy"></i></div> <div>Shop Fall Accessories</div> </div> </div> </div> </div> <div class="seasonal-alert"> <div class="alert-icon"><i class="fas fa-leaf"></i></div> <div class="alert-message">Leaf peeping season peaks this weekend! Perfect time for outdoor apparel.</div> </div> <div class="trend-chart"> <div class="trend-line"></div> <div class="trend-data"> <div class="trend-bar" style="height: 70%;"> <div class="trend-tooltip">Boots: +32%</div> </div> <div class="trend-bar" style="height: 85%;"> <div class="trend-tooltip">Sweaters: +46%</div> </div> <div class="trend-bar" style="height: 60%;"> <div class="trend-tooltip">Scarves: +28%</div> </div> <div class="trend-bar" style="height: 40%;"> <div class="trend-tooltip">Hats: +15%</div> </div> <div class="trend-bar" style="height: 75%;"> <div class="trend-tooltip">Jackets: +38%</div> </div> </div> <div class="trend-labels"> <div class="trend-label">Boots</div> <div class="trend-label">Sweaters</div> <div class="trend-label">Scarves</div> <div class="trend-label">Hats</div> <div class="trend-label">Jackets</div> </div> </div> <div class="seasonal-hint"> Trending now: Items with warm earthy tones matching the season </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Seasonal data configuration const seasonalData = { spring: { mainColor: '#7dce82', accentColor: '#f9c0c7', title: 'Spring Refresh', subtitle: 'Freshen your wardrobe with our lightweight collections perfect for the warming days ahead.', icon: 'fa-seedling', bgPattern: 'url("data:image/svg+xml,%3Csvg width=\'40\' height=\'40\' viewBox=\'0 0 40 40\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cg fill=\'%237dce82\' fill-opacity=\'0.2\' fill-rule=\'evenodd\'%3E%3Cpath d=\'M0 20C0 8.954 8.954 0 20 0s20 8.954 20 20c0 1.154-0.1 2.286-0.29 3.386C37.954 34.32 29.446 40 20 40 8.954 40 0 31.046 0 20zm2 0c0 9.94 8.06 18 18 18 9.288 0 16.936-7.035 17.879-16.059C37.928 13.123 30.06 6 20 6 11.163 6 4 13.163 4 22c0 5.6 2.936 10.43 7.322 13.264C7.09 31.886 4.999 26.345 5 20zm28-2c0 4-6 4-6 0s6-4 6 0z\'/%3E%3C/g%3E%3C/svg%3E")', bannerPattern: 'url("data:image/svg+xml,%3Csvg width=\'52\' height=\'26\' viewBox=\'0 0 52 26\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cg fill=\'none\' fill-rule=\'evenodd\'%3E%3Cg fill=\'%23ffffff\' fill-opacity=\'0.3\'%3E%3Cpath d=\'M10 10c0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6h2c0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4v2c-3.314 0-6-2.686-6-6 0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6zm25.464-1.95l8.486 8.486-1.414 1.414-8.486-8.486 1.414-1.414z\' /%3E%3C/g%3E%3C/g%3E%3C/svg%3E")', alertIcon: 'fa-umbrella', alertMessage: 'April showers bring May flowers—and a 20% discount on our rain collection!', temperature: '58°F', weatherIcon: 'fa-cloud-sun-rain', weatherDesc: 'Light Showers', forecast: [ { day: 'Today', icon: 'fa-cloud-sun-rain', temp: '58°F', desc: 'Light Showers' }, { day: 'Tomorrow', icon: 'fa-cloud-sun', temp: '62°F', desc: 'Partly Cloudy' }, { day: 'Friday', icon: 'fa-sun', temp: '65°F', desc: 'Sunny' } ], trends: [ { name: 'Raincoats', value: 75, label: '+38%' }, { name: 'Dresses', value: 85, label: '+46%' }, { name: 'Sandals', value: 55, label: '+22%' }, { name: 'Sunglasses', value: 40, label: '+15%' }, { name: 'T-shirts', value: 60, label: '+28%' } ], hint: 'Trending now: Pastel colors and floral prints for the season' }, summer: { mainColor: '#f8b04e', accentColor: '#ff7e67', title: 'Summer Essentials', subtitle: 'Beat the heat with our breezy summer collection. Perfect for beaches, parks, and outdoor adventures.', icon: 'fa-sun', bgPattern: 'url("data:image/svg+xml,%3Csvg width=\'40\' height=\'40\' viewBox=\'0 0 40 40\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath d=\'M0 0h40v40H0V0zm40 40h-4v-4h4v4zm0-8h-4v-4h4v4zm-8 8h-4v-4h4v4zm-8 0h-4v-4h4v4zm16-16h-4v-4h4v4zm-16 0h-4v-4h4v4zm-8 8h-4v-4h4v4zm0-8h-4v-4h4v4zm24-8h4v4h-4v-4zm-16 0h4v4h-4v-4zm8 0h4v4h-4v-4zm-16 0h4v4h-4v-4zm16-8h4v4h-4V8zm-8 0h4v4h-4V8zm8-8h4v4h-4V0zm-8 0h4v4h-4V0z\' fill=\'%23f8b04e\' fill-opacity=\'0.2\' fill-rule=\'evenodd\'/%3E%3C/svg%3E")', bannerPattern: 'url("data:image/svg+xml,%3Csvg width=\'48\' height=\'32\' viewBox=\'0 0 48 32\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cg fill=\'none\' fill-rule=\'evenodd\'%3E%3Cg fill=\'%23ffffff\' fill-opacity=\'0.25\'%3E%3Cpath d=\'M27 32c0-3.314 2.686-6 6-6 5.523 0 10-4.477 10-10S38.523 6 33 6c-3.314 0-6-2.686-6-6h2c0 2.21 1.79 4 4 4 6.627 0 12 5.373 12 12s-5.373 12-12 12c-2.21 0-4 1.79-4 4h-2zm-6 0c0-3.314-2.686-6-6-6-5.523 0-10-4.477-10-10S9.477 6 15 6c3.314 0 6-2.686 6-6h-2c0 2.21-1.79 4-4 4C8.373 4 3 9.373 3 16s5.373 12 12 12c2.21 0 4 1.79 4 4h2z\'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")', alertIcon: 'fa-temperature-high', alertMessage: 'Heat wave expected next week! Stock up on our UV-protective beachwear.', temperature: '86°F', weatherIcon: 'fa-sun', weatherDesc: 'Sunny & Hot', forecast: [ { day: 'Today', icon: 'fa-sun', temp: '86°F', desc: 'Sunny & Hot' }, { day: 'Tomorrow', icon: 'fa-sun', temp: '88°F', desc: 'Clear Skies' }, { day: 'Friday', icon: 'fa-cloud-sun', temp: '85°F', desc: 'Partly Cloudy' } ], trends: [ { name: 'Swimwear', value: 90, label: '+52%' }, { name: 'Sunscreen', value: 80, label: '+45%' }, { name: 'Hats', value: 65, label: '+32%' }, { name: 'Sandals', value: 75, label: '+40%' }, { name: 'Shorts', value: 85, label: '+48%' } ], hint: 'Trending now: Vibrant colors and lightweight fabrics for hot days' }, fall: { mainColor: '#e9764d', accentColor: '#ffd465', title: 'Autumn Arrivals', subtitle: 'Falling temperatures call for warmer wardrobes. Explore our new collection of fall essentials.', icon: 'fa-leaf', bgPattern: 'url("data:image/svg+xml,%3Csvg width=\'44\' height=\'12\' viewBox=\'0 0 44 12\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath d=\'M20 12v-2L0 0v10l4 2h16zm18 0l4-2V0L22 10v2h16zM20 0v8L4 0h16zm18 0L22 8V0h16z\' fill=\'%23e9764d\' fill-opacity=\'0.2\' fill-rule=\'evenodd\'/%3E%3C/svg%3E")', bannerPattern: 'url("data:image/svg+xml,%3Csvg width=\'60\' height=\'48\' viewBox=\'0 0 60 48\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cg fill=\'none\' fill-rule=\'evenodd\'%3E%3Cg fill=\'%23ffffff\' fill-opacity=\'0.25\'%3E%3Cpath d=\'M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z\'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")', alertIcon: 'fa-leaf', alertMessage: 'Leaf peeping season peaks this weekend! Perfect time for outdoor apparel.', temperature: '62°F', weatherIcon: 'fa-cloud-sun', weatherDesc: 'Partly Cloudy', forecast: [ { day: 'Today', icon: 'fa-cloud-sun', temp: '62°F', desc: 'Partly Cloudy' }, { day: 'Tomorrow', icon: 'fa-cloud-rain', temp: '58°F', desc: 'Light Rain' }, { day: 'Friday', icon: 'fa-sun', temp: '64°F', desc: 'Sunny' } ], trends: [ { name: 'Boots', value: 70, label: '+32%' }, { name: 'Sweaters', value: 85, label: '+46%' }, { name: 'Scarves', value: 60, label: '+28%' }, { name: 'Hats', value: 40, label: '+15%' }, { name: 'Jackets', value: 75, label: '+38%' } ], hint: 'Trending now: Items with warm earthy tones matching the season' }, winter: { mainColor: '#4baee8', accentColor: '#c3e3f7', title: 'Winter Warmers', subtitle: 'Stay cozy during the coldest months with our premium winter collection. From ski gear to fireside fashion.', icon: 'fa-snowflake', bgPattern: 'url("data:image/svg+xml,%3Csvg width=\'12\' height=\'24\' viewBox=\'0 0 12 24\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cg fill=\'none\' fill-rule=\'evenodd\'%3E%3Cg fill=\'%234baee8\' fill-opacity=\'0.2\'%3E%3Cpath d=\'M2 0h2v12H2V0zm1 20c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM9 8c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zm-7 4c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z\'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")', bannerPattern: 'url("data:image/svg+xml,%3Csvg width=\'84\' height=\'48\' viewBox=\'0 0 84 48\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cg fill=\'none\' fill-rule=\'evenodd\'%3E%3Cg fill=\'%23ffffff\' fill-opacity=\'0.3\' fill-rule=\'nonzero\'%3E%3Cpath d=\'M42 48c0-7.732 6.268-14 14-14s14 6.268 14 14h-4c0-5.523-4.477-10-10-10s-10 4.477-10 10h-4zm-28 0c0-7.732 6.268-14 14-14s14 6.268 14 14h-4c0-5.523-4.477-10-10-10s-10 4.477-10 10h-4zm-14 0c0-7.732
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Digital Signage Weather Widget</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Montserrat', 'Arial', sans-serif; } body { width: 100%; height: 100%; background-color: #000; color: #fff; overflow: hidden; } .widget-container { width: 700px; height: 700px; position: relative; margin: 0 auto; background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%); padding: 20px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); } .top-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; padding-bottom: 15px; border-bottom: 2px solid rgba(255, 255, 255, 0.2); } .logo { font-size: 24px; font-weight: 700; letter-spacing: 1px; display: flex; align-items: center; } .logo svg { margin-right: 10px; filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.5)); } .clock { font-size: 30px; font-weight: 600; color: #fff; text-shadow: 0 0 10px rgba(255, 255, 255, 0.3); } .date { font-size: 20px; font-weight: 400; margin-top: 5px; color: #e0e0e0; } .current-weather { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; background: rgba(0, 0, 0, 0.2); padding: 20px; border-radius: 12px; backdrop-filter: blur(5px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); height: 240px; } .temp-info { display: flex; flex-direction: column; justify-content: center; } .location { font-size: 32px; font-weight: 700; margin-bottom: 5px; color: #fff; text-shadow: 0 0 10px rgba(255, 255, 255, 0.3); } .temperature { font-size: 80px; font-weight: 700; margin-bottom: 10px; line-height: 1; } .weather-condition { font-size: 24px; margin-bottom: 10px; color: #e0e0e0; } .weather-icon { width: 160px; height: 160px; position: relative; display: flex; justify-content: center; align-items: center; } .weather-icon svg { width: 100%; height: 100%; filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.5)); } .additional-info { display: flex; justify-content: space-between; margin-bottom: 30px; } .info-box { flex: 1; padding: 15px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; margin: 0 10px; text-align: center; transition: transform 0.3s ease, background 0.3s ease; } .info-box:first-child { margin-left: 0; } .info-box:last-child { margin-right: 0; } .info-box:hover { transform: translateY(-5px); background: rgba(255, 255, 255, 0.15); } .info-icon { font-size: 24px; margin-bottom: 10px; color: #fff; } .info-label { font-size: 14px; margin-bottom: 5px; color: #e0e0e0; } .info-value { font-size: 24px; font-weight: 600; color: #fff; } .forecast { padding: 15px; background: rgba(0, 0, 0, 0.15); border-radius: 12px; overflow: hidden; } .forecast-title { font-size: 24px; font-weight: 600; margin-bottom: 15px; color: #fff; } .forecast-wrapper { display: flex; overflow-x: hidden; width: 100%; } .forecast-container { display: flex; transition: transform 0.5s ease; } .forecast-item { flex: 0 0 auto; padding: 15px; margin-right: 15px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; width: 140px; text-align: center; transition: all 0.3s ease; } .forecast-item:hover { background: rgba(255, 255, 255, 0.2); transform: scale(1.05); } .forecast-day { font-size: 18px; font-weight: 600; margin-bottom: 10px; color: #fff; } .forecast-icon { font-size: 36px; margin-bottom: 10px; color: #fff; } .forecast-temp { font-size: 20px; font-weight: 600; color: #fff; } .weather-alert { position: absolute; bottom: 20px; left: 20px; right: 20px; padding: 15px; background: rgba(255, 65, 54, 0.85); border-radius: 10px; display: none; align-items: center; animation: alertPulse 2s infinite; } .alert-icon { font-size: 24px; margin-right: 15px; } .alert-text { font-size: 18px; font-weight: 600; flex: 1; } .pulse { animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes alertPulse { 0% { background: rgba(255, 65, 54, 0.85); } 50% { background: rgba(255, 65, 54, 0.95); } 100% { background: rgba(255, 65, 54, 0.85); } } .animated-bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; overflow: hidden; border-radius: 15px; } .bg-element { position: absolute; background: rgba(255, 255, 255, 0.1); border-radius: 50%; filter: blur(8px); animation: float 20s infinite linear; } @keyframes float { 0% { transform: translateY(0) translateX(0) rotate(0deg); } 50% { transform: translateY(-30px) translateX(30px) rotate(180deg); } 100% { transform: translateY(0) translateX(0) rotate(360deg); } } @media screen and (max-width: 700px) { .widget-container { width: 100%; height: auto; min-height: 700px; border-radius: 0; } .current-weather { flex-direction: column; height: auto; padding: 15px; } .temp-info { margin-bottom: 20px; align-items: center; } .additional-info { flex-wrap: wrap; } .info-box { flex: 0 0 45%; margin: 5px; } } </style> </head> <body> <div class="widget-container"> <div class="animated-bg" id="animated-bg"></div> <div class="top-bar"> <div class="logo"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 3V5M5.6 18.4L7 17M18.4 18.4L17 17M6 12H4M20 12H18M17 7L18.4 5.6M7 7L5.6 5.6M16 12C16 14.2091 14.2091 16 12 16C9.79086 16 8 14.2091 8 12C8 9.79086 9.79086 8 12 8C14.2091 8 16 9.79086 16 12Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <span>METRO WEATHER</span> </div> <div class="time-display"> <div class="clock" id="clock">12:00</div> <div class="date" id="date">Monday, January 1</div> </div> </div> <div class="current-weather"> <div class="temp-info"> <div class="location">Downtown Metro</div> <div class="temperature" id="temperature">24°</div> <div class="weather-condition" id="weather-condition">Mostly Sunny</div> </div> <div class="weather-icon" id="weather-icon"> <svg id="weatherSVG" width="160" height="160" viewBox="0 0 160 160" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="80" cy="80" r="40" fill="#FFD600"/> <path d="M80 20V10" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M80 150V140" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M20 80H10" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M150 80H140" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M36.9 36.9L30 30" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M130 130L123.1 123.1" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M36.9 123.1L30 130" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M130 30L123.1 36.9" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> </svg> </div> </div> <div class="additional-info"> <div class="info-box"> <div class="info-icon">💨</div> <div class="info-label">WIND</div> <div class="info-value" id="wind-speed">12 km/h</div> </div> <div class="info-box"> <div class="info-icon">💧</div> <div class="info-label">HUMIDITY</div> <div class="info-value" id="humidity">65%</div> </div> <div class="info-box"> <div class="info-icon">🌡️</div> <div class="info-label">FEELS LIKE</div> <div class="info-value" id="feels-like">26°</div> </div> <div class="info-box"> <div class="info-icon">☔</div> <div class="info-label">RAIN CHANCE</div> <div class="info-value" id="rain-chance">10%</div> </div> </div> <div class="forecast"> <div class="forecast-title">5-DAY FORECAST</div> <div class="forecast-wrapper"> <div class="forecast-container" id="forecast-container"> <div class="forecast-item"> <div class="forecast-day">TUE</div> <div class="forecast-icon">☀️</div> <div class="forecast-temp">25°</div> </div> <div class="forecast-item"> <div class="forecast-day">WED</div> <div class="forecast-icon">⛅</div> <div class="forecast-temp">23°</div> </div> <div class="forecast-item"> <div class="forecast-day">THU</div> <div class="forecast-icon">🌧️</div> <div class="forecast-temp">19°</div> </div> <div class="forecast-item"> <div class="forecast-day">FRI</div> <div class="forecast-icon">⛈️</div> <div class="forecast-temp">18°</div> </div> <div class="forecast-item"> <div class="forecast-day">SAT</div> <div class="forecast-icon">🌤️</div> <div class="forecast-temp">22°</div> </div> <div class="forecast-item"> <div class="forecast-day">SUN</div> <div class="forecast-icon">☀️</div> <div class="forecast-temp">26°</div> </div> </div> </div> </div> <div class="weather-alert" id="weather-alert"> <div class="alert-icon">⚠️</div> <div class="alert-text">HEAVY RAIN ADVISORY: Expect localized flooding in low-lying areas.</div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Create animated background const bg = document.getElementById('animated-bg'); for (let i = 0; i < 10; i++) { const element = document.createElement('div'); element.classList.add('bg-element'); element.style.width = Math.random() * 200 + 50 + 'px'; element.style.height = element.style.width; element.style.left = Math.random() * 100 + '%'; element.style.top = Math.random() * 100 + '%'; element.style.opacity = Math.random() * 0.5; element.style.animationDuration = (Math.random() * 10 + 15) + 's'; element.style.animationDelay = (Math.random() * 5) + 's'; bg.appendChild(element); } // Update clock and date function updateTime() { const now = new Date(); // Clock let hours = now.getHours(); let minutes = now.getMinutes(); hours = hours < 10 ? '0' + hours : hours; minutes = minutes < 10 ? '0' + minutes : minutes; document.getElementById('clock').textContent = `${hours}:${minutes}`; // Date const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; const day = days[now.getDay()]; const month = months[now.getMonth()]; const date = now.getDate(); document.getElementById('date').textContent = `${day}, ${month} ${date}`; } updateTime(); setInterval(updateTime, 60000); // Update every minute // Weather data simulation - would be replaced with real API data const weatherScenarios = [ { temp: '24°', condition: 'Mostly Sunny', icon: 'sun', wind: '12 km/h', humidity: '65%', feelsLike: '26°', rainChance: '10%', alert: false }, { temp: '19°', condition: 'Partly Cloudy', icon: 'partly-cloudy', wind: '15 km/h', humidity: '72%', feelsLike: '17°', rainChance: '30%', alert: false }, { temp: '14°', condition: 'Rain Showers', icon: 'rain', wind: '20 km/h', humidity: '85%', feelsLike: '12°', rainChance: '80%', alert: true }, { temp: '10°', condition: 'Thunderstorms', icon: 'thunderstorm', wind: '25 km/h', humidity: '90%', feelsLike: '8°', rainChance: '90%', alert: true }, { temp: '28°', condition: 'Hot & Sunny', icon: 'hot', wind: '8 km/h', humidity: '50%', feelsLike: '31°', rainChance: '5%', alert: true } ]; // Weather icons const weatherIcons = { 'sun': `<circle cx="80" cy="80" r="40" fill="#FFD600"/> <path d="M80 20V10" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M80 150V140" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M20 80H10" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M150 80H140" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M36.9 36.9L30 30" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M130 130L123.1 123.1" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M36.9 123.1L30 130" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/> <path d="M130 30L123.1 36.9" stroke="#FFD600" stroke-width="6" stroke-linecap="round"/>`, 'partly-cloudy': `<circle cx="60" cy="70" r="30" fill="#FFD600"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M110 130H50C39 130 30 121 30 110C30 99 39 90 50 90C50 73.5 63.5 60 80 60C96.5 60 110 73.5 110 90C121 90 130 99 130 110C130 121 121 130 110 130Z" fill="white" fill-opacity="0.8"/>`, 'rain': `<path fill-rule="evenodd" clip-rule="evenodd" d="M110 100H50C39 100 30 91 30 80C30 69 39 60 50 60C50 43.5 63.5 30 80 30C96.5 30 110 43.5 110 60C121 60 130 69 130 80C130 91 121 100 110 100Z" fill="white" fill-opacity="0.8"/> <path d="M60 110L50 130" stroke="#5C9CE5" stroke-width="6" stroke-linecap="round"/> <path d="M80 110L70 130" stroke="#5C9CE5" stroke-width="6" stroke-linecap="round"/> <path d="M100 110L90 130" stroke="#5C9CE5" stroke-width="6" stroke-linecap="round"/> <path d="M70 120L60 140" stroke="#5C9CE5" stroke-width="6" stroke-linecap="round"/> <path d="M90 120L80 140" stroke="#5C9CE5" stroke-width="6" stroke-linecap="round"/>`, 'thunderstorm': `<path fill-rule="evenodd" clip-rule="evenodd" d="M110 90H50C39 90 30 81 30 70C30 59 39 50 50 50C50 33.5 63.5 20 80 20C96.5 20 110 33.5 110 50C121 50 130 59 130 70C130 81 121 90 110 90Z" fill="#9DA3B3" fill-opacity="0.8"/> <path d="M80 90L60 120L80 120L60 150" stroke="#FFD600" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/> <path d="M100 90L80 120L100 120L80 150" stroke="#FFD600" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"/> <path d="M60 100L50 120" stroke="#5C9CE5" stroke-width="6" stroke-linecap="round"/> <path d="M110 100L100 120" stroke="#5C9CE5" stroke-width="6" stroke-linecap="round"/>`, 'hot': `<circle cx="80" cy="80" r="50" fill="#FF7E00"/> <path d="M80 20V10" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/> <path d="M80 150V140" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/> <path d="M20 80H10" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/> <path d="M150 80H140" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/> <path d="M36.9 36.9L26.9 26.9" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/> <path d="M133.1 133.1L123.1 123.1" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/> <path d="M36.9 123.1L26.9 133.1" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/> <path d="M133.1 26.9L123.1 36.9" stroke="#FF7E00" stroke-width="8" stroke-linecap="round"/>` }; // Update weather data function updateWeather() { const scenario = weatherScenarios[Math.floor(Math.random() * weatherScenarios.length)]; document.getElementById('temperature').textContent = scenario.temp; document.getElementById('weather-condition').textContent = scenario.condition; document.getElementById('weatherSVG').innerHTML = weatherIcons[scenario.icon]; document.getElementById('wind-speed').textContent = scenario.wind; document.getElementById('humidity').textContent = scenario.humidity; document.getElementById('feels-like').textContent = scenario.feelsLike; document.getElementById('rain-chance').textContent = scenario.rainChance; // Weather alert const alertElement = document.getElementById('weather-alert'); if (scenario.alert) { alertElement.style.display = 'flex'; // Set alert based on condition let alertText = ''; if (scenario.icon === 'rain') { alertText = 'HEAVY RAIN ADVISORY: Expect localized flooding in low-lying areas.'; } else if (scenario.icon === 'thunderstorm') { alertText = 'SEVERE THUNDERSTORM WARNING: Seek shelter immediately.'; } else if (scenario.icon === 'hot') { alertText = 'EXTREME HEAT WARNING: Stay hydrated and avoid prolonged outdoor activity.'; } alertElement.querySelector('.alert-text').textContent = alertText; } else { alertElement.style.display = 'none'; } // Update background gradient based on weather let bgGradient = ''; if (scenario.icon === 'sun' || scenario.icon === 'hot') { bgGradient = 'linear-gradient(135deg, #1e3c72 0%, #2a5298 100%)'; } else if (scenario.icon === 'partly-cloudy') { bgGradient = 'linear-gradient(135deg, #3c4377 0%, #5b6caa 100%)'; } else if (scenario.icon === 'rain') { bgGradient = 'linear-gradient(135deg, #334d50 0%, #4a746a 100%)'; } else if (scenario.icon === 'thunderstorm') { bgGradient = 'linear-gradient(135deg, #232526 0%, #414345 100%)'; } document.querySelector('.widget-container').style.background = bgGradient; } updateWeather(); // Forecast scrolling animation const forecastContainer = document.getElementById('forecast-container'); let forecastPosition = 0; const itemWidth = 155; // Width + margin const totalItems = document.querySelectorAll('.forecast-item').length; const visibleItems = Math.floor(document.querySelector('.forecast-wrapper').offsetWidth / itemWidth); function scrollForecast() { forecastPosition++; if (forecastPosition > totalItems - visibleItems) { forecastPosition = 0; } forecastContainer.style.transform = `translateX(-${forecastPosition * itemWidth}px)`; } // Auto-update the forecast scrolling and weather data setInterval(scrollForecast, 5000); setInterval(updateWeather, 15000); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Serenity Resort Weather Portal</title> <style> @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=Cormorant+Garamond:wght@300;400;600&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } :root { --sand: #e6ddd0; --sage: #b5c9b7; --ocean: #6a8d92; --dusk: #4a5759; --night: #2a3638; --gold: #c9b18b; } body { font-family: 'Cormorant Garamond', serif; background: linear-gradient(135deg, var(--sand), var(--sage)); color: var(--night); width: 100%; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; } .resort-portal { width: 680px; height: 680px; background-color: rgba(255, 255, 255, 0.85); backdrop-filter: blur(10px); border-radius: 10px; box-shadow: 0 25px 50px -12px rgba(74, 87, 89, 0.25); overflow: hidden; position: relative; display: flex; flex-direction: column; } .portal-header { padding: 2rem; text-align: center; border-bottom: 1px solid rgba(201, 177, 139, 0.3); } h1 { font-family: 'Playfair Display', serif; font-weight: 700; font-size: 2.2rem; color: var(--night); margin-bottom: 0.5rem; letter-spacing: 0.5px; } .tagline { font-style: italic; font-size: 1.1rem; color: var(--ocean); margin-bottom: 1rem; font-weight: 300; } .current-date { font-family: 'Cormorant Garamond', serif; font-size: 1rem; color: var(--dusk); letter-spacing: 1px; } .portal-main { display: flex; flex: 1; position: relative; } .location-sidebar { width: 250px; padding: 2rem; border-right: 1px solid rgba(201, 177, 139, 0.3); background-color: rgba(229, 221, 208, 0.3); } .location-title { font-family: 'Playfair Display', serif; font-size: 1.4rem; margin-bottom: 1.5rem; color: var(--night); position: relative; } .location-title::after { content: ''; position: absolute; bottom: -8px; left: 0; width: 30px; height: 1px; background-color: var(--gold); } .location-list { list-style: none; } .location-item { margin-bottom: 1.2rem; cursor: pointer; transition: all 0.3s ease; padding: 0.5rem 0; position: relative; overflow: hidden; } .location-item::before { content: ''; position: absolute; bottom: 0; left: 0; width: 0; height: 1px; background-color: var(--gold); transition: width 0.4s ease; } .location-item:hover::before { width: 100%; } .location-item.active { color: var(--dusk); font-weight: 600; padding-left: 10px; } .location-item.active::before { width: 100%; } .weather-display { flex: 1; padding: 2rem; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; transition: all 0.5s ease; opacity: 0; transform: translateY(20px); } .weather-display.active { opacity: 1; transform: translateY(0); } .weather-location { font-family: 'Playfair Display', serif; font-size: 1.8rem; margin-bottom: 0.5rem; color: var(--night); } .weather-icon { width: 120px; height: 120px; margin: 1rem 0; position: relative; } .weather-icon svg { width: 100%; height: 100%; filter: drop-shadow(0 5px 15px rgba(106, 141, 146, 0.3)); } .temperature { font-size: 3.5rem; font-weight: 600; color: var(--night); margin: 0.5rem 0; position: relative; } .weather-description { font-size: 1.3rem; color: var(--ocean); margin-bottom: 2rem; font-style: italic; } .weather-details { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; width: 100%; margin-top: 1rem; } .detail-item { display: flex; flex-direction: column; align-items: center; } .detail-label { font-size: 0.9rem; color: var(--dusk); margin-bottom: 0.3rem; letter-spacing: 1px; text-transform: uppercase; } .detail-value { font-size: 1.2rem; color: var(--night); font-weight: 600; } .recommendation { margin-top: 2rem; padding: 1rem; background-color: rgba(181, 201, 183, 0.2); border-radius: 6px; border-left: 3px solid var(--gold); } .recommendation-title { font-family: 'Playfair Display', serif; font-size: 1.1rem; margin-bottom: 0.5rem; color: var(--night); } .recommendation-text { font-size: 1rem; color: var(--ocean); line-height: 1.5; } .portal-footer { padding: 1rem 2rem; border-top: 1px solid rgba(201, 177, 139, 0.3); text-align: center; font-size: 0.9rem; color: var(--dusk); } .refresh-weather { background: none; border: none; color: var(--gold); text-decoration: underline; cursor: pointer; font-family: 'Cormorant Garamond', serif; font-size: 0.9rem; transition: all 0.3s ease; } .refresh-weather:hover { color: var(--ocean); } .ambient-background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; opacity: 0.15; transition: opacity 1s ease; } @media (max-width: 700px) { .resort-portal { width: 100%; height: 100%; border-radius: 0; } .portal-main { flex-direction: column; } .location-sidebar { width: 100%; border-right: none; border-bottom: 1px solid rgba(201, 177, 139, 0.3); padding: 1rem; } .location-list { display: flex; flex-wrap: wrap; gap: 0.5rem; } .location-item { padding: 0.3rem 0.7rem; margin-bottom: 0.5rem; border: 1px solid transparent; } .location-item.active { border: 1px solid var(--gold); border-radius: 4px; padding: 0.3rem 0.7rem; } .weather-display { padding: 1rem; } .weather-details { grid-template-columns: repeat(2, 1fr); } .portal-header h1 { font-size: 1.8rem; } .temperature { font-size: 2.8rem; } } .wave-decoration { position: absolute; bottom: 0; left: 0; width: 100%; height: 120px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%23b5c9b7' fill-opacity='0.2' d='M0,128L48,133.3C96,139,192,149,288,138.7C384,128,480,96,576,96C672,96,768,128,864,138.7C960,149,1056,139,1152,133.3C1248,128,1344,128,1392,128L1440,128L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z'%3E%3C/path%3E%3C/svg%3E"); background-size: cover; opacity: 0.5; z-index: -1; } .time-of-day { position: absolute; top: 2rem; right: 2rem; font-family: 'Playfair Display', serif; font-size: 1rem; color: var(--ocean); display: flex; align-items: center; gap: 0.5rem; } .circle-indicator { width: 12px; height: 12px; border-radius: 50%; background-color: var(--gold); box-shadow: 0 0 10px rgba(201, 177, 139, 0.5); } @keyframes shimmer { 0% { opacity: 0.5; } 50% { opacity: 1; } 100% { opacity: 0.5; } } .location-item.shimmer { position: relative; overflow: hidden; } .location-item.shimmer::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); animation: shimmer 2s infinite; transform: translateX(-100%); } .location-item:hover.shimmer::after { animation: shimmer 1s infinite; } @keyframes fade-in { 0% { opacity: 0; transform: translateY(10px); } 100% { opacity: 1; transform: translateY(0); } } .fade-in { animation: fade-in 0.8s forwards; } .fade-in-delay-1 { opacity: 0; animation: fade-in 0.8s forwards; animation-delay: 0.2s; } .fade-in-delay-2 { opacity: 0; animation: fade-in 0.8s forwards; animation-delay: 0.4s; } .fade-in-delay-3 { opacity: 0; animation: fade-in 0.8s forwards; animation-delay: 0.6s; } </style> </head> <body> <div class="resort-portal"> <div class="portal-header"> <h1>Serenity Resort Weather</h1> <p class="tagline">Curated climate insights for your perfect getaway</p> <p class="current-date" id="current-date"></p> </div> <div class="portal-main"> <div class="location-sidebar"> <h2 class="location-title">Our Destinations</h2> <ul class="location-list"> <li class="location-item active shimmer" data-location="maldives">Maldives Private Island</li> <li class="location-item shimmer" data-location="amalfi">Amalfi Coast Retreat</li> <li class="location-item shimmer" data-location="bali">Bali Beachfront Villa</li> <li class="location-item shimmer" data-location="swiss">Swiss Alpine Chalet</li> <li class="location-item shimmer" data-location="santorini">Santorini Cliffside</li> </ul> <div class="time-of-day"> <div class="circle-indicator"></div> <span id="time-display">Local Time</span> </div> </div> <div class="weather-display active" id="weather-display"> <!-- Weather content will be dynamically populated --> </div> <div class="wave-decoration"></div> </div> <div class="portal-footer"> <p>Weather data updated hourly. <button class="refresh-weather" id="refresh-weather">Refresh Now</button></p> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Set current date const currentDate = new Date(); const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; document.getElementById('current-date').textContent = currentDate.toLocaleDateString('en-US', options); // Update local time display function updateLocalTime() { const now = new Date(); const hours = now.getHours(); const minutes = now.getMinutes(); const formattedMinutes = minutes < 10 ? `0${minutes}` : minutes; const period = hours >= 12 ? 'PM' : 'AM'; const formattedHours = hours % 12 || 12; document.getElementById('time-display').textContent = `${formattedHours}:${formattedMinutes} ${period}`; // Change circle indicator color based on time of day const circleIndicator = document.querySelector('.circle-indicator'); if (hours >= 6 && hours < 12) { // Morning circleIndicator.style.backgroundColor = '#e6c787'; } else if (hours >= 12 && hours < 17) { // Afternoon circleIndicator.style.backgroundColor = '#e6a587'; } else if (hours >= 17 && hours < 20) { // Evening circleIndicator.style.backgroundColor = '#a587e6'; } else { // Night circleIndicator.style.backgroundColor = '#4a5759'; } } updateLocalTime(); setInterval(updateLocalTime, 60000); // Update every minute // Weather data for each location (simulated) const weatherData = { maldives: { location: 'Maldives Private Island', temperature: 29, description: 'Sunny with gentle ocean breezes', humidity: '75%', wind: '12 km/h', uv: 'High', icon: 'sunny', localTime: 'GMT+5', recommendation: 'Perfect conditions for snorkeling or our sunset champagne cruise. Book our coral reef excursion for optimal visibility today.' }, amalfi: { location: 'Amalfi Coast Retreat', temperature: 24, description: 'Clear skies with Mediterranean charm', humidity: '62%', wind: '8 km/h', uv: 'Moderate', icon: 'partly-cloudy', localTime: 'GMT+2', recommendation: 'Ideal day for our private yacht tour to Capri. Consider booking our evening rooftop dining with the sommelier's special selection.' }, bali: { location: 'Bali Beachfront Villa', temperature: 27, description: 'Warm with passing tropical showers', humidity: '80%', wind: '6 km/h', uv: 'Moderate', icon: 'rain', localTime: 'GMT+8', recommendation: 'Morning clear for waterfall hike. Afternoon spa treatments recommended during brief showers. Reserve our candlelit beach dinner after sunset.' }, swiss: { location: 'Swiss Alpine Chalet', temperature: 4, description: 'Fresh snowfall with crystal clear skies', humidity: '85%', wind: '15 km/h', uv: 'Low', icon: 'snow', localTime: 'GMT+1', recommendation: 'Pristine skiing conditions on north-facing slopes. Our heated infinity pool with mountain views is particularly spectacular today.' }, santorini: { location: 'Santorini Cliffside', temperature: 22, description: 'Gentle breeze with panoramic horizon', humidity: '58%', wind: '14 km/h', uv: 'Moderate', icon: 'clear', localTime: 'GMT+3', recommendation: 'Exceptional visibility for our caldera sunset tour. Reserve your private terrace dinner to enjoy the golden hour and stargazing.' } }; // Icons for weather display const weatherIcons = { 'sunny': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="5" stroke="#e6a587" stroke-width="2"/> <path d="M12 2V4" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> <path d="M12 20V22" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> <path d="M4 12L2 12" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> <path d="M22 12L20 12" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> <path d="M19.7782 4.22183L18.364 5.63604" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> <path d="M5.63608 18.364L4.22187 19.7782" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> <path d="M19.7782 19.7782L18.364 18.364" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> <path d="M5.63608 5.63603L4.22187 4.22182" stroke="#e6a587" stroke-width="2" stroke-linecap="round"/> </svg>`, 'partly-cloudy': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3 15H16.5C18.9853 15 21 12.9853 21 10.5C21 8.01472 18.9853 6 16.5 6C16.1717 6 15.8516 6.03111 15.5425 6.0897C14.8596 4.27041 13.0722 3 11 3C8.23858 3 6 5.23858 6 8C6 8.11179 6.00459 8.22268 6.01379 8.33254C4.26863 8.88168 3 10.5435 3 12.5C3 13.1426 3.13076 13.7548 3.36994 14.3069" stroke="#6a8d92" stroke-width="2" stroke-linecap="round"/> <path d="M7 13.0002L7 15.0002" stroke="#6a8d92" stroke-width="2" stroke-linecap="round"/> <path d="M11 13.0002L11 18.0002" stroke="#6a8d92" stroke-width="2" stroke-linecap="round"/> <path d="M15 13.0002L15 15.0002" stroke="#6a8d92" stroke-width="2" stroke-linecap="round"/> </svg>`, 'rain': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M3 13.6622C3 17.0328 5.73716 19.7699 9.10778 19.7699H12.7437C16.1143 19.7699 18.8515 17.0328 18.8515 13.6622C18.8515 10.2916 16.1143 7.5544 12.7437 7.5544C12.4532 7.5544 12.1672 7.57745 11.8878 7.62224C10.9387 5.01273 8.48075 3.1465 5.63432 3.1465C2.01939 3.1465 -0.947266 6.60051 3.0026 9.77675" stroke="#6a8d92" stroke-width="2" stroke-linecap="round"/> <path d="M10 14L9 18" stroke="#6a8d92" stroke-width="2" stroke-linecap="round"/> <path d="M15 14L14 18" stroke="#6a8d92" stroke-width="2" stroke-linecap="round"/> </svg>`, 'snow': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 3V21" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round"/> <path d="M9 4.5L12 3L15 4.5" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M9 19.5L12 21L15 19.5" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M3 10.5L21 13.5" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round"/> <path d="M4.5 7.5L3 10.5L6 12" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M19.5 16.5L21 13.5L18 12" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M21 10.5L3 13.5" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round"/> <path d="M19.5 7.5L21 10.5L18 12" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M4.5 16.5L3 13.5L6 12" stroke="#b5c9b7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg>`, 'clear': `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="7" stroke="#c9b18b" stroke-width="2"/> <path d="M12 2V4" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> <path d="M12 20V22" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> <path d="M4 12L2 12" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> <path d="M22 12L20 12" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> <path d="M19.7782 4.22183L18.364 5.63604" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> <path d="M5.63608 18.364L4.22187 19.7782" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> <path d="M19.7782 19.7782L18.364 18.364" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> <path d="M5.63608 5.63603L4.22187 4.22182" stroke="#c9b18b" stroke-width="2" stroke-linecap="round"/> </svg>` }; // Default location let currentLocation = 'maldives'; updateWeatherDisplay(currentLocation); // Location selection const locationItems = document.querySelectorAll('.location-item'); locationItems.forEach(item => { item.addEventListener('click', function() { // Remove active class from all locations locationItems.forEach(loc => loc.classList.remove('active')); // Add active class to selected location this.classList.add('active'); // Update weather display const location = this.getAttribute('data-location'); currentLocation = location; // Animate transition const weatherDisplay = document.getElementById('weather-display'); weatherDisplay.classList.remove('active'); setTimeout(() => { updateWeatherDisplay(location); weatherDisplay.classList.add('active'); }, 300); }); }); // Refresh button document.getElementById('refresh-weather').addEventListener('click', function() { const weatherDisplay = document.getElementById('weather-display'); weatherDisplay.classList.remove('active'); setTimeout(() => { updateWeatherDisplay(currentLocation); weatherDisplay.classList.add('active'); }, 300); }); // Update weather display function updateWeatherDisplay(location) { const data = weatherData[location]; const weatherDisplay = document.getElementById('weather-display'); weatherDisplay.innerHTML = ` <h2 class="weather-location fade-in">${data.location}</h2> <div class="weather-icon fade-in-delay-1"> ${weatherIcons[data.icon]} </div> <div class="temperature fade-in-delay-1">${data.temperature}°C</div> <div class="weather-description fade-in-delay-1">${data.description}</div> <div class="weather-details"> <div class="detail-item fade-in-delay-2"> <span class="detail-label">Humidity</span> <span class="detail-value">${data.humidity}</span> </div> <div class="detail-item fade-in-delay-2"> <span class="detail-label">Wind</span> <span class="detail-value">${data.wind}</span> </div> <div class="detail-item fade-in-delay-2"> <span class="detail-label">UV Index</span> <span class="detail-value">${data.uv}</span> </div> </div> <div class="recommendation fade-in-delay-3"> <h3 class="recommendation-title">Concierge Recommendation</h3> <p class="recommendation-text">${data.recommendation}</p> </div> `; } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Weather Social Widget</title> <style> :root { --primary: #FF6D92; --secondary: #4E54FF; --tertiary: #33D6A6; --dark: #2A2B5F; --light: #F5F7FF; --gradient1: linear-gradient(135deg, #FF6D92, #FF9671); --gradient2: linear-gradient(135deg, #4E54FF, #6A7CFF); --gradient3: linear-gradient(135deg, #33D6A6, #6DFFE1); --shadow: 0 10px 30px rgba(74, 85, 255, 0.15); --font-main: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-main); background-color: var(--light); color: var(--dark); width: 100%; height: 100%; overflow: hidden; display: flex; justify-content: center; align-items: center; } @font-face { font-family: 'Outfit'; src: url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;700&display=swap'); font-display: swap; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; padding: 20px; position: relative; } .widget { background: white; border-radius: 24px; overflow: hidden; box-shadow: var(--shadow); height: 100%; display: flex; flex-direction: column; position: relative; } .header { padding: 24px 30px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid rgba(0, 0, 0, 0.05); } .logo { display: flex; align-items: center; } .logo-icon { width: 36px; height: 36px; background: var(--gradient1); border-radius: 10px; display: flex; align-items: center; justify-content: center; margin-right: 12px; } .logo-text { font-weight: 700; font-size: 18px; background: var(--gradient1); -webkit-background-clip: text; background-clip: text; color: transparent; } .share-btn { background: var(--light); border: none; border-radius: 40px; padding: 8px 16px; display: flex; align-items: center; gap: 8px; font-weight: 500; font-size: 14px; color: var(--dark); cursor: pointer; transition: all 0.3s ease; } .share-btn:hover { background: var(--dark); color: white; } .share-btn svg { width: 16px; height: 16px; } .location-selector { display: flex; align-items: center; gap: 8px; margin: 20px 30px; padding: 14px 18px; background: var(--light); border-radius: 16px; cursor: pointer; transition: all 0.3s ease; } .location-selector:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); } .location-text { font-weight: 600; font-size: 16px; } .location-arrow { margin-left: auto; transform: rotate(0deg); transition: transform 0.3s ease; } .weather-cards { display: flex; gap: 15px; padding: 0 30px; margin-bottom: 25px; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; -ms-overflow-style: none; } .weather-cards::-webkit-scrollbar { display: none; } .weather-card { flex: 0 0 auto; width: 120px; height: 160px; border-radius: 20px; padding: 20px; display: flex; flex-direction: column; align-items: center; justify-content: space-between; scroll-snap-align: start; position: relative; overflow: hidden; transition: transform 0.3s ease, box-shadow 0.3s ease; cursor: pointer; } .weather-card:hover { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.08); } .weather-card.today { background: var(--gradient1); color: white; } .weather-card.tomorrow { background: var(--gradient2); color: white; } .weather-card.day-after { background: var(--gradient3); color: white; } .future-day { background: var(--light); color: var(--dark); } .day-name { font-size: 14px; font-weight: 500; margin-bottom: 5px; } .weather-temp { font-size: 24px; font-weight: 700; margin: 10px 0; } .weather-icon { width: 48px; height: 48px; margin-bottom: 5px; } .graph-section { flex: 1; padding: 0 30px; margin-bottom: 20px; position: relative; } .graph-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .graph-title { font-size: 18px; font-weight: 600; } .graph-toggles { display: flex; gap: 10px; } .graph-toggle { background: none; border: none; padding: 6px 12px; border-radius: 20px; font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; } .graph-toggle.active { background: var(--primary); color: white; } .graph-container { position: relative; height: 160px; width: 100%; } canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .social-actions { padding: 0 30px 20px; } .action-title { font-size: 14px; font-weight: 500; margin-bottom: 12px; color: #666; } .action-buttons { display: flex; gap: 10px; } .social-btn { flex: 1; padding: 12px; border-radius: 14px; border: none; font-weight: 600; font-size: 14px; display: flex; align-items: center; justify-content: center; gap: 8px; cursor: pointer; transition: all 0.3s ease; } .social-btn svg { width: 20px; height: 20px; } .social-btn.instagram { background: linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888); color: white; } .social-btn.twitter { background: #1DA1F2; color: white; } .social-btn.facebook { background: #4267B2; color: white; } .social-btn:hover { transform: translateY(-3px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } .tooltip { position: absolute; display: none; background: rgba(255, 255, 255, 0.95); border-radius: 8px; padding: 10px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); font-size: 14px; pointer-events: none; z-index: 100; transition: opacity 0.3s ease; } .chart-dot { position: absolute; width: 8px; height: 8px; border-radius: 50%; background-color: var(--primary); transform: translate(-50%, -50%); z-index: 10; pointer-events: none; box-shadow: 0 0 0 4px rgba(255, 109, 146, 0.3); opacity: 0; transition: opacity 0.3s ease; } /* Animations */ @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 109, 146, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(255, 109, 146, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 109, 146, 0); } } @keyframes fadeUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .weather-card { animation: fadeUp 0.5s ease forwards; } .weather-card:nth-child(2) { animation-delay: 0.1s; } .weather-card:nth-child(3) { animation-delay: 0.2s; } .weather-card:nth-child(4) { animation-delay: 0.3s; } .weather-card:nth-child(5) { animation-delay: 0.4s; } .swipe-indicator { position: absolute; bottom: 20px; right: 15px; background: rgba(255, 255, 255, 0.8); padding: 8px 12px; border-radius: 20px; font-size: 12px; display: flex; align-items: center; gap: 5px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); opacity: 0.8; animation: fadeIn 1s ease 2s forwards, fadeOut 1s ease 6s forwards; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 0.8; } } @keyframes fadeOut { from { opacity: 0.8; } to { opacity: 0; } } /* Media Queries */ @media (max-width: 500px) { .header { padding: 20px; } .location-selector, .graph-section, .social-actions { padding-left: 20px; padding-right: 20px; } .weather-cards { padding: 0 20px; } .weather-card { width: 110px; padding: 15px; } .social-btn { font-size: 13px; padding: 10px; } } /* Pattern background behind cards */ .weather-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23ffffff' fill-opacity='0.1' fill-rule='evenodd'/%3E%3C/svg%3E"); opacity: 0.5; z-index: 0; } .weather-card > * { position: relative; z-index: 1; } </style> </head> <body> <div class="container"> <div class="widget"> <div class="header"> <div class="logo"> <div class="logo-icon"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" fill="white" /> </svg> </div> <div class="logo-text">WeatherShare</div> </div> <button class="share-btn" id="main-share-btn"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18 8C19.6569 8 21 6.65685 21 5C21 3.34315 19.6569 2 18 2C16.3431 2 15 3.34315 15 5C15 5.12548 15.0077 5.24917 15.0227 5.37061L8.08261 9.00884C7.54354 8.40752 6.8157 8 6 8C4.34315 8 3 9.34315 3 11C3 12.6569 4.34315 14 6 14C6.8157 14 7.54354 13.5925 8.08261 12.9912L15.0227 16.6294C15.0077 16.7508 15 16.8745 15 17C15 18.6569 16.3431 20 18 20C19.6569 20 21 18.6569 21 17C21 15.3431 19.6569 14 18 14C17.1843 14 16.4565 14.4075 15.9174 15.0088L8.97733 11.3706C8.99229 11.2492 9 11.1255 9 11C9 10.8745 8.99229 10.7508 8.97733 10.6294L15.9174 6.99116C16.4565 7.59248 17.1843 8 18 8Z" fill="currentColor" /> </svg> Share </button> </div> <div class="location-selector" id="location-selector"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 2C8.13 2 5 5.13 5 9C5 14.25 12 22 12 22C12 22 19 14.25 19 9C19 5.13 15.87 2 12 2ZM12 11.5C10.62 11.5 9.5 10.38 9.5 9C9.5 7.62 10.62 6.5 12 6.5C13.38 6.5 14.5 7.62 14.5 9C14.5 10.38 13.38 11.5 12 11.5Z" fill="#4E54FF" /> </svg> <span class="location-text">San Francisco, CA</span> <svg class="location-arrow" width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M7 10L12 15L17 10" stroke="#2A2B5F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> </div> <div class="weather-cards" id="weather-cards"> <div class="weather-card today"> <div class="day-name">Today</div> <div class="weather-icon"> <svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="5" fill="white" /> <path d="M12 2V4" stroke="white" stroke-width="2" stroke-linecap="round" /> <path d="M12 20V22" stroke="white" stroke-width="2" stroke-linecap="round" /> <path d="M4.93 4.93L6.34 6.34" stroke="white" stroke-width="2" stroke-linecap="round" /> <path d="M17.66 17.66L19.07 19.07" stroke="white" stroke-width="2" stroke-linecap="round" /> <path d="M2 12H4" stroke="white" stroke-width="2" stroke-linecap="round" /> <path d="M20 12H22" stroke="white" stroke-width="2" stroke-linecap="round" /> <path d="M6.34 17.66L4.93 19.07" stroke="white" stroke-width="2" stroke-linecap="round" /> <path d="M19.07 4.93L17.66 6.34" stroke="white" stroke-width="2" stroke-linecap="round" /> </svg> </div> <div class="weather-temp">72°F</div> </div> <div class="weather-card tomorrow"> <div class="day-name">Tomorrow</div> <div class="weather-icon"> <svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17 7H7C4.79086 7 3 8.79086 3 11C3 13.2091 4.79086 15 7 15H17C19.2091 15 21 13.2091 21 11C21 8.79086 19.2091 7 17 7Z" fill="white" /> <path d="M5 15.2V15.3C5 16.7912 6.20883 18 7.7 18H16.3C17.7912 18 19 16.7912 19 15.3V15.2" stroke="white" stroke-width="1.5" stroke-linecap="round" /> </svg> </div> <div class="weather-temp">68°F</div> </div> <div class="weather-card day-after"> <div class="day-name">Friday</div> <div class="weather-icon"> <svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17 7H7C4.79086 7 3 8.79086 3 11C3 13.2091 4.79086 15 7 15H17C19.2091 15 21 13.2091 21 11C21 8.79086 19.2091 7 17 7Z" fill="white" /> <path d="M7 15L6 18" stroke="white" stroke-width="1.5" stroke-linecap="round" /> <path d="M15 15L14 18" stroke="white" stroke-width="1.5" stroke-linecap="round" /> <path d="M11 15L10 18" stroke="white" stroke-width="1.5" stroke-linecap="round" /> </svg> </div> <div class="weather-temp">65°F</div> </div> <div class="weather-card future-day"> <div class="day-name">Saturday</div> <div class="weather-icon"> <svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <circle cx="12" cy="12" r="5" fill="#4E54FF" /> <path d="M12 2V4" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> <path d="M12 20V22" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> <path d="M4.93 4.93L6.34 6.34" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> <path d="M17.66 17.66L19.07 19.07" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> <path d="M2 12H4" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> <path d="M20 12H22" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> <path d="M6.34 17.66L4.93 19.07" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> <path d="M19.07 4.93L17.66 6.34" stroke="#4E54FF" stroke-width="2" stroke-linecap="round" /> </svg> </div> <div class="weather-temp">70°F</div> </div> <div class="weather-card future-day"> <div class="day-name">Sunday</div> <div class="weather-icon"> <svg width="48" height="48" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M17 7H7C4.79086 7 3 8.79086 3 11C3 13.2091 4.79086 15 7 15H17C19.2091 15 21 13.2091 21 11C21 8.79086 19.2091 7 17 7Z" fill="#4E54FF" /> <path d="M7 15L6 18" stroke="#4E54FF" stroke-width="1.5" stroke-linecap="round" /> <path d="M15 15L14 18" stroke="#4E54FF" stroke-width="1.5" stroke-linecap="round" /> <path d="M11 15L10 18" stroke="#4E54FF" stroke-width="1.5" stroke-linecap="round" /> </svg> </div> <div class="weather-temp">67°F</div> </div> </div> <div class="swipe-indicator"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M7 3L2 8L7 13" stroke="#2A2B5F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M17 3L22 8L17 13" stroke="#2A2B5F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> Swipe for more </div> <div class="graph-section"> <div class="graph-header"> <div class="graph-title">Temperature Trend</div> <div class="graph-toggles"> <button class="graph-toggle active" data-type="temp">Temperature</button> <button class="graph-toggle" data-type="precip">Precipitation</button> </div> </div> <div class="graph-container"> <canvas id="weather-chart"></canvas> <div class="chart-dot" id="chart-dot"></div> <div class="tooltip" id="tooltip"></div> </div> </div> <div class="social-actions"> <div class="action-title">Share your weather with friends</div> <div class="action-buttons"> <button class="social-btn instagram"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M12 2C14.717 2 15.056 2.01 16.122 2.06C17.187 2.11 17.912 2.277 18.55 2.525C19.21 2.779 19.766 3.123 20.322 3.678C20.8305 4.1779 21.224 4.78259 21.475 5.45C21.722 6.087 21.89 6.813 21.94 7.878C21.987 8.944 22 9.283 22 12C22 14.717 21.99 15.056 21.94 16.122C21.89 17.187 21.722 17.912 21.475 18.55C21.2247 19.2178 20.8311 19.8226 20.322 20.322C19.822 20.8303 19.2173 21.2238 18.55 21.475C17.913 21.722 17.187 21.89 16.122 21.94C15.056 21.987 14.717 22 12 22C9.283 22 8.944 21.99 7.878 21.94C6.813 21.89 6.088 21.722 5.45 21.475C4.78233 21.2245 4.17753 20.8309 3.678 20.322C3.16941 19.8222 2.77593 19.2175 2.525 18.55C2.277 17.913 2.11 17.187 2.06 16.122C2.013 15.056 2 14.717 2 12C2 9.283 2.01 8.944 2.06 7.878C2.11 6.812 2.277 6.088 2.525 5.45C2.77524 4.78218 3.1688 4.17732 3.678 3.678C4.17767 3.16923 4.78243 2.77573 5.45 2.525C6.088 2.277 6.812 2.11 7.878 2.06C8.944 2.013 9.283 2 12 2ZM12 7C10.6739 7 9.40215 7.52678 8.46447 8.46447C7.52678 9.40215 7 10.6739 7 12C7 13.3261 7.52678 14.5979 8.46447 15.5355C9.40215 16.4732 10.6739 17 12 17C13.3261 17 14.5979 16.4732 15.5355 15.5355C16.4732 14.5979 17 13.3261 17 12C17 10.6739 16.4732 9.40215 15.5355 8.46447C14.5979 7.52678 13.3261 7 12 7ZM18.5 6.75C18.5 6.41848 18.3683 6.10054 18.1339 5.86612C17.8995 5.6317 17.5815 5.5 17.25 5.5C16.9185 5.5 16.6005 5.6317 16.3661 5.86612C16.1317 6.10054 16 6.41848 16 6.75C16 7.08152 16.1317 7.39946 16.3661 7.63388C16.6005 7.8683 16.9185 8 17.25 8C17.5815 8 17.8995 7.8683 18.1339 7.63388C18.3683 7.39946 18.5 7.08152 18.5 6.75ZM12 9C12.7956 9 13.5587 9.31607 14.1213 9.87868C14.6839 10.4413 15 11.2044 15 12C15 12.7956 14.6839 13.5587 14.1213 14.1213C13.5587 14.6839 12.7956 15 12 15C11.2044 15 10.4413 14.6839 9.87868 14.1213C9.31607 13.5587 9 12.7956 9 12C9 11.2044 9.31607 10.4413 9.87868 9.87868C10.4413 9.31607 11.2044 9 12 9Z" fill="white" /> </svg> Instagram </button> <button class="social-btn twitter"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M22 4.01C21.0424 4.67548 19.9821 5.19211 18.86 5.54C18.2577 4.84751 17.4573 4.34669 16.567 4.12391C15.6767 3.90113 14.7395 3.96725 13.8821 4.3143C13.0247 4.66135 12.2884 5.27575 11.773 6.07388C11.2575 6.87201 10.9877 7.81056 11 8.77V9.77C9.24557 9.81837 7.50485 9.40908 5.93132 8.58334C4.35779 7.7576 3.00249 6.54434 2 5.04C2 5.04 -2 13.04 8 17.04C5.94053 18.4308 3.48716 19.1412 1 19.04C11 24.04 23 19.04 23 8.74C22.9991 8.48797 22.9723 8.23691 22.92 7.99C23.9406 6.98106 24.6608 5.6626 25 4.24L22 4.01Z" fill="white" /> </svg> Twitter </button> <button class="social-btn facebook"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M18 2H15C13.6739 2 12.4021 2.52678 11.4645 3.46447C10.5268 4.40215 10 5.67392 10 7V10H7V14H10V22H14V14H17L18 10H14V7C14 6.73478 14.1054 6.48043 14.2929 6.29289C14.4804 6.10536 14.7348 6 15 6H18V2Z" fill="white" /> </svg> Facebook </button> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Initialize chart with temperature data const tempData = { labels: ['6AM', '9AM', '12PM', '3PM', '6PM', '9PM'], values: [62, 65, 71, 72, 70, 67] }; const precipData = { labels: ['6AM', '9AM', '12PM', '3PM', '6PM', '9PM'], values: [10, 20, 15, 40, 30, 25] }; let currentData = tempData; let activeType = 'temp'; const canvas = document.getElementById('weather-chart'); const ctx = canvas.getContext('2d'); const chartDot = document.getElementById('chart-dot'); const tooltip = document.getElementById('tooltip'); // Set canvas dimensions for higher resolution const displayWidth = canvas.clientWidth; const displayHeight = canvas.clientHeight; canvas.width = displayWidth * 2; canvas.height = displayHeight
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CycleWeather Pro</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f5f7fa; display: flex; justify-content: center; align-items: center; height: 700px; width: 700px; overflow: hidden; } .app-container { width: 100%; max-width: 680px; height: 680px; background: linear-gradient(145deg, #ffffff, #f0f4f8); border-radius: 30px; box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07); padding: 25px; position: relative; overflow: hidden; } .app-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .app-title { font-size: 28px; font-weight: 700; color: #2D3748; position: relative; } .app-title::after { content: ""; position: absolute; left: 0; bottom: -6px; width: 40px; height: 4px; background: #4299E1; border-radius: 2px; } .tabs { display: flex; gap: 15px; margin-bottom: 25px; } .tab { padding: 12px 22px; background: rgba(237, 242, 247, 0.8); border-radius: 16px; font-weight: 600; color: #718096; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; } .tab.active { background: #4299E1; color: white; } .tab.active::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.2) 50%, rgba(255,255,255,0) 100%); transform: translateX(-100%); animation: shimmer 2s infinite; } @keyframes shimmer { 100% { transform: translateX(100%); } } .weather-info { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 25px; } .metric-card { background: white; border-radius: 24px; padding: 20px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); transition: transform 0.3s ease, box-shadow 0.3s ease; position: relative; overflow: hidden; } .metric-card:hover { transform: translateY(-5px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1); } .metric-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .metric-title { font-size: 16px; font-weight: 600; color: #4A5568; } .metric-icon { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: 12px; color: white; } .wind .metric-icon { background: linear-gradient(135deg, #48BB78, #38B2AC); } .rain .metric-icon { background: linear-gradient(135deg, #4299E1, #667EEA); } .metric-value { font-size: 32px; font-weight: 700; color: #2D3748; margin-bottom: 5px; } .metric-description { font-size: 14px; color: #718096; } .forecast-container { background: white; border-radius: 24px; padding: 25px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); margin-bottom: 25px; } .forecast-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .forecast-title { font-size: 18px; font-weight: 700; color: #2D3748; } .forecast-toggle { display: flex; background: #EDF2F7; border-radius: 12px; padding: 4px; } .forecast-toggle-option { padding: 8px 16px; font-size: 14px; font-weight: 600; color: #718096; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; } .forecast-toggle-option.active { background: white; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); color: #2D3748; } .forecast-hours { display: flex; gap: 15px; overflow-x: auto; scrollbar-width: none; padding-bottom: 10px; } .forecast-hours::-webkit-scrollbar { display: none; } .forecast-hour { display: flex; flex-direction: column; align-items: center; min-width: 80px; padding: 15px 10px; background: #F7FAFC; border-radius: 16px; transition: all 0.3s ease; } .forecast-hour:hover, .forecast-hour.active { background: #EBF8FF; transform: translateY(-5px); } .forecast-hour.active { border: 2px solid #4299E1; } .hour-time { font-size: 14px; font-weight: 600; color: #4A5568; margin-bottom: 10px; } .hour-icon { margin-bottom: 10px; color: #4299E1; } .hour-condition { font-size: 12px; color: #718096; text-align: center; } .safety-index { background: white; border-radius: 24px; padding: 25px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); position: relative; } .safety-index-title { font-size: 18px; font-weight: 700; color: #2D3748; margin-bottom: 20px; } .safety-progress { width: 100%; height: 20px; background: #EDF2F7; border-radius: 10px; overflow: hidden; position: relative; margin-bottom: 20px; } .safety-progress-bar { height: 100%; background: linear-gradient(90deg, #48BB78, #38B2AC); border-radius: 10px; transition: width 1s ease; position: relative; } .safety-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; } .safety-item { display: flex; flex-direction: column; align-items: center; } .safety-circle { width: 70px; height: 70px; border-radius: 50%; background: #EDF2F7; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; position: relative; transition: all 0.3s ease; } .safety-circle::before { content: ''; position: absolute; width: 100%; height: 100%; border-radius: 50%; border: 3px solid transparent; clip: rect(0, 70px, 70px, 35px); transform: rotate(0deg); transition: all 1s ease; } .safety-circle.level-good::before { border-color: #48BB78; transform: rotate(180deg); } .safety-circle.level-medium::before { border-color: #ECC94B; transform: rotate(108deg); } .safety-circle.level-poor::before { border-color: #F56565; transform: rotate(72deg); } .safety-value { font-size: 18px; font-weight: 700; color: #2D3748; } .safety-label { font-size: 12px; color: #718096; text-align: center; } .backdrop-circle { position: absolute; border-radius: 50%; background: rgba(66, 153, 225, 0.05); z-index: -1; } .backdrop-circle-1 { width: 300px; height: 300px; top: -100px; right: -100px; } .backdrop-circle-2 { width: 200px; height: 200px; bottom: 50px; left: -50px; } .custom-alert { position: fixed; top: -100px; left: 50%; transform: translateX(-50%); background: #2D3748; color: white; padding: 15px 25px; border-radius: 12px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); transition: top 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); z-index: 1000; font-weight: 600; display: flex; align-items: center; gap: 10px; } .custom-alert.show { top: 20px; } @media (max-width: 600px) { .app-container { border-radius: 0; padding: 15px; height: 100%; } .app-title { font-size: 24px; } .weather-info { grid-template-columns: 1fr; } .tabs { gap: 10px; } .tab { padding: 10px 15px; font-size: 14px; } .safety-grid { grid-template-columns: 1fr 1fr; } .forecast-hour { min-width: 70px; } } .bike-animation { position: absolute; bottom: 15px; right: 20px; width: 36px; height: 36px; animation: bikeMove 8s linear infinite; } @keyframes bikeMove { 0% { transform: translateX(200px) rotate(0deg); } 50% { transform: translateX(-100px) rotate(0deg); } 51% { transform: translateX(-100px) rotate(180deg); } 100% { transform: translateX(200px) rotate(180deg); } } .refresh-btn { padding: 10px 15px; background: #4299E1; color: white; border: none; border-radius: 12px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; gap: 8px; } .refresh-btn:hover { background: #3182CE; transform: translateY(-2px); } .refresh-btn:active { transform: translateY(0); } .spin { animation: spin 1s linear; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } </style> </head> <body> <div class="app-container"> <div class="backdrop-circle backdrop-circle-1"></div> <div class="backdrop-circle backdrop-circle-2"></div> <div class="app-header"> <h1 class="app-title">CycleWeather Pro</h1> <button class="refresh-btn" id="refreshBtn"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="refreshIcon"> <path d="M23 4v6h-6"></path> <path d="M1 20v-6h6"></path> <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10"></path> <path d="M20.49 15a9 9 0 0 1-14.85 3.36L1 14"></path> </svg> Update </button> </div> <div class="tabs"> <div class="tab active" data-tab="weather">Current Conditions</div> <div class="tab" data-tab="route">Route Planning</div> <div class="tab" data-tab="profile">My Rides</div> </div> <div class="weather-info"> <div class="metric-card wind"> <div class="metric-header"> <h3 class="metric-title">Wind Speed & Direction</h3> <div class="metric-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M9.59 4.59A2 2 0 1 1 11 8H2m10.59 11.41A2 2 0 1 0 14 16H2m15.73-8.27A2.5 2.5 0 1 1 19.5 12H2"></path> </svg> </div> </div> <div class="metric-value">16 km/h NW</div> <div class="metric-description">Moderate headwind on Broadway</div> </div> <div class="metric-card rain"> <div class="metric-header"> <h3 class="metric-title">Precipitation</h3> <div class="metric-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <line x1="16" y1="13" x2="16" y2="21"></line> <line x1="8" y1="13" x2="8" y2="21"></line> <line x1="12" y1="15" x2="12" y2="23"></line> <path d="M20 16.58A5 5 0 0 0 18 7h-1.26A8 8 0 1 0 4 15.25"></path> </svg> </div> </div> <div class="metric-value">25%</div> <div class="metric-description">Light drizzle possible after 4 PM</div> </div> </div> <div class="forecast-container"> <div class="forecast-header"> <h3 class="forecast-title">Hourly Forecast</h3> <div class="forecast-toggle"> <div class="forecast-toggle-option active">Precipitation</div> <div class="forecast-toggle-option">Wind</div> </div> </div> <div class="forecast-hours"> <div class="forecast-hour active"> <div class="hour-time">Now</div> <div class="hour-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M21 11.05A9 9 0 1 1 11.05 1 7.5 7.5 0 0 0 21 11.05z"></path> </svg> </div> <div class="hour-condition">Clear<br>16 km/h</div> </div> <div class="forecast-hour"> <div class="hour-time">2 PM</div> <div class="hour-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M21 11.05A9 9 0 1 1 11.05 1 7.5 7.5 0 0 0 21 11.05z"></path> </svg> </div> <div class="hour-condition">Clear<br>14 km/h</div> </div> <div class="forecast-hour"> <div class="hour-time">3 PM</div> <div class="hour-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </div> <div class="hour-condition">Sunny<br>12 km/h</div> </div> <div class="forecast-hour"> <div class="hour-time">4 PM</div> <div class="hour-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path> </svg> </div> <div class="hour-condition">Partly Cloudy<br>10 km/h</div> </div> <div class="forecast-hour"> <div class="hour-time">5 PM</div> <div class="hour-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M20 16.58A5 5 0 0 0 18 7h-1.26A8 8 0 1 0 4 15.25"></path> <line x1="8" y1="16" x2="8.01" y2="16"></line> <line x1="8" y1="20" x2="8.01" y2="20"></line> <line x1="12" y1="18" x2="12.01" y2="18"></line> <line x1="12" y1="22" x2="12.01" y2="22"></line> <line x1="16" y1="16" x2="16.01" y2="16"></line> <line x1="16" y1="20" x2="16.01" y2="20"></line> </svg> </div> <div class="hour-condition">Light Rain<br>8 km/h</div> </div> <div class="forecast-hour"> <div class="hour-time">6 PM</div> <div class="hour-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M20 16.58A5 5 0 0 0 18 7h-1.26A8 8 0 1 0 4 15.25"></path> <line x1="8" y1="16" x2="8.01" y2="16"></line> <line x1="8" y1="20" x2="8.01" y2="20"></line> <line x1="12" y1="18" x2="12.01" y2="18"></line> <line x1="12" y1="22" x2="12.01" y2="22"></line> <line x1="16" y1="16" x2="16.01" y2="16"></line> <line x1="16" y1="20" x2="16.01" y2="20"></line> </svg> </div> <div class="hour-condition">Light Rain<br>12 km/h</div> </div> </div> </div> <div class="safety-index"> <h3 class="safety-index-title">Ride Safety Index</h3> <div class="safety-progress"> <div class="safety-progress-bar" style="width: 78%;"></div> </div> <div class="safety-grid"> <div class="safety-item"> <div class="safety-circle level-good"> <span class="safety-value">78%</span> </div> <div class="safety-label">Overall</div> </div> <div class="safety-item"> <div class="safety-circle level-good"> <span class="safety-value">90%</span> </div> <div class="safety-label">Visibility</div> </div> <div class="safety-item"> <div class="safety-circle level-medium"> <span class="safety-value">60%</span> </div> <div class="safety-label">Traction</div> </div> </div> <div class="bike-animation"> <svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#4299E1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="5.5" cy="17.5" r="3.5"></circle> <circle cx="18.5" cy="17.5" r="3.5"></circle> <path d="M15 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm-3 11.5V14l-3-3 4-3 2 3h2"></path> </svg> </div> </div> </div> <div class="custom-alert" id="customAlert"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path> <line x1="12" y1="9" x2="12" y2="13"></line> <line x1="12" y1="17" x2="12.01" y2="17"></line> </svg> <span id="alertMessage">This is an alert message</span> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Tab switching const tabs = document.querySelectorAll('.tab'); tabs.forEach(tab => { tab.addEventListener('click', function() { tabs.forEach(t => t.classList.remove('active')); this.classList.add('active'); showAlert(`${this.textContent} view selected`); }); }); // Forecast hour selection const forecastHours = document.querySelectorAll('.forecast-hour'); forecastHours.forEach(hour => { hour.addEventListener('click', function() { forecastHours.forEach(h => h.classList.remove('active')); this.classList.add('active'); const time = this.querySelector('.hour-time').textContent; const condition = this.querySelector('.hour-condition').textContent.split('\n')[0]; showAlert(`Selected forecast: ${time} - ${condition}`); }); }); // Forecast toggle const toggleOptions = document.querySelectorAll('.forecast-toggle-option'); toggleOptions.forEach(option => { option.addEventListener('click', function() { toggleOptions.forEach(o => o.classList.remove('active')); this.classList.add('active'); showAlert(`Showing ${this.textContent} forecast`); }); }); // Refresh button const refreshBtn = document.getElementById('refreshBtn'); const refreshIcon = document.getElementById('refreshIcon'); refreshBtn.addEventListener('click', function() { refreshIcon.classList.add('spin'); // Randomly update weather values for demo const windValues = ['12 km/h NW', '15 km/h SE', '18 km/h W', '9 km/h NE', '16 km/h NW']; const precipValues = ['10%', '25%', '30%', '5%', '0%']; const descriptions = [ 'Clear skies on your route', 'Light drizzle possible after 4 PM', 'Moderate headwind on Broadway', 'Perfect conditions for cycling', 'Strong crosswinds near the bridge' ]; const windValue = document.querySelector('.wind .metric-value'); const rainValue = document.querySelector('.rain .metric-value'); const windDesc = document.querySelector('.wind .metric-description'); const rainDesc = document.querySelector('.rain .metric-description'); setTimeout(() => { windValue.textContent = windValues[Math.floor(Math.random() * windValues.length)]; rainValue.textContent = precipValues[Math.floor(Math.random() * precipValues.length)]; windDesc.textContent = descriptions[Math.floor(Math.random() * descriptions.length)]; rainDesc.textContent = descriptions[Math.floor(Math.random() * descriptions.length)]; // Update safety index const safetyBar = document.querySelector('.safety-progress-bar'); const newSafety = Math.floor(Math.random() * 30) + 60; // 60-90% safetyBar.style.width = `${newSafety}%`; const safetyValue = document.querySelector('.safety-circle.level-good .safety-value'); safetyValue.textContent = `${newSafety}%`; refreshIcon.classList.remove('spin'); showAlert('Weather data updated!'); }, 1000); }); // Custom alert function function showAlert(message) { const alertEl = document.getElementById('customAlert'); const alertMessage = document.getElementById('alertMessage'); alertMessage.textContent = message; alertEl.classList.add('show'); setTimeout(() => { alertEl.classList.remove('show'); }, 3000); } // Initialize animation for safety circles document.querySelectorAll('.safety-circle').forEach(circle => { const value = parseInt(circle.querySelector('.safety-value').textContent); if (value >= 70) { circle.classList.add('level-good'); } else if (value >= 40) { circle.classList.add('level-medium'); } else { circle.classList.add('level-poor'); } }); // Show initial alert setTimeout(() => { showAlert('Current conditions are good for cycling!'); }, 1000); }); </script> </body> </html>