You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							102 lines
						
					
					
						
							2.9 KiB
						
					
					
				
			
		
		
	
	
							102 lines
						
					
					
						
							2.9 KiB
						
					
					
				| import { useTheme } from 'next-themes';
 | |
| import React from 'react';
 | |
| 
 | |
| 
 | |
| const ThemeSwitch = (): JSX.Element => {
 | |
|   const [mounted, setMounted] = React.useState(false);
 | |
|   const { theme, setTheme } = useTheme();
 | |
| 
 | |
|   // After mounting, we have access to the theme
 | |
|   React.useEffect(() => setMounted(true), []);
 | |
| 
 | |
|   if (!mounted) {
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   const isDark = theme === 'dark';
 | |
|   const color = isDark ? '#fff' : '#000';
 | |
|   const maskColor = isDark ? '#000' : '#fff';
 | |
|   return (
 | |
|     <button
 | |
|       className="theme-button"
 | |
|       type="button"
 | |
|       aria-label="Toggle Dark Mode"
 | |
|       onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
 | |
|     >
 | |
|       <div className="moon-or-sun" />
 | |
|       <div className="moon-mask" />
 | |
|       <style jsx>{`
 | |
|         .theme-button {
 | |
|           opacity: 0.5;
 | |
|           position: relative;
 | |
|           border-radius: 5px;
 | |
|           width: 42px;
 | |
|           height: 42px;
 | |
|           display: flex;
 | |
|           align-items: center;
 | |
|           justify-content: center;
 | |
|           transition: opacity 0.3s ease;
 | |
|         }
 | |
|         .theme-button:hover {
 | |
|           opacity: 1;
 | |
|         }
 | |
|         .moon-or-sun {
 | |
|           position: relative;
 | |
|           width: 20px;
 | |
|           height: 20px;
 | |
|           border-radius: 50%;
 | |
|           border: ${isDark ? '4px' : '2px'} solid;
 | |
|           border-color: ${color};
 | |
|           background: ${color};
 | |
|           transform: scale(${isDark ? 0.5 : 1});
 | |
|           transition: all 0.45s ease;
 | |
|           overflow: ${isDark ? 'visible' : 'hidden'};
 | |
|         }
 | |
|         .moon-or-sun::before {
 | |
|           content: '';
 | |
|           position: absolute;
 | |
|           right: -9px;
 | |
|           top: -9px;
 | |
|           height: 20px;
 | |
|           width: 20px;
 | |
|           border: 2px solid;
 | |
|           border-color: ${color};
 | |
|           border-radius: 50%;
 | |
|           transform: translate(${isDark ? '14px, -14px' : '0, 0'});
 | |
|           opacity: ${isDark ? 0 : 1};
 | |
|           transition: transform 0.45s ease;
 | |
|         }
 | |
|         .moon-or-sun::after {
 | |
|           content: '';
 | |
|           width: 8px;
 | |
|           height: 8px;
 | |
|           border-radius: 50%;
 | |
|           margin: -4px 0 0 -4px;
 | |
|           position: absolute;
 | |
|           top: 50%;
 | |
|           left: 50%;
 | |
|           box-shadow: 0 -23px 0 ${color}, 0 23px 0 ${color}, 23px 0 0 ${color},
 | |
|             -23px 0 0 ${color}, 15px 15px 0 ${color}, -15px 15px 0 ${color},
 | |
|             15px -15px 0 ${color}, -15px -15px 0 ${color};
 | |
|           transform: scale(${isDark ? 1 : 0});
 | |
|           transition: all 0.35s ease;
 | |
|         }
 | |
|         .moon-mask {
 | |
|           position: absolute;
 | |
|           right: 4px;
 | |
|           top: 4px;
 | |
|           height: 20px;
 | |
|           width: 20px;
 | |
|           border-radius: 50%;
 | |
|           border: 0;
 | |
|           background: ${maskColor};
 | |
|           transform: translate(${isDark ? '4px, -4px' : '0, 0'});
 | |
|           opacity: ${isDark ? 0 : 1};
 | |
|           transition: transform 0.45s ease;
 | |
|         }
 | |
|       `}</style>
 | |
|     </button>
 | |
|   );
 | |
| };
 | |
| 
 | |
| export default ThemeSwitch;
 | |
| 
 |