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

reactify SystemVersion and ShortcutsModal

Yuki Takei 3 лет назад
Родитель
Сommit
822e8c88e6

+ 5 - 0
packages/app/src/client/base.jsx

@@ -6,6 +6,8 @@ import AppContainer from '~/client/services/AppContainer';
 import SocketIoContainer from '~/client/services/SocketIoContainer';
 import { DescendantsPageListModal } from '~/components/DescendantsPageListModal';
 import PutbackPageModal from '~/components/PutbackPageModal';
+import ShortcutsModal from '~/components/ShortcutsModal';
+import SystemVersion from '~/components/SystemVersion';
 import InterceptorManager from '~/services/interceptor-manager';
 import Xss from '~/services/xss';
 import loggerFactory from '~/utils/logger';
@@ -61,8 +63,11 @@ const componentMappings = {
   'page-accessories-modal': <PageAccessoriesModal />,
   'descendants-page-list-modal': <DescendantsPageListModal />,
   'page-put-back-modal': <PutbackPageModal />,
+  'shortcuts-modal': <ShortcutsModal />,
 
   'grw-hotkeys-manager': <HotkeysManager />,
+  'system-version': <SystemVersion />,
+
 
 };
 

+ 2 - 2
packages/app/src/client/services/ContextExtractor.tsx

@@ -18,7 +18,7 @@ import {
   useShareLinkId, useShareLinksNumber, useTemplateTagData, useCurrentUpdatedAt, useCreator, useRevisionAuthor, useCurrentUser, useTargetAndAncestors,
   useNotFoundTargetPathOrId, useIsSearchPage, useIsForbidden, useIsIdenticalPath, useHasParent,
   useIsAclEnabled, useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsEnabledAttachTitleHeader, useIsNotFoundPermalink,
-  useDefaultIndentSize, useIsIndentSizeForced, useCsrfToken,
+  useDefaultIndentSize, useIsIndentSizeForced, useCsrfToken, useGrowiVersion,
 } from '../../stores/context';
 
 const { isTrashPage: _isTrashPage } = pagePathUtils;
@@ -119,7 +119,7 @@ const ContextExtractorOnce: FC = () => {
   useIsEnabledAttachTitleHeader(configByContextHydrate.isEnabledAttachTitleHeader);
   useIsIndentSizeForced(configByContextHydrate.isIndentSizeForced);
   useDefaultIndentSize(configByContextHydrate.adminPreferredIndentSize);
-
+  useGrowiVersion(configByContextHydrate.crowi.version);
 
   // Page
   useCurrentCreatedAt(createdAt);

+ 0 - 26
packages/app/src/components/Hotkeys/Subscribers/ShowShortcutsModal.jsx

@@ -1,26 +0,0 @@
-import React, { useEffect } from 'react';
-import PropTypes from 'prop-types';
-
-const ShowShortcutsModal = (props) => {
-
-  // setup effect
-  useEffect(() => {
-    // show modal to create a page
-    $('#shortcuts-modal').modal('toggle');
-
-    // remove this
-    props.onDeleteRender(this);
-  }, [props]);
-
-  return <></>;
-};
-
-ShowShortcutsModal.propTypes = {
-  onDeleteRender: PropTypes.func.isRequired,
-};
-
-ShowShortcutsModal.getHotkeyStrokes = () => {
-  return [['/+ctrl'], ['/+meta']];
-};
-
-export default ShowShortcutsModal;

+ 34 - 0
packages/app/src/components/Hotkeys/Subscribers/ShowShortcutsModal.tsx

@@ -0,0 +1,34 @@
+import React, { useEffect } from 'react';
+
+import { useShortcutsModal } from '~/stores/modal';
+
+type Props = {
+  onDeleteRender: () => void,
+}
+const ShowShortcutsModal = (props: Props): JSX.Element => {
+
+  const { data: status, open } = useShortcutsModal();
+
+  const { onDeleteRender } = props;
+
+  // setup effect
+  useEffect(() => {
+    if (status == null) {
+      return;
+    }
+
+    if (!status.isOpened) {
+      open();
+      // remove this
+      onDeleteRender();
+    }
+  }, [onDeleteRender, open, status]);
+
+  return <></>;
+};
+
+ShowShortcutsModal.getHotkeyStrokes = () => {
+  return [['/+ctrl'], ['/+meta']];
+};
+
+export default ShowShortcutsModal;

+ 13 - 0
packages/app/src/components/Icons/KeyboardReturnEnterIcon.tsx

@@ -0,0 +1,13 @@
+import React from 'react';
+
+const KeyboardReturnEnterIcon = ():JSX.Element => (
+  <svg xmlns="http://www.w3.org/2000/svg" width="20px" viewBox="0 0 34 21">
+    <g id="ba5f4106-f870-416b-bb0c-2580c9a76268">
+      <g id="1def15e1-5198-4ca2-9457-3b509e83053f">
+        <polygon points="31 0 31 9 5 9 11.8 1.8 10 0 0 10.5 10 21 11.8 19.2 5 12 34 12 34 0 31 0" />
+      </g>
+    </g>
+  </svg>
+);
+
+export default KeyboardReturnEnterIcon;

+ 166 - 0
packages/app/src/components/ShortcutsModal.tsx

@@ -0,0 +1,166 @@
+import React from 'react';
+
+import { useTranslation } from 'react-i18next';
+import { Modal, ModalHeader, ModalBody } from 'reactstrap';
+
+import KeyboardReturnEnterIcon from '~/components/Icons/KeyboardReturnEnterIcon';
+import { useShortcutsModal } from '~/stores/modal';
+
+const ShortcutsModal = (): JSX.Element => {
+  const { t } = useTranslation();
+
+  const { data: status, close } = useShortcutsModal();
+
+  // add classes to cmd-key by OS
+  const platform = window.navigator.platform.toLowerCase();
+  const isMac = (platform.indexOf('mac') > -1);
+  const additionalClassByOs = isMac ? 'mac' : 'key-longer win';
+
+  return (
+    <>
+      { status != null && (
+        <Modal id="shortcuts-modal" size="lg" isOpen={status.isOpened} toggle={close} className="grw-create-page">
+          <ModalHeader tag="h4" toggle={close} className="bg-primary text-light">
+            {t('Shortcuts')}
+          </ModalHeader>
+          <ModalBody>
+            <div className="container">
+              <div className="row">
+                <div className="col-lg-6">
+                  <h3>
+                    <strong>{t('modal_shortcuts.global.title')}</strong>
+                  </h3>
+
+                  <table className="table">
+                    <tbody>
+                      <tr>
+                        <th>
+                          {/* eslint-disable-next-line react/no-danger */}
+                          <span dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Open/Close shortcut help') }} />:
+                        </th>
+                        <td>
+                          <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">/</span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.global.Create Page')}:</th>
+                        <td>
+                          <span className="key">C</span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.global.Edit Page')}:</th>
+                        <td>
+                          <span className="key">E</span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.global.Search')}:</th>
+                        <td><span className="key">/</span></td>
+                      </tr>
+                      <tr>
+                        <th>
+                          {/* eslint-disable-next-line react/no-danger */}
+                          <span dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Show Contributors') }} />:
+                        </th>
+                        <td>
+                          <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
+                            {t('modal_shortcuts.global.Konami Code')}
+                          </a>
+                          <br />
+                          <span className="key key-small">&uarr;</span>&nbsp;<span className="key key-small">&uarr;</span>
+                          <span className="key key-small">&darr;</span>&nbsp;<span className="key key-small">&darr;</span>
+                          <span className="key key-small">&larr;</span>
+                          <br />
+                          <span className="key key-small">&rarr;</span>
+                          <span className="key key-small">&larr;</span>&nbsp;<span className="key key-small">&rarr;</span>
+                          <span className="key key-small">B</span>&nbsp;<span className="key key-small">A</span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.global.MirrorMode')}:</th>
+                        <td>
+                          <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
+                            {t('modal_shortcuts.global.Konami Code')}
+                          </a>
+                          <br />
+                          <span className="key key-small">X</span>&nbsp;<span className="key key-small">X</span>
+                          <span className="key key-small">B</span>&nbsp;<span className="key key-small">B</span>
+                          <span className="key key-small">A</span>
+                          <br />
+                          <span className="key key-small">Y</span>
+                          <span className="key key-small">A</span>&nbsp;<span className="key key-small">Y</span>
+                          <span className="key key-small">&darr;</span>&nbsp;<span className="key key-small">&larr;</span>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+                </div>
+
+                <div className="col-lg-6">
+                  <h3>
+                    <strong>{t('modal_shortcuts.editor.title')}</strong>
+                  </h3>
+                  <table className="table">
+                    <tbody>
+                      <tr>
+                        <th>{t('modal_shortcuts.editor.Indent')}:</th>
+                        <td>
+                          <span className="key key-longer">Tab</span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.editor.Outdent')}:</th>
+                        <td className="text-nowrap">
+                          <span className="key key-long">Shift</span> + <span className="key key-longer">Tab</span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.editor.Save Page')}:</th>
+                        <td>
+                          <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">S</span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.editor.Delete Line')}:</th>
+                        <td>
+                          <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">D</span>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+
+                  <h3>
+                    <strong>{t('modal_shortcuts.commentform.title')}</strong>
+                  </h3>
+
+                  <table className="table">
+                    <tbody>
+                      <tr>
+                        <th>{t('modal_shortcuts.commentform.Post')}:</th>
+                        <td className="text-nowrap">
+                          <span className={`key cmd-key ${additionalClassByOs}`}></span> +
+                          <span className="key key-longer">
+                            <KeyboardReturnEnterIcon />
+                          </span>
+                        </td>
+                      </tr>
+                      <tr>
+                        <th>{t('modal_shortcuts.editor.Delete Line')}:</th>
+                        <td>
+                          <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">D</span>
+                        </td>
+                      </tr>
+                    </tbody>
+                  </table>
+                </div>
+              </div>
+            </div>
+          </ModalBody>
+        </Modal>
+      ) }
+    </>
+  );
+};
+
+export default ShortcutsModal;

+ 31 - 0
packages/app/src/components/SystemVersion.tsx

@@ -0,0 +1,31 @@
+import React from 'react';
+
+import { useGrowiVersion } from '~/stores/context';
+import { useShortcutsModal } from '~/stores/modal';
+
+const SystemVersion = (): JSX.Element => {
+
+  const { open: openShortcutsModal } = useShortcutsModal();
+
+  const { data: growiVersion } = useGrowiVersion();
+  // add classes to cmd-key by OS
+  const platform = window.navigator.platform.toLowerCase();
+  const isMac = (platform.indexOf('mac') > -1);
+  const os = isMac ? 'mac' : 'win';
+
+  return (
+    <>
+      <div className="system-version d-none d-md-flex d-edit-none d-print-none align-items-center">
+        <span>
+          <a href="https://growi.org">GROWI</a> {growiVersion}
+        </span>
+        <button type="button" className="btn btn-link ml-2 p-0" onClick={() => openShortcutsModal()}>
+          <i className="fa fa-keyboard-o"></i>&nbsp;<span className={`cmd-key ${os}`}></span>-/
+        </button>
+      </div>
+
+    </>
+  );
+};
+
+export default SystemVersion;

+ 2 - 1
packages/app/src/server/models/config.ts

@@ -1,7 +1,7 @@
+import { getOrCreateModel } from '@growi/core';
 import { Types, Schema } from 'mongoose';
 import uniqueValidator from 'mongoose-unique-validator';
 
-import { getOrCreateModel } from '@growi/core';
 
 export interface Config {
   _id: Types.ObjectId;
@@ -194,6 +194,7 @@ schema.statics.getLocalconfig = function(crowi) {
       title: crowi.appService.getAppTitle(),
       url: crowi.appService.getSiteUrl(),
       confidential: crowi.appService.getAppConfidential(),
+      version: crowi.version,
     },
     upload: {
       image: crowi.fileUploadService.getIsUploadable(),

+ 0 - 4
packages/app/src/server/util/swigFunctions.js

@@ -27,10 +27,6 @@ module.exports = function(crowi, req, locals) {
     return crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version : '-';
   };
 
-  locals.growiVersion = function() {
-    return crowi.version;
-  };
-
   // token getter
   locals.csrf = function() {
     return req.csrfToken;

+ 2 - 3
packages/app/src/server/views/layout/layout.html

@@ -102,7 +102,7 @@
 
 <div id="grw-hotkeys-manager"></div>
 
-{% include '../widget/system-version.html' %}
+<div id="system-version"></div>
 
 <div id="page-create-modal"></div>
 <div id="page-delete-modal"></div>
@@ -113,8 +113,7 @@
 <div id="page-accessories-modal"></div>
 <div id="descendants-page-list-modal"></div>
 <div id="page-put-back-modal"></div>
-
-{% include '../modal/shortcuts.html' %}
+<div id="shortcuts-modal"></div>
 
 {% block body_end %}
 {% endblock %}

+ 0 - 105
packages/app/src/server/views/modal/shortcuts.html

@@ -1,105 +0,0 @@
-<div class="modal" id="shortcuts-modal" tabindex="-1">
-  <div class="modal-dialog modal-lg">
-    <div class="modal-content">
-
-      <div class="modal-header bg-primary text-light">
-        <div class="modal-title">{{ t('Shortcuts') }}</div>
-        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-      </div>
-
-      <div class="modal-body">
-        <div class="container">
-          <div class="row">
-            <div class="col-lg-6">
-              <h3><strong>{{ t('modal_shortcuts.global.title') }}</strong></h3>
-
-                <table class="table">
-                  <tr>
-                    <th>{{ t('modal_shortcuts.global.Open/Close shortcut help') }}:</th>
-                    <td><span class="key cmd-key"></span> + <span class="key">/</span></td>
-                  </tr>
-                  <tr>
-                    <th>{{ t('modal_shortcuts.global.Create Page') }}:</th>
-                    <td><span class="key">C</span></td>
-                  </tr>
-                  <tr>
-                    <th>{{ t('modal_shortcuts.global.Edit Page') }}:</th>
-                    <td><span class="key">E</span></td>
-                  </tr>
-                  <tr>
-                    <th>{{ t('modal_shortcuts.global.Search') }}:</th>
-                    <td><span class="key">/</span></td>
-                  </tr>
-                  <tr>
-                    <th>{{ t('modal_shortcuts.global.Show Contributors') }}:</th>
-                    <td>
-                      <a href="{{ t('modal_shortcuts.global.konami_code_url') }}" target="_blank">{{ t('modal_shortcuts.global.Konami Code') }}</a><br>
-                      <span class="key key-small">↑</span>&nbsp;<span class="key key-small">↑</span>
-                      <span class="key key-small">↓</span>&nbsp;<span class="key key-small">↓</span>
-                      <span class="key key-small">←</span><br><span class="key key-small">→</span>
-                      <span class="key key-small">←</span>&nbsp;<span class="key key-small">→</span>
-                      <span class="key key-small">B</span>&nbsp;<span class="key key-small">A</span>
-                    </td>
-                  </tr>
-                  <tr>
-                    <th>{{ t('modal_shortcuts.global.MirrorMode') }}:</th>
-                    <td>
-                      <a href="{{ t('modal_shortcuts.global.konami_code_url') }}" target="_blank">{{ t('modal_shortcuts.global.Konami Code') }}</a><br>
-                      <span class="key key-small">X</span>&nbsp;<span class="key key-small">X</span>
-                      <span class="key key-small">B</span>&nbsp;<span class="key key-small">B</span>
-                      <span class="key key-small">A</span><br><span class="key key-small">Y</span>
-                      <span class="key key-small">A</span>&nbsp;<span class="key key-small">Y</span>
-                      <span class="key key-small">↓</span>&nbsp;<span class="key key-small">←</span>
-                    </td>
-                  </tr>
-                </table>
-            </div><!-- /.col-lg-6 -->
-
-
-            <div class="col-lg-6">
-              <h3><strong>{{ t('modal_shortcuts.editor.title') }}</strong></h3>
-
-              <table class="table">
-                <tr>
-                  <th>{{ t('modal_shortcuts.editor.Indent') }}:</th>
-                  <td><span class="key key-longer">Tab</span></td>
-                </tr>
-                <tr>
-                  <th>{{ t('modal_shortcuts.editor.Outdent') }}:</th>
-                  <td class="text-nowrap"><span class="key key-long">Shift</span> + <span class="key key-longer">Tab</span></td>
-                </tr>
-                <tr>
-                  <th>{{ t('modal_shortcuts.editor.Save Page') }}:</th>
-                  <td><span class="key cmd-key"></span> + <span class="key">S</span></td>
-                </tr>
-                <tr>
-                  <th>{{ t('modal_shortcuts.editor.Delete Line') }}:</th>
-                  <td><span class="key cmd-key"></span> + <span class="key">D</span></td>
-                </tr>
-              </table>
-
-              <h3><strong>{{ t('modal_shortcuts.commentform.title') }}</strong></h3>
-
-              <table class="table">
-                <tr>
-                  <th>{{ t('modal_shortcuts.commentform.Post') }}:</th>
-                  <td class="text-nowrap"><span class="key cmd-key"></span> + <span class="key key-longer">{% include '../widget/icon-keyboard-return-enter.html' %}</span></td>
-                </tr>
-                <tr>
-                  <th>{{ t('modal_shortcuts.editor.Delete Line') }}:</th>
-                  <td><span class="key cmd-key"></span> + <span class="key">D</span></td>
-                </tr>
-              </table>
-
-            </div><!-- /.col-lg-6 -->
-          </div><!-- /.row -->
-        </div><!-- /.container -->
-
-      </div>
-    </div>
-
-
-    </div><!-- /.modal-content -->
-  </div><!-- /.modal-dialog -->
-
-</div><!-- /.modal -->

+ 0 - 7
packages/app/src/server/views/widget/icon-keyboard-return-enter.html

@@ -1,7 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="20px" viewBox="0 0 34 21">
-  <g id="ba5f4106-f870-416b-bb0c-2580c9a76268">
-    <g id="1def15e1-5198-4ca2-9457-3b509e83053f">
-      <polygon points="31 0 31 9 5 9 11.8 1.8 10 0 0 10.5 10 21 11.8 19.2 5 12 34 12 34 0 31 0" />
-    </g>
-  </g>
-</svg>

+ 0 - 8
packages/app/src/server/views/widget/system-version.html

@@ -1,8 +0,0 @@
-<div class="system-version d-none d-md-block d-edit-none d-print-none">
-  <span>
-    <a href="https://growi.org">GROWI</a> {{ growiVersion() }}
-  </span>
-  <span>
-    <a href="" data-target="#shortcuts-modal" data-toggle="modal"><i class="fa fa-keyboard-o"></i>&nbsp;<span class="cmd-key"></span>-/</a>
-  </span>
-</div>

+ 4 - 0
packages/app/src/stores/context.tsx

@@ -168,6 +168,10 @@ export const useDefaultIndentSize = (initialData?: number) : SWRResponse<number,
   return useStaticSWR<number, Error>('defaultIndentSize', initialData, { fallbackData: 4 });
 };
 
+export const useGrowiVersion = (initialData?: string): SWRResponse<string, any> => {
+  return useStaticSWR('growiVersion', initialData);
+};
+
 
 /** **********************************************************
  *                     Computed contexts

+ 28 - 0
packages/app/src/stores/modal.tsx

@@ -410,3 +410,31 @@ export const useUpdateUserGroupConfirmModal = (): SWRResponse<UpdateUserGroupCon
     },
   };
 };
+
+/*
+ * ShortcutsModal
+ */
+type ShortcutsModalStatus = {
+  isOpened: boolean,
+}
+
+type ShortcutsModalUtils = {
+  open(): void,
+  close(): void,
+}
+
+export const useShortcutsModal = (): SWRResponse<ShortcutsModalStatus, Error> & ShortcutsModalUtils => {
+
+  const initialStatus: ShortcutsModalStatus = { isOpened: false };
+  const swrResponse = useStaticSWR<ShortcutsModalStatus, Error>('shortcutsModal', undefined, { fallbackData: initialStatus });
+
+  return {
+    ...swrResponse,
+    open() {
+      swrResponse.mutate({ isOpened: true });
+    },
+    close() {
+      swrResponse.mutate({ isOpened: false });
+    },
+  };
+};

+ 0 - 4
packages/app/src/styles/_layout.scss

@@ -146,8 +146,4 @@ body.growi-layout-fluid .grw-container-convertible {
   right: 0.5em;
   bottom: 0;
   opacity: 0.6;
-
-  > span {
-    margin-left: 0.5em;
-  }
 }