Create a modern, attractive SaaS website landing page with the use of smart gradients and slick animations including appealing, modern mouse hover animations.
0bfd444 verified Download components/theme-toggle.js from wanderingcloud/gradientflow-saas: direct link, hf CLI and curl.
- Browser
- Download file 5.79 kB
-
https://huggingface.co/spaces/wanderingcloud/gradientflow-saas/resolve/main/components/theme-toggle.js
- Command line
-
hf download hf://spaces/wanderingcloud/gradientflow-saas/components/theme-toggle.js
-
curl -L -o theme-toggle.js https://huggingface.co/spaces/wanderingcloud/gradientflow-saas/resolve/main/components/theme-toggle.js
5.79 kB
| class ThemeToggle extends HTMLElement { | |
| constructor() { | |
| super(); | |
| this.currentTheme = 'system'; | |
| } | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.render(); | |
| this.bindEvents(); | |
| this.loadSavedTheme(); | |
| } | |
| render() { | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| z-index: 50; | |
| } | |
| .theme-toggle { | |
| background: rgba(255, 255, 255, 0.1); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.2); | |
| border-radius: 12px; | |
| padding: 8px; | |
| display: flex; | |
| gap: 4px; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| } | |
| .theme-option { | |
| width: 40px; | |
| height: 40px; | |
| border: none; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.3s ease; | |
| background: transparent; | |
| } | |
| .theme-option:hover { | |
| background: rgba(255, 255, 255, 0.1); | |
| transform: translateY(-2px); | |
| } | |
| .theme-option.active { | |
| background: rgba(147, 51, 234, 0.3); | |
| box-shadow: 0 0 0 2px rgba(147, 51, 234, 0.5); | |
| } | |
| .theme-option svg { | |
| width: 20px; | |
| height: 20px; | |
| stroke: currentColor; | |
| fill: none; | |
| stroke-width: 2; | |
| stroke-linecap: round; | |
| stroke-linejoin: round; | |
| } | |
| .dark .theme-toggle { | |
| background: rgba(0, 0, 0, 0.3); | |
| border-color: rgba(255, 255, 255, 0.1); | |
| } | |
| .dark .theme-option { | |
| color: #e5e7eb; | |
| } | |
| .dark .theme-option:hover { | |
| background: rgba(255, 255, 255, 0.05); | |
| } | |
| .dark .theme-option.active { | |
| background: rgba(147, 51, 234, 0.4); | |
| box-shadow: 0 0 0 2px rgba(147, 51, 234, 0.6); | |
| } | |
| </style> | |
| <div class="theme-toggle"> | |
| <button class="theme-option" data-theme="light" title="Light Mode"> | |
| <svg viewBox="0 0 24 24"> | |
| <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> | |
| </button> | |
| <button class="theme-option" data-theme="dark" title="Dark Mode"> | |
| <svg viewBox="0 0 24 24"> | |
| <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path> | |
| </svg> | |
| </button> | |
| <button class="theme-option" data-theme="system" title="System Preference"> | |
| <svg viewBox="0 0 24 24"> | |
| <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> | |
| </button> | |
| </div> | |
| `; | |
| } | |
| bindEvents() { | |
| this.shadowRoot.querySelectorAll('.theme-option').forEach(button => { | |
| button.addEventListener('click', (e) => { | |
| const theme = e.currentTarget.getAttribute('data-theme'); | |
| this.setTheme(theme); | |
| }); | |
| }); | |
| } | |
| loadSavedTheme() { | |
| const savedTheme = localStorage.getItem('theme') || 'system'; | |
| this.setTheme(savedTheme); | |
| } | |
| setTheme(theme) { | |
| this.currentTheme = theme; | |
| // Update active state | |
| this.shadowRoot.querySelectorAll('.theme-option').forEach(btn => { | |
| btn.classList.remove('active'); | |
| }); | |
| this.shadowRoot.querySelector(`[data-theme="${theme}"]`).classList.add('active'); | |
| // Apply theme | |
| const event = new CustomEvent('themechange', { detail: { theme } }); | |
| window.dispatchEvent(event); | |
| // Update parent component | |
| if (window.themeManager) { | |
| window.themeManager.setTheme(theme); | |
| } | |
| } | |
| static get observedAttributes() { | |
| return ['current-theme']; | |
| } | |
| attributeChangedCallback(name, oldValue, newValue) { | |
| if (name === 'current-theme' && newValue) { | |
| this.setTheme(newValue); | |
| } | |
| } | |
| } | |
| customElements.define('custom-theme-toggle', ThemeToggle); |