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

Merge branch 'dev/7.0.x' into feat/142109-reflect-update-results-from-view-in-ydoc

Shun Miyazawa 2 лет назад
Родитель
Сommit
c3fcdd972f
70 измененных файлов с 222 добавлено и 181 удалено
  1. 10 10
      apps/app/resource/locales/en_US/sandbox-bootstrap5.md
  2. 2 2
      apps/app/resource/locales/ja_JP/sandbox.md
  3. 1 1
      apps/app/src/components/Admin/App/QuestionnaireSettings.tsx
  4. 3 2
      apps/app/src/components/Admin/AuditLog/AuditLogDisableMode.tsx
  5. 1 1
      apps/app/src/components/Admin/AuditLogManagement.tsx
  6. 1 1
      apps/app/src/components/Admin/Customize/CustomizeLayoutSetting.tsx
  7. 1 1
      apps/app/src/components/Admin/ElasticsearchManagement/ReconnectControls.tsx
  8. 2 1
      apps/app/src/components/Admin/G2GDataTransferStatusIcon.tsx
  9. 3 3
      apps/app/src/components/Admin/Security/SecurityManagementContents.jsx
  10. 1 1
      apps/app/src/components/Admin/SlackIntegration/SlackIntegration.jsx
  11. 1 1
      apps/app/src/components/Admin/Users/PasswordResetModal.jsx
  12. 1 1
      apps/app/src/components/Common/Dropdown/PageItemControl.tsx
  13. 0 17
      apps/app/src/components/Common/PageViewLayout.module.scss
  14. 3 4
      apps/app/src/components/Common/PageViewLayout.tsx
  15. 1 1
      apps/app/src/components/DescendantsPageList.tsx
  16. 1 1
      apps/app/src/components/InAppNotification/InAppNotificationList.tsx
  17. 1 1
      apps/app/src/components/InAppNotification/InAppNotificationPage.tsx
  18. 1 1
      apps/app/src/components/InfiniteScroll.tsx
  19. 1 1
      apps/app/src/components/InstallerForm.tsx
  20. 1 2
      apps/app/src/components/InvitedForm.tsx
  21. 1 1
      apps/app/src/components/Layout/AdminLayout.tsx
  22. 0 7
      apps/app/src/components/LoadingSpinner.tsx
  23. 2 2
      apps/app/src/components/LoginForm.tsx
  24. 7 7
      apps/app/src/components/Me/AssociateModal.tsx
  25. 1 2
      apps/app/src/components/Me/QuestionnaireSettings.tsx
  26. 4 0
      apps/app/src/components/Navbar/GroundGlassBar.module.scss
  27. 17 0
      apps/app/src/components/Navbar/GroundGlassBar.tsx
  28. 0 5
      apps/app/src/components/Navbar/GrowiContextualSubNavigation.module.scss
  29. 4 2
      apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  30. 0 8
      apps/app/src/components/Navbar/GrowiNavbarBottom.module.scss
  31. 4 2
      apps/app/src/components/Navbar/GrowiNavbarBottom.tsx
  32. 1 2
      apps/app/src/components/Page/RevisionLoader.tsx
  33. 1 1
      apps/app/src/components/PageAccessoriesModal/PageAttachment.tsx
  34. 1 2
      apps/app/src/components/PageAttachment/DeleteAttachmentModal.tsx
  35. 1 1
      apps/app/src/components/PageControls/BookmarkButtons.tsx
  36. 1 1
      apps/app/src/components/PageEditor/DrawioModal.tsx
  37. 6 2
      apps/app/src/components/PageEditor/PageEditorReadOnly.tsx
  38. 1 1
      apps/app/src/components/PageList/PageList.tsx
  39. 1 1
      apps/app/src/components/PagePresentationModal.tsx
  40. 1 1
      apps/app/src/components/PrivateLegacyPages.tsx
  41. 1 1
      apps/app/src/components/SavePageControls.tsx
  42. 1 1
      apps/app/src/components/SavePageControls/GrantSelector/GrantSelector.tsx
  43. 1 1
      apps/app/src/components/SearchPage/SearchPageBase.tsx
  44. 1 1
      apps/app/src/components/TemplateModal/TemplateModal.tsx
  45. 1 1
      apps/app/src/components/TreeItem/SimpleItem.tsx
  46. 0 1
      apps/app/src/pages/_private-legacy-pages.page.tsx
  47. 0 1
      apps/app/src/pages/_search.page.tsx
  48. 2 2
      apps/app/src/pages/forgot-password-errors.page.tsx
  49. 6 7
      apps/app/src/pages/forgot-password.page.tsx
  50. 1 1
      apps/app/src/pages/maintenance.page.tsx
  51. 8 10
      apps/app/src/pages/me/[[...path]].page.tsx
  52. 2 2
      apps/app/src/pages/reset-password.page.tsx
  53. 0 2
      apps/app/src/pages/share/[[...path]].page.tsx
  54. 32 25
      apps/app/src/pages/tags.page.tsx
  55. 9 5
      apps/app/src/pages/trash.page.tsx
  56. 20 0
      apps/app/src/styles/_layout.scss
  57. 2 0
      apps/app/src/styles/vendor.scss
  58. 2 0
      apps/app/turbo.json
  59. 1 0
      packages/custom-icons/svg/facebook.svg
  60. 1 0
      packages/custom-icons/svg/github.svg
  61. 1 0
      packages/custom-icons/svg/google.svg
  62. 1 0
      packages/custom-icons/svg/slack.svg
  63. 17 15
      packages/editor/src/services/paste-util/paste-markdown-util.ts
  64. 3 1
      packages/remark-attachment-refs/package.json
  65. 2 2
      packages/remark-attachment-refs/src/client/components/AttachmentList.tsx
  66. 3 1
      packages/remark-lsx/src/client/components/Lsx.tsx
  67. 3 0
      packages/ui/package.json
  68. 1 0
      packages/ui/src/components/LoadingSpinner.module.scss
  69. 9 0
      packages/ui/src/components/LoadingSpinner.tsx
  70. 1 0
      packages/ui/src/components/index.ts

+ 10 - 10
apps/app/resource/locales/en_US/sandbox-bootstrap5.md

@@ -120,19 +120,19 @@
 
 
 # 4. Colors
-## 背景颜色
+## Contextual colors
 <p class="text-primary">Look, I'm in a well!</p>
 <p class="text-warning">Look, I'm in a well!</p>
 <p class="text-danger">Look, I'm in a well!</p>
 
-## 背景情况
+## Contextual backgrounds
 <p class="text-danger bg-primary">Look, I'm in a well!</p>
 <p class="text-primary bg-warning">Look, I'm in a well!</p>
 <p class="text-warning bg-danger">Look, I'm in a well!</p>
 
 
 # 5. Collapse
-## 显示内容
+## Displaying content
 <a class="btn btn-primary text-white" data-bs-toggle="collapse" href="#collapse-1">
   Show content
 </a>
@@ -146,7 +146,7 @@
   </div>
 </div>
 
-## 隐藏内容
+## Hiding content
 <a class="btn btn-secondary text-white" data-bs-toggle="collapse" href="#collapse-2">
   Hide content
 </a>
@@ -161,9 +161,9 @@
 </div>
 
 
-# 官方文件
-- [点击此处了解徽章详情](https://getbootstrap.com/docs/5.3/components/badge/)
-- [单击此处了解警报详情](https://getbootstrap.com/docs/5.3/components/alerts/)
-- [点击此处了解贺卡详情](https://getbootstrap.com/docs/5.3/components/card/)
-- [点击此处了解颜色详情](https://getbootstrap.com/docs/5.3/utilities/colors/)
-- [点击此处查看折叠详情](https://getbootstrap.com/docs/5.3/components/collapse/)
+# Official docs
+- [Click here for Badges details](https://getbootstrap.jp/docs/5.3/components/badge/)
+- [Click here for Alerts details](https://getbootstrap.jp/docs/5.3/components/alerts/)
+- [Click here for Cards details](https://getbootstrap.jp/docs/5.3/components/card/)
+- [Click here for Colors details](https://getbootstrap.jp/docs/5.3/utilities/colors/)
+- [Click here for Collapse details](https://getbootstrap.jp/docs/5.3/components/collapse/)

+ 2 - 2
apps/app/resource/locales/ja_JP/sandbox.md

@@ -166,7 +166,7 @@
 - 記述中のページを基点とした相対リンクと、表示テキストに対するリンクを同時に実現できます
 
 #### 活用例
-Bootstrap によるページの装飾方法の記述方法は [[こちらをご確認ください>./1. ページの装飾方法(Bootstrap)]]
+Bootstrap によるページの装飾方法の記述方法は [[こちらをご確認ください>./Bootstrap5]]
 
 
 # :memo:画像の挿入
@@ -297,6 +297,6 @@ ___
 # :memo:さらに応用的な表現
 - [ページの装飾方法(Bootstrap5)](/Sandbox/Bootstrap5)
 
-- [図形の表現方法(Daigrams)](/Sandbox/Daigrams)
+- [図形の表現方法(Diagrams)](/Sandbox/Diagrams)
 
 - [数式の表現方法(Math)](/Sandbox/Math)

+ 1 - 1
apps/app/src/components/Admin/App/QuestionnaireSettings.tsx

@@ -2,11 +2,11 @@ import {
   useState, useCallback, useEffect,
 } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
-import { LoadingSpinner } from '~/components/LoadingSpinner';
 import { useSWRxAppSettings } from '~/stores/admin/app-settings';
 
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';

+ 3 - 2
apps/app/src/components/Admin/AuditLog/AuditLogDisableMode.tsx

@@ -1,4 +1,5 @@
-import React, { FC } from 'react';
+import type { FC } from 'react';
+import React from 'react';
 
 import { useTranslation } from 'react-i18next';
 
@@ -6,7 +7,7 @@ export const AuditLogDisableMode: FC = () => {
   const { t } = useTranslation('admin');
 
   return (
-    <div id="content-main" className="content-main container-lg">
+    <div className="ccontainer-lg">
       <div className="container">
         <div className="row justify-content-md-center">
           <div className="col-md-6 mt-5">

+ 1 - 1
apps/app/src/components/Admin/AuditLogManagement.tsx

@@ -1,6 +1,7 @@
 import type { FC } from 'react';
 import React, { useState, useCallback, useRef } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { format } from 'date-fns';
 import { useTranslation } from 'react-i18next';
 
@@ -10,7 +11,6 @@ import type { SupportedActionType } from '~/interfaces/activity';
 import { useSWRxActivity } from '~/stores/activity';
 import { useAuditLogEnabled, useAuditLogAvailableActions } from '~/stores/context';
 
-import { LoadingSpinner } from '../LoadingSpinner';
 import PaginationWrapper from '../PaginationWrapper';
 
 import { ActivityTable } from './AuditLog/ActivityTable';

+ 1 - 1
apps/app/src/components/Admin/Customize/CustomizeLayoutSetting.tsx

@@ -2,10 +2,10 @@ import React, {
   useCallback, useEffect, useState,
 } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
 import { toastSuccess, toastError } from '~/client/util/toastr';
-import { LoadingSpinner } from '~/components/LoadingSpinner';
 import { useSWRxLayoutSetting } from '~/stores/admin/customize';
 import { useNextThemes } from '~/stores/use-next-themes';
 

+ 1 - 1
apps/app/src/components/Admin/ElasticsearchManagement/ReconnectControls.tsx

@@ -1,8 +1,8 @@
 import React from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
-import { LoadingSpinner } from '~/components/LoadingSpinner';
 
 type Props = {
   isEnabled?: boolean,

+ 2 - 1
apps/app/src/components/Admin/G2GDataTransferStatusIcon.tsx

@@ -1,8 +1,9 @@
 import React, { type ComponentPropsWithoutRef } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
+
 import { G2G_PROGRESS_STATUS, type G2GProgressStatus } from '~/interfaces/g2g-transfer';
 
-import { LoadingSpinner } from '../LoadingSpinner';
 
 /**
  * Props for {@link G2GDataTransferStatusIcon}

+ 3 - 3
apps/app/src/components/Admin/Security/SecurityManagementContents.jsx

@@ -46,15 +46,15 @@ const SecurityManagementContents = () => {
         i18n: 'OIDC',
       },
       passport_google: {
-        Icon: () => <i className="fa fa-google" />,
+        Icon: () => <span className="growi-custom-icons align-bottom">google</span>,
         i18n: 'Google',
       },
       passport_github: {
-        Icon: () => <i className="fa fa-github" />,
+        Icon: () => <span className="growi-custom-icons align-bottom">github</span>,
         i18n: 'GitHub',
       },
       // passport_facebook: {
-      //   Icon: () => <i className="fa fa-facebook" />,
+      //   Icon: () => <span className="growi-custom-icons align-bottom">facebook</span>,
       //   i18n: '(TBD) Facebook',
       // },
     };

+ 1 - 1
apps/app/src/components/Admin/SlackIntegration/SlackIntegration.jsx

@@ -1,6 +1,7 @@
 import React, { useState, useEffect, useCallback } from 'react';
 
 import { SlackbotType } from '@growi/slack';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
 
@@ -8,7 +9,6 @@ import {
   apiv3Delete, apiv3Get, apiv3Post, apiv3Put,
 } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
-import { LoadingSpinner } from '~/components/LoadingSpinner';
 
 import BotTypeCard from './BotTypeCard';
 import ConfirmBotChangeModal from './ConfirmBotChangeModal';

+ 1 - 1
apps/app/src/components/Admin/Users/PasswordResetModal.jsx

@@ -1,5 +1,6 @@
 import React from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import PropTypes from 'prop-types';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
@@ -10,7 +11,6 @@ import {
 import AdminUsersContainer from '~/client/services/AdminUsersContainer';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastError } from '~/client/util/toastr';
-import { LoadingSpinner } from '~/components/LoadingSpinner';
 import { useIsMailerSetup } from '~/stores/context';
 
 class PasswordResetModal extends React.Component {

+ 1 - 1
apps/app/src/components/Common/Dropdown/PageItemControl.tsx

@@ -5,12 +5,12 @@ import React, {
 import {
   type IPageInfoAll, isIPageInfoForOperation,
 } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import {
   Dropdown, DropdownMenu, DropdownToggle, DropdownItem,
 } from 'reactstrap';
 
-import { LoadingSpinner } from '~/components/LoadingSpinner';
 import { NotAvailableForGuest } from '~/components/NotAvailableForGuest';
 import type { IPageOperationProcessData } from '~/interfaces/page-operation';
 import { useSWRxPageInfo } from '~/stores/page';

+ 0 - 17
apps/app/src/components/Common/PageViewLayout.module.scss

@@ -12,23 +12,6 @@ $page-view-layout-margin-top: 32px;
   min-height: calc(100vh - #{$subnavigation-height + $page-view-layout-margin-top + $page-content-footer-min-heigh});
 }
 
-// md/lg layout padding
-.page-view-layout :global {
-  @include bs.media-breakpoint-between(md, xl) {
-    padding-left: var.$grw-sidebar-nav-width;
-  }
-}
-
-// container padding
-.page-view-layout :global,
-.footer-layout :global {
-  @include bs.media-breakpoint-up(lg) {
-    .container-lg {
-      --bs-gutter-x: 3rem;
-    }
-  }
-}
-
 // fluid layout
 .fluid-layout :global {
   .grw-container-convertible {

+ 3 - 4
apps/app/src/components/Common/PageViewLayout.tsx

@@ -3,7 +3,6 @@ import type { ReactNode } from 'react';
 import styles from './PageViewLayout.module.scss';
 
 const pageViewLayoutClass = styles['page-view-layout'] ?? '';
-const footerLayoutClass = styles['footer-layout'] ?? '';
 const _fluidLayoutClass = styles['fluid-layout'] ?? '';
 
 type Props = {
@@ -24,8 +23,8 @@ export const PageViewLayout = (props: Props): JSX.Element => {
 
   return (
     <>
-      <div id="main" className={`main ${pageViewLayoutClass} ${fluidLayoutClass} flex-expand-vert`}>
-        <div id="content-main" className="content-main container-lg grw-container-convertible flex-expand-vert">
+      <div className={`main ${pageViewLayoutClass} ${fluidLayoutClass} flex-expand-vert ps-sidebar`}>
+        <div className="container-lg wide-gutter-x-lg grw-container-convertible flex-expand-vert">
           { headerContents != null && headerContents }
           { sideContents != null
             ? (
@@ -48,7 +47,7 @@ export const PageViewLayout = (props: Props): JSX.Element => {
       </div>
 
       { footerContents != null && (
-        <footer className={`footer d-edit-none ${footerLayoutClass} ${fluidLayoutClass}`}>
+        <footer className={`footer d-edit-none wide-gutter-x-lg ${fluidLayoutClass}`}>
           {footerContents}
         </footer>
       ) }

+ 1 - 1
apps/app/src/components/DescendantsPageList.tsx

@@ -5,6 +5,7 @@ import type {
   IPageHasId,
   IPageInfoForOperation,
 } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
 import { toastSuccess } from '~/client/util/toastr';
@@ -17,7 +18,6 @@ import {
 } from '~/stores/page-listing';
 
 import type { ForceHideMenuItems } from './Common/Dropdown/PageItemControl';
-import { LoadingSpinner } from './LoadingSpinner';
 import PageList from './PageList/PageList';
 import PaginationWrapper from './PaginationWrapper';
 

+ 1 - 1
apps/app/src/components/InAppNotification/InAppNotificationList.tsx

@@ -2,10 +2,10 @@ import type { FC } from 'react';
 import React from 'react';
 
 import type { HasObjectId } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 
 import type { IInAppNotification, PaginateResult } from '~/interfaces/in-app-notification';
 
-import { LoadingSpinner } from '../LoadingSpinner';
 
 import InAppNotificationElm from './InAppNotificationElm';
 

+ 1 - 1
apps/app/src/components/InAppNotification/InAppNotificationPage.tsx

@@ -1,6 +1,7 @@
 import type { FC } from 'react';
 import React, { useState, useEffect, useCallback } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
 import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
@@ -10,7 +11,6 @@ import loggerFactory from '~/utils/logger';
 
 import { useSWRxInAppNotifications, useSWRxInAppNotificationStatus } from '../../stores/in-app-notification';
 import CustomNavAndContents from '../CustomNavigation/CustomNavAndContents';
-import { LoadingSpinner } from '../LoadingSpinner';
 import PaginationWrapper from '../PaginationWrapper';
 
 import InAppNotificationList from './InAppNotificationList';

+ 1 - 1
apps/app/src/components/InfiniteScroll.tsx

@@ -1,9 +1,9 @@
 import type { Ref } from 'react';
 import React, { useEffect, useState } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import type { SWRInfiniteResponse } from 'swr/infinite';
 
-import { LoadingSpinner } from './LoadingSpinner';
 
 type Props<T> = {
   swrInifiniteResponse: SWRInfiniteResponse<T>

+ 1 - 1
apps/app/src/components/InstallerForm.tsx

@@ -2,6 +2,7 @@ import type { FormEventHandler } from 'react';
 import { memo, useCallback, useState } from 'react';
 
 import { Lang, AllLang } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
 
@@ -10,7 +11,6 @@ import { i18n as i18nConfig } from '^/config/next-i18next.config';
 import { apiv3Post } from '~/client/util/apiv3-client';
 import { toastError } from '~/client/util/toastr';
 
-import { LoadingSpinner } from './LoadingSpinner';
 
 const InstallerForm = memo((): JSX.Element => {
   const { t, i18n } = useTranslation();

+ 1 - 2
apps/app/src/components/InvitedForm.tsx

@@ -1,5 +1,6 @@
 import React, { useCallback, useState } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
 
@@ -7,8 +8,6 @@ import { apiv3Post } from '~/client/util/apiv3-client';
 
 import { useCurrentUser } from '../stores/context';
 
-import { LoadingSpinner } from './LoadingSpinner';
-
 
 export type InvitedFormProps = {
   invitedFormUsername: string,

+ 1 - 1
apps/app/src/components/Layout/AdminLayout.tsx

@@ -39,7 +39,7 @@ const AdminLayout = ({
             {componentTitle}
           </h1>
         </header>
-        <div id="main" className="main">
+        <div className="main">
           <div className="container-fluid">
             <div className="row">
               <div className="col-lg-3">

+ 0 - 7
apps/app/src/components/LoadingSpinner.tsx

@@ -1,7 +0,0 @@
-import React, { type ComponentPropsWithoutRef } from 'react';
-
-import styles from './LoadingSpinner.module.scss';
-
-export const LoadingSpinner = ({ className = '' }: ComponentPropsWithoutRef<'span'>): JSX.Element => (
-  <span className={`material-symbols-outlined pb-0 ${styles.spinner} ${className}`}>progress_activity</span>
-);

+ 2 - 2
apps/app/src/components/LoginForm.tsx

@@ -2,6 +2,7 @@ import React, {
   useState, useEffect, useCallback,
 } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
 import ReactCardFlip from 'react-card-flip';
@@ -14,7 +15,6 @@ import { RegistrationMode } from '~/interfaces/registration-mode';
 import { toArrayIfNot } from '~/utils/array-utils';
 
 import { CompleteUserRegistration } from './CompleteUserRegistration';
-import { LoadingSpinner } from './LoadingSpinner';
 
 import styles from './LoginForm.module.scss';
 
@@ -277,7 +277,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
         <button type="button" className="btn btn-fill rounded-0" id={auth} onClick={handleLoginWithExternalAuth}>
           <div className="eff"></div>
           <span className="btn-label">
-            <i className={`fa fa-${authIconNames[auth]}`}></i>
+            <span className="growi-custom-icons align-bottom">{authIconNames[auth]}</span>
           </span>
           <span className="btn-label-text">{t('Sign in')}</span>
         </button>

+ 7 - 7
apps/app/src/components/Me/AssociateModal.tsx

@@ -63,28 +63,28 @@ const AssociateModal = (props: Props): JSX.Element => {
         <div>
           <Nav tabs className="mb-2">
             <NavLink
-              className={activeTab === 1 ? 'active' : ''}
+              className={`${activeTab === 1 ? 'active' : ''} d-flex gap-1 align-items-center`}
               onClick={() => setActiveTab(1)}
             >
               <span className="material-symbols-outlined fs-5">network_node</span> LDAP
             </NavLink>
             <NavLink
-              className={activeTab === 2 ? 'active' : ''}
+              className={`${activeTab === 2 ? 'active' : ''} d-flex gap-1 align-items-center`}
               onClick={() => setActiveTab(2)}
             >
-              <i className="fa fa-github"></i> (TBD) GitHub
+              <span className="growi-custom-icons">github</span> (TBD) GitHub
             </NavLink>
             <NavLink
-              className={activeTab === 3 ? 'active' : ''}
+              className={`${activeTab === 3 ? 'active' : ''} d-flex gap-1 align-items-center`}
               onClick={() => setActiveTab(3)}
             >
-              <i className="fa fa-google"></i> (TBD) Google OAuth
+              <span className="growi-custom-icons">google</span> (TBD) Google OAuth
             </NavLink>
             {/* <NavLink
-              className={activeTab === 4 ? 'active' : ''}
+              className={`${activeTab === 4 ? 'active' : ''} d-flex gap-1 align-items-center`}
               onClick={() => setActiveTab(4)}
             >
-              <i className="fa fa-facebook"></i> (TBD) Facebook
+              <span className="growi-custom-icons">facebook</span> (TBD) Facebook
             </NavLink> */}
           </Nav>
           <TabContent activeTab={activeTab}>

+ 1 - 2
apps/app/src/components/Me/QuestionnaireSettings.tsx

@@ -1,5 +1,6 @@
 import { useCallback, useEffect, useState } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'react-i18next';
 import { UncontrolledTooltip } from 'reactstrap';
 
@@ -8,8 +9,6 @@ import { toastError, toastSuccess } from '~/client/util/toastr';
 import { useSWRxIsQuestionnaireEnabled } from '~/features/questionnaire/client/stores/questionnaire';
 import { useCurrentUser } from '~/stores/context';
 
-import { LoadingSpinner } from '../LoadingSpinner';
-
 
 export const QuestionnaireSettings = (): JSX.Element => {
   const { t } = useTranslation();

+ 4 - 0
apps/app/src/components/Navbar/GroundGlassBar.module.scss

@@ -0,0 +1,4 @@
+.ground-glass-bar {
+  background-color: rgba(var(--bs-body-bg-rgb), 0.7);
+  backdrop-filter: blur(35px);
+}

+ 17 - 0
apps/app/src/components/Navbar/GroundGlassBar.tsx

@@ -0,0 +1,17 @@
+import type { DetailedHTMLProps } from 'react';
+
+import styles from './GroundGlassBar.module.scss';
+
+const moduleClass = styles['ground-glass-bar'];
+
+type Props = DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
+
+export const GroundGlassBar = (props: Props): JSX.Element => {
+  const { className, children, ...rest } = props;
+
+  return (
+    <div className={`${moduleClass} ${className ?? ''}`} {...rest}>
+      {children}
+    </div>
+  );
+};

+ 0 - 5
apps/app/src/components/Navbar/GrowiContextualSubNavigation.module.scss

@@ -1,10 +1,5 @@
 @use '~/styles/mixins';
 
-.grw-contextual-sub-navigation :global {
-  background-color: rgba(var(--bs-body-bg-rgb), 0.7);
-  backdrop-filter: blur(35px);
-}
-
 @include mixins.editing() {
   .grw-contextual-sub-navigation {
     position: fixed;

+ 4 - 2
apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -36,6 +36,8 @@ import { CreateTemplateModal } from '../CreateTemplateModal';
 import { NotAvailable } from '../NotAvailable';
 import { Skeleton } from '../Skeleton';
 
+import { GroundGlassBar } from './GroundGlassBar';
+
 import styles from './GrowiContextualSubNavigation.module.scss';
 import PageEditorModeManagerStyles from './PageEditorModeManager.module.scss';
 
@@ -288,7 +290,7 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
 
   return (
     <>
-      <div
+      <GroundGlassBar
         className={`${styles['grw-contextual-sub-navigation']}
           d-flex align-items-center justify-content-end px-2 px-sm-3 px-md-4 py-1 gap-2 gap-md-4 d-print-none
         `}
@@ -331,7 +333,7 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
             </Link>
           </div>
         ) }
-      </div>
+      </GroundGlassBar>
 
       {path != null && currentUser != null && !isReadOnlyUser && (
         <CreateTemplateModal

+ 0 - 8
apps/app/src/components/Navbar/GrowiNavbarBottom.module.scss

@@ -22,11 +22,3 @@
     align-items: center;
   }
 }
-
-// == Colors
-.grw-navbar-bottom :global {
-  .navbar {
-    background-color: rgba(var(--bs-body-bg-rgb), 0.7);
-    backdrop-filter: blur(35px);
-  }
-}

+ 4 - 2
apps/app/src/components/Navbar/GrowiNavbarBottom.tsx

@@ -6,6 +6,8 @@ import { usePageCreateModal } from '~/stores/modal';
 import { useCurrentPagePath } from '~/stores/page';
 import { useDrawerOpened } from '~/stores/ui';
 
+import { GroundGlassBar } from './GroundGlassBar';
+
 import styles from './GrowiNavbarBottom.module.scss';
 
 
@@ -18,7 +20,7 @@ export const GrowiNavbarBottom = (): JSX.Element => {
   const { open: openSearchModal } = useSearchModal();
 
   return (
-    <div className={`
+    <GroundGlassBar className={`
       ${styles['grw-navbar-bottom']}
       ${isDrawerOpened ? styles['grw-navbar-bottom-drawer-opened'] : ''}
       d-md-none d-edit-none d-print-none fixed-bottom`}
@@ -73,6 +75,6 @@ export const GrowiNavbarBottom = (): JSX.Element => {
         </ul>
       </div>
 
-    </div>
+    </GroundGlassBar>
   );
 };

+ 1 - 2
apps/app/src/components/Page/RevisionLoader.tsx

@@ -1,6 +1,7 @@
 import React, { useState, useEffect } from 'react';
 
 import type { Ref, IRevision, IRevisionHasId } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
 import type { RendererOptions } from '~/interfaces/renderer-options';
@@ -8,8 +9,6 @@ import { useSWRxPageRevision } from '~/stores/page';
 import loggerFactory from '~/utils/logger';
 
 
-import { LoadingSpinner } from '../LoadingSpinner';
-
 import RevisionRenderer from './RevisionRenderer';
 
 export const ROOT_ELEM_ID = 'revision-loader' as const;

+ 1 - 1
apps/app/src/components/PageAccessoriesModal/PageAttachment.tsx

@@ -3,13 +3,13 @@ import React, {
 } from 'react';
 
 import type { IAttachmentHasId } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 
 import { useSWRxAttachments } from '~/stores/attachment';
 import { useIsGuestUser, useIsReadOnlyUser } from '~/stores/context';
 import { useDeleteAttachmentModal } from '~/stores/modal';
 import { useSWRxCurrentPage, useCurrentPageId } from '~/stores/page';
 
-import { LoadingSpinner } from '../LoadingSpinner';
 import { PageAttachmentList } from '../PageAttachment/PageAttachmentList';
 import PaginationWrapper from '../PaginationWrapper';
 

+ 1 - 2
apps/app/src/components/PageAttachment/DeleteAttachmentModal.tsx

@@ -3,7 +3,7 @@ import React, {
 } from 'react';
 
 import type { IUser } from '@growi/core';
-import { UserPicture } from '@growi/ui/dist/components';
+import { UserPicture, LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import {
   Button, Modal, ModalHeader, ModalBody, ModalFooter,
@@ -13,7 +13,6 @@ import { toastSuccess, toastError } from '~/client/util/toastr';
 import { useDeleteAttachmentModal } from '~/stores/modal';
 import loggerFactory from '~/utils/logger';
 
-import { LoadingSpinner } from '../LoadingSpinner';
 import { Username } from '../User/Username';
 
 import styles from './DeleteAttachmentModal.module.scss';

+ 1 - 1
apps/app/src/components/PageControls/BookmarkButtons.tsx

@@ -1,6 +1,7 @@
 import type { FC } from 'react';
 import React, { useState, useCallback } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import DropdownToggle from 'reactstrap/esm/DropdownToggle';
 import Popover from 'reactstrap/esm/Popover';
@@ -12,7 +13,6 @@ import { useIsGuestUser } from '~/stores/context';
 
 import { BookmarkFolderMenu } from '../Bookmarks/BookmarkFolderMenu';
 import UserPictureList from '../Common/UserPictureList';
-import { LoadingSpinner } from '../LoadingSpinner';
 
 import styles from './BookmarkButtons.module.scss';
 import popoverStyles from './user-list-popover.module.scss';

+ 1 - 1
apps/app/src/components/PageEditor/DrawioModal.tsx

@@ -6,6 +6,7 @@ import React, {
 
 import { useCodeMirrorEditorIsolated } from '@growi/editor';
 import { useDrawioModalForEditor } from '@growi/editor/src/stores/use-drawio';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import {
   Modal,
   ModalBody,
@@ -18,7 +19,6 @@ import { useDrawioModal } from '~/stores/modal';
 import { usePersonalSettings } from '~/stores/personal-settings';
 import loggerFactory from '~/utils/logger';
 
-import { LoadingSpinner } from '../LoadingSpinner';
 
 import { type DrawioConfig, DrawioCommunicationHelper } from './DrawioCommunicationHelper';
 

+ 6 - 2
apps/app/src/components/PageEditor/PageEditorReadOnly.tsx

@@ -11,7 +11,11 @@ import { EditorNavbar } from './EditorNavbar';
 import Preview from './Preview';
 import { useScrollSync } from './ScrollSyncHelper';
 
-export const PageEditorReadOnly = react.memo((): JSX.Element => {
+type Props = {
+  visibility?: boolean,
+}
+
+export const PageEditorReadOnly = react.memo(({ visibility }: Props): JSX.Element => {
   const previewRef = useRef<HTMLDivElement>(null);
 
   const { data: currentPage } = useSWRxCurrentPage();
@@ -30,7 +34,7 @@ export const PageEditorReadOnly = react.memo((): JSX.Element => {
   }
 
   return (
-    <div id="page-editor" className="flex-expand-vert">
+    <div id="page-editor" className={`flex-expand-vert ${visibility ? '' : 'd-none'}`}>
       <EditorNavbar />
 
       <div className="flex-expand-horiz">

+ 1 - 1
apps/app/src/components/PageList/PageList.tsx

@@ -1,12 +1,12 @@
 import React from 'react';
 
 import type { IPageInfoForEntity, IPageWithMeta } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 
 import type { OnDeletedFunction, OnPutBackedFunction } from '~/interfaces/ui';
 
 import type { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
-import { LoadingSpinner } from '../LoadingSpinner';
 
 import { PageListItemL } from './PageListItemL';
 

+ 1 - 1
apps/app/src/components/PagePresentationModal.tsx

@@ -1,6 +1,7 @@
 import React, { useCallback } from 'react';
 
 import type { PresentationProps } from '@growi/presentation';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useFullScreen } from '@growi/ui/dist/utils';
 import dynamic from 'next/dynamic';
 import type { ReactMarkdownOptions } from 'react-markdown/lib/react-markdown';
@@ -14,7 +15,6 @@ import { useSWRxCurrentPage } from '~/stores/page';
 import { usePresentationViewOptions } from '~/stores/renderer';
 import { useNextThemes } from '~/stores/use-next-themes';
 
-import { LoadingSpinner } from './LoadingSpinner';
 
 import styles from './PagePresentationModal.module.scss';
 

+ 1 - 1
apps/app/src/components/PrivateLegacyPages.tsx

@@ -3,6 +3,7 @@ import React, {
 } from 'react';
 
 import { useGlobalSocket } from '@growi/core/dist/swr';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import {
   UncontrolledButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem, Modal, ModalHeader, ModalBody, ModalFooter,
@@ -25,7 +26,6 @@ import {
 } from '~/stores/search';
 
 import { MenuItemType } from './Common/Dropdown/PageItemControl';
-import { LoadingSpinner } from './LoadingSpinner';
 import PaginationWrapper from './PaginationWrapper';
 import { PrivateLegacyPagesMigrationModal } from './PrivateLegacyPagesMigrationModal';
 import { OperateAllControl } from './SearchPage/OperateAllControl';

+ 1 - 1
apps/app/src/components/SavePageControls.tsx

@@ -3,6 +3,7 @@ import React, { useCallback, useState, useEffect } from 'react';
 import type EventEmitter from 'events';
 
 import { isTopPage, isUsersProtectedPages } from '@growi/core/dist/utils/page-path-utils';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import {
   UncontrolledButtonDropdown, Button,
@@ -28,7 +29,6 @@ import loggerFactory from '~/utils/logger';
 
 import { unpublish } from '../client/services/page-operation';
 
-import { LoadingSpinner } from './LoadingSpinner';
 import { GrantSelector } from './SavePageControls/GrantSelector';
 import { SlackNotification } from './SlackNotification';
 

+ 1 - 1
apps/app/src/components/SavePageControls/GrantSelector/GrantSelector.tsx

@@ -3,6 +3,7 @@ import React, { useCallback, useState } from 'react';
 import {
   PageGrant, isPopulated, GroupType, type IGrantedGroup,
 } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import {
   UncontrolledDropdown,
@@ -11,7 +12,6 @@ import {
   Modal, ModalHeader, ModalBody,
 } from 'reactstrap';
 
-import { LoadingSpinner } from '~/components/LoadingSpinner';
 import type { IPageGrantData } from '~/interfaces/page';
 import { useCurrentUser } from '~/stores/context';
 

+ 1 - 1
apps/app/src/components/SearchPage/SearchPageBase.tsx

@@ -3,6 +3,7 @@ import React, {
   forwardRef, useEffect, useImperativeHandle, useRef, useState,
 } from 'react';
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
 
@@ -17,7 +18,6 @@ import { usePageDeleteModal } from '~/stores/modal';
 import { mutatePageTree } from '~/stores/page-listing';
 
 import type { ForceHideMenuItems } from '../Common/Dropdown/PageItemControl';
-import { LoadingSpinner } from '../LoadingSpinner';
 
 // Do not import with next/dynamic
 // see: https://github.com/weseek/growi/pull/7923

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

@@ -9,6 +9,7 @@ import { useTemplateModal, type TemplateModalStatus } from '@growi/editor/src/st
 import {
   extractSupportedLocales, getLocalizedTemplate, type TemplateSummary,
 } from '@growi/pluginkit/dist/v4';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import {
   Modal,
@@ -26,7 +27,6 @@ import { usePersonalSettings } from '~/stores/personal-settings';
 import { usePreviewOptions } from '~/stores/renderer';
 import loggerFactory from '~/utils/logger';
 
-import { LoadingSpinner } from '../LoadingSpinner';
 import Preview from '../PageEditor/Preview';
 
 import { useFormatter } from './use-formatter';

+ 1 - 1
apps/app/src/components/TreeItem/SimpleItem.tsx

@@ -6,6 +6,7 @@ import React, {
 import nodePath from 'path';
 
 import type { Nullable } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import { UncontrolledTooltip } from 'reactstrap';
 
@@ -15,7 +16,6 @@ import { usePageTreeDescCountMap } from '~/stores/ui';
 import { shouldRecoverPagePaths } from '~/utils/page-operation';
 
 import CountBadge from '../Common/CountBadge';
-import { LoadingSpinner } from '../LoadingSpinner';
 
 import { ItemNode } from './ItemNode';
 import { useNewPageInput } from './NewPageInput';

+ 0 - 1
apps/app/src/pages/_private-legacy-pages.page.tsx

@@ -6,7 +6,6 @@ import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
-import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
 import type { CrowiRequest } from '~/interfaces/crowi-request';

+ 0 - 1
apps/app/src/pages/_search.page.tsx

@@ -6,7 +6,6 @@ import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
-import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import SearchResultLayout from '~/components/Layout/SearchResultLayout';
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';

+ 2 - 2
apps/app/src/pages/forgot-password-errors.page.tsx

@@ -19,8 +19,8 @@ const ForgotPasswordErrorsPage: NextPage<Props> = (props: Props) => {
   const { errorCode } = props;
 
   return (
-    <div id="main" className="main">
-      <div id="content-main" className="content-main container-lg">
+    <div className="main">
+      <div className="container-lg">
         <div className="container">
           <div className="row justify-content-md-center">
             <div className="col-md-6 mt-5">

+ 6 - 7
apps/app/src/pages/forgot-password.page.tsx

@@ -1,15 +1,14 @@
 import React from 'react';
 
-import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
+import type { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 
-import { CrowiRequest } from '~/interfaces/crowi-request';
+import type { CrowiRequest } from '~/interfaces/crowi-request';
 import { useIsMailerSetup } from '~/stores/context';
 
-import {
-  CommonProps, getNextI18NextConfig, getServerSideCommonProps,
-} from './utils/commons';
+import type { CommonProps } from './utils/commons';
+import { getNextI18NextConfig, getServerSideCommonProps } from './utils/commons';
 
 const PasswordResetRequestForm = dynamic(() => import('~/components/PasswordResetRequestForm'), { ssr: false });
 
@@ -21,8 +20,8 @@ const ForgotPasswordPage: NextPage<Props> = (props: Props) => {
   useIsMailerSetup(props.isMailerSetup);
 
   return (
-    <div id="main" className="main">
-      <div id="content-main" className="content-main container-lg">
+    <div className="main">
+      <div className="container-lg">
         <div className="container">
           <div className="row justify-content-md-center">
             <div className="col-md-6 mt-5">

+ 1 - 1
apps/app/src/pages/maintenance.page.tsx

@@ -32,7 +32,7 @@ const MaintenancePage: NextPage<CommonProps> = (props: Props) => {
   };
 
   return (
-    <div id="content-main" className="content-main container-lg">
+    <div className="container-lg">
       <div className="container">
         <div className="row justify-content-md-center">
           <div className="col-md-6 mt-5">

+ 8 - 10
apps/app/src/pages/me/[[...path]].page.tsx

@@ -8,9 +8,9 @@ import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
 import { useRouter } from 'next/router';
-import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { BasicLayout } from '~/components/Layout/BasicLayout';
+import { GroundGlassBar } from '~/components/Navbar/GroundGlassBar';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 import type { RendererConfig } from '~/interfaces/services/renderer';
 import {
@@ -123,18 +123,16 @@ const MePage: NextPageWithLayout<Props> = (props: Props) => {
       <Head>
         <title>{title}</title>
       </Head>
-      <div className="dynamic-layout-root mx-md-3">
-        <header className="py-3">
-          <div className="container">
-            <h1 className="title fs-3 mt-5">{ targetPage.title }</h1>
-          </div>
-        </header>
+      <div className="dynamic-layout-root">
+        <GroundGlassBar className="sticky-top py-4"></GroundGlassBar>
+
+        <div className="main ps-sidebar">
+          <div className="container-lg wide-gutter-x-lg">
 
-        <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
+            <h1 className="sticky-top py-2 fs-3">{ targetPage.title }</h1>
 
-        <div id="main" className="main">
-          <div id="content-main" className="content-main container">
             {targetPage.component}
+
           </div>
         </div>
       </div>

+ 2 - 2
apps/app/src/pages/reset-password.page.tsx

@@ -19,8 +19,8 @@ const ForgotPasswordPage: NextPage<Props> = (props: Props) => {
   const { t } = useTranslation();
 
   return (
-    <div id="main" className="main">
-      <div id="content-main" className="content-main container-lg">
+    <div className="main">
+      <div className="container-lg">
         <div className="container">
           <div className="row justify-content-md-center">
             <div className="col-md-6 mt-5">

+ 0 - 2
apps/app/src/pages/share/[[...path]].page.tsx

@@ -124,8 +124,6 @@ const SharedPage: NextPageWithLayout<Props> = (props: Props) => {
           <GrowiContextualSubNavigationForSharedPage page={currentPage ?? props.shareLinkRelatedPage} isLinkSharingDisabled={props.disableLinkSharing} />
         </nav>
 
-        <div id="grw-fav-sticky-trigger" className="sticky-top"></div>
-
         <ShareLinkPageView
           pagePath={pagePath}
           rendererConfig={props.rendererConfig}

+ 32 - 25
apps/app/src/pages/tags.page.tsx

@@ -2,14 +2,14 @@ import type { ReactNode } from 'react';
 import React, { useState, useCallback } from 'react';
 
 import type { IUser } from '@growi/core';
+import { LoadingSpinner } from '@growi/ui/dist/components';
 import type { GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { useTranslation } from 'next-i18next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
-import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
-import { LoadingSpinner } from '~/components/LoadingSpinner';
+import { GroundGlassBar } from '~/components/Navbar/GroundGlassBar';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 import type { RendererConfig } from '~/interfaces/services/renderer';
 import type { IDataTagCount } from '~/interfaces/tag';
@@ -84,30 +84,37 @@ const TagPage: NextPageWithLayout<CommonProps> = (props: Props) => {
         <title>{title}</title>
       </Head>
       <div className="dynamic-layout-root">
-        <div className="container-lg 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} />
+        <GroundGlassBar className="sticky-top py-4"></GroundGlassBar>
+
+        <div className="main ps-sidebar" data-testid="tags-page">
+          <div className="container-lg wide-gutter-x-lg">
+
+            <h2 className="sticky-top py-1">
+              {`${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">
+                  <LoadingSpinner className="mt-3 fs-3" />
+                </div>
+              )
+              : (
+                <div data-testid="grw-tags-list">
+                  <TagList
+                    tagData={tagData}
+                    totalTags={totalCount}
+                    activePage={activePage}
+                    onChangePage={setOffsetByPageNumber}
+                    pagingLimit={PAGING_LIMIT}
+                  />
+                </div>
+              )
+            }
           </div>
-          { isLoading
-            ? (
-              <div className="text-muted text-center">
-                <LoadingSpinner className="mt-3 fs-3" />
-              </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>
       </div>
     </>

+ 9 - 5
apps/app/src/pages/trash.page.tsx

@@ -1,14 +1,14 @@
 import type { ReactNode } from 'react';
 import React from 'react';
 
-import type { IUser, IUserHasId } from '@growi/core';
+import type { IUser } from '@growi/core';
 import type { GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import Head from 'next/head';
-import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { PagePathNavSticky } from '~/components/Common/PagePathNav';
+import { GroundGlassBar } from '~/components/Navbar/GroundGlassBar';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 import type { RendererConfig } from '~/interfaces/services/renderer';
 import { useCurrentPageId, useSWRxCurrentPage } from '~/stores/page';
@@ -70,9 +70,13 @@ const TrashPage: NextPageWithLayout<CommonProps> = (props: Props) => {
         <title>{title}</title>
       </Head>
       <div className="dynamic-layout-root">
-        <div className="content-main container-lg mt-5 ms-md-5 ms-xl-0">
-          <PagePathNavSticky pagePath="/trash" />
-          <TrashPageList />
+        <GroundGlassBar className="sticky-top py-4"></GroundGlassBar>
+
+        <div className="main ps-sidebar">
+          <div className="container-lg wide-gutter-x-lg">
+            <PagePathNavSticky pagePath="/trash" />
+            <TrashPageList />
+          </div>
         </div>
       </div>
     </>

+ 20 - 0
apps/app/src/styles/_layout.scss

@@ -48,6 +48,26 @@
   }
 }
 
+// md/lg layout padding
+.ps-sidebar {
+  @include bs.media-breakpoint-between(md, xl) {
+    padding-left: var.$grw-sidebar-nav-width;
+  }
+}
+
+.wide-gutter-x-lg {
+  @include bs.media-breakpoint-up(lg) {
+    &,
+    .container,
+    .container-fluid,
+    .container-xxl,
+    .container-xl,
+    .container-lg {
+      --bs-gutter-x: 3rem;
+    }
+  }
+}
+
 // printable style
 @media print {
   body {

+ 2 - 0
apps/app/src/styles/vendor.scss

@@ -1,5 +1,7 @@
 @import '@growi/core/scss/bootstrap/apply';
 
+@import '@growi/ui/dist/style';
+
 // react-bootstrap-typeahead
 @import 'react-bootstrap-typeahead/css/Typeahead';
 

+ 2 - 0
apps/app/turbo.json

@@ -4,6 +4,7 @@
   "pipeline": {
 
     "styles-prebuilt": {
+      "dependsOn": ["@growi/ui#build"],
       "outputs": ["src/styles/prebuilt/**"],
       "inputs": [
         "src/styles/**/*.scss",
@@ -24,6 +25,7 @@
       "outputMode": "new-only"
     },
     "dev:styles-prebuilt": {
+      "dependsOn": ["@growi/ui#dev"],
       "outputs": ["src/styles/prebuilt/**"],
       "inputs": [
         "src/styles/**/*.scss",

+ 1 - 0
packages/custom-icons/svg/facebook.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><defs><style>.a{fill:none;}</style></defs><g transform="translate(-372 -420)"><path class="a" d="M20,10A10,10,0,1,0,7.584,19.706v-6.65H5.522V10H7.584V8.683c0-3.4,1.54-4.981,4.882-4.981a11.026,11.026,0,0,1,2.174.248v2.77c-.236-.025-.646-.037-1.155-.037-1.64,0-2.273.621-2.273,2.236V10h3.266l-.561,3.056H11.211v6.871A10,10,0,0,0,20,10" transform="translate(374 422)"/></g></svg>

+ 1 - 0
packages/custom-icons/svg/github.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><defs><style>.a,.b{fill:none;}.a{fill-rule:evenodd;}</style></defs><g transform="translate(-207 -420)"><path class="a" d="M10.008,0A10.093,10.093,0,0,0,6.843,19.648c.5.1.679-.217.679-.484,0-.234-.016-1.035-.016-1.87-2.784.6-3.364-1.2-3.364-1.2a2.576,2.576,0,0,0-1.11-1.469c-.911-.618.066-.618.066-.618A2.1,2.1,0,0,1,4.64,15.04a2.12,2.12,0,0,0,2.916.835,2.148,2.148,0,0,1,.63-1.352c-2.22-.234-4.557-1.1-4.557-4.975a3.947,3.947,0,0,1,1.027-2.7,3.667,3.667,0,0,1,.1-2.671s.845-.267,2.75,1.035a9.541,9.541,0,0,1,5,0c1.906-1.3,2.751-1.035,2.751-1.035a3.667,3.667,0,0,1,.1,2.671,3.872,3.872,0,0,1,1.027,2.7c0,3.873-2.336,4.724-4.573,4.975a2.4,2.4,0,0,1,.679,1.87c0,1.352-.016,2.437-.016,2.771,0,.267.182.584.679.484A10.093,10.093,0,0,0,10.008,0Z" transform="translate(209 422)"/></g></svg>

+ 1 - 0
packages/custom-icons/svg/google.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><defs><style>.a{fill:none;}</style></defs><g transform="translate(-291 -420)"><path class="a" d="M19.418,8.182H10V12.05h5.382a4.6,4.6,0,0,1-2,3.018A6.026,6.026,0,1,1,10,3.977a5.4,5.4,0,0,1,3.822,1.5l2.869-2.868A9.611,9.611,0,0,0,10,0a10,10,0,1,0,0,20,9.544,9.544,0,0,0,6.618-2.423,9.75,9.75,0,0,0,2.982-7.35,11.507,11.507,0,0,0-.182-2.045" transform="translate(293.2 422)"/></g></svg>

+ 1 - 0
packages/custom-icons/svg/slack.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><defs><style>.a{fill:none;}</style></defs><g transform="translate(-131 -420)"><g transform="translate(133 422)"><path class="a" d="M4.2,66.8a2.1,2.1,0,1,1-2.1-2.1H4.2Z" transform="translate(0 -54.162)"/><path class="a" d="M32.3,66.8a2.1,2.1,0,1,1,4.2,0v5.261a2.1,2.1,0,1,1-4.2,0V66.8" transform="translate(-27.039 -54.162)"/><path class="a" d="M34.4,4.2a2.1,2.1,0,1,1,2.1-2.1V4.2Z" transform="translate(-27.039)"/><path class="a" d="M7.362,32.3a2.1,2.1,0,1,1,0,4.2H2.1a2.1,2.1,0,1,1,0-4.2H7.362" transform="translate(0 -27.039)"/><path class="a" d="M97,34.4a2.1,2.1,0,1,1,2.1,2.1H97Z" transform="translate(-81.202 -27.039)"/><path class="a" d="M68.9,7.362a2.1,2.1,0,1,1-4.2,0V2.1a2.1,2.1,0,1,1,4.2,0Z" transform="translate(-54.162)"/><path class="a" d="M66.8,97a2.1,2.1,0,1,1-2.1,2.1V97Z" transform="translate(-54.162 -81.201)"/><path class="a" d="M66.8,68.9a2.1,2.1,0,1,1,0-4.2h5.261a2.1,2.1,0,1,1,0,4.2Z" transform="translate(-54.162 -54.162)"/></g></g></svg>

+ 17 - 15
packages/editor/src/services/paste-util/paste-markdown-util.ts

@@ -20,28 +20,30 @@ export const adjustPasteData = (strFromBol: string, text: string): string => {
 
   let adjusted = text;
 
-  if (text.match(indentAndMarkRE)) {
-    const matchResult = strFromBol.match(indentAndMarkRE);
-    const indent = matchResult ? matchResult[1] : '';
+  if (indentAndMarkOnlyRE.test(strFromBol)) {
+    if (text.match(indentAndMarkRE)) {
+      const matchResult = strFromBol.match(indentAndMarkRE);
+      const indent = matchResult ? matchResult[1] : '';
 
-    const lines = text.match(/[^\r\n]+/g);
+      const lines = text.match(/[^\r\n]+/g);
 
-    const replacedLines = lines?.map((line, index) => {
+      const replacedLines = lines?.map((line, index) => {
 
-      if (index === 0 && strFromBol.match(indentAndMarkOnlyRE)) {
-        return line.replace(indentAndMarkRE, '');
-      }
+        if (index === 0 && strFromBol.match(indentAndMarkOnlyRE)) {
+          return line.replace(indentAndMarkRE, '');
+        }
 
-      return indent + line;
-    });
+        return indent + line;
+      });
 
-    adjusted = replacedLines ? replacedLines.join('\n') : '';
-  }
+      adjusted = replacedLines ? replacedLines.join('\n') : '';
+    }
 
-  else if (strFromBol.match(indentAndMarkRE)) {
-    const replacedText = text.replace(/(\r\n|\r|\n)/g, `$1${strFromBol}`);
+    else {
+      const replacedText = text.replace(/(\r\n|\r|\n)/g, `$1${strFromBol}`);
 
-    adjusted = replacedText;
+      adjusted = replacedText;
+    }
   }
 
   return adjusted;

+ 3 - 1
packages/remark-attachment-refs/package.json

@@ -33,7 +33,9 @@
     "dev": "run-p dev:*",
     "dev:server": "vite build -c vite.server.config.ts --mode dev",
     "dev:client": "vite build -c vite.client.config.ts --mode dev",
-    "watch": "yarn dev -w --emptyOutDir=false",
+    "watch": "run-p watch:*",
+    "watch:client": "yarn dev:client -w --emptyOutDir=false",
+    "watch:server": "yarn dev:server -w --emptyOutDir=false",
     "lint:js": "yarn eslint **/*.{js,jsx,ts,tsx}",
     "lint:styles": "stylelint src/**/*.scss src/**/*.css",
     "lint:typecheck": "tsc",

+ 2 - 2
packages/remark-attachment-refs/src/client/components/AttachmentList.tsx

@@ -1,7 +1,7 @@
 import { useCallback } from 'react';
 
 import type { IAttachmentHasId } from '@growi/core';
-import { Attachment } from '@growi/ui/dist/components';
+import { Attachment, LoadingSpinner } from '@growi/ui/dist/components';
 
 import { ExtractedAttachments } from './ExtractedAttachments';
 import { RefsContext } from './util/refs-context';
@@ -43,7 +43,7 @@ export const AttachmentList = ({
     if (isLoading) {
       return (
         <div className="text-muted">
-          <i className="fa fa-spinner fa-pulse me-1"></i>
+          <LoadingSpinner className="me-1" />
           <span className="attachment-refs-blink">{refsContext.toString()}</span>
         </div>
       );

+ 3 - 1
packages/remark-lsx/src/client/components/Lsx.tsx

@@ -1,6 +1,8 @@
 import React, { useCallback, useMemo } from 'react';
 
 
+import { LoadingSpinner } from '@growi/ui/dist/components';
+
 import { useSWRxLsx } from '../stores/lsx';
 import { generatePageNodeTree } from '../utils/page-node';
 
@@ -71,7 +73,7 @@ const LsxSubstance = React.memo(({
     return (
       <div className={`text-muted ${isLoading ? 'lsx-blink' : ''}`}>
         <small>
-          <i className="fa fa-spinner fa-pulse me-1"></i>
+          <LoadingSpinner className="me-1" />
           {lsxContext.toString()}
         </small>
       </div>

+ 3 - 0
packages/ui/package.json

@@ -21,6 +21,9 @@
     "./dist/utils": {
       "import": "./dist/utils/index.js"
     },
+    "./dist/style": {
+      "import": "./dist/style.css"
+    },
     "./scss/*": "./scss/*.scss"
   },
   "scripts": {

+ 1 - 0
apps/app/src/components/LoadingSpinner.module.scss → packages/ui/src/components/LoadingSpinner.module.scss

@@ -37,3 +37,4 @@
     transform: rotate(360deg);
   }
 }
+

+ 9 - 0
packages/ui/src/components/LoadingSpinner.tsx

@@ -0,0 +1,9 @@
+import type { ComponentPropsWithoutRef } from 'react';
+
+import styles from './LoadingSpinner.module.scss';
+
+const moduleClass = styles.spinner ?? '';
+
+export const LoadingSpinner = ({ className = '' }: ComponentPropsWithoutRef<'span'>): JSX.Element => (
+  <span className={`material-symbols-outlined pb-0 ${moduleClass} ${className}`}>progress_activity</span>
+);

+ 1 - 0
packages/ui/src/components/index.ts

@@ -1,4 +1,5 @@
 export * from './Attachment';
 export * from './FootstampIcon';
 export * from './PagePath';
+export * from './LoadingSpinner';
 export * from './UserPicture';