light_dark.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import React, { useState,useEffect } from 'react';
  2. import { createTheme } from '@material-ui/core/styles';
  3. import { ThemeProvider } from '@material-ui/styles';
  4. const ToggleButton = styled.button`
  5. --toggle-width: 80px;
  6. --toggle-height: 38px;
  7. --toggle-padding: 4px;
  8. position: relative;
  9. display: flex;
  10. align-items: center;
  11. justify-content: space-around;
  12. font-size: 1.5rem;
  13. line-height: 1;
  14. width: var(--toggle-width);
  15. height: var(--toggle-height);
  16. padding: var(--toggle-padding);
  17. border: 0;
  18. border-radius: calc(var(--toggle-width) / 2);
  19. cursor: pointer;
  20. background: var(--color-bg-toggle);
  21. transition: background 0.25s ease-in-out, box-shadow 0.25s ease-in-out;
  22. &:focus {
  23. outline-offset: 5px;
  24. }
  25. &:focus:not(:focus-visible) {
  26. outline: none;
  27. }
  28. &:hover {
  29. box-shadow: 0 0 5px 2px var(--color-bg-toggle);
  30. },
  31. `;
  32. const ToggleThumb = styled.span`
  33. position: absolute;
  34. top: var(--toggle-padding);
  35. left: var(--toggle-padding);
  36. width: calc(var(--toggle-height) - (var(--toggle-padding) * 2));
  37. height: calc(var(--toggle-height) - (var(--toggle-padding) * 2));
  38. border-radius: 50%;
  39. background: white;
  40. transition: transform 0.25s ease-in-out;
  41. transform: ${(p) =>
  42. p.activeTheme === "dark"
  43. ? "translate3d(calc(var(--toggle-width) - var(--toggle-height)), 0, 0)"
  44. : "none"};
  45. `;
  46. const light = createTheme({
  47. palette: {
  48. mode: 'light',
  49. },
  50. });
  51. const dark = createTheme({
  52. palette: {
  53. mode: 'dark',
  54. },
  55. });
  56. function activeTheme(themeMode){
  57. return themeMode === 'light'? light : dark;
  58. }
  59. export const toggleTheme = () => {
  60. const [activeTheme, setTheme] = useState("light");
  61. const altheme = activeTheme === "light" ? "dark" : "light";
  62. useEffect(() => {
  63. const savedTheme = window.localStorage.getItem("theme");
  64. savedTheme && setActiveTheme(savedTheme);
  65. }, []);
  66. useEffect(() => {
  67. document.body.dataset.theme = activeTheme;
  68. window.localStorage.setItem("theme", activeTheme);
  69. }, [activeTheme]);
  70. return (
  71. <ToggleButton
  72. aria-label={`Change to ${altheme} mode`}
  73. title={`Change to ${altheme} mode`}
  74. type="button"
  75. onClick={() => setActiveTheme(altheme)}
  76. >
  77. <ToggleThumb activeTheme={activeTheme} />
  78. <span>🌙</span>
  79. <span>☀️</span>
  80. </ToggleButton>
  81. );
  82. };