소스 검색

Merge pull request #10553 from growilabs/imprv/173835-new-help-button

imprv: New help button
Yuki Takei 3 달 전
부모
커밋
977b261ad2

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

@@ -786,6 +786,11 @@
       "updatedAt": "Last update date"
       "updatedAt": "Last update date"
     }
     }
   },
   },
+  "help_dropdown": {
+    "show_shortcuts": "Show shortcuts",
+    "growi_cloud_help": "GROWI.cloud Help",
+    "growi_version": "GROWI version"
+  },
   "private_legacy_pages": {
   "private_legacy_pages": {
     "title": "Private Legacy Pages",
     "title": "Private Legacy Pages",
     "bulk_operation": "Bulk operation",
     "bulk_operation": "Bulk operation",

+ 5 - 0
apps/app/public/static/locales/fr_FR/translation.json

@@ -780,6 +780,11 @@
       "updatedAt": "Dernière modification"
       "updatedAt": "Dernière modification"
     }
     }
   },
   },
+  "help_dropdown": {
+    "show_shortcuts": "Afficher les raccourcis",
+    "growi_cloud_help": "Aide GROWI.cloud",
+    "growi_version": "Version GROWI"
+  },
   "private_legacy_pages": {
   "private_legacy_pages": {
     "title": "Anciennes pages privées",
     "title": "Anciennes pages privées",
     "bulk_operation": "Opération de masse",
     "bulk_operation": "Opération de masse",

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

@@ -819,6 +819,11 @@
       "updatedAt": "更新日時"
       "updatedAt": "更新日時"
     }
     }
   },
   },
+  "help_dropdown": {
+    "show_shortcuts": "ショートカットを表示",
+    "growi_cloud_help": "GROWI.cloud ヘルプ",
+    "growi_version": "GROWI バージョン"
+  },
   "private_legacy_pages": {
   "private_legacy_pages": {
     "title": "旧形式のプライベートページ",
     "title": "旧形式のプライベートページ",
     "bulk_operation": "一括操作",
     "bulk_operation": "一括操作",

+ 5 - 0
apps/app/public/static/locales/ko_KR/translation.json

@@ -746,6 +746,11 @@
       "updatedAt": "마지막 업데이트일"
       "updatedAt": "마지막 업데이트일"
     }
     }
   },
   },
+  "help_dropdown": {
+    "show_shortcuts": "단축키 표시",
+    "growi_cloud_help": "GROWI.cloud 도움말",
+    "growi_version": "GROWI 버전"
+  },
   "private_legacy_pages": {
   "private_legacy_pages": {
     "title": "비공개 레거시 페이지",
     "title": "비공개 레거시 페이지",
     "bulk_operation": "대량 작업",
     "bulk_operation": "대량 작업",

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

@@ -791,6 +791,11 @@
       "updatedAt": "按更新日期排序"
       "updatedAt": "按更新日期排序"
     }
     }
   },
   },
+  "help_dropdown": {
+    "show_shortcuts": "显示快捷键",
+    "growi_cloud_help": "GROWI.cloud 帮助",
+    "growi_version": "GROWI 版本"
+  },
   "private_legacy_pages": {
   "private_legacy_pages": {
     "title": "私人遗留页面",
     "title": "私人遗留页面",
     "bulk_operation": "批量操作",
     "bulk_operation": "批量操作",

+ 2 - 2
apps/app/src/client/components/ShortcutsModal/ShortcutsModal.tsx

@@ -19,8 +19,8 @@ const ShortcutsModalSubstance = (): React.JSX.Element => {
 
 
   // Memoize OS-specific class
   // Memoize OS-specific class
   const additionalClassByOs = useMemo(() => {
   const additionalClassByOs = useMemo(() => {
-    const platform = window.navigator.platform.toLowerCase();
-    const isMac = platform.indexOf('mac') > -1;
+    const userAgent = window.navigator.userAgent.toLowerCase();
+    const isMac = userAgent.indexOf('mac') > -1;
     return isMac ? 'mac' : 'win';
     return isMac ? 'mac' : 'win';
   }, []);
   }, []);
 
 

+ 14 - 0
apps/app/src/client/components/Sidebar/SidebarNav/HelpDropdown.module.scss

@@ -0,0 +1,14 @@
+@use '@growi/core-styles/scss/helpers/modifier-keys';
+
+.help-dropdown :global {
+  @include modifier-keys.modifier-key;
+}
+
+.help-dropdown-menu :global {
+  @include modifier-keys.modifier-key;
+}
+
+.help-dropdown-menu :global {
+  --bs-dropdown-font-size: 14px;
+  min-width: 240px;
+}

+ 97 - 0
apps/app/src/client/components/Sidebar/SidebarNav/HelpDropdown.tsx

@@ -0,0 +1,97 @@
+import type { FC } from 'react';
+import { memo } from 'react';
+import { useTranslation } from 'next-i18next';
+import {
+  DropdownItem,
+  DropdownMenu,
+  DropdownToggle,
+  UncontrolledDropdown,
+} from 'reactstrap';
+
+import { useGrowiCloudUri, useGrowiVersion } from '~/states/global';
+import { useShortcutsModalActions } from '~/states/ui/modal/shortcuts';
+
+import { SkeletonItem } from './SkeletonItem';
+
+import styles from './HelpDropdown.module.scss';
+
+export const HelpDropdown: FC = memo(() => {
+  const { t } = useTranslation();
+  const growiVersion = useGrowiVersion();
+  const { open: openShortcutsModal } = useShortcutsModalActions();
+  const growiCloudUri = useGrowiCloudUri();
+
+  if (growiVersion == null) {
+    return <SkeletonItem />;
+  }
+
+  // add classes to cmd-key by OS
+  const userAgent = window.navigator.userAgent.toLowerCase();
+  const isMac = userAgent.indexOf('mac') > -1;
+  const os = isMac ? 'mac' : 'win';
+
+  // Cloud users see Help, others see Docs
+  const isCloudUser = growiCloudUri != null;
+  const helpUrl = isCloudUser
+    ? 'https://growi.cloud/help/'
+    : 'https://docs.growi.org';
+  const helpLabel = isCloudUser ? t('Help') : 'GROWI Docs';
+
+  return (
+    <UncontrolledDropdown direction="end" className={styles['help-dropdown']}>
+      <DropdownToggle
+        className="btn btn-primary d-flex align-items-center justify-content-center"
+        data-testid="help-dropdown-button"
+      >
+        <span className="material-symbols-outlined">help</span>
+      </DropdownToggle>
+
+      <DropdownMenu
+        container="body"
+        data-testid="help-dropdown-menu"
+        className={styles['help-dropdown-menu']}
+      >
+        <DropdownItem header className="text-secondary py-1">
+          {t('Help')}
+        </DropdownItem>
+        <DropdownItem
+          tag="a"
+          href={helpUrl}
+          target="_blank"
+          rel="noopener noreferrer"
+          className="my-1"
+          data-testid="help-link"
+        >
+          <span className="d-flex align-items-center">
+            {helpLabel}
+            <span className="growi-custom-icons ms-1 small">external_link</span>
+          </span>
+        </DropdownItem>
+
+        <DropdownItem className="my-1" onClick={() => openShortcutsModal()}>
+          <span className="d-flex align-items-center">
+            <span className="flex-grow-1">
+              {t('help_dropdown.show_shortcuts')}
+            </span>
+            <span className="text-secondary">
+              <span className={`cmd-key ${os}`} />
+              &nbsp;+ /
+            </span>
+          </span>
+        </DropdownItem>
+
+        <DropdownItem divider className="my-2" />
+
+        <DropdownItem header className="py-1">
+          <span className="d-flex text-secondary">
+            <span className="flex-grow-1">
+              {' '}
+              {t('help_dropdown.growi_version')}
+            </span>
+            {growiVersion}
+          </span>
+        </DropdownItem>
+      </DropdownMenu>
+    </UncontrolledDropdown>
+  );
+});

+ 2 - 12
apps/app/src/client/components/Sidebar/SidebarNav/SecondaryItems.tsx

@@ -4,8 +4,8 @@ import dynamic from 'next/dynamic';
 import Link from 'next/link';
 import Link from 'next/link';
 
 
 import { useIsAdmin, useIsGuestUser } from '~/states/context';
 import { useIsAdmin, useIsGuestUser } from '~/states/context';
-import { useGrowiCloudUri } from '~/states/global';
 
 
+import { HelpDropdown } from './HelpDropdown';
 import { SkeletonItem } from './SkeletonItem';
 import { SkeletonItem } from './SkeletonItem';
 
 
 import styles from './SecondaryItems.module.scss';
 import styles from './SecondaryItems.module.scss';
@@ -42,21 +42,11 @@ const SecondaryItem: FC<SecondaryItemProps> = (props: SecondaryItemProps) => {
 
 
 export const SecondaryItems: FC = memo(() => {
 export const SecondaryItems: FC = memo(() => {
   const isAdmin = useIsAdmin();
   const isAdmin = useIsAdmin();
-  const growiCloudUri = useGrowiCloudUri();
   const isGuestUser = useIsGuestUser();
   const isGuestUser = useIsGuestUser();
 
 
   return (
   return (
     <div className={styles['grw-secondary-items']}>
     <div className={styles['grw-secondary-items']}>
-      <SecondaryItem
-        label="Help"
-        iconName="help"
-        href={
-          growiCloudUri != null
-            ? 'https://growi.cloud/help/'
-            : 'https://docs.growi.org'
-        }
-        isBlank
-      />
+      <HelpDropdown />
       {isAdmin && (
       {isAdmin && (
         <SecondaryItem label="Admin" iconName="settings" href="/admin" />
         <SecondaryItem label="Admin" iconName="settings" href="/admin" />
       )}
       )}

+ 0 - 10
apps/app/src/client/components/SystemVersion.module.scss

@@ -1,10 +0,0 @@
-@use '@growi/core-styles/scss/helpers/modifier-keys';
-
-.system-version :global {
-  position: fixed;
-  right: 0.5em;
-  bottom: 0;
-  opacity: 0.6;
-
-  @include modifier-keys.modifier-key;
-}

+ 0 - 46
apps/app/src/client/components/SystemVersion.tsx

@@ -1,46 +0,0 @@
-import React, { type JSX } from 'react';
-
-import { useGrowiVersion } from '~/states/global';
-import { useShortcutsModalActions } from '~/states/ui/modal/shortcuts';
-
-import styles from './SystemVersion.module.scss';
-
-type Props = {
-  showShortcutsButton?: boolean;
-};
-
-const SystemVersion = (props: Props): JSX.Element => {
-  const { showShortcutsButton } = props;
-
-  const { open: openShortcutsModal } = useShortcutsModalActions();
-
-  const 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={`${styles['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>
-        {showShortcutsButton && (
-          <button
-            type="button"
-            className="btn btn-link ms-2 p-0"
-            onClick={() => openShortcutsModal()}
-          >
-            <span className="material-symbols-outlined">keyboard</span>&nbsp;
-            <span className={`cmd-key ${os}`}></span>-/
-          </button>
-        )}
-      </div>
-    </>
-  );
-};
-
-export default SystemVersion;

+ 0 - 6
apps/app/src/components/Layout/AdminLayout.tsx

@@ -20,11 +20,6 @@ const PageCreateModal = dynamic(
   () => import('~/client/components/PageCreateModal'),
   () => import('~/client/components/PageCreateModal'),
   { ssr: false },
   { ssr: false },
 );
 );
-const SystemVersion = dynamic(
-  // biome-ignore lint/style/noRestrictedImports: no-problem dynamic import
-  () => import('~/client/components/SystemVersion'),
-  { ssr: false },
-);
 const HotkeysManager = dynamic(
 const HotkeysManager = dynamic(
   // biome-ignore lint/style/noRestrictedImports: no-problem dynamic import
   // biome-ignore lint/style/noRestrictedImports: no-problem dynamic import
   () => import('~/client/components/Hotkeys/HotkeysManager'),
   () => import('~/client/components/Hotkeys/HotkeysManager'),
@@ -60,7 +55,6 @@ const AdminLayout = ({ children, componentTitle }: Props): JSX.Element => {
         </div>
         </div>
 
 
         <PageCreateModal />
         <PageCreateModal />
-        <SystemVersion />
       </div>
       </div>
 
 
       <HotkeysManager />
       <HotkeysManager />

+ 0 - 5
apps/app/src/components/Layout/BasicLayout.tsx

@@ -43,10 +43,6 @@ const GrowiNavbarBottom = dynamic(
     ),
     ),
   { ssr: false },
   { ssr: false },
 );
 );
-const SystemVersion = dynamic(
-  () => import('~/client/components/SystemVersion'),
-  { ssr: false },
-);
 // Page modals
 // Page modals
 const PageCreateModal = dynamic(
 const PageCreateModal = dynamic(
   () => import('~/client/components/PageCreateModal'),
   () => import('~/client/components/PageCreateModal'),
@@ -100,7 +96,6 @@ export const BasicLayout = ({ children, className }: Props): JSX.Element => {
       <ShortcutsModalLazyLoaded />
       <ShortcutsModalLazyLoaded />
       <PageBulkExportSelectModalLazyLoaded />
       <PageBulkExportSelectModalLazyLoaded />
       <GrantedGroupsInheritanceSelectModalLazyLoaded />
       <GrantedGroupsInheritanceSelectModalLazyLoaded />
-      <SystemVersion showShortcutsButton />
     </RawLayout>
     </RawLayout>
   );
   );
 };
 };

+ 0 - 5
apps/app/src/components/Layout/ShareLinkLayout.tsx

@@ -18,10 +18,6 @@ const GrowiNavbarBottom = dynamic(
     ),
     ),
   { ssr: false },
   { ssr: false },
 );
 );
-const SystemVersion = dynamic(
-  () => import('~/client/components/SystemVersion'),
-  { ssr: false },
-);
 // biome-ignore-end lint/style/noRestrictedImports: no-problem dynamic import
 // biome-ignore-end lint/style/noRestrictedImports: no-problem dynamic import
 
 
 type Props = {
 type Props = {
@@ -37,7 +33,6 @@ export const ShareLinkLayout = ({ children }: Props): JSX.Element => {
 
 
       <ShortcutsModalLazyLoaded />
       <ShortcutsModalLazyLoaded />
       <PageCreateModal />
       <PageCreateModal />
-      <SystemVersion showShortcutsButton />
     </RawLayout>
     </RawLayout>
   );
   );
 };
 };