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

Merge pull request #8200 from weseek/imprv/responsive-layout

imprv: Responsive layout
Yuki Takei 2 лет назад
Родитель
Сommit
719f6b3cbe
44 измененных файлов с 419 добавлено и 249 удалено
  1. 1 1
      apps/app/src/components/Admin/UserGroupDetail/UserGroupDetailPage.module.scss
  2. 18 0
      apps/app/src/components/Common/DrawerToggler/DrawerToggler.module.scss
  3. 36 0
      apps/app/src/components/Common/DrawerToggler/DrawerToggler.tsx
  4. 1 0
      apps/app/src/components/Common/DrawerToggler/index.ts
  5. 1 6
      apps/app/src/components/IdenticalPathPage.module.scss
  6. 1 1
      apps/app/src/components/InAppNotification/PageNotification/ModelNotification.tsx
  7. 34 0
      apps/app/src/components/Layout/PageViewLayout.module.scss
  8. 3 3
      apps/app/src/components/Layout/PageViewLayout.tsx
  9. 0 31
      apps/app/src/components/Navbar/DrawerToggler.tsx
  10. 17 18
      apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  11. 15 0
      apps/app/src/components/Navbar/GrowiNavbarBottom.module.scss
  12. 25 12
      apps/app/src/components/Navbar/GrowiNavbarBottom.tsx
  13. 11 10
      apps/app/src/components/Navbar/PageEditorModeManager.module.scss
  14. 4 4
      apps/app/src/components/Navbar/PageEditorModeManager.tsx
  15. 3 1
      apps/app/src/components/PageControls/BookmarkButtons.module.scss
  16. 3 1
      apps/app/src/components/PageControls/LikeButtons.module.scss
  17. 3 1
      apps/app/src/components/PageControls/PageControls.module.scss
  18. 3 1
      apps/app/src/components/PageControls/SeenUserInfo.module.scss
  19. 3 1
      apps/app/src/components/PageControls/SubscribeButton.module.scss
  20. 0 17
      apps/app/src/components/PageControls/_button-styles.scss
  21. 7 18
      apps/app/src/components/PageEditor/EditorNavbarBottom.tsx
  22. 1 1
      apps/app/src/components/PageList/PageList.module.scss
  23. 7 8
      apps/app/src/components/PageList/PageListItemL.tsx
  24. 1 2
      apps/app/src/components/PageList/PageListItemS.tsx
  25. 30 0
      apps/app/src/components/PageSideContents/PageAccessoriesControl.module.scss
  26. 42 0
      apps/app/src/components/PageSideContents/PageAccessoriesControl.tsx
  27. 1 4
      apps/app/src/components/PageSideContents/PageSideContents.module.scss
  28. 27 41
      apps/app/src/components/PageSideContents/PageSideContents.tsx
  29. 1 1
      apps/app/src/components/SearchPage/SearchPageBase.module.scss
  30. 1 2
      apps/app/src/components/SearchTypeahead.tsx
  31. 20 3
      apps/app/src/components/Sidebar/AppTitle/AppTitle.module.scss
  32. 10 3
      apps/app/src/components/Sidebar/Sidebar.tsx
  33. 8 5
      apps/app/src/components/Sidebar/SidebarHead/ToggleCollapseButton.tsx
  34. 1 1
      apps/app/src/components/UsersHomepageFooter.module.scss
  35. 44 16
      apps/app/src/stores/ui.tsx
  36. 0 16
      apps/app/src/styles/_layout.scss
  37. 1 1
      apps/app/src/styles/_variables.scss
  38. 0 16
      apps/app/src/styles/molecules/_page-accessories-control.scss
  39. 1 1
      packages/remark-lsx/src/client/components/LsxPageList/LsxListView.module.scss
  40. 1 1
      packages/remark-lsx/src/client/components/LsxPageList/LsxPage.tsx
  41. 14 1
      packages/ui/package.json
  42. 18 0
      packages/ui/scss/atoms/_btn-muted.scss
  43. 0 0
      packages/ui/scss/molecules/_page_list.scss
  44. 1 0
      packages/ui/src/components/index.ts

+ 1 - 1
apps/app/src/components/Admin/UserGroupDetail/UserGroupDetailPage.module.scss

@@ -1,2 +1,2 @@
-@use '@growi/ui/src/styles/molecules/page_list';
+@use '@growi/ui/scss/molecules/page_list';
 

+ 18 - 0
apps/app/src/components/Common/DrawerToggler/DrawerToggler.module.scss

@@ -0,0 +1,18 @@
+@use '@growi/core/scss/bootstrap/init' as bs;
+
+@use '@growi/ui/scss/atoms/btn-muted';
+
+@use '~/styles/variables' as var;
+
+
+.grw-drawer-toggler :global {
+  .btn {
+    --bs-btn-color: rgba(var(--bs-tertiary-color-rgb), 0.5);
+    --bs-btn-bg: transparent;
+
+    --bs-btn-hover-color: rgba(var(--bs-tertiary-color-rgb), 0.7);
+
+    width: var.$grw-sidebar-nav-width;
+    height: var.$grw-sidebar-nav-width;
+  }
+}

+ 36 - 0
apps/app/src/components/Common/DrawerToggler/DrawerToggler.tsx

@@ -0,0 +1,36 @@
+import { type ReactNode } from 'react';
+
+import { useDrawerOpened } from '~/stores/ui';
+
+
+import styles from './DrawerToggler.module.scss';
+
+const moduleClass = styles['grw-drawer-toggler'];
+
+
+type Props = {
+  className?: string,
+  children?: ReactNode,
+}
+
+export const DrawerToggler = (props: Props): JSX.Element => {
+
+  const { className, children } = props;
+
+  const { data: isOpened, mutate } = useDrawerOpened();
+
+  return (
+    <div className={`${moduleClass} ${className ?? ''}`}>
+      <button
+        className="btn d-flex align-items-center border-0"
+        type="button"
+        aria-expanded="false"
+        aria-label="Toggle navigation"
+        onClick={() => mutate(!isOpened)}
+      >
+        {children}
+      </button>
+    </div>
+  );
+
+};

+ 1 - 0
apps/app/src/components/Common/DrawerToggler/index.ts

@@ -0,0 +1 @@
+export * from './DrawerToggler';

+ 1 - 6
apps/app/src/components/IdenticalPathPage.module.scss

@@ -1,6 +1 @@
-@use '@growi/ui/src/styles/molecules/page_list';
-@use '~/styles/molecules/page-accessories-control';
-
-.grw-page-accessories-control :global {
-  @extend %grw-page-accessories-control;
-}
+@use '@growi/ui/scss/molecules/page_list';

+ 1 - 1
apps/app/src/components/InAppNotification/PageNotification/ModelNotification.tsx

@@ -1,7 +1,7 @@
 import React, { FC, useImperativeHandle } from 'react';
 
 import type { HasObjectId } from '@growi/core';
-import { PagePathLabel } from '@growi/ui/dist/components/PagePath';
+import { PagePathLabel } from '@growi/ui/dist/components';
 
 import type { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
 import type { IInAppNotification } from '~/interfaces/in-app-notification';

+ 34 - 0
apps/app/src/components/Layout/PageViewLayout.module.scss

@@ -1,3 +1,37 @@
+@use '@growi/core/scss/bootstrap/init' as bs;
+
+@use '~/styles/variables' as var;
+
+
 .page-view-layout :global {
   min-height: calc(100vh - 48px - 250px); // 100vh - subnavigation height - page-comments-row minimum height
+
+  .grw-side-contents-container {
+    margin-bottom: 1rem;
+
+    @include bs.media-breakpoint-up(lg) {
+      width: 250px;
+      min-width: 250px;
+      margin-left: 30px;
+    }
+  }
+}
+
+// md/lg layout padding
+.page-view-layout :global {
+  @include bs.media-breakpoint-between(md, xl) {
+    padding-left: var.$grw-sidebar-nav-width;
+  }
+}
+
+// sticky side contents
+.page-view-layout :global {
+  .grw-side-contents-sticky-container {
+    position: sticky;
+
+    $subnavigation-height: 50px;
+    $page-view-layout-margin-top: 32px;
+    $page-path-nav-height: 99px;
+    top: calc($subnavigation-height + $page-view-layout-margin-top + $page-path-nav-height + 4px);
+  }
 }

+ 3 - 3
apps/app/src/components/Layout/PageViewLayout.tsx

@@ -16,16 +16,16 @@ export const PageViewLayout = (props: Props): JSX.Element => {
 
   return (
     <>
-      <div id="main" className={`main page-view-layout ${styles['page-view-layout']}`}>
+      <div id="main" className={`main ${styles['page-view-layout']}`}>
         <div id="content-main" className="content-main container-lg grw-container-convertible">
           { headerContents != null && headerContents }
           { sideContents != null
             ? (
-              <div className="d-flex flex-column flex-column-reverse flex-lg-row">
+              <div className="d-flex gap-3">
                 <div className="flex-grow-1 flex-basis-0 mw-0">
                   {children}
                 </div>
-                <div className="grw-side-contents-container d-edit-none" data-vrt-blackout-side-contents>
+                <div className="grw-side-contents-container col-lg-3  d-edit-none" data-vrt-blackout-side-contents>
                   <div className="grw-side-contents-sticky-container">
                     {sideContents}
                   </div>

+ 0 - 31
apps/app/src/components/Navbar/DrawerToggler.tsx

@@ -1,31 +0,0 @@
-import React from 'react';
-
-import { useDrawerOpened } from '~/stores/ui';
-
-type Props = {
-  iconClass?: string,
-}
-
-const DrawerToggler = (props: Props): JSX.Element => {
-
-  const { data: isOpened, mutate } = useDrawerOpened();
-
-  const iconClass = props.iconClass ?? isOpened
-    ? 'icon-arrow-left'
-    : 'icon-arrow-right';
-
-  return (
-    <button
-      className="grw-drawer-toggler btn btn-secondary"
-      type="button"
-      aria-expanded="false"
-      aria-label="Toggle navigation"
-      onClick={() => mutate(!isOpened)}
-    >
-      <i className={iconClass}></i>
-    </button>
-  );
-
-};
-
-export default DrawerToggler;

+ 17 - 18
apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -335,24 +335,23 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
         `}
         data-testid="grw-contextual-sub-nav"
       >
-        <div className="h-50">
-          {pageId != null && (
-            <PageControls
-              pageId={pageId}
-              revisionId={revisionId}
-              shareLinkId={shareLinkId}
-              path={path ?? currentPathname} // If the page is empty, "path" is undefined
-              expandContentWidth={currentPage?.expandContentWidth ?? isContainerFluid}
-              disableSeenUserInfoPopover={isSharedUser}
-              showPageControlDropdown={isAbleToShowPageManagement}
-              additionalMenuItemRenderer={additionalMenuItemsRenderer}
-              onClickDuplicateMenuItem={duplicateItemClickedHandler}
-              onClickRenameMenuItem={renameItemClickedHandler}
-              onClickDeleteMenuItem={deleteItemClickedHandler}
-              onClickSwitchContentWidth={switchContentWidthHandler}
-            />
-          )}
-        </div>
+        {pageId != null && (
+          <PageControls
+            pageId={pageId}
+            revisionId={revisionId}
+            shareLinkId={shareLinkId}
+            path={path ?? currentPathname} // If the page is empty, "path" is undefined
+            expandContentWidth={currentPage?.expandContentWidth ?? isContainerFluid}
+            disableSeenUserInfoPopover={isSharedUser}
+            showPageControlDropdown={isAbleToShowPageManagement}
+            additionalMenuItemRenderer={additionalMenuItemsRenderer}
+            onClickDuplicateMenuItem={duplicateItemClickedHandler}
+            onClickRenameMenuItem={renameItemClickedHandler}
+            onClickDeleteMenuItem={deleteItemClickedHandler}
+            onClickSwitchContentWidth={switchContentWidthHandler}
+          />
+        )}
+
         {isAbleToChangeEditorMode && (
           <PageEditorModeManager
             editorMode={editorMode}

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

@@ -14,3 +14,18 @@
     bottom: #{-1 * var.$grw-navbar-bottom-height};
   }
 }
+
+
+// centering icons
+.grw-navbar-bottom :global {
+  .nav-link {
+    display: flex;
+    align-items: center;
+  }
+}
+
+// == Colors
+.grw-navbar-bottom {
+  background-color: rgba(var(--bs-body-bg-rgb), 0.7);
+  backdrop-filter: blur(35px);
+}

+ 25 - 12
apps/app/src/components/Navbar/GrowiNavbarBottom.tsx

@@ -3,7 +3,7 @@ import React from 'react';
 import { useIsSearchPage } from '~/stores/context';
 import { usePageCreateModal } from '~/stores/modal';
 import { useCurrentPagePath } from '~/stores/page';
-import { useIsDeviceSmallerThanMd, useDrawerOpened } from '~/stores/ui';
+import { useIsDeviceLargerThanMd, useDrawerOpened } from '~/stores/ui';
 
 import { GlobalSearch } from './GlobalSearch';
 
@@ -13,12 +13,12 @@ import styles from './GrowiNavbarBottom.module.scss';
 export const GrowiNavbarBottom = (): JSX.Element => {
 
   const { data: isDrawerOpened, mutate: mutateDrawerOpened } = useDrawerOpened();
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
+  const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
   const { open: openCreateModal } = usePageCreateModal();
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: isSearchPage } = useIsSearchPage();
 
-  const additionalClasses = ['grw-navbar-bottom', styles['grw-navbar-bottom']];
+  const additionalClasses = [styles['grw-navbar-bottom']];
   if (isDrawerOpened) {
     additionalClasses.push('grw-navbar-bottom-drawer-opened');
   }
@@ -26,7 +26,7 @@ export const GrowiNavbarBottom = (): JSX.Element => {
   return (
     <div className="d-md-none d-edit-none fixed-bottom">
 
-      { isDeviceSmallerThanMd && !isSearchPage && (
+      { !isDeviceLargerThanMd && !isSearchPage && (
         <div id="grw-global-search-collapse" className="grw-global-search collapse bg-dark">
           <div className="p-3">
             <GlobalSearch dropup />
@@ -34,18 +34,29 @@ export const GrowiNavbarBottom = (): JSX.Element => {
         </div>
       ) }
 
-      <div className={`navbar navbar-expand navbar-dark bg-primary px-0 ${additionalClasses.join(' ')}`}>
+      <div className={`navbar navbar-expand px-4 px-sm-5 ${additionalClasses.join(' ')}`}>
 
-        <ul className="navbar-nav w-100">
-          <li className="nav-item me-auto">
+        <ul className="navbar-nav flex-grow-1 d-flex align-items-center justify-content-between">
+          <li className="nav-item">
             <a
               role="button"
               className="nav-link btn-lg"
               onClick={() => mutateDrawerOpened(true)}
             >
-              <i className="icon-menu"></i>
+              <span className="material-symbols-outlined fs-2">reorder</span>
             </a>
           </li>
+
+          <li className="nav-item">
+            <a
+              role="button"
+              className="nav-link btn-lg"
+              onClick={() => openCreateModal(currentPagePath || '')}
+            >
+              <span className="material-symbols-outlined fs-2">edit</span>
+            </a>
+          </li>
+
           {
             !isSearchPage && (
               <li className="nav-item">
@@ -55,20 +66,22 @@ export const GrowiNavbarBottom = (): JSX.Element => {
                   data-bs-target="#grw-global-search-collapse"
                   data-bs-toggle="collapse"
                 >
-                  <i className="icon-magnifier"></i>
+                  <span className="material-symbols-outlined fs-2">search</span>
                 </a>
               </li>
             )
           }
-          <li className="nav-item ms-auto">
+
+          <li className="nav-item">
             <a
               role="button"
               className="nav-link btn-lg"
-              onClick={() => openCreateModal(currentPagePath || '')}
+              onClick={() => {}}
             >
-              <i className="icon-pencil"></i>
+              <span className="material-symbols-outlined fs-2">notifications</span>
             </a>
           </li>
+
         </ul>
       </div>
 

+ 11 - 10
apps/app/src/components/Navbar/PageEditorModeManager.module.scss

@@ -7,11 +7,12 @@
     --bs-btn-font-size: 13px;
     --bs-btn-border-width: 2px;
 
-    width: 70px;
-    height: 30px;
-    @include bs.media-breakpoint-down(sm) {
-      width: 90px;
-      height: 38px;
+    width: 90px;
+    height: 38px;
+
+    @include bs.media-breakpoint-up(md) {
+      width: 70px;
+      height: 30px;
     }
 
     @include mixins.border-vertical('before', 70%, 1, true);
@@ -19,11 +20,11 @@
 }
 
 .grw-page-editor-mode-manager-skeleton :global {
-  width: 179px;
-  height: 30px;
-  @include bs.media-breakpoint-down(sm) {
-    width: 90px;
-    height: 38px;
+  width: 90px;
+  height: 38px;
+  @include bs.media-breakpoint-up(md) {
+    width: 179px;
+    height: 30px;
   }
 }
 

+ 4 - 4
apps/app/src/components/Navbar/PageEditorModeManager.tsx

@@ -2,7 +2,7 @@ import React, { type ReactNode, useCallback, useState } from 'react';
 
 import { useTranslation } from 'next-i18next';
 
-import { EditorMode, useIsDeviceSmallerThanMd } from '~/stores/ui';
+import { EditorMode, useIsDeviceLargerThanMd } from '~/stores/ui';
 
 import { useOnPageEditorModeButtonClicked } from './hooks';
 
@@ -61,7 +61,7 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
   const { t } = useTranslation();
   const [isCreating, setIsCreating] = useState(false);
 
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
+  const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
 
   const onPageEditorModeButtonClicked = useOnPageEditorModeButtonClicked(setIsCreating, path, grant, grantUserGroupId);
   const _isBtnDisabled = isCreating || isBtnDisabled;
@@ -82,7 +82,7 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
         aria-label="page-editor-mode-manager"
         id="grw-page-editor-mode-manager"
       >
-        {(!isDeviceSmallerThanMd || editorMode !== EditorMode.View) && (
+        {(isDeviceLargerThanMd || editorMode !== EditorMode.View) && (
           <PageEditorModeButton
             currentEditorMode={editorMode}
             editorMode={EditorMode.View}
@@ -92,7 +92,7 @@ export const PageEditorModeManager = (props: Props): JSX.Element => {
             <span className="material-symbols-outlined fs-4">play_arrow</span>{t('View')}
           </PageEditorModeButton>
         )}
-        {(!isDeviceSmallerThanMd || editorMode === EditorMode.View) && (
+        {(isDeviceLargerThanMd || editorMode === EditorMode.View) && (
           <PageEditorModeButton
             currentEditorMode={editorMode}
             editorMode={EditorMode.Editor}

+ 3 - 1
apps/app/src/components/PageControls/BookmarkButtons.module.scss

@@ -1,5 +1,7 @@
 @use '@growi/core/scss/bootstrap/init' as bs;
 
+@use '@growi/ui/scss/atoms/btn-muted';
+
 @use './button-styles';
 
 .btn-group-bookmark :global {
@@ -18,7 +20,7 @@
 // == Colors
 .btn-group-bookmark :global {
   .btn-bookmark {
-    @include button-styles.btn-color(bs.$orange);
+    @include btn-muted.colorize(bs.$orange);
   }
 }
 

+ 3 - 1
apps/app/src/components/PageControls/LikeButtons.module.scss

@@ -1,5 +1,7 @@
 @use '@growi/core/scss/bootstrap/init' as bs;
 
+@use '@growi/ui/scss/atoms/btn-muted';
+
 @use './button-styles';
 
 .btn-group-like :global {
@@ -18,6 +20,6 @@
 // == Colors
 .btn-group-like :global {
   .btn-like {
-    @include button-styles.btn-color(bs.$red);
+    @include btn-muted.colorize(bs.$red);
   }
 }

+ 3 - 1
apps/app/src/components/PageControls/PageControls.module.scss

@@ -1,5 +1,7 @@
 @use '@growi/core/scss/bootstrap/init' as bs;
 
+@use '@growi/ui/scss/atoms/btn-muted';
+
 @use './button-styles';
 
 // PageItemControl styles
@@ -13,6 +15,6 @@
 // PageItemControl colors
 .grw-page-controls :global {
   .btn-page-item-control {
-    @include button-styles.btn-color(bs.$gray-500);
+    @include btn-muted.colorize(bs.$gray-500);
   }
 }

+ 3 - 1
apps/app/src/components/PageControls/SeenUserInfo.module.scss

@@ -1,5 +1,7 @@
 @use '@growi/core/scss/bootstrap/init' as bs;
 
+@use '@growi/ui/scss/atoms/btn-muted';
+
 @use './button-styles';
 
 .grw-seen-user-info :global {
@@ -18,6 +20,6 @@
   $color: #549c79;
 
   .btn-seen-user {
-    @include button-styles.btn-color($color);
+    @include btn-muted.colorize($color);
   }
 }

+ 3 - 1
apps/app/src/components/PageControls/SubscribeButton.module.scss

@@ -1,5 +1,7 @@
 @use '@growi/core/scss/bootstrap/init' as bs;
 
+@use '@growi/ui/scss/atoms/btn-muted';
+
 @use './button-styles';
 
 .btn-subscribe :global {
@@ -12,5 +14,5 @@
 
 // == Colors
 .btn-subscribe {
-  @include button-styles.btn-color(bs.$success);
+  @include btn-muted.colorize(bs.$success);
 }

+ 0 - 17
apps/app/src/components/PageControls/_button-styles.scss

@@ -15,20 +15,3 @@
 %text-total-counts-basis {
   font-size: 13px;
 }
-
-@mixin btn-color($color) {
-  $color-rgb: #{bs.to-rgb($color)};
-
-  --bs-btn-color: var(--bs-tertiary-color);
-  --bs-btn-bg: transparent;
-
-  --bs-btn-hover-color: #{$color};
-  --bs-btn-hover-bg: rgba(#{$color-rgb}, 0.2);
-
-  --bs-btn-active-color: #{$color};
-  --bs-btn-active-bg: transparent;
-
-  &:hover {
-    --bs-btn-active-bg: rgba(#{$color-rgb}, 0.2);
-  }
-}

+ 7 - 18
apps/app/src/components/PageEditor/EditorNavbarBottom.tsx

@@ -9,7 +9,7 @@ import { useIsSlackConfigured } from '~/stores/context';
 import { useSWRxSlackChannels, useIsSlackEnabled } from '~/stores/editor';
 import { useCurrentPagePath } from '~/stores/page';
 import {
-  useDrawerOpened, useEditorMode, useIsDeviceSmallerThanMd,
+  useDrawerOpened, useEditorMode, useIsDeviceLargerThanLg, useIsDeviceLargerThanMd,
 } from '~/stores/ui';
 
 
@@ -31,8 +31,8 @@ const EditorNavbarBottom = (): JSX.Element => {
 
   const { data: editorMode } = useEditorMode();
   const { data: isSlackConfigured } = useIsSlackConfigured();
-  const { mutate: mutateDrawerOpened } = useDrawerOpened();
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
+  const { data: isDeviceLargerThanMd } = useIsDeviceLargerThanMd();
+  const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
   const { data: currentPagePath } = useCurrentPagePath();
   const { data: slackChannelsData } = useSWRxSlackChannels(currentPagePath);
 
@@ -58,16 +58,6 @@ const EditorNavbarBottom = (): JSX.Element => {
   }, []);
 
 
-  const renderDrawerButton = () => (
-    <button
-      type="button"
-      className="btn btn-outline-secondary border-0"
-      onClick={() => mutateDrawerOpened(true)}
-    >
-      <i className="icon-menu"></i>
-    </button>
-  );
-
   const renderExpandButton = () => (
     <div className="d-md-none ms-2">
       <button
@@ -80,13 +70,13 @@ const EditorNavbarBottom = (): JSX.Element => {
     </div>
   );
 
-  const isCollapsedOptionsSelectorEnabled = isDeviceSmallerThanMd;
+  const isCollapsedOptionsSelectorEnabled = !isDeviceLargerThanLg;
 
   return (
     <div className={`${isCollapsedOptionsSelectorEnabled ? 'fixed-bottom' : ''} `}>
       {/* Collapsed SlackNotification */}
       {isSlackConfigured && (
-        <Collapse isOpen={isSlackExpanded && isDeviceSmallerThanMd === true}>
+        <Collapse isOpen={isSlackExpanded && !isDeviceLargerThanLg}>
           <nav className={`navbar navbar-expand-lg border-top ${moduleClass}`}>
             {isSlackEnabled != null
             && (
@@ -105,13 +95,12 @@ const EditorNavbarBottom = (): JSX.Element => {
       }
       <div className={`flex-expand-horiz align-items-center border-top px-2 px-md-3 ${moduleClass}`}>
         <form>
-          { isDeviceSmallerThanMd && renderDrawerButton() }
-          { !isDeviceSmallerThanMd && <OptionsSelector /> }
+          { isDeviceLargerThanMd && <OptionsSelector /> }
         </form>
         <form className="flex-nowrap ms-auto">
           {/* Responsive Design for the SlackNotification */}
           {/* Button or the normal Slack banner */}
-          {isSlackConfigured && (isDeviceSmallerThanMd ? (
+          {isSlackConfigured && (!isDeviceLargerThanMd ? (
             <Button
               className="grw-btn-slack border me-2"
               onClick={() => (setSlackExpanded(!isSlackExpanded))}

+ 1 - 1
apps/app/src/components/PageList/PageList.module.scss

@@ -1 +1 @@
-@use '@growi/ui/src/styles/molecules/page_list';
+@use '@growi/ui/scss/molecules/page_list';

+ 7 - 8
apps/app/src/components/PageList/PageListItemL.tsx

@@ -9,8 +9,7 @@ import type {
 import { isIPageInfoForListing, isIPageInfoForEntity } from '@growi/core';
 import { DevidedPagePath } from '@growi/core/dist/models';
 import { pathUtils } from '@growi/core/dist/utils';
-import { UserPicture } from '@growi/ui/dist/components';
-import { PageListMeta } from '@growi/ui/dist/components/PagePath';
+import { UserPicture, PageListMeta } from '@growi/ui/dist/components';
 import { format } from 'date-fns';
 import { useTranslation } from 'next-i18next';
 import Link from 'next/link';
@@ -29,7 +28,7 @@ import { useSWRMUTxCurrentUserBookmarks } from '~/stores/bookmark';
 import {
   usePageRenameModal, usePageDuplicateModal, usePageDeleteModal, usePutBackPageModal,
 } from '~/stores/modal';
-import { useIsDeviceSmallerThanLg } from '~/stores/ui';
+import { useIsDeviceLargerThanLg } from '~/stores/ui';
 
 import { useSWRMUTxPageInfo, useSWRxPageInfo } from '../../stores/page';
 import { ForceHideMenuItems, PageItemControl } from '../Common/Dropdown/PageItemControl';
@@ -83,7 +82,7 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
     },
   }));
 
-  const { data: isDeviceSmallerThanLg } = useIsDeviceSmallerThanLg();
+  const { data: isDeviceLargerThanLg } = useIsDeviceLargerThanLg();
   const { open: openDuplicateModal } = usePageDuplicateModal();
   const { open: openRenameModal } = usePageRenameModal();
   const { open: openDeleteModal } = usePageDeleteModal();
@@ -117,14 +116,14 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
   // click event handler
   const clickHandler = useCallback(() => {
     // do nothing if mobile
-    if (isDeviceSmallerThanLg) {
+    if (!isDeviceLargerThanLg) {
       return;
     }
 
     if (onClickItem != null) {
       onClickItem(pageData._id);
     }
-  }, [isDeviceSmallerThanLg, onClickItem, pageData._id]);
+  }, [isDeviceLargerThanLg, onClickItem, pageData._id]);
 
   const bookmarkMenuItemClickHandler = async(_pageId: string, _newValue: boolean): Promise<void> => {
     const bookmarkOperation = _newValue ? bookmark : unbookmark;
@@ -174,9 +173,9 @@ const PageListItemLSubstance: ForwardRefRenderFunction<ISelectable, Props> = (pr
     openPutBackPageModal({ pageId, path }, { onPutBacked: putBackedHandler });
   }, [onPagePutBacked, openPutBackPageModal, pageData]);
 
-  const styleListGroupItem = (!isDeviceSmallerThanLg && onClickItem != null) ? 'list-group-item-action' : '';
+  const styleListGroupItem = (isDeviceLargerThanLg && onClickItem != null) ? 'list-group-item-action' : '';
   // background color of list item changes when class "active" exists under 'list-group-item'
-  const styleActive = !isDeviceSmallerThanLg && isSelected ? 'active' : '';
+  const styleActive = isDeviceLargerThanLg && isSelected ? 'active' : '';
 
   const shouldDangerouslySetInnerHTMLForPaths = elasticSearchResult != null && elasticSearchResult.highlightedPath != null;
 

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

@@ -1,8 +1,7 @@
 import React from 'react';
 
 import type { IPageHasId } from '@growi/core';
-import { UserPicture } from '@growi/ui/dist/components';
-import { PageListMeta, PagePathLabel } from '@growi/ui/dist/components/PagePath';
+import { UserPicture, PageListMeta, PagePathLabel } from '@growi/ui/dist/components';
 import Link from 'next/link';
 import Clamp from 'react-multiline-clamp';
 

+ 30 - 0
apps/app/src/components/PageSideContents/PageAccessoriesControl.module.scss

@@ -0,0 +1,30 @@
+@use '@growi/core/scss/bootstrap/init' as bs;
+
+.btn-page-accessories :global {
+  display: flex;
+  align-items: center;
+  padding: 6px 8px;
+
+  .grw-labels {
+    flex-grow: 1;
+    align-items: center;
+    justify-content: space-between;
+  }
+}
+
+// apply larger font when smaller than lg
+@include bs.media-breakpoint-down(lg) {
+  .btn-page-accessories :global {
+    .material-symbols-outlined {
+      font-size: 2em;
+    }
+  }
+}
+
+// expand when larger than lg
+@include bs.media-breakpoint-up(lg) {
+  .btn-page-accessories :global {
+    flex-grow: 1;
+    padding: 1px 5px 1px 10px;
+  }
+}

+ 42 - 0
apps/app/src/components/PageSideContents/PageAccessoriesControl.tsx

@@ -0,0 +1,42 @@
+import { type ReactNode, memo } from 'react';
+
+import CountBadge from '../Common/CountBadge';
+
+
+import styles from './PageAccessoriesControl.module.scss';
+
+const moduleClass = styles['btn-page-accessories'];
+
+
+type Props = {
+  className?: string,
+  icon: ReactNode,
+  label: ReactNode,
+  count?: number,
+  onClick?: () => void,
+}
+
+export const PageAccessoriesControl = memo((props: Props): JSX.Element => {
+  const {
+    icon, label, count,
+    className,
+    onClick,
+  } = props;
+
+  return (
+    <button
+      type="button"
+      className={`btn btn-sm btn-outline-secondary ${moduleClass} ${className} rounded-pill`}
+      onClick={onClick}
+    >
+      <span className="grw-icon d-flex">{icon}</span>
+      <span className="grw-labels ms-1 d-none d-lg-flex">
+        {label}
+        {/* Do not display CountBadge if '/trash/*': https://github.com/weseek/growi/pull/7600 */}
+        { count != null
+          ? <CountBadge count={count} offset={1} />
+          : <div className="px-2"></div>}
+      </span>
+    </button>
+  );
+});

+ 1 - 4
apps/app/src/components/PageSideContents/PageSideContents.module.scss

@@ -1,5 +1,2 @@
-@use '~/styles/molecules/page-accessories-control';
-
-.grw-page-accessories-control :global {
-  @extend %grw-page-accessories-control;
+.grw-page-accessories-controls :global {
 }

+ 27 - 41
apps/app/src/components/PageSideContents/PageSideContents.tsx

@@ -4,7 +4,7 @@ import { getIdForRef, type IPageHasId, type IPageInfoForOperation } from '@growi
 import { pagePathUtils } from '@growi/core/dist/utils';
 import { useTranslation } from 'next-i18next';
 import dynamic from 'next/dynamic';
-import { Link } from 'react-scroll';
+import { scroller } from 'react-scroll';
 
 import { useUpdateStateAfterSave } from '~/client/services/page-operation';
 import { apiPost } from '~/client/util/apiv1-client';
@@ -14,12 +14,12 @@ import { useDescendantsPageListModal } from '~/stores/modal';
 import { useSWRxPageInfo, useSWRxTagsInfo } from '~/stores/page';
 import { useIsAbleToShowTagLabel } from '~/stores/ui';
 
-import CountBadge from '../Common/CountBadge';
 import { ContentLinkButtons } from '../ContentLinkButtons';
-import PageListIcon from '../Icons/PageListIcon';
 import { PageTagsSkeleton } from '../PageTags';
 import TableOfContents from '../TableOfContents';
 
+import { PageAccessoriesControl } from './PageAccessoriesControl';
+
 import styles from './PageSideContents.module.scss';
 
 
@@ -104,48 +104,34 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
       {/* Tags */}
       <Tags pageId={page._id} revisionId={getIdForRef(page.revision)} />
 
-      {/* Page list */}
-      <div className={`grw-page-accessories-control ${styles['grw-page-accessories-control']} d-print-none`}>
+      <div className={`${styles['grw-page-accessories-controls']} d-flex flex-column gap-2 d-print-none`}>
+        {/* Page list */}
         {!isSharedUser && (
-          <button
-            type="button"
-            className="btn btn-outline-secondary grw-btn-page-accessories rounded-pill d-flex justify-content-between align-items-center"
-            onClick={() => openDescendantPageListModal(pagePath)}
-            data-testid="pageListButton"
-          >
-            <div className="grw-page-accessories-control-icon">
-              <PageListIcon />
-            </div>
-            {t('page_list')}
-
-            {/* Do not display CountBadge if '/trash/*': https://github.com/weseek/growi/pull/7600 */}
-            { !isTrash && pageInfo != null
-              ? <CountBadge count={(pageInfo as IPageInfoForOperation).descendantCount} offset={1} />
-              : <div className="px-2"></div>}
-          </button>
+          <div className="d-flex" data-testid="pageListButton">
+            <PageAccessoriesControl
+              icon={<span className="material-symbols-outlined">subject</span>}
+              label={t('page_list')}
+              // Do not display CountBadge if '/trash/*': https://github.com/weseek/growi/pull/7600
+              count={!isTrash && pageInfo != null ? (pageInfo as IPageInfoForOperation).descendantCount : undefined}
+              onClick={() => openDescendantPageListModal(pagePath)}
+            />
+          </div>
+        )}
+
+        {/* Comments */}
+        {!isTopPagePath && (
+          <div className="d-flex" data-testid="page-comment-button">
+            <PageAccessoriesControl
+              icon={<span className="material-symbols-outlined">chat</span>}
+              label="Comments"
+              count={pageInfo != null ? (pageInfo as IPageInfoForOperation).commentCount : undefined}
+              onClick={() => scroller.scrollTo('comments-container', { smooth: false, offset: -120 })}
+            />
+          </div>
         )}
       </div>
 
-      {/* Comments */}
-      {!isTopPagePath && (
-        <div className={`mt-2 grw-page-accessories-control ${styles['grw-page-accessories-control']} d-print-none`}>
-          <Link to="page-comments" offset={-120}>
-            <button
-              type="button"
-              className="btn btn-outline-secondary grw-btn-page-accessories rounded-pill d-flex justify-content-between align-items-center"
-              data-testid="page-comment-button"
-            >
-              <i className="icon-fw icon-bubbles grw-page-accessories-control-icon"></i>
-              <span>Comments</span>
-              { pageInfo != null
-                ? <CountBadge count={(pageInfo as IPageInfoForOperation).commentCount} />
-                : <div className="px-2"></div>}
-            </button>
-          </Link>
-        </div>
-      )}
-
-      <div className="d-none d-lg-block">
+      <div className="d-none d-xl-block">
         <TableOfContents />
         {isUsersHomepagePath && <ContentLinkButtons author={page?.creator} />}
       </div>

+ 1 - 1
apps/app/src/components/SearchPage/SearchPageBase.module.scss

@@ -1 +1 @@
-@use '@growi/ui/src/styles/molecules/page_list';
+@use '@growi/ui/scss/molecules/page_list';

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

@@ -3,8 +3,7 @@ import React, {
   KeyboardEvent, useCallback, useRef, useState, MouseEvent, useEffect,
 } from 'react';
 
-import { UserPicture } from '@growi/ui/dist/components';
-import { PageListMeta, PagePathLabel } from '@growi/ui/dist/components/PagePath';
+import { UserPicture, PageListMeta, PagePathLabel } from '@growi/ui/dist/components';
 import { AsyncTypeahead, Menu, MenuItem } from 'react-bootstrap-typeahead';
 
 import { IFocusable } from '~/client/interfaces/focusable';

+ 20 - 3
apps/app/src/components/Sidebar/AppTitle/AppTitle.module.scss

@@ -27,11 +27,28 @@
 
 // == Location
 .on-subnavigation {
-  $grw-contextual-sub-navigation-width: 500px;
+  top: 0;
 
-  left: var.$grw-sidebar-nav-width;
+  @include bs.media-breakpoint-up(md) {
+    left: var.$grw-sidebar-nav-width;
+  }
+}
+
+
+// == App title truncation
+.on-subnavigation {
   // set width for truncation
-  width: calc(100vw - $grw-contextual-sub-navigation-width);
+  $grw-page-controls-width: 226px;
+  $grw-page-editor-mode-manager-width: 90px;
+  $grw-contextual-subnavigation-padding-right: 8px;
+  $gap: 8px;
+  width: calc(100vw - #{$grw-page-controls-width + $grw-page-editor-mode-manager-width + $grw-contextual-subnavigation-padding-right + $gap * 2});
+
+  @include bs.media-breakpoint-up(md) {
+    $grw-page-editor-mode-manager-width: 140px;
+    $gap: 24px;
+    width: calc(100vw - #{var.$grw-sidebar-nav-width + $grw-page-controls-width + $grw-page-editor-mode-manager-width + $grw-contextual-subnavigation-padding-right + $gap * 2});
+  }
 }
 
 .on-sidebar-head {

+ 10 - 3
apps/app/src/components/Sidebar/Sidebar.tsx

@@ -15,6 +15,8 @@ import {
   useSidebarMode,
 } from '~/stores/ui';
 
+import { DrawerToggler } from '../Common/DrawerToggler';
+
 import { AppTitleOnSidebarHead, AppTitleOnSubnavigation } from './AppTitle/AppTitle';
 import { ResizableArea } from './ResizableArea/ResizableArea';
 import { SidebarHead } from './SidebarHead';
@@ -168,7 +170,7 @@ const DrawableContainer = memo((props: DrawableContainerProps): JSX.Element => {
 
 export const Sidebar = (): JSX.Element => {
 
-  const { data: sidebarMode, isCollapsedMode } = useSidebarMode();
+  const { data: sidebarMode, isDrawerMode, isDockMode } = useSidebarMode();
 
   // css styles
   const grwSidebarClass = styles['grw-sidebar'];
@@ -188,10 +190,15 @@ export const Sidebar = (): JSX.Element => {
 
   return (
     <>
-      { sidebarMode != null && isCollapsedMode() && <AppTitleOnSubnavigation /> }
+      { sidebarMode != null && isDrawerMode() && (
+        <DrawerToggler className="position-fixed d-none d-md-block">
+          <span className="material-symbols-outlined">reorder</span>
+        </DrawerToggler>
+      ) }
+      { sidebarMode != null && !isDockMode() && <AppTitleOnSubnavigation /> }
       <DrawableContainer className={`${grwSidebarClass} ${modeClass} border-end vh-100`} data-testid="grw-sidebar">
         <ResizableContainer>
-          { sidebarMode != null && !isCollapsedMode() && <AppTitleOnSidebarHead /> }
+          { sidebarMode != null && isDockMode() && <AppTitleOnSidebarHead /> }
           <SidebarHead />
           <CollapsibleContainer Nav={SidebarNav} className="border-top">
             <SidebarContents />

+ 8 - 5
apps/app/src/components/Sidebar/SidebarHead/ToggleCollapseButton.tsx

@@ -1,4 +1,4 @@
-import { memo, useCallback } from 'react';
+import { memo, useCallback, useMemo } from 'react';
 
 import {
   useCollapsedContentsOpened, usePreferCollapsedMode, useDrawerOpened, useSidebarMode,
@@ -10,7 +10,7 @@ import styles from './ToggleCollapseButton.module.scss';
 
 export const ToggleCollapseButton = memo((): JSX.Element => {
 
-  const { isDrawerMode, isCollapsedMode, isDockMode } = useSidebarMode();
+  const { isDrawerMode, isCollapsedMode } = useSidebarMode();
   const { data: isDrawerOpened, mutate: mutateDrawerOpened } = useDrawerOpened();
   const { mutate: mutatePreferCollapsedMode } = usePreferCollapsedMode();
   const { mutate: mutateCollapsedContentsOpened } = useCollapsedContentsOpened();
@@ -25,9 +25,12 @@ export const ToggleCollapseButton = memo((): JSX.Element => {
   }, [isCollapsedMode, mutateCollapsedContentsOpened, mutatePreferCollapsedMode]);
 
   const rotationClass = isCollapsedMode() ? 'rotate180' : '';
-  const icon = isDrawerMode() || isDockMode()
-    ? 'first_page'
-    : 'keyboard_double_arrow_left';
+  const icon = useMemo(() => {
+    if (isCollapsedMode()) {
+      return 'keyboard_double_arrow_left';
+    }
+    return 'first_page';
+  }, [isCollapsedMode]);
 
   return (
     <button

+ 1 - 1
apps/app/src/components/UsersHomepageFooter.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/ui/src/styles/molecules/page_list';
+@use '@growi/ui/scss/molecules/page_list';
 $grw-sidebar-content-header-height: 58px;
 $grw-sidebar-content-footer-height: 50px;
 

+ 44 - 16
apps/app/src/stores/ui.tsx

@@ -166,8 +166,8 @@ export const useEditorMode = (): SWRResponseWithUtils<EditorModeUtils, EditorMod
   });
 };
 
-export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean, Error> => {
-  const key: Key = isClient() ? 'isDeviceSmallerThanMd' : null;
+export const useIsDeviceLargerThanMd = (): SWRResponse<boolean, Error> => {
+  const key: Key = isClient() ? 'isDeviceLargerThanMd' : null;
 
   const { cache, mutate } = useSWRConfig();
 
@@ -176,13 +176,13 @@ export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean, Error> => {
       const mdOrAvobeHandler = function(this: MediaQueryList): void {
         // sm -> md: matches will be true
         // md -> sm: matches will be false
-        mutate(key, !this.matches);
+        mutate(key, this.matches);
       };
       const mql = addBreakpointListener(Breakpoint.MD, mdOrAvobeHandler);
 
       // initialize
       if (cache.get(key)?.data == null) {
-        cache.set(key, { ...cache.get(key), data: !mql.matches });
+        cache.set(key, { ...cache.get(key), data: mql.matches });
       }
 
       return () => {
@@ -191,11 +191,11 @@ export const useIsDeviceSmallerThanMd = (): SWRResponse<boolean, Error> => {
     }
   }, [cache, key, mutate]);
 
-  return useStaticSWR(key);
+  return useSWRStatic(key);
 };
 
-export const useIsDeviceSmallerThanLg = (): SWRResponse<boolean, Error> => {
-  const key: Key = isClient() ? 'isDeviceSmallerThanLg' : null;
+export const useIsDeviceLargerThanLg = (): SWRResponse<boolean, Error> => {
+  const key: Key = isClient() ? 'isDeviceLargerThanLg' : null;
 
   const { cache, mutate } = useSWRConfig();
 
@@ -204,13 +204,13 @@ export const useIsDeviceSmallerThanLg = (): SWRResponse<boolean, Error> => {
       const lgOrAvobeHandler = function(this: MediaQueryList): void {
         // md -> lg: matches will be true
         // lg -> md: matches will be false
-        mutate(key, !this.matches);
+        mutate(key, this.matches);
       };
       const mql = addBreakpointListener(Breakpoint.LG, lgOrAvobeHandler);
 
       // initialize
       if (cache.get(key)?.data == null) {
-        cache.set(key, { ...cache.get(key), data: !mql.matches });
+        cache.set(key, { ...cache.get(key), data: mql.matches });
       }
 
       return () => {
@@ -219,7 +219,35 @@ export const useIsDeviceSmallerThanLg = (): SWRResponse<boolean, Error> => {
     }
   }, [cache, key, mutate]);
 
-  return useStaticSWR(key);
+  return useSWRStatic(key);
+};
+
+export const useIsDeviceLargerThanXl = (): SWRResponse<boolean, Error> => {
+  const key: Key = isClient() ? 'isDeviceLargerThanXl' : null;
+
+  const { cache, mutate } = useSWRConfig();
+
+  useEffect(() => {
+    if (key != null) {
+      const xlOrAvobeHandler = function(this: MediaQueryList): void {
+        // lg -> xl: matches will be true
+        // xl -> lg: matches will be false
+        mutate(key, this.matches);
+      };
+      const mql = addBreakpointListener(Breakpoint.XL, xlOrAvobeHandler);
+
+      // initialize
+      if (cache.get(key)?.data == null) {
+        cache.set(key, { ...cache.get(key), data: mql.matches });
+      }
+
+      return () => {
+        cleanupBreakpointListener(mql, xlOrAvobeHandler);
+      };
+    }
+  }, [cache, key, mutate]);
+
+  return useSWRStatic(key);
 };
 
 
@@ -250,28 +278,28 @@ type DetectSidebarModeUtils = {
 }
 
 export const useSidebarMode = (): SWRResponseWithUtils<DetectSidebarModeUtils, SidebarMode> => {
-  const { data: isDeviceSmallerThanMd } = useIsDeviceSmallerThanMd();
+  const { data: isDeviceLargerThanXl } = useIsDeviceLargerThanXl();
   const { data: editorMode } = useEditorMode();
   const { data: isCollapsedModeUnderDockMode } = usePreferCollapsedMode();
 
-  const condition = isDeviceSmallerThanMd != null && editorMode != null && isCollapsedModeUnderDockMode != null;
+  const condition = isDeviceLargerThanXl != null && editorMode != null && isCollapsedModeUnderDockMode != null;
 
   const isEditorMode = editorMode === EditorMode.Editor;
 
   const fetcher = useCallback((
-      [, isDeviceSmallerThanMd, isEditorMode, isCollapsedModeUnderDockMode]: [Key, boolean|undefined, boolean|undefined, boolean|undefined],
+      [, isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode]: [Key, boolean|undefined, boolean|undefined, boolean|undefined],
   ) => {
-    if (isDeviceSmallerThanMd) {
+    if (!isDeviceLargerThanXl) {
       return SidebarMode.DRAWER;
     }
     return isEditorMode || isCollapsedModeUnderDockMode ? SidebarMode.COLLAPSED : SidebarMode.DOCK;
   }, []);
 
   const swrResponse = useSWRImmutable(
-    condition ? ['sidebarMode', isDeviceSmallerThanMd, isEditorMode, isCollapsedModeUnderDockMode] : null,
+    condition ? ['sidebarMode', isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode] : null,
     // calcDrawerMode,
     fetcher,
-    { fallbackData: fetcher(['sidebarMode', isDeviceSmallerThanMd, isEditorMode, isCollapsedModeUnderDockMode]) },
+    { fallbackData: fetcher(['sidebarMode', isDeviceLargerThanXl, isEditorMode, isCollapsedModeUnderDockMode]) },
   );
 
   const _isDrawerMode = useCallback(() => swrResponse.data === SidebarMode.DRAWER, [swrResponse.data]);

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

@@ -63,22 +63,6 @@
   }
 }
 
-.grw-side-contents-container {
-  margin-bottom: 1rem;
-
-  @include bs.media-breakpoint-up(lg) {
-    width: 250px;
-    min-width: 250px;
-    margin-left: 30px;
-  }
-}
-
-.grw-side-contents-sticky-container {
-  position: sticky;
-  // growisubnavigation + grw-navbar-boder + some spacing
-  top: calc(100px + 4px + 20px);
-}
-
 // printable style
 @media print {
   body {

+ 1 - 1
apps/app/src/styles/_variables.scss

@@ -8,7 +8,7 @@ $grw-marker-green: #6f6;
 //== Layout
 $grw-sidebar-nav-width: 48px;
 
-$grw-navbar-bottom-height: 48px;
+$grw-navbar-bottom-height: 62px;
 $grw-editor-navbar-bottom-height: 48px;
 
 $grw-scroll-margin-top-in-view: 130px;

+ 0 - 16
apps/app/src/styles/molecules/_page-accessories-control.scss

@@ -1,16 +0,0 @@
-%grw-page-accessories-control {
-  .grw-btn-page-accessories {
-    padding-right: 1rem;
-    padding-left: 1rem;
-
-    svg {
-      width: 16px;
-      height: 16px;
-    }
-  }
-  .grw-page-accessories-control-icon {
-    display: flex;
-    justify-content: center;
-    width: 20px;
-  }
-}

+ 1 - 1
packages/remark-lsx/src/client/components/LsxPageList/LsxListView.module.scss

@@ -1,4 +1,4 @@
-@use '@growi/ui/src/styles/molecules/page_list';
+@use '@growi/ui/scss/molecules/page_list';
 
 .page-list :global {
   .page-list-ul > li > a:not(:hover) {

+ 1 - 1
packages/remark-lsx/src/client/components/LsxPageList/LsxPage.tsx

@@ -1,7 +1,7 @@
 import React, { useMemo } from 'react';
 
 import { pathUtils } from '@growi/core/dist/utils';
-import { PageListMeta, PagePathLabel } from '@growi/ui/dist/components/PagePath';
+import { PageListMeta, PagePathLabel } from '@growi/ui/dist/components';
 import Link from 'next/link';
 
 import type { PageNode } from '../../../interfaces/page-node';

+ 14 - 1
packages/ui/package.json

@@ -8,8 +8,21 @@
   ],
   "type": "module",
   "files": [
-    "dist"
+    "dist",
+    "scss"
   ],
+  "exports": {
+    "./dist/components": {
+      "import": "./dist/components/index.js"
+    },
+    "./dist/interfaces": {
+      "import": "./dist/interfaces/index.js"
+    },
+    "./dist/utils": {
+      "import": "./dist/utils/index.js"
+    },
+    "./scss/*": "./scss/*.scss"
+  },
   "scripts": {
     "build": "vite build",
     "clean": "shx rm -rf dist",

+ 18 - 0
packages/ui/scss/atoms/_btn-muted.scss

@@ -0,0 +1,18 @@
+@use '@growi/core/scss/bootstrap/init' as bs;
+
+@mixin colorize($color-active, $color: var(--bs-tertiary-color)) {
+  $color-active-rgb: #{bs.to-rgb($color-active)};
+
+  --bs-btn-color: #{$color};
+  --bs-btn-bg: transparent;
+
+  --bs-btn-hover-color: #{$color-active};
+  --bs-btn-hover-bg: rgba(#{$color-active-rgb}, 0.2);
+
+  --bs-btn-active-color: #{$color-active};
+  --bs-btn-active-bg: transparent;
+
+  &:hover {
+    --bs-btn-active-bg: rgba(#{$color-active-rgb}, 0.2);
+  }
+}

+ 0 - 0
packages/ui/src/styles/molecules/_page_list.scss → packages/ui/scss/molecules/_page_list.scss


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

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