theme-toggle.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import React from "react";
  2. import { useStorybookApi } from "storybook/manager-api";
  3. import { IconButton } from "storybook/internal/components";
  4. import { MoonIcon, SunIcon } from "@storybook/icons";
  5. import { ADDON_ID, TOOL_ID, THEMES, DEFAULT_THEME } from "./constants";
  6. import { useAtom, useAtomValue } from "jotai/react";
  7. import { evaluatedThemeAtom, themeAtom } from "./atoms";
  8. export const ThemeTool = React.memo(function MyAddonSelector() {
  9. const [theme, setTheme] = useAtom(themeAtom);
  10. const evaluatedTheme = useAtomValue(evaluatedThemeAtom);
  11. const api = useStorybookApi();
  12. const toggleTheme = React.useCallback(() => {
  13. setTheme((previousTheme) => THEMES[(THEMES.indexOf(previousTheme) + 1) % THEMES.length]);
  14. }, []);
  15. React.useEffect(() => {
  16. api.setAddonShortcut(ADDON_ID, {
  17. label: "Toggle Theme [8]",
  18. defaultShortcut: ["8"],
  19. actionName: "toggleTheme",
  20. showInMenu: false,
  21. action: toggleTheme,
  22. });
  23. }, [toggleTheme, api]);
  24. return (
  25. <IconButton
  26. style={{ height: "28px", width: "28px" }}
  27. key={TOOL_ID}
  28. active={theme !== DEFAULT_THEME}
  29. title="Toggle theme"
  30. onClick={toggleTheme}
  31. >
  32. {theme === DEFAULT_THEME ? (
  33. <div style={{ position: "relative" }}>
  34. {evaluatedTheme === "light" ? (
  35. <>
  36. <SunIcon style={{ top: "50%", left: "50%", position: "absolute", transform: "translate(-50%, -50%)" }} />
  37. <MoonIcon
  38. style={{
  39. height: "8px",
  40. width: "8px",
  41. opacity: "0.5",
  42. top: "50%",
  43. left: "50%",
  44. position: "absolute",
  45. transform: "translate(80%, -120%)",
  46. }}
  47. />
  48. </>
  49. ) : (
  50. <>
  51. <MoonIcon style={{ top: "50%", left: "50%", position: "absolute", transform: "translate(-50%, -50%)" }} />
  52. <SunIcon
  53. style={{
  54. height: "10px",
  55. width: "10px",
  56. opacity: "0.5",
  57. top: "50%",
  58. left: "50%",
  59. position: "absolute",
  60. transform: "translate(40%, -100%)",
  61. }}
  62. />
  63. </>
  64. )}
  65. </div>
  66. ) : evaluatedTheme === "dark" ? (
  67. <MoonIcon />
  68. ) : (
  69. <SunIcon />
  70. )}
  71. </IconButton>
  72. );
  73. });