UISettings.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { useCallback } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { UncontrolledTooltip } from 'reactstrap';
  4. import { updateUserUISettings } from '~/client/services/user-ui-settings';
  5. import { toastError, toastSuccess } from '~/client/util/toastr';
  6. import { useCollapsedContentsOpened, usePreferCollapsedMode, useSidebarMode } from '~/stores/ui';
  7. import SidebarCollapsedIcon from './SidebarCollapsedIcon';
  8. import SidebarDockIcon from './SidebarDockIcon';
  9. import styles from './UISettings.module.scss';
  10. const IconWithTooltip = ({
  11. id, label, children, additionalClasses,
  12. }: {
  13. id: string,
  14. label: string,
  15. children: JSX.Element,
  16. additionalClasses: string
  17. }) => (
  18. <>
  19. <div id={id} className={`${additionalClasses != null ? additionalClasses : ''}`}>{children}</div>
  20. <UncontrolledTooltip placement="bottom" fade={false} target={id}>{label}</UncontrolledTooltip>
  21. </>
  22. );
  23. export const UISettings = (): JSX.Element => {
  24. const { t } = useTranslation();
  25. const {
  26. isDockMode, isCollapsedMode,
  27. } = useSidebarMode();
  28. const { mutate: mutatePreferCollapsedMode } = usePreferCollapsedMode();
  29. const { mutate: mutateCollapsedContentsOpened } = useCollapsedContentsOpened();
  30. const toggleCollapsed = useCallback(() => {
  31. mutatePreferCollapsedMode(!isCollapsedMode());
  32. mutateCollapsedContentsOpened(false);
  33. }, [mutatePreferCollapsedMode, isCollapsedMode, mutateCollapsedContentsOpened]);
  34. const updateButtonHandler = useCallback(async() => {
  35. try {
  36. await updateUserUISettings({ preferCollapsedModeByUser: isCollapsedMode() });
  37. toastSuccess(t('toaster.update_successed', { target: t('ui_settings.side_bar_mode.settings'), ns: 'commons' }));
  38. }
  39. catch (err) {
  40. toastError(err);
  41. }
  42. }, [isCollapsedMode, t]);
  43. const renderSidebarModeSwitch = () => {
  44. return (
  45. <>
  46. <div className="d-flex align-items-start">
  47. <div className="d-flex align-items-center">
  48. <IconWithTooltip
  49. id="iwt-sidebar-collapsed"
  50. label="Collapsed"
  51. additionalClasses={styles['grw-sidebar-mode-icon']}
  52. >
  53. <span className="growi-custom-icon">sidebar-collapsed</span>
  54. </IconWithTooltip>
  55. <div className="form-check form-switch ms-2">
  56. <input
  57. id="swSidebarMode"
  58. className="form-check-input"
  59. type="checkbox"
  60. checked={isDockMode()}
  61. onChange={toggleCollapsed}
  62. />
  63. <label className="form-label form-check-label" htmlFor="swSidebarMode"></label>
  64. </div>
  65. <IconWithTooltip id="iwt-sidebar-dock" label="Dock" additionalClasses={styles['grw-sidebar-mode-icon']}>
  66. <span className="growi-custom-icon">sidebar-dock</span>
  67. </IconWithTooltip>
  68. </div>
  69. <div className="ms-2">
  70. <label className="form-label form-check-label" htmlFor="swSidebarMode">
  71. {t('ui_settings.side_bar_mode.side_bar_mode_setting')}
  72. </label>
  73. <p className="form-text text-muted small">{t('ui_settings.side_bar_mode.description')}</p>
  74. </div>
  75. </div>
  76. </>
  77. );
  78. };
  79. return (
  80. <>
  81. <h2 className="border-bottom mb-4">{t('ui_settings.ui_settings')}</h2>
  82. <div className="row justify-content-center">
  83. <div className="col-md-6">
  84. { renderSidebarModeSwitch() }
  85. <div>
  86. </div>
  87. </div>
  88. </div>
  89. <div className="row my-3">
  90. <div className="offset-4 col-5">
  91. <button data-testid="" type="button" className="btn btn-primary" onClick={updateButtonHandler}>
  92. {t('Update')}
  93. </button>
  94. </div>
  95. </div>
  96. </>
  97. );
  98. };