CustomizeHighlightSetting.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /* eslint-disable no-useless-escape */
  2. import React, { useCallback, useState } from 'react';
  3. import { useTranslation } from 'react-i18next';
  4. import {
  5. Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
  6. } from 'reactstrap';
  7. import AdminCustomizeContainer from '~/client/services/AdminCustomizeContainer';
  8. import { toastSuccess, toastError } from '~/client/util/apiNotification';
  9. import { withUnstatedContainers } from '../../UnstatedUtils';
  10. import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
  11. type Props = {
  12. adminCustomizeContainer: AdminCustomizeContainer
  13. }
  14. type HljsDemoProps = {
  15. isHighlightJsStyleBorderEnabled: boolean
  16. }
  17. const HljsDemo = React.memo((props: HljsDemoProps): JSX.Element => {
  18. const { isHighlightJsStyleBorderEnabled } = props;
  19. /* eslint-disable max-len */
  20. const html = `<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MersenneTwister</span>(<span class="hljs-params">seed</span>) </span>{
  21. <span class="hljs-keyword">if</span> (<span class="hljs-built_in">arguments</span>.length == <span class="hljs-number">0</span>) {
  22. seed = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>().getTime();
  23. }
  24. <span class="hljs-keyword">this</span>._mt = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Array</span>(<span class="hljs-number">624</span>);
  25. <span class="hljs-keyword">this</span>.setSeed(seed);
  26. }</span>`;
  27. /* eslint-enable max-len */
  28. return (
  29. <pre className={`hljs ${!isHighlightJsStyleBorderEnabled && 'hljs-no-border'}`}>
  30. {/* eslint-disable-next-line react/no-danger */}
  31. <code dangerouslySetInnerHTML={{ __html: html }}></code>
  32. </pre>
  33. );
  34. });
  35. const CustomizeHighlightSetting = (props: Props): JSX.Element => {
  36. const { adminCustomizeContainer } = props;
  37. const { t } = useTranslation();
  38. const [isDropdownOpen, setIsDropdownOpen] = useState(false);
  39. const options = adminCustomizeContainer.state.highlightJsCssSelectorOptions;
  40. const onToggleDropdown = useCallback(() => {
  41. setIsDropdownOpen(!isDropdownOpen);
  42. }, [isDropdownOpen]);
  43. const onClickSubmit = useCallback(async() => {
  44. try {
  45. await adminCustomizeContainer.updateHighlightJsStyle();
  46. toastSuccess(t('toaster.update_successed', { target: t('admin:customize_setting.code_highlight') }));
  47. }
  48. catch (err) {
  49. toastError(err);
  50. }
  51. }, [t, adminCustomizeContainer]);
  52. const renderMenuItems = useCallback(() => {
  53. const items = Object.entries(options).map((option) => {
  54. const styleId = option[0];
  55. const styleName = option[1].name;
  56. const isBorderEnable = option[1].border;
  57. return (
  58. <DropdownItem
  59. key={styleId}
  60. role="presentation"
  61. onClick={() => adminCustomizeContainer.switchHighlightJsStyle(styleId, styleName, isBorderEnable)}
  62. >
  63. <a role="menuitem">{styleName}</a>
  64. </DropdownItem>
  65. );
  66. });
  67. return items;
  68. }, [adminCustomizeContainer, options]);
  69. return (
  70. <React.Fragment>
  71. <div className="row">
  72. <div className="col-12">
  73. <h2 className="admin-setting-header">{t('admin:customize_setting.code_highlight')}</h2>
  74. <div className="form-group row">
  75. <div className="offset-md-3 col-md-6 text-left">
  76. <div className="my-0">
  77. <label>{t('admin:customize_setting.theme')}</label>
  78. </div>
  79. <Dropdown isOpen={isDropdownOpen} toggle={onToggleDropdown}>
  80. <DropdownToggle className="text-right col-6" caret>
  81. <span className="float-left">{adminCustomizeContainer.state.currentHighlightJsStyleName}</span>
  82. </DropdownToggle>
  83. <DropdownMenu className="dropdown-menu" role="menu">
  84. {renderMenuItems()}
  85. </DropdownMenu>
  86. </Dropdown>
  87. <p className="form-text text-warning">
  88. {/* eslint-disable-next-line react/no-danger */}
  89. <span dangerouslySetInnerHTML={{ __html: t('admin:customize_setting.nocdn_desc') }} />
  90. </p>
  91. </div>
  92. </div>
  93. <div className="form-group row">
  94. <div className="offset-md-3 col-md-6 text-left">
  95. <div className="custom-control custom-switch custom-checkbox-success">
  96. <input
  97. type="checkbox"
  98. className="custom-control-input"
  99. id="highlightBorder"
  100. checked={adminCustomizeContainer.state.isHighlightJsStyleBorderEnabled}
  101. onChange={() => { adminCustomizeContainer.switchHighlightJsStyleBorder() }}
  102. />
  103. <label className="custom-control-label" htmlFor="highlightBorder">
  104. <strong>Border</strong>
  105. </label>
  106. </div>
  107. </div>
  108. </div>
  109. <div className="form-text text-muted">
  110. <label>Examples:</label>
  111. <div className="wiki">
  112. <HljsDemo isHighlightJsStyleBorderEnabled={adminCustomizeContainer.state.isHighlightJsStyleBorderEnabled} />
  113. </div>
  114. </div>
  115. <AdminUpdateButtonRow onClick={onClickSubmit} disabled={adminCustomizeContainer.state.retrieveError != null} />
  116. </div>
  117. </div>
  118. </React.Fragment>
  119. );
  120. };
  121. const CustomizeHighlightSettingWrapper = withUnstatedContainers(CustomizeHighlightSetting, [AdminCustomizeContainer]);
  122. export default CustomizeHighlightSettingWrapper;