SidebarNav.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import React, { FC, memo, useCallback } from 'react';
  2. import Link from 'next/link';
  3. import { useUserUISettings } from '~/client/services/user-ui-settings';
  4. import { SidebarContentsType } from '~/interfaces/ui';
  5. import { useCurrentUser } from '~/stores/context';
  6. import { useCurrentSidebarContents } from '~/stores/ui';
  7. import styles from './SidebarNav.module.scss';
  8. type PrimaryItemProps = {
  9. contents: SidebarContentsType,
  10. label: string,
  11. iconName: string,
  12. onItemSelected: (contents: SidebarContentsType) => void,
  13. }
  14. const PrimaryItem: FC<PrimaryItemProps> = (props: PrimaryItemProps) => {
  15. const {
  16. contents, label, iconName, onItemSelected,
  17. } = props;
  18. const { data: currentContents, mutate } = useCurrentSidebarContents();
  19. const { scheduleToPut } = useUserUISettings();
  20. const isSelected = contents === currentContents;
  21. const itemSelectedHandler = useCallback(() => {
  22. if (onItemSelected != null) {
  23. onItemSelected(contents);
  24. }
  25. mutate(contents, false);
  26. scheduleToPut({ currentSidebarContents: contents });
  27. }, [contents, mutate, onItemSelected, scheduleToPut]);
  28. const labelForTestId = label.toLowerCase().replace(' ', '-');
  29. return (
  30. <button
  31. type="button"
  32. data-testid={`grw-sidebar-nav-primary-${labelForTestId}`}
  33. className={`d-block btn btn-primary ${isSelected ? 'active' : ''}`}
  34. onClick={itemSelectedHandler}
  35. >
  36. <i className="material-icons">{iconName}</i>
  37. </button>
  38. );
  39. };
  40. type SecondaryItemProps = {
  41. label: string,
  42. href: string,
  43. iconName: string,
  44. isBlank?: boolean,
  45. }
  46. const SecondaryItem: FC<SecondaryItemProps> = memo((props: SecondaryItemProps) => {
  47. const { iconName, href, isBlank } = props;
  48. return (
  49. <Link href={href}>
  50. <a className="d-block btn btn-primary" target={`${isBlank ? '_blank' : ''}`}>
  51. <i className="material-icons">{iconName}</i>
  52. </a>
  53. </Link>
  54. );
  55. });
  56. SecondaryItem.displayName = 'SecondaryItem';
  57. type Props = {
  58. onItemSelected: (contents: SidebarContentsType) => void,
  59. }
  60. export const SidebarNav: FC<Props> = (props: Props) => {
  61. const { data: currentUser } = useCurrentUser();
  62. const isAdmin = currentUser?.admin;
  63. const { onItemSelected } = props;
  64. return (
  65. <div className={`grw-sidebar-nav ${styles['grw-sidebar-nav']}`}>
  66. <div className="grw-sidebar-nav-primary-container">
  67. {/* eslint-disable max-len */}
  68. <PrimaryItem contents={SidebarContentsType.TREE} label="Page Tree" iconName="format_list_bulleted" onItemSelected={onItemSelected} />
  69. <PrimaryItem contents={SidebarContentsType.CUSTOM} label="Custom Sidebar" iconName="code" onItemSelected={onItemSelected} />
  70. <PrimaryItem contents={SidebarContentsType.RECENT} label="Recent Changes" iconName="update" onItemSelected={onItemSelected} />
  71. {/* <PrimaryItem id="tag" label="Tags" iconName="icon-tag" /> */}
  72. {/* <PrimaryItem id="favorite" label="Favorite" iconName="fa fa-bookmark-o" /> */}
  73. <PrimaryItem contents={SidebarContentsType.TAG} label="Tags" iconName="local_offer" onItemSelected={onItemSelected} />
  74. {/* <PrimaryItem id="favorite" label="Favorite" iconName="icon-star" /> */}
  75. {/* eslint-enable max-len */}
  76. </div>
  77. <div className="grw-sidebar-nav-secondary-container">
  78. {isAdmin && <SecondaryItem label="Admin" iconName="settings" href="/admin" />}
  79. <SecondaryItem label="Draft" iconName="file_copy" href="/me/drafts" />
  80. <SecondaryItem label="Help" iconName="help" href="https://docs.growi.org" isBlank />
  81. <SecondaryItem label="Trash" iconName="delete" href="/trash" />
  82. </div>
  83. </div>
  84. );
  85. };