AppearanceModeDropdown.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import React, { FC, useState, useCallback } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { UncontrolledTooltip } from 'reactstrap';
  4. import { useUserUISettings } from '~/client/services/user-ui-settings';
  5. import {
  6. isUserPreferenceExists,
  7. isDarkMode as isDarkModeByUtil,
  8. applyColorScheme,
  9. removeUserPreference,
  10. updateUserPreference,
  11. updateUserPreferenceWithOsSettings,
  12. } from '~/client/util/color-scheme';
  13. import { usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser } from '~/stores/ui';
  14. import MoonIcon from '../Icons/MoonIcon';
  15. import SidebarDockIcon from '../Icons/SidebarDockIcon';
  16. import SidebarDrawerIcon from '../Icons/SidebarDrawerIcon';
  17. import SunIcon from '../Icons/SunIcon';
  18. type AppearanceModeDropdownProps = {
  19. isAuthenticated: boolean,
  20. }
  21. export const AppearanceModeDropdown:FC<AppearanceModeDropdownProps> = (props: AppearanceModeDropdownProps) => {
  22. const { t } = useTranslation();
  23. const { isAuthenticated } = props;
  24. const [useOsSettings, setOsSettings] = useState(!isUserPreferenceExists());
  25. const [isDarkMode, setIsDarkMode] = useState(isDarkModeByUtil());
  26. const { data: isPreferDrawerMode, update: updatePreferDrawerMode } = usePreferDrawerModeByUser();
  27. const { data: isPreferDrawerModeOnEdit, mutate: mutatePreferDrawerModeOnEdit } = usePreferDrawerModeOnEditByUser();
  28. const { scheduleToPut } = useUserUISettings();
  29. const preferDrawerModeSwitchModifiedHandler = useCallback((preferDrawerMode: boolean, isEditMode: boolean) => {
  30. if (isEditMode) {
  31. mutatePreferDrawerModeOnEdit(preferDrawerMode);
  32. scheduleToPut({ preferDrawerModeOnEditByUser: preferDrawerMode });
  33. }
  34. else {
  35. updatePreferDrawerMode(preferDrawerMode);
  36. }
  37. }, [updatePreferDrawerMode, mutatePreferDrawerModeOnEdit, scheduleToPut]);
  38. const followOsCheckboxModifiedHandler = useCallback((useOsSettings: boolean) => {
  39. if (useOsSettings) {
  40. removeUserPreference();
  41. }
  42. else {
  43. updateUserPreferenceWithOsSettings();
  44. }
  45. applyColorScheme();
  46. // update states
  47. setOsSettings(useOsSettings);
  48. setIsDarkMode(isDarkModeByUtil());
  49. }, []);
  50. const userPreferenceSwitchModifiedHandler = useCallback((isDarkMode: boolean) => {
  51. updateUserPreference(isDarkMode);
  52. applyColorScheme();
  53. // update state
  54. setIsDarkMode(isDarkModeByUtil());
  55. }, []);
  56. /* eslint-disable react/prop-types */
  57. const IconWithTooltip = ({
  58. id, label, children, additionalClasses,
  59. }) => (
  60. <>
  61. <div id={id} className={`px-2 grw-icon-container ${additionalClasses != null ? additionalClasses : ''}`}>{children}</div>
  62. <UncontrolledTooltip placement="bottom" fade={false} target={id}>{label}</UncontrolledTooltip>
  63. </>
  64. );
  65. const renderSidebarModeSwitch = useCallback((isEditMode: boolean) => {
  66. return (
  67. <>
  68. <h6 className="dropdown-header">{t(isEditMode ? 'personal_dropdown.sidebar_mode_editor' : 'personal_dropdown.sidebar_mode')}</h6>
  69. <form className="px-4">
  70. <div className="form-row justify-content-center">
  71. <div className="form-group col-auto mb-0 d-flex align-items-center">
  72. <IconWithTooltip id={isEditMode ? 'iwt-sidebar-editor-drawer' : 'iwt-sidebar-drawer'} label="Drawer" additionalClasses="grw-sidebar-mode-icon">
  73. <SidebarDrawerIcon />
  74. </IconWithTooltip>
  75. <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
  76. <input
  77. id={isEditMode ? 'swSidebarModeOnEditor' : 'swSidebarMode'}
  78. className="custom-control-input"
  79. type="checkbox"
  80. checked={isEditMode ? !isPreferDrawerModeOnEdit : !isPreferDrawerMode}
  81. onChange={e => preferDrawerModeSwitchModifiedHandler(!e.target.checked, isEditMode)}
  82. />
  83. <label className="custom-control-label" htmlFor={isEditMode ? 'swSidebarModeOnEditor' : 'swSidebarMode'}></label>
  84. </div>
  85. <IconWithTooltip id={isEditMode ? 'iwt-sidebar-editor-dock' : 'iwt-sidebar-dock'} label="Dock" additionalClasses="grw-sidebar-mode-icon">
  86. <SidebarDockIcon />
  87. </IconWithTooltip>
  88. </div>
  89. </div>
  90. </form>
  91. </>
  92. );
  93. }, [isPreferDrawerMode, isPreferDrawerModeOnEdit, preferDrawerModeSwitchModifiedHandler, t]);
  94. return (
  95. <>
  96. {/* setting button */}
  97. <button className="bg-transparent border-0 nav-link" type="button" data-toggle="dropdown" aria-haspopup="true">
  98. <i className="icon-settings"></i>
  99. </button>
  100. {/* dropdown */}
  101. <div className="dropdown-menu dropdown-menu-right">
  102. {/* sidebar mode */}
  103. {renderSidebarModeSwitch(false)}
  104. <div className="dropdown-divider"></div>
  105. {/* side bar mode on editor */}
  106. {isAuthenticated && renderSidebarModeSwitch(true)}
  107. <div className="dropdown-divider"></div>
  108. {/* color mode */}
  109. <h6 className="dropdown-header">{t('personal_dropdown.color_mode')}</h6>
  110. <form className="px-4">
  111. <div className="form-row justify-content-center">
  112. <div className="form-group col-auto d-flex align-items-center">
  113. <IconWithTooltip id="iwt-light" label="Light" additionalClasses={useOsSettings ? 'grw-color-mode-icon-muted' : 'grw-color-mode-icon'}>
  114. <SunIcon />
  115. </IconWithTooltip>
  116. <div className="custom-control custom-switch custom-checkbox-secondary ml-2">
  117. <input
  118. id="swUserPreference"
  119. className="custom-control-input"
  120. type="checkbox"
  121. checked={isDarkMode}
  122. disabled={useOsSettings}
  123. onChange={e => userPreferenceSwitchModifiedHandler(e.target.checked)}
  124. />
  125. <label className="custom-control-label" htmlFor="swUserPreference"></label>
  126. </div>
  127. <IconWithTooltip id="iwt-dark" label="Dark" additionalClasses={useOsSettings ? 'grw-color-mode-icon-muted' : 'grw-color-mode-icon'}>
  128. <MoonIcon />
  129. </IconWithTooltip>
  130. </div>
  131. </div>
  132. <div className="form-row">
  133. <div className="form-group col-auto">
  134. <div className="custom-control custom-checkbox">
  135. <input
  136. id="cbFollowOs"
  137. className="custom-control-input"
  138. type="checkbox"
  139. checked={useOsSettings}
  140. onChange={e => followOsCheckboxModifiedHandler(e.target.checked)}
  141. />
  142. <label className="custom-control-label text-nowrap" htmlFor="cbFollowOs">{t('personal_dropdown.use_os_settings')}</label>
  143. </div>
  144. </div>
  145. </div>
  146. </form>
  147. </div>
  148. </>
  149. );
  150. };