RevisionDiff.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import React from 'react';
  2. import type { IRevisionHasPageId } from '@growi/core';
  3. import { returnPathForURL } from '@growi/core/dist/utils/path-utils';
  4. import { createPatch } from 'diff';
  5. import type { Diff2HtmlConfig } from 'diff2html';
  6. import { html } from 'diff2html';
  7. import { useTranslation } from 'next-i18next';
  8. import Link from 'next/link';
  9. import urljoin from 'url-join';
  10. import UserDate from '../User/UserDate';
  11. import styles from './RevisionDiff.module.scss';
  12. import 'diff2html/bundles/css/diff2html.min.css';
  13. type RevisioinDiffProps = {
  14. currentRevision: IRevisionHasPageId,
  15. previousRevision: IRevisionHasPageId,
  16. revisionDiffOpened: boolean,
  17. currentPageId: string,
  18. currentPagePath: string,
  19. onClose: () => void,
  20. }
  21. export const RevisionDiff = (props: RevisioinDiffProps): JSX.Element => {
  22. const { t } = useTranslation();
  23. const {
  24. currentRevision, previousRevision, revisionDiffOpened, currentPageId, currentPagePath, onClose,
  25. } = props;
  26. const previousText = (currentRevision._id === previousRevision._id) ? '' : previousRevision.body;
  27. const patch = createPatch(
  28. currentRevision.pageId, // currentRevision.path is DEPRECATED
  29. previousText,
  30. currentRevision.body,
  31. );
  32. const option: Diff2HtmlConfig = {
  33. outputFormat: 'side-by-side',
  34. drawFileList: false,
  35. };
  36. const diffViewHTML = revisionDiffOpened ? html(patch, option) : '';
  37. const diffView = { __html: diffViewHTML };
  38. return (
  39. <div className={`${styles['revision-diff-container']}`}>
  40. <div className="comparison-header">
  41. <div className="container pt-1 pe-0">
  42. <div className="row">
  43. <div className="col comparison-source-wrapper pt-1 px-0">
  44. <span className="comparison-source pe-3">{t('page_history.comparing_source')}</span><UserDate dateTime={previousRevision.createdAt} />
  45. <Link
  46. href={urljoin(returnPathForURL(currentPagePath, currentPageId), `?revisionId=${previousRevision._id}`)}
  47. className="ms-3"
  48. onClick={onClose}
  49. prefetch={false}
  50. >
  51. <span className="material-symbols-outlined">login</span>
  52. </Link>
  53. </div>
  54. <div className="col comparison-target-wrapper pt-1">
  55. <span className="comparison-target pe-3">{t('page_history.comparing_target')}</span><UserDate dateTime={currentRevision.createdAt} />
  56. <Link
  57. href={urljoin(returnPathForURL(currentPagePath, currentPageId), `?revisionId=${currentRevision._id}`)}
  58. className="ms-3"
  59. onClick={onClose}
  60. prefetch={false}
  61. >
  62. <span className="material-symbols-outlined">login</span>
  63. </Link>
  64. </div>
  65. </div>
  66. </div>
  67. </div>
  68. <div className="revision-history-diff pb-1" dangerouslySetInnerHTML={diffView} />
  69. </div>
  70. );
  71. };