Просмотр исходного кода

Merge pull request #7764 from weseek/imprv/insert-template

imprv: Insert template
Yuki Takei 2 лет назад
Родитель
Сommit
930b85870a

+ 1 - 0
apps/app/public/static/locales/en_US/commons.json

@@ -2,6 +2,7 @@
   "Show": "Show",
   "Hide": "Hide",
   "Add": "Add",
+  "Insert": "Insert",
   "Reset": "Reset",
   "Sign out": "Logout",
   "New": "New",

+ 1 - 0
apps/app/public/static/locales/en_US/translation.json

@@ -454,6 +454,7 @@
   },
   "template": {
     "modal_label": {
+      "Select template": "Select template",
       "Create/Edit Template Page": "Create/Edit template page",
       "Create template under": "Create template page under this page"
     },

+ 1 - 0
apps/app/public/static/locales/ja_JP/commons.json

@@ -2,6 +2,7 @@
   "Show": "公開",
   "Hide": "非公開",
   "Add": "追加",
+  "Insert": "挿入",
   "Reset": "リセット",
   "Sign out": "ログアウト",
   "New": "作成",

+ 1 - 0
apps/app/public/static/locales/ja_JP/translation.json

@@ -487,6 +487,7 @@
   },
   "template": {
     "modal_label": {
+      "Select template": "テンプレートの選択",
       "Create/Edit Template Page": "テンプレートページの作成/編集",
       "Create template under": "配下にテンプレートページを作成"
     },

+ 1 - 0
apps/app/public/static/locales/zh_CN/commons.json

@@ -2,6 +2,7 @@
 	"Show": "显示",
 	"Hide": "隐藏",
   "Add": "添加",
+  "Insert": "插入",
   "Reset": "重启",
 	"Sign out": "退出",
   "New": "新建",

+ 1 - 0
apps/app/public/static/locales/zh_CN/translation.json

@@ -441,6 +441,7 @@
   },
 	"template": {
 		"modal_label": {
+      "Select template": "选择模板",
 			"Create/Edit Template Page": "创建/编辑模板页",
 			"Create template under": "在下面创建模板页"
 		},

+ 2 - 2
apps/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -848,8 +848,8 @@ class CodeMirrorEditor extends AbstractEditor {
   // }
 
   showTemplateModal() {
-    const onSubmit = templateText => this.setValue(templateText);
-    this.props.onClickTemplateBtn(onSubmit);
+    const onSubmit = templateText => this.insertText(templateText);
+    this.props.onClickTemplateBtn({ onSubmit });
   }
 
   showLinkEditModal() {

+ 130 - 0
apps/app/src/components/TemplateModal/TemplateModal.tsx

@@ -0,0 +1,130 @@
+import React, {
+  useCallback, useEffect, useState,
+} from 'react';
+
+import type { ITemplate } from '@growi/core/dist/interfaces/template';
+import { useTranslation } from 'next-i18next';
+import {
+  Modal,
+  ModalHeader,
+  ModalBody,
+  ModalFooter,
+} from 'reactstrap';
+
+import { useTemplateModal } from '~/stores/modal';
+import { usePreviewOptions } from '~/stores/renderer';
+import { useTemplates } from '~/stores/template';
+import loggerFactory from '~/utils/logger';
+
+import Preview from '../PageEditor/Preview';
+
+import { useFormatter } from './use-formatter';
+
+const logger = loggerFactory('growi:components:TemplateModal');
+
+
+type TemplateRadioButtonProps = {
+  template: ITemplate,
+  onChange: (selectedTemplate: ITemplate) => void,
+  isSelected?: boolean,
+}
+
+const TemplateRadioButton = ({ template, onChange, isSelected }: TemplateRadioButtonProps): JSX.Element => {
+  const radioButtonId = `rb-${template.id}`;
+
+  return (
+    <div key={template.id} className="custom-control custom-radio mb-2">
+      <input
+        id={radioButtonId}
+        type="radio"
+        className="custom-control-input"
+        checked={isSelected}
+        onChange={() => onChange(template)}
+      />
+      <label className="custom-control-label" htmlFor={radioButtonId}>
+        {template.name}
+      </label>
+    </div>
+  );
+};
+
+export const TemplateModal = (): JSX.Element => {
+  const { t } = useTranslation(['translation', 'commons']);
+
+
+  const { data: templateModalStatus, close } = useTemplateModal();
+
+  const { data: rendererOptions } = usePreviewOptions();
+  const { data: templates } = useTemplates();
+
+  const [selectedTemplate, setSelectedTemplate] = useState<ITemplate>();
+
+  const { format } = useFormatter();
+
+  const submitHandler = useCallback((template?: ITemplate) => {
+    if (templateModalStatus == null || selectedTemplate == null) {
+      return;
+    }
+
+    if (templateModalStatus.onSubmit == null || template == null) {
+      close();
+      return;
+    }
+
+    templateModalStatus.onSubmit(format(selectedTemplate));
+    close();
+  }, [close, format, selectedTemplate, templateModalStatus]);
+
+  useEffect(() => {
+    if (!templateModalStatus?.isOpened) {
+      setSelectedTemplate(undefined);
+    }
+  }, [templateModalStatus?.isOpened]);
+
+  if (templates == null || templateModalStatus == null) {
+    return <></>;
+  }
+
+  return (
+    <Modal className="link-edit-modal" isOpen={templateModalStatus.isOpened} toggle={close} size="lg" autoFocus={false}>
+      <ModalHeader tag="h4" toggle={close} className="bg-primary text-light">
+        {t('template.modal_label.Select template')}
+      </ModalHeader>
+
+      <ModalBody className="container">
+        <div className="row">
+          <div className="col-12">
+            { templates.map(template => (
+              <TemplateRadioButton
+                key={template.id}
+                template={template}
+                onChange={selected => setSelectedTemplate(selected)}
+                isSelected={template.id === selectedTemplate?.id}
+              />
+            )) }
+          </div>
+        </div>
+
+        <hr />
+
+        <h3>{t('Preview')}</h3>
+        <div className='card'>
+          <div className="card-body" style={{ height: '400px', overflowY: 'auto' }}>
+            { rendererOptions != null && selectedTemplate != null && (
+              <Preview rendererOptions={rendererOptions} markdown={format(selectedTemplate)}/>
+            ) }
+          </div>
+        </div>
+
+      </ModalBody>
+      <ModalFooter>
+        <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={close}>
+          {t('Cancel')}
+        </button>
+        <button type="submit" className="btn btn-sm btn-primary mx-1" onClick={() => submitHandler(selectedTemplate)} disabled={selectedTemplate == null}>
+          {t('commons:Insert')}
+        </button>
+      </ModalFooter>
+    </Modal>
+  );
+};

+ 1 - 131
apps/app/src/components/TemplateModal/index.tsx

@@ -1,131 +1 @@
-import React, {
-  useCallback, useEffect, useState,
-} from 'react';
-
-import type { ITemplate } from '@growi/core/dist/interfaces/template';
-import { useTranslation } from 'next-i18next';
-import {
-  Modal,
-  ModalHeader,
-  ModalBody,
-  ModalFooter,
-} from 'reactstrap';
-
-import { useTemplateModal } from '~/stores/modal';
-import { usePreviewOptions } from '~/stores/renderer';
-import { useTemplates } from '~/stores/template';
-import loggerFactory from '~/utils/logger';
-
-import Preview from '../PageEditor/Preview';
-
-import { useFormatter } from './use-formatter';
-
-const logger = loggerFactory('growi:components:TemplateModal');
-
-
-type TemplateRadioButtonProps = {
-  template: ITemplate,
-  onChange: (selectedTemplate: ITemplate) => void,
-  isSelected?: boolean,
-}
-
-const TemplateRadioButton = ({ template, onChange, isSelected }: TemplateRadioButtonProps): JSX.Element => {
-  const radioButtonId = `rb-${template.id}`;
-
-  return (
-    <div key={template.id} className="custom-control custom-radio mb-2">
-      <input
-        id={radioButtonId}
-        type="radio"
-        className="custom-control-input"
-        checked={isSelected}
-        onChange={() => onChange(template)}
-      />
-      <label className="custom-control-label" htmlFor={radioButtonId}>
-        {template.name}
-      </label>
-    </div>
-  );
-};
-
-export const TemplateModal = (): JSX.Element => {
-  const { t } = useTranslation();
-
-
-  const { data: templateModalStatus, close } = useTemplateModal();
-
-  const { data: rendererOptions } = usePreviewOptions();
-  const { data: templates } = useTemplates();
-
-  const [selectedTemplate, setSelectedTemplate] = useState<ITemplate>();
-
-  const { format } = useFormatter();
-
-  const submitHandler = useCallback((template?: ITemplate) => {
-    if (templateModalStatus == null || selectedTemplate == null) {
-      return;
-    }
-
-    if (templateModalStatus.onSubmit == null || template == null) {
-      close();
-      return;
-    }
-
-    templateModalStatus.onSubmit(format(selectedTemplate));
-    close();
-  }, [close, format, selectedTemplate, templateModalStatus]);
-
-  useEffect(() => {
-    if (!templateModalStatus?.isOpened) {
-      setSelectedTemplate(undefined);
-    }
-  }, [templateModalStatus?.isOpened]);
-
-  if (templates == null || templateModalStatus == null) {
-    return <></>;
-  }
-
-  return (
-    <Modal className="link-edit-modal" isOpen={templateModalStatus.isOpened} toggle={close} size="lg" autoFocus={false}>
-      <ModalHeader tag="h4" toggle={close} className="bg-primary text-light">
-        Template
-      </ModalHeader>
-
-      <ModalBody className="container">
-        <div className="row">
-          <div className="col-12">
-            { templates.map(template => (
-              <TemplateRadioButton
-                key={template.id}
-                template={template}
-                onChange={t => setSelectedTemplate(t)}
-                isSelected={template.id === selectedTemplate?.id}
-              />
-            )) }
-          </div>
-        </div>
-
-        { rendererOptions != null && selectedTemplate != null && (
-          <>
-            <hr />
-            <h3>Preview</h3>
-            <div className='card'>
-              <div className="card-body" style={{ maxHeight: '60vh', overflowY: 'auto' }}>
-                <Preview rendererOptions={rendererOptions} markdown={format(selectedTemplate)}/>
-              </div>
-            </div>
-          </>
-        ) }
-
-      </ModalBody>
-      <ModalFooter>
-        <button type="button" className="btn btn-sm btn-outline-secondary mx-1" onClick={close}>
-          {t('Cancel')}
-        </button>
-        <button type="submit" className="btn btn-sm btn-primary mx-1" onClick={() => submitHandler(selectedTemplate)} disabled={selectedTemplate == null}>
-          {t('Update')}
-        </button>
-      </ModalFooter>
-    </Modal>
-  );
-};
+export * from './TemplateModal';