RevisionDiff.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { useMemo } from 'react';
  2. import type { IRevisionHasId } from '@growi/core';
  3. import { GrowiThemeSchemeType } from '@growi/core';
  4. import { returnPathForURL } from '@growi/core/dist/utils/path-utils';
  5. import { PresetThemesMetadatas } from '@growi/preset-themes';
  6. import { createPatch } from 'diff';
  7. import type { Diff2HtmlConfig } from 'diff2html';
  8. import { html } from 'diff2html';
  9. import { ColorSchemeType } from 'diff2html/lib/types';
  10. import { useTranslation } from 'next-i18next';
  11. import Link from 'next/link';
  12. import urljoin from 'url-join';
  13. import { Themes, useNextThemes } from '~/stores-universal/use-next-themes';
  14. import UserDate from '../../../components/User/UserDate';
  15. import { useSWRxGrowiThemeSetting } from '../../../stores/admin/customize';
  16. import styles from './RevisionDiff.module.scss';
  17. import 'diff2html/bundles/css/diff2html.min.css';
  18. const moduleClass = styles['revision-diff-container'];
  19. type RevisioinDiffProps = {
  20. currentRevision: IRevisionHasId,
  21. previousRevision: IRevisionHasId,
  22. revisionDiffOpened: boolean,
  23. currentPageId: string,
  24. currentPagePath: string,
  25. onClose: () => void,
  26. }
  27. export const RevisionDiff = (props: RevisioinDiffProps): JSX.Element => {
  28. const { t } = useTranslation();
  29. const {
  30. currentRevision, previousRevision, revisionDiffOpened, currentPageId, currentPagePath, onClose,
  31. } = props;
  32. const { theme: userTheme } = useNextThemes();
  33. const { data: growiTheme } = useSWRxGrowiThemeSetting();
  34. const colorScheme: ColorSchemeType = useMemo(() => {
  35. if (growiTheme == null) {
  36. return ColorSchemeType.AUTO;
  37. }
  38. const growiThemeSchemeType = growiTheme.pluginThemesMetadatas[0]?.schemeType
  39. ?? PresetThemesMetadatas.find(theme => theme.name === growiTheme.currentTheme)?.schemeType;
  40. switch (growiThemeSchemeType) {
  41. case GrowiThemeSchemeType.DARK:
  42. return ColorSchemeType.DARK;
  43. case GrowiThemeSchemeType.LIGHT:
  44. return ColorSchemeType.LIGHT;
  45. default:
  46. // growiThemeSchemeType === GrowiThemeSchemeType.BOTH
  47. }
  48. switch (userTheme) {
  49. case Themes.DARK:
  50. return ColorSchemeType.DARK;
  51. case Themes.LIGHT:
  52. return ColorSchemeType.LIGHT;
  53. default:
  54. return ColorSchemeType.AUTO;
  55. }
  56. }, [growiTheme, userTheme]);
  57. const previousText = (currentRevision._id === previousRevision._id) ? '' : previousRevision.body;
  58. const patch = createPatch(
  59. currentRevision.pageId, // currentRevision.path is DEPRECATED
  60. previousText,
  61. currentRevision.body,
  62. );
  63. const option: Diff2HtmlConfig = {
  64. outputFormat: 'side-by-side',
  65. drawFileList: false,
  66. colorScheme,
  67. };
  68. const diffViewHTML = revisionDiffOpened ? html(patch, option) : '';
  69. const diffView = { __html: diffViewHTML };
  70. return (
  71. <div className={moduleClass}>
  72. <div className="container">
  73. <div className="row mt-2">
  74. <div className="col px-0 py-2">
  75. <span className="fw-bold">{t('page_history.comparing_source')}</span>
  76. <Link
  77. href={urljoin(returnPathForURL(currentPagePath, currentPageId), `?revisionId=${previousRevision._id}`)}
  78. className="small ms-2
  79. link-created-at
  80. link-secondary link-opacity-75 link-opacity-100-hover
  81. link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover"
  82. onClick={onClose}
  83. prefetch={false}
  84. >
  85. <UserDate dateTime={previousRevision.createdAt} />
  86. </Link>
  87. </div>
  88. <div className="col px-0 py-2">
  89. <span className="fw-bold">{t('page_history.comparing_target')}</span>
  90. <Link
  91. href={urljoin(returnPathForURL(currentPagePath, currentPageId), `?revisionId=${currentRevision._id}`)}
  92. className="small ms-2
  93. link-created-at
  94. link-secondary link-opacity-75 link-opacity-100-hover
  95. link-offset-2 link-underline-opacity-25 link-underline-opacity-100-hover"
  96. onClick={onClose}
  97. prefetch={false}
  98. >
  99. <UserDate dateTime={currentRevision.createdAt} />
  100. </Link>
  101. </div>
  102. </div>
  103. </div>
  104. {/* eslint-disable-next-line react/no-danger */}
  105. <div className="revision-history-diff pb-1" dangerouslySetInnerHTML={diffView} />
  106. </div>
  107. );
  108. };