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

exclude title from layout files

Yuki Takei 3 лет назад
Родитель
Сommit
01fa79441c
36 измененных файлов с 237 добавлено и 119 удалено
  1. 5 6
      packages/app/src/components/Layout/AdminLayout.tsx
  2. 2 3
      packages/app/src/components/Layout/BasicLayout.tsx
  3. 2 3
      packages/app/src/components/Layout/NoLoginLayout.tsx
  4. 1 3
      packages/app/src/components/Layout/RawLayout.tsx
  5. 2 3
      packages/app/src/components/Layout/SearchResultLayout.tsx
  6. 2 3
      packages/app/src/components/Layout/ShareLinkLayout.tsx
  7. 7 10
      packages/app/src/pages/[[...path]].page.tsx
  8. 4 5
      packages/app/src/pages/_private-legacy-pages.page.tsx
  9. 3 5
      packages/app/src/pages/_search.page.tsx
  10. 7 1
      packages/app/src/pages/admin/[...path].page.tsx
  11. 7 2
      packages/app/src/pages/admin/app.page.tsx
  12. 6 1
      packages/app/src/pages/admin/audit-log.page.tsx
  13. 7 2
      packages/app/src/pages/admin/customize.page.tsx
  14. 7 2
      packages/app/src/pages/admin/export.page.tsx
  15. 5 1
      packages/app/src/pages/admin/global-notification/[globalNotificationId].page.tsx
  16. 5 1
      packages/app/src/pages/admin/global-notification/new.page.tsx
  17. 7 2
      packages/app/src/pages/admin/importer.page.tsx
  18. 5 1
      packages/app/src/pages/admin/index.page.tsx
  19. 8 2
      packages/app/src/pages/admin/markdown.page.tsx
  20. 7 2
      packages/app/src/pages/admin/notification.page.tsx
  21. 6 1
      packages/app/src/pages/admin/search.page.tsx
  22. 7 3
      packages/app/src/pages/admin/security.page.tsx
  23. 6 1
      packages/app/src/pages/admin/slack-integration-legacy.page.tsx
  24. 7 2
      packages/app/src/pages/admin/slack-integration.page.tsx
  25. 5 1
      packages/app/src/pages/admin/user-group-detail/[userGroupId].page.tsx
  26. 6 1
      packages/app/src/pages/admin/user-groups.page.tsx
  27. 5 1
      packages/app/src/pages/admin/users/external-accounts.page.tsx
  28. 6 1
      packages/app/src/pages/admin/users/index.page.tsx
  29. 6 1
      packages/app/src/pages/installer.page.tsx
  30. 6 1
      packages/app/src/pages/invited.page.tsx
  31. 6 1
      packages/app/src/pages/login.page.tsx
  32. 18 15
      packages/app/src/pages/me/[[...path]].page.tsx
  33. 8 1
      packages/app/src/pages/share/[[...path]].page.tsx
  34. 31 29
      packages/app/src/pages/tags.page.tsx
  35. 7 1
      packages/app/src/pages/trash.page.tsx
  36. 8 1
      packages/app/src/pages/user-activation.page.tsx

+ 5 - 6
packages/app/src/components/Layout/AdminLayout.tsx

@@ -8,25 +8,24 @@ import { RawLayout } from './RawLayout';
 
 
 import styles from './Admin.module.scss';
 import styles from './Admin.module.scss';
 
 
+
+const AdminNavigation = dynamic(() => import('~/components/Admin/Common/AdminNavigation'), { ssr: false });
+const SystemVersion = dynamic(() => import('../SystemVersion'), { ssr: false });
 const HotkeysManager = dynamic(() => import('../Hotkeys/HotkeysManager'), { ssr: false });
 const HotkeysManager = dynamic(() => import('../Hotkeys/HotkeysManager'), { ssr: false });
 
 
 
 
 type Props = {
 type Props = {
-  title?: string
   componentTitle?: string
   componentTitle?: string
   children?: ReactNode
   children?: ReactNode
 }
 }
 
 
 
 
 const AdminLayout = ({
 const AdminLayout = ({
-  children, title, componentTitle,
+  children, componentTitle,
 }: Props): JSX.Element => {
 }: Props): JSX.Element => {
 
 
-  const AdminNavigation = dynamic(() => import('~/components/Admin/Common/AdminNavigation'), { ssr: false });
-  const SystemVersion = dynamic(() => import('../SystemVersion'), { ssr: false });
-
   return (
   return (
-    <RawLayout title={title}>
+    <RawLayout>
       <div className={`admin-page ${styles['admin-page']}`}>
       <div className={`admin-page ${styles['admin-page']}`}>
         <GrowiNavbar />
         <GrowiNavbar />
 
 

+ 2 - 3
packages/app/src/components/Layout/BasicLayout.tsx

@@ -27,20 +27,19 @@ const Fab = dynamic(() => import('../Fab').then(mod => mod.Fab), { ssr: false })
 
 
 
 
 type Props = {
 type Props = {
-  title: string
   className?: string,
   className?: string,
   expandContainer?: boolean,
   expandContainer?: boolean,
   children?: ReactNode
   children?: ReactNode
 }
 }
 
 
 export const BasicLayout = ({
 export const BasicLayout = ({
-  children, title, className, expandContainer,
+  children, className, expandContainer,
 }: Props): JSX.Element => {
 }: Props): JSX.Element => {
 
 
   const myClassName = `${className ?? ''} ${expandContainer ? 'growi-layout-fluid' : ''}`;
   const myClassName = `${className ?? ''} ${expandContainer ? 'growi-layout-fluid' : ''}`;
 
 
   return (
   return (
-    <RawLayout title={title} className={myClassName}>
+    <RawLayout className={myClassName}>
 
 
       <DndProvider backend={HTML5Backend}>
       <DndProvider backend={HTML5Backend}>
         <GrowiNavbar />
         <GrowiNavbar />

+ 2 - 3
packages/app/src/components/Layout/NoLoginLayout.tsx

@@ -7,20 +7,19 @@ import { RawLayout } from './RawLayout';
 import commonStyles from './NoLoginLayout.module.scss';
 import commonStyles from './NoLoginLayout.module.scss';
 
 
 type Props = {
 type Props = {
-  title: string,
   className?: string,
   className?: string,
   children?: ReactNode,
   children?: ReactNode,
 }
 }
 
 
 export const NoLoginLayout = ({
 export const NoLoginLayout = ({
-  children, title, className,
+  children, className,
 }: Props): JSX.Element => {
 }: Props): JSX.Element => {
   const classNames: string[] = ['wrapper'];
   const classNames: string[] = ['wrapper'];
   if (className != null) {
   if (className != null) {
     classNames.push(className);
     classNames.push(className);
   }
   }
   return (
   return (
-    <RawLayout title={title} className={`${commonStyles.nologin}`}>
+    <RawLayout className={`${commonStyles.nologin}`}>
       <div className="nologin">
       <div className="nologin">
         <div id="wrapper">
         <div id="wrapper">
           <div id="page-wrapper">
           <div id="page-wrapper">

+ 1 - 3
packages/app/src/components/Layout/RawLayout.tsx

@@ -15,12 +15,11 @@ const logger = loggerFactory('growi:cli:RawLayout');
 
 
 
 
 type Props = {
 type Props = {
-  title?: string,
   className?: string,
   className?: string,
   children?: ReactNode,
   children?: ReactNode,
 }
 }
 
 
-export const RawLayout = ({ children, title, className }: Props): JSX.Element => {
+export const RawLayout = ({ children, className }: Props): JSX.Element => {
   const classNames: string[] = ['layout-root', 'growi'];
   const classNames: string[] = ['layout-root', 'growi'];
   if (className != null) {
   if (className != null) {
     classNames.push(className);
     classNames.push(className);
@@ -40,7 +39,6 @@ export const RawLayout = ({ children, title, className }: Props): JSX.Element =>
   return (
   return (
     <>
     <>
       <Head>
       <Head>
-        <title>{title}</title>
         <meta charSet="utf-8" />
         <meta charSet="utf-8" />
         <meta name="viewport" content="initial-scale=1.0, width=device-width" />
         <meta name="viewport" content="initial-scale=1.0, width=device-width" />
       </Head>
       </Head>

+ 2 - 3
packages/app/src/components/Layout/SearchResultLayout.tsx

@@ -5,13 +5,12 @@ import { BasicLayout } from '~/components/Layout/BasicLayout';
 import commonStyles from './SearchResultLayout.module.scss';
 import commonStyles from './SearchResultLayout.module.scss';
 
 
 type Props = {
 type Props = {
-  title: string,
   className?: string,
   className?: string,
   children?: ReactNode,
   children?: ReactNode,
 }
 }
 
 
 const SearchResultLayout = ({
 const SearchResultLayout = ({
-  children, title, className,
+  children, className,
 }: Props): JSX.Element => {
 }: Props): JSX.Element => {
 
 
   const classNames: string[] = [];
   const classNames: string[] = [];
@@ -21,7 +20,7 @@ const SearchResultLayout = ({
 
 
   return (
   return (
     <div className={`on-search ${commonStyles['on-search']}`}>
     <div className={`on-search ${commonStyles['on-search']}`}>
-      <BasicLayout title={title} className={classNames.join(' ')}>
+      <BasicLayout className={classNames.join(' ')}>
         <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
         <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
         <div id="main" className="main search-page mt-0">
         <div id="main" className="main search-page mt-0">
           { children }
           { children }

+ 2 - 3
packages/app/src/components/Layout/ShareLinkLayout.tsx

@@ -16,20 +16,19 @@ const Fab = dynamic(() => import('../Fab').then(mod => mod.Fab), { ssr: false })
 
 
 
 
 type Props = {
 type Props = {
-  title: string
   className?: string,
   className?: string,
   expandContainer?: boolean,
   expandContainer?: boolean,
   children?: ReactNode
   children?: ReactNode
 }
 }
 
 
 export const ShareLinkLayout = ({
 export const ShareLinkLayout = ({
-  children, title, className, expandContainer,
+  children, className, expandContainer,
 }: Props): JSX.Element => {
 }: Props): JSX.Element => {
 
 
   const myClassName = `${className ?? ''} ${expandContainer ? 'growi-layout-fluid' : ''}`;
   const myClassName = `${className ?? ''} ${expandContainer ? 'growi-layout-fluid' : ''}`;
 
 
   return (
   return (
-    <RawLayout title={title} className={myClassName}>
+    <RawLayout className={myClassName}>
       <GrowiNavbar />
       <GrowiNavbar />
 
 
       <div className="page-wrapper d-flex d-print-block">
       <div className="page-wrapper d-flex d-print-block">

+ 7 - 10
packages/app/src/pages/[[...path]].page.tsx

@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import React, { ReactElement, useEffect } from 'react';
 
 
 
 
 import EventEmitter from 'events';
 import EventEmitter from 'events';
@@ -184,7 +184,7 @@ type Props = CommonProps & {
   sidebarConfig: ISidebarConfig,
   sidebarConfig: ISidebarConfig,
 };
 };
 
 
-const GrowiPage: NextPage<Props> = (props: Props) => {
+const Page: NextPage<Props> = (props: Props) => {
   // const { t } = useTranslation();
   // const { t } = useTranslation();
   const router = useRouter();
   const router = useRouter();
 
 
@@ -297,19 +297,16 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   const isContainerFluidDefault = props.isContainerFluid;
   const isContainerFluidDefault = props.isContainerFluid;
   const isContainerFluid = isContainerFluidEachPage ?? isContainerFluidDefault;
   const isContainerFluid = isContainerFluidEachPage ?? isContainerFluidDefault;
 
 
+  const title = useCustomTitle(props, 'GROWI');
+
   return (
   return (
     <>
     <>
       <Head>
       <Head>
-        {/*
-        {renderScriptTagByName('drawio-viewer')}
-        {renderScriptTagByName('highlight-addons')}
-        {renderHighlightJsStyleTag(props.highlightJsStyle)}
-        */}
+        <title>{title}</title>
       </Head>
       </Head>
-
       <DrawioViewerScript />
       <DrawioViewerScript />
 
 
-      <BasicLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')} expandContainer={isContainerFluid}>
+      <BasicLayout className={classNames.join(' ')} expandContainer={isContainerFluid}>
 
 
         <div className="h-100 d-flex flex-column justify-content-between">
         <div className="h-100 d-flex flex-column justify-content-between">
           <header className="py-0 position-relative">
           <header className="py-0 position-relative">
@@ -632,4 +629,4 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
   };
   };
 };
 };
 
 
-export default GrowiPage;
+export default Page;

+ 4 - 5
packages/app/src/pages/_private-legacy-pages.page.tsx

@@ -74,18 +74,17 @@ const PrivateLegacyPage: NextPage<Props> = (props: Props) => {
   // render config
   // render config
   useRendererConfig(props.rendererConfig);
   useRendererConfig(props.rendererConfig);
 
 
+  const title = useCustomTitle(props, 'GROWI');
+
   return (
   return (
     <>
     <>
       <Head>
       <Head>
-        {/*
-        {renderScriptTagByName('drawio-viewer')}
-        {renderScriptTagByName('highlight-addons')}
-        */}
+        <title>{title}</title>
       </Head>
       </Head>
 
 
       <DrawioViewerScript />
       <DrawioViewerScript />
 
 
-      <SearchResultLayout title={useCustomTitle(props, 'GROWI')}>
+      <SearchResultLayout>
         <div id="private-regacy-pages">
         <div id="private-regacy-pages">
           <PrivateLegacyPages />
           <PrivateLegacyPages />
         </div>
         </div>

+ 3 - 5
packages/app/src/pages/_search.page.tsx

@@ -87,6 +87,7 @@ const SearchResultPage: NextPage<Props> = (props: Props) => {
     return <PutbackPageModal />;
     return <PutbackPageModal />;
   };
   };
 
 
+  const title = useCustomTitle(props, 'GROWI');
   const classNames: string[] = [];
   const classNames: string[] = [];
   // if (props.isContainerFluid) {
   // if (props.isContainerFluid) {
   //   classNames.push('growi-layout-fluid');
   //   classNames.push('growi-layout-fluid');
@@ -95,15 +96,12 @@ const SearchResultPage: NextPage<Props> = (props: Props) => {
   return (
   return (
     <>
     <>
       <Head>
       <Head>
-        {/*
-        {renderScriptTagByName('drawio-viewer')}
-        {renderScriptTagByName('highlight-addons')}
-        */}
+        <title>{title}</title>
       </Head>
       </Head>
 
 
       <DrawioViewerScript />
       <DrawioViewerScript />
 
 
-      <SearchResultLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
+      <SearchResultLayout className={classNames.join(' ')}>
         <div id="search-page">
         <div id="search-page">
           <SearchPage />
           <SearchPage />
         </div>
         </div>

+ 7 - 1
packages/app/src/pages/admin/[...path].page.tsx

@@ -2,8 +2,9 @@ import {
   NextPage, GetServerSideProps, GetServerSidePropsContext,
   NextPage, GetServerSideProps, GetServerSidePropsContext,
 } from 'next';
 } from 'next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
-import { CommonProps } from '~/pages/utils/commons';
+import { CommonProps, useCustomTitle } from '~/pages/utils/commons';
 import { useCurrentUser } from '~/stores/context';
 import { useCurrentUser } from '~/stores/context';
 import { useIsMaintenanceMode } from '~/stores/maintenanceMode';
 import { useIsMaintenanceMode } from '~/stores/maintenanceMode';
 
 
@@ -17,8 +18,13 @@ const AdminAppPage: NextPage<CommonProps> = (props) => {
   useIsMaintenanceMode(props.isMaintenanceMode);
   useIsMaintenanceMode(props.isMaintenanceMode);
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
+  const title = useCustomTitle(props, 'GROWI');
+
   return (
   return (
     <AdminLayout>
     <AdminLayout>
+      <Head>
+        <title>{title}</title>
+      </Head>
       <AdminNotFoundPage />
       <AdminNotFoundPage />
     </AdminLayout>
     </AdminLayout>
   );
   );

+ 7 - 2
packages/app/src/pages/admin/app.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 
 
@@ -24,7 +25,6 @@ const AdminAppPage: NextPage<CommonProps> = (props) => {
   useIsMaintenanceMode(props.isMaintenanceMode);
   useIsMaintenanceMode(props.isMaintenanceMode);
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
-  const title = t('headers.app_settings');
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -32,9 +32,14 @@ const AdminAppPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminAppContainer);
     injectableContainers.push(adminAppContainer);
   }
   }
 
 
+  const title = useCustomTitle(props, t('headers.app_settings'));
+
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={title}>
+        <Head>
+          <title>{title}</title>
+        </Head>
         <AppSettingsPageContents />
         <AppSettingsPageContents />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 6 - 1
packages/app/src/pages/admin/audit-log.page.tsx

@@ -3,6 +3,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
 import { SupportedActionType } from '~/interfaces/activity';
 import { SupportedActionType } from '~/interfaces/activity';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CrowiRequest } from '~/interfaces/crowi-request';
@@ -29,9 +30,13 @@ const AdminAuditLogPage: NextPage<Props> = (props) => {
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
   const title = t('audit_log_management.audit_log');
   const title = t('audit_log_management.audit_log');
+  const headTitle = useCustomTitle(props, title);
 
 
   return (
   return (
-    <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+    <AdminLayout componentTitle={title}>
+      <Head>
+        <title>{headTitle}</title>
+      </Head>
       <AuditLogManagement />
       <AuditLogManagement />
     </AdminLayout>
     </AdminLayout>
   );
   );

+ 7 - 2
packages/app/src/pages/admin/customize.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminCustomizeContainer from '~/client/services/AdminCustomizeContainer';
 import AdminCustomizeContainer from '~/client/services/AdminCustomizeContainer';
@@ -27,7 +28,8 @@ const AdminCustomizeSettingsPage: NextPage<Props> = (props) => {
   useCustomizeTitle(props.customizeTitle);
   useCustomizeTitle(props.customizeTitle);
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
-  const title = t('customize_settings.customize_settings');
+  const componentTitle = t('customize_settings.customize_settings');
+  const pageTitle = useCustomTitle(props, componentTitle);
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -39,7 +41,10 @@ const AdminCustomizeSettingsPage: NextPage<Props> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={componentTitle}>
+        <Head>
+          <title>{pageTitle}</title>
+        </Head>
         <CustomizeSettingContents />
         <CustomizeSettingContents />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 7 - 2
packages/app/src/pages/admin/export.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminAppContainer from '~/client/services/AdminAppContainer';
 import AdminAppContainer from '~/client/services/AdminAppContainer';
@@ -20,7 +21,8 @@ const AdminExportDataArchivePage: NextPage<CommonProps> = (props) => {
   const { t } = useTranslation('admin');
   const { t } = useTranslation('admin');
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
-  const title = t('export_management.export_archive_data');
+  const componentTitle = t('export_management.export_archive_data');
+  const pageTitle = useCustomTitle(props, componentTitle);
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -30,7 +32,10 @@ const AdminExportDataArchivePage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={componentTitle}>
+        <Head>
+          <title>{pageTitle}</title>
+        </Head>
         <ExportArchiveDataPage />
         <ExportArchiveDataPage />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 5 - 1
packages/app/src/pages/admin/global-notification/[globalNotificationId].page.tsx

@@ -6,6 +6,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { useRouter } from 'next/router';
 import { useRouter } from 'next/router';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
@@ -56,7 +57,10 @@ const AdminGlobalNotificationNewPage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={customTitle} componentTitle={title} >
+      <AdminLayout componentTitle={title}>
+        <Head>
+          <title>{customTitle}</title>
+        </Head>
         {
         {
           currentGlobalNotificationId != null && router.isReady
           currentGlobalNotificationId != null && router.isReady
       && <ManageGlobalNotification globalNotificationId={currentGlobalNotificationId} />
       && <ManageGlobalNotification globalNotificationId={currentGlobalNotificationId} />

+ 5 - 1
packages/app/src/pages/admin/global-notification/new.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminNotificationContainer from '~/client/services/AdminNotificationContainer';
 import AdminNotificationContainer from '~/client/services/AdminNotificationContainer';
@@ -31,7 +32,10 @@ const AdminGlobalNotificationNewPage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={title}>
+        <Head>
+          <title>{title}</title>
+        </Head>
         <ManageGlobalNotification />
         <ManageGlobalNotification />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 7 - 2
packages/app/src/pages/admin/importer.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminImportContainer from '~/client/services/AdminImportContainer';
 import AdminImportContainer from '~/client/services/AdminImportContainer';
@@ -20,7 +21,8 @@ const AdminDataImportPage: NextPage<CommonProps> = (props) => {
   const { t } = useTranslation('admin');
   const { t } = useTranslation('admin');
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
-  const title = t('importer_management.import_data');
+  const componentTitle = t('importer_management.import_data');
+  const pageTitle = useCustomTitle(props, componentTitle);
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -31,7 +33,10 @@ const AdminDataImportPage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={componentTitle}>
+        <Head>
+          <title>{pageTitle}</title>
+        </Head>
         <DataImportPageContents />
         <DataImportPageContents />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 5 - 1
packages/app/src/pages/admin/index.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminHomeContainer from '~/client/services/AdminHomeContainer';
 import AdminHomeContainer from '~/client/services/AdminHomeContainer';
@@ -47,7 +48,10 @@ const AdminHomePage: NextPage<Props> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={title}>
+        <Head>
+          <title>{title}</title>
+        </Head>
         <AdminHome
         <AdminHome
           nodeVersion={props.nodeVersion}
           nodeVersion={props.nodeVersion}
           npmVersion={props.npmVersion}
           npmVersion={props.npmVersion}

+ 8 - 2
packages/app/src/pages/admin/markdown.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 
 
@@ -21,7 +22,9 @@ const AdminMarkdownPage: NextPage<CommonProps> = (props) => {
   const { t } = useTranslation('admin');
   const { t } = useTranslation('admin');
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
-  const title = t('markdown_settings.markdown_settings');
+  const componentTitle = t('markdown_settings.markdown_settings');
+  const pageTitle = useCustomTitle(props, componentTitle);
+
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -32,7 +35,10 @@ const AdminMarkdownPage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={componentTitle}>
+        <Head>
+          <title>{pageTitle}</title>
+        </Head>
         <MarkDownSettingContents />
         <MarkDownSettingContents />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 7 - 2
packages/app/src/pages/admin/notification.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminNotificationContainer from '~/client/services/AdminNotificationContainer';
 import AdminNotificationContainer from '~/client/services/AdminNotificationContainer';
@@ -20,7 +21,8 @@ const AdminExternalNotificationPage: NextPage<CommonProps> = (props) => {
   const { t } = useTranslation('admin');
   const { t } = useTranslation('admin');
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
-  const title = t('external_notification.external_notification');
+  const componentTitle = t('external_notification.external_notification');
+  const pageTitle = useCustomTitle(props, componentTitle);
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -32,7 +34,10 @@ const AdminExternalNotificationPage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={componentTitle}>
+        <Head>
+          <title>{pageTitle}</title>
+        </Head>
         <NotificationSetting />
         <NotificationSetting />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 6 - 1
packages/app/src/pages/admin/search.page.tsx

@@ -3,6 +3,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CommonProps, useCustomTitle } from '~/pages/utils/commons';
 import { CommonProps, useCustomTitle } from '~/pages/utils/commons';
@@ -27,9 +28,13 @@ const AdminFullTextSearchManagementPage: NextPage<Props> = (props) => {
   useIsSearchServiceReachable(props.isSearchServiceReachable);
   useIsSearchServiceReachable(props.isSearchServiceReachable);
 
 
   const title = t('full_text_search_management.full_text_search_management');
   const title = t('full_text_search_management.full_text_search_management');
+  const headTitle = useCustomTitle(props, title);
 
 
   return (
   return (
-    <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+    <AdminLayout componentTitle={title}>
+      <Head>
+        <title>{headTitle}</title>
+      </Head>
       <FullTextSearchManagement />
       <FullTextSearchManagement />
     </AdminLayout>
     </AdminLayout>
   );
   );

+ 7 - 3
packages/app/src/pages/admin/security.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 
 
@@ -38,7 +39,8 @@ const AdminSecuritySettingsPage: NextPage<Props> = (props) => {
   useSiteUrl(props.siteUrl);
   useSiteUrl(props.siteUrl);
   useIsMailerSetup(props.isMailerSetup);
   useIsMailerSetup(props.isMailerSetup);
 
 
-  const title = t('security_settings.security_settings');
+  const componentTitle = t('security_settings.security_settings');
+  const pageTitle = useCustomTitle(props, componentTitle);
   const adminSecurityContainers: Container<any>[] = [];
   const adminSecurityContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -69,10 +71,12 @@ const AdminSecuritySettingsPage: NextPage<Props> = (props) => {
     }
     }
   }
   }
 
 
-
   return (
   return (
     <Provider inject={[...adminSecurityContainers]}>
     <Provider inject={[...adminSecurityContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={componentTitle}>
+        <Head>
+          <title>{pageTitle}</title>
+        </Head>
         <SecurityManagement />
         <SecurityManagement />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 6 - 1
packages/app/src/pages/admin/slack-integration-legacy.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminSlackIntegrationLegacyContainer from '~/client/services/AdminSlackIntegrationLegacyContainer';
 import AdminSlackIntegrationLegacyContainer from '~/client/services/AdminSlackIntegrationLegacyContainer';
@@ -21,6 +22,7 @@ const AdminLegacySlackIntegrationPage: NextPage<CommonProps> = (props) => {
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
 
 
   const title = t('slack_integration_legacy.slack_integration_legacy');
   const title = t('slack_integration_legacy.slack_integration_legacy');
+  const headTitle = useCustomTitle(props, title);
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -31,7 +33,10 @@ const AdminLegacySlackIntegrationPage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={title}>
+        <Head>
+          <title>{headTitle}</title>
+        </Head>
         <LegacySlackIntegration />
         <LegacySlackIntegration />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 7 - 2
packages/app/src/pages/admin/slack-integration.page.tsx

@@ -3,6 +3,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CommonProps, useCustomTitle } from '~/pages/utils/commons';
 import { CommonProps, useCustomTitle } from '~/pages/utils/commons';
@@ -25,10 +26,14 @@ const AdminSlackIntegrationPage: NextPage<Props> = (props) => {
   useCurrentUser(props.currentUser ?? null);
   useCurrentUser(props.currentUser ?? null);
   useSiteUrl(props.siteUrl);
   useSiteUrl(props.siteUrl);
 
 
-  const title = t('slack_integration.slack_integration');
+  const componentTitle = t('slack_integration.slack_integration');
+  const pageTitle = useCustomTitle(props, componentTitle);
 
 
   return (
   return (
-    <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+    <AdminLayout componentTitle={componentTitle}>
+      <Head>
+        <title>{pageTitle}</title>
+      </Head>
       <SlackIntegration />
       <SlackIntegration />
     </AdminLayout>
     </AdminLayout>
   );
   );

+ 5 - 1
packages/app/src/pages/admin/user-group-detail/[userGroupId].page.tsx

@@ -3,6 +3,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { useRouter } from 'next/router';
 import { useRouter } from 'next/router';
 
 
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CrowiRequest } from '~/interfaces/crowi-request';
@@ -34,7 +35,10 @@ const AdminUserGroupDetailPage: NextPage<Props> = (props: Props) => {
   useIsAclEnabled(props.isAclEnabled);
   useIsAclEnabled(props.isAclEnabled);
 
 
   return (
   return (
-    <AdminLayout title={customTitle} componentTitle={title} >
+    <AdminLayout componentTitle={title}>
+      <Head>
+        <title>{customTitle}</title>
+      </Head>
       {
       {
         currentUserGroupId != null && router.isReady
         currentUserGroupId != null && router.isReady
       && <UserGroupDetailPage userGroupId={currentUserGroupId} />
       && <UserGroupDetailPage userGroupId={currentUserGroupId} />

+ 6 - 1
packages/app/src/pages/admin/user-groups.page.tsx

@@ -3,6 +3,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CommonProps, useCustomTitle } from '~/pages/utils/commons';
 import { CommonProps, useCustomTitle } from '~/pages/utils/commons';
@@ -25,9 +26,13 @@ const AdminUserGroupPage: NextPage<Props> = (props) => {
   useIsAclEnabled(props.isAclEnabled);
   useIsAclEnabled(props.isAclEnabled);
 
 
   const title = t('user_group_management.user_group_management');
   const title = t('user_group_management.user_group_management');
+  const headTitle = useCustomTitle(props, title);
 
 
   return (
   return (
-    <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+    <AdminLayout componentTitle={title}>
+      <Head>
+        <title>{headTitle}</title>
+      </Head>
       <UserGroupPage />
       <UserGroupPage />
     </AdminLayout>
     </AdminLayout>
   );
   );

+ 5 - 1
packages/app/src/pages/admin/users/external-accounts.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminExternalAccountsContainer from '~/client/services/AdminExternalAccountsContainer';
 import AdminExternalAccountsContainer from '~/client/services/AdminExternalAccountsContainer';
@@ -34,7 +35,10 @@ const AdminUserManagementPage: NextPage<CommonProps> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={title}>
+        <Head>
+          <title>{title}</title>
+        </Head>
         <ManageExternalAccount />
         <ManageExternalAccount />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 6 - 1
packages/app/src/pages/admin/users/index.page.tsx

@@ -4,6 +4,7 @@ import {
 } from 'next';
 } from 'next';
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 import { Container, Provider } from 'unstated';
 
 
 import AdminUsersContainer from '~/client/services/AdminUsersContainer';
 import AdminUsersContainer from '~/client/services/AdminUsersContainer';
@@ -29,6 +30,7 @@ const AdminUserManagementPage: NextPage<Props> = (props) => {
   useIsMailerSetup(props.isMailerSetup);
   useIsMailerSetup(props.isMailerSetup);
 
 
   const title = t('user_management.user_management');
   const title = t('user_management.user_management');
+  const headTitle = useCustomTitle(props, title);
   const injectableContainers: Container<any>[] = [];
   const injectableContainers: Container<any>[] = [];
 
 
   if (isClient()) {
   if (isClient()) {
@@ -40,7 +42,10 @@ const AdminUserManagementPage: NextPage<Props> = (props) => {
 
 
   return (
   return (
     <Provider inject={[...injectableContainers]}>
     <Provider inject={[...injectableContainers]}>
-      <AdminLayout title={useCustomTitle(props, title)} componentTitle={title} >
+      <AdminLayout componentTitle={title}>
+        <Head>
+          <title>{headTitle}</title>
+        </Head>
         <UserManagement />
         <UserManagement />
       </AdminLayout>
       </AdminLayout>
     </Provider>
     </Provider>

+ 6 - 1
packages/app/src/pages/installer.page.tsx

@@ -5,6 +5,7 @@ import {
   NextPage, GetServerSideProps, GetServerSidePropsContext,
   NextPage, GetServerSideProps, GetServerSidePropsContext,
 } from 'next';
 } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
+import Head from 'next/head';
 
 
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 
 
@@ -39,10 +40,14 @@ const InstallerPage: NextPage<Props> = (props: Props) => {
   useConfidential(props.confidential);
   useConfidential(props.confidential);
   useCsrfToken(props.csrfToken);
   useCsrfToken(props.csrfToken);
 
 
+  const title = useCustomTitle(props, 'GROWI');
   const classNames: string[] = [];
   const classNames: string[] = [];
 
 
   return (
   return (
-    <NoLoginLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
+    <NoLoginLayout className={classNames.join(' ')}>
+      <Head>
+        <title>{title}</title>
+      </Head>
       <div id="installer-form-container">
       <div id="installer-form-container">
         <InstallerForm />
         <InstallerForm />
       </div>
       </div>

+ 6 - 1
packages/app/src/pages/invited.page.tsx

@@ -4,6 +4,7 @@ import type { IUserHasId, IUser } from '@growi/core';
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
 import { InvitedFormProps } from '~/components/InvitedForm';
 import { InvitedFormProps } from '~/components/InvitedForm';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
@@ -29,10 +30,14 @@ const InvitedPage: NextPage<Props> = (props: Props) => {
   useCurrentPathname(props.currentPathname);
   useCurrentPathname(props.currentPathname);
   useCurrentUser(props.currentUser);
   useCurrentUser(props.currentUser);
 
 
+  const title = useCustomTitle(props, 'GROWI');
   const classNames: string[] = ['invited-page'];
   const classNames: string[] = ['invited-page'];
 
 
   return (
   return (
-    <NoLoginLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
+    <NoLoginLayout className={classNames.join(' ')}>
+      <Head>
+        <title>{title}</title>
+      </Head>
       <InvitedForm invitedFormUsername={props.invitedFormUsername} invitedFormName={props.invitedFormName} />
       <InvitedForm invitedFormUsername={props.invitedFormUsername} invitedFormName={props.invitedFormName} />
     </NoLoginLayout>
     </NoLoginLayout>
   );
   );

+ 6 - 1
packages/app/src/pages/login.page.tsx

@@ -4,6 +4,7 @@ import {
   NextPage, GetServerSideProps, GetServerSidePropsContext,
   NextPage, GetServerSideProps, GetServerSidePropsContext,
 } from 'next';
 } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
+import Head from 'next/head';
 
 
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 import { LoginForm } from '~/components/LoginForm';
 import { LoginForm } from '~/components/LoginForm';
@@ -42,10 +43,14 @@ const LoginPage: NextPage<Props> = (props: Props) => {
   // page
   // page
   useCurrentPathname(props.currentPathname);
   useCurrentPathname(props.currentPathname);
 
 
+  const title = useCustomTitle(props, 'GROWI');
   const classNames: string[] = ['login-page'];
   const classNames: string[] = ['login-page'];
 
 
   return (
   return (
-    <NoLoginLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
+    <NoLoginLayout className={classNames.join(' ')}>
+      <Head>
+        <title>{title}</title>
+      </Head>
       <LoginForm
       <LoginForm
         objOfIsExternalAuthEnableds={props.enabledStrategies}
         objOfIsExternalAuthEnableds={props.enabledStrategies}
         isLocalStrategySetup={props.isLocalStrategySetup}
         isLocalStrategySetup={props.isLocalStrategySetup}

+ 18 - 15
packages/app/src/pages/me/[[...path]].page.tsx

@@ -8,6 +8,7 @@ import {
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 import { useRouter } from 'next/router';
 import { useRouter } from 'next/router';
 
 
 import { BasicLayout } from '~/components/Layout/BasicLayout';
 import { BasicLayout } from '~/components/Layout/BasicLayout';
@@ -105,26 +106,28 @@ const MePage: NextPage<Props> = (props: Props) => {
   useIsSearchServiceReachable(props.isSearchServiceReachable);
   useIsSearchServiceReachable(props.isSearchServiceReachable);
   useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
   useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
 
 
-  return (
-    <>
-      <BasicLayout title={useCustomTitle(props, 'GROWI')}>
+  const title = useCustomTitle(props, 'GROWI');
 
 
-        <header className="py-3">
-          <div className="container-fluid">
-            <h1 className="title">{ targetPage.title }</h1>
-          </div>
-        </header>
+  return (
+    <BasicLayout title={useCustomTitle(props, 'GROWI')}>
+      <Head>
+        <title>{title}</title>
+      </Head>
+      <header className="py-3">
+        <div className="container-fluid">
+          <h1 className="title">{ targetPage.title }</h1>
+        </div>
+      </header>
 
 
-        <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
+      <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
 
 
-        <div id="main" className='main'>
-          <div id="content-main" className="content-main grw-container-convertible">
-            {targetPage.component}
-          </div>
+      <div id="main" className='main'>
+        <div id="content-main" className="content-main grw-container-convertible">
+          {targetPage.component}
         </div>
         </div>
+      </div>
 
 
-      </BasicLayout>
-    </>
+    </BasicLayout>
   );
   );
 };
 };
 
 

+ 8 - 1
packages/app/src/pages/share/[[...path]].page.tsx

@@ -7,6 +7,7 @@ import {
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
 import CountBadge from '~/components/Common/CountBadge';
 import CountBadge from '~/components/Common/CountBadge';
 import PageListIcon from '~/components/Icons/PageListIcon';
 import PageListIcon from '~/components/Icons/PageListIcon';
@@ -66,11 +67,17 @@ const SharedPage: NextPage<Props> = (props: Props) => {
   const isShowSharedPage = !props.disableLinkSharing && !isNotFound && !props.isExpired;
   const isShowSharedPage = !props.disableLinkSharing && !isNotFound && !props.isExpired;
   const shareLink = props.shareLink;
   const shareLink = props.shareLink;
 
 
+  const title = useCustomTitle(props, 'GROWI');
+
   return (
   return (
     <>
     <>
+      <Head>
+        <title>{title}</title>
+      </Head>
+
       <DrawioViewerScript />
       <DrawioViewerScript />
 
 
-      <ShareLinkLayout title={useCustomTitle(props, 'GROWI')} expandContainer={props.isContainerFluid}>
+      <ShareLinkLayout expandContainer={props.isContainerFluid}>
         <div className="h-100 d-flex flex-column justify-content-between">
         <div className="h-100 d-flex flex-column justify-content-between">
           <header className="py-0 position-relative">
           <header className="py-0 position-relative">
             {isShowSharedPage && <GrowiContextualSubNavigation isLinkSharingDisabled={props.disableLinkSharing} />}
             {isShowSharedPage && <GrowiContextualSubNavigation isLinkSharingDisabled={props.disableLinkSharing} />}

+ 31 - 29
packages/app/src/pages/tags.page.tsx

@@ -60,7 +60,7 @@ const TagPage: NextPage<CommonProps> = (props: Props) => {
   const tagData: IDataTagCount[] = tagDataList?.data || [];
   const tagData: IDataTagCount[] = tagDataList?.data || [];
   const totalCount: number = tagDataList?.totalCount || 0;
   const totalCount: number = tagDataList?.totalCount || 0;
   const isLoading = tagDataList === undefined && error == null;
   const isLoading = tagDataList === undefined && error == null;
-  const classNames: string[] = [];
+
 
 
   useIsSearchPage(false);
   useIsSearchPage(false);
   useIsSearchServiceConfigured(props.isSearchServiceConfigured);
   useIsSearchServiceConfigured(props.isSearchServiceConfigured);
@@ -73,38 +73,40 @@ const TagPage: NextPage<CommonProps> = (props: Props) => {
   useCurrentSidebarContents(props.userUISettings?.currentSidebarContents);
   useCurrentSidebarContents(props.userUISettings?.currentSidebarContents);
   useCurrentProductNavWidth(props.userUISettings?.currentProductNavWidth);
   useCurrentProductNavWidth(props.userUISettings?.currentProductNavWidth);
 
 
+  const title = useCustomTitle(props, 'GROWI');
+  const classNames: string[] = [];
+
   return (
   return (
-    <>
+    <BasicLayout className={classNames.join(' ')}>
       <Head>
       <Head>
+        <title>{title}</title>
       </Head>
       </Head>
-      <BasicLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
-        <div className="grw-container-convertible mb-5 pb-5" data-testid="tags-page">
-          <h2 className="my-3">{`${t('Tags')}(${totalCount})`}</h2>
-          <div className="px-3 mb-5 text-center">
-            <TagCloudBox tags={tagData} minSize={20} />
-          </div>
-          { isLoading
-            ? (
-              <div className="text-muted text-center">
-                <i className="fa fa-2x fa-spinner fa-pulse mt-3"></i>
-              </div>
-            )
-            : (
-              <div data-testid="grw-tags-list">
-                <TagList
-                  tagData={tagData}
-                  totalTags={totalCount}
-                  activePage={activePage}
-                  onChangePage={setOffsetByPageNumber}
-                  pagingLimit={PAGING_LIMIT}
-                />
-              </div>
-            )
-          }
-          <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
+      <div className="grw-container-convertible mb-5 pb-5" data-testid="tags-page">
+        <h2 className="my-3">{`${t('Tags')}(${totalCount})`}</h2>
+        <div className="px-3 mb-5 text-center">
+          <TagCloudBox tags={tagData} minSize={20} />
         </div>
         </div>
-      </BasicLayout>
-    </>
+        { isLoading
+          ? (
+            <div className="text-muted text-center">
+              <i className="fa fa-2x fa-spinner fa-pulse mt-3"></i>
+            </div>
+          )
+          : (
+            <div data-testid="grw-tags-list">
+              <TagList
+                tagData={tagData}
+                totalTags={totalCount}
+                activePage={activePage}
+                onChangePage={setOffsetByPageNumber}
+                pagingLimit={PAGING_LIMIT}
+              />
+            </div>
+          )
+        }
+        <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
+      </div>
+    </BasicLayout>
   );
   );
 };
 };
 
 

+ 7 - 1
packages/app/src/pages/trash.page.tsx

@@ -4,6 +4,7 @@ import type { IUser, IUserHasId } from '@growi/core';
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
+import Head from 'next/head';
 
 
 import { GrowiSubNavigation } from '~/components/Navbar/GrowiSubNavigation';
 import { GrowiSubNavigation } from '~/components/Navbar/GrowiSubNavigation';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
@@ -65,9 +66,14 @@ const TrashPage: NextPage<CommonProps> = (props: Props) => {
   const { data: isDrawerMode } = useDrawerMode();
   const { data: isDrawerMode } = useDrawerMode();
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isGuestUser } = useIsGuestUser();
 
 
+  const title = useCustomTitle(props, 'GROWI');
+
   return (
   return (
     <>
     <>
-      <BasicLayout title={useCustomTitle(props, 'GROWI')} >
+      <Head>
+        <title>{title}</title>
+      </Head>
+      <BasicLayout>
         <header className="py-0 position-relative">
         <header className="py-0 position-relative">
           <GrowiSubNavigation
           <GrowiSubNavigation
             pagePath="/trash"
             pagePath="/trash"

+ 8 - 1
packages/app/src/pages/user-activation.page.tsx

@@ -1,5 +1,6 @@
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
+import Head from 'next/head';
 
 
 import CompleteUserRegistrationForm from '~/components/CompleteUserRegistrationForm';
 import CompleteUserRegistrationForm from '~/components/CompleteUserRegistrationForm';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
@@ -21,8 +22,14 @@ type Props = CommonProps & {
 }
 }
 
 
 const UserActivationPage: NextPage<Props> = (props: Props) => {
 const UserActivationPage: NextPage<Props> = (props: Props) => {
+
+  const title = useCustomTitle(props, 'GROWI');
+
   return (
   return (
-    <NoLoginLayout title={useCustomTitle(props, 'GROWI')}>
+    <NoLoginLayout>
+      <Head>
+        <title>{title}</title>
+      </Head>
       <CompleteUserRegistrationForm
       <CompleteUserRegistrationForm
         token={props.token}
         token={props.token}
         email={props.email}
         email={props.email}