Yuki Takei 2 лет назад
Родитель
Сommit
f182d8ca39

+ 1 - 31
apps/app/src/components/Sidebar/Sidebar.tsx

@@ -28,36 +28,6 @@ const sidebarMinWidth = 240;
 const sidebarMinimizeWidth = 20;
 const sidebarFixedWidthInDrawerMode = 320;
 
-const GlobalNavigation = memo(() => {
-  const { data: isDrawerMode } = useDrawerMode();
-  const { data: currentContents } = useCurrentSidebarContents();
-  const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
-
-  const { scheduleToPut } = useUserUISettings();
-
-  const itemSelectedHandler = useCallback((selectedContents) => {
-    if (isDrawerMode) {
-      return;
-    }
-
-    let newValue = false;
-
-    // already selected
-    if (currentContents === selectedContents) {
-      // toggle collapsed
-      newValue = !isCollapsed;
-    }
-
-    mutateSidebarCollapsed(newValue, false);
-    scheduleToPut({ isSidebarCollapsed: newValue });
-
-  }, [currentContents, isCollapsed, isDrawerMode, mutateSidebarCollapsed, scheduleToPut]);
-
-  return <SidebarNav onItemSelected={itemSelectedHandler} />;
-
-});
-GlobalNavigation.displayName = 'GlobalNavigation';
-
 
 export const Sidebar = memo((): JSX.Element => {
 
@@ -270,7 +240,7 @@ export const Sidebar = memo((): JSX.Element => {
           >
             <div className="grw-navigation-wrap">
               <div className="grw-global-navigation">
-                <GlobalNavigation></GlobalNavigation>
+                <SidebarNav />
               </div>
               <div
                 ref={resizableContainer}

+ 67 - 0
apps/app/src/components/Sidebar/SidebarNav/PrimaryItems.module.scss

@@ -0,0 +1,67 @@
+@use '@growi/core/scss/bootstrap/init' as bs;
+
+@use '~/styles/variables' as var;
+
+@use './button-styles';
+
+.grw-primary-items :global {
+  .btn {
+    @extend %btn-primary-basis;
+
+    i {
+      opacity: 0.7;
+
+      &:hover,
+      &:focus {
+        opacity: 0.8;
+      }
+    }
+  }
+}
+
+// Add indicator
+.grw-primary-items :global {
+  $btn-active-indicator-height: 34px;
+
+  .btn {
+    &.active {
+      position: relative;
+
+      // indicator
+      &:after {
+        position: absolute;
+        top: 0;
+        left: 0;
+        display: block;
+        width: 3px;
+        height: $btn-active-indicator-height;
+        content: '';
+        background-color: var(--bs-primary);
+        transform: translateY(#{(var.$grw-sidebar-nav-height - $btn-active-indicator-height) / 2});
+      }
+    }
+  }
+}
+
+// == Colors
+.grw-primary-items :global {
+  .btn.btn-primary {
+    @extend %btn-primary-color-vars;
+  }
+}
+@include bs.color-mode(light) {
+  .grw-primary-items :global {
+    .btn-primary {
+      --bs-btn-color: var(--grw-sidebar-nav-btn-color, var(--grw-primary-600));
+      --bs-btn-hover-bg: var(--grw-sidebar-nav-btn-hover-bg, var(--grw-highlight-300));
+    }
+  }
+}
+@include bs.color-mode(dark) {
+  .grw-primary-items :global {
+    .btn-primary {
+      --bs-btn-color: var(--grw-sidebar-nav-btn-color, var(--grw-primary-300));
+      --bs-btn-hover-bg: var(--grw-sidebar-nav-btn-hover-bg, var(--grw-highlight-700));
+    }
+  }
+}

+ 93 - 0
apps/app/src/components/Sidebar/SidebarNav/PrimaryItems.tsx

@@ -0,0 +1,93 @@
+import { FC, memo, useCallback } from 'react';
+
+import dynamic from 'next/dynamic';
+
+import { useUserUISettings } from '~/client/services/user-ui-settings';
+import { SidebarContentsType } from '~/interfaces/ui';
+import { useCurrentSidebarContents, useDrawerMode, useSidebarCollapsed } from '~/stores/ui';
+
+import styles from './PrimaryItems.module.scss';
+
+
+const InAppNotificationDropdown = dynamic(() => import('../../InAppNotification/InAppNotificationDropdown')
+  .then(mod => mod.InAppNotificationDropdown), { ssr: false });
+
+
+type PrimaryItemProps = {
+  contents: SidebarContentsType,
+  label: string,
+  iconName: string,
+  onItemSelected: (contents: SidebarContentsType) => void,
+}
+
+const PrimaryItem: FC<PrimaryItemProps> = (props: PrimaryItemProps) => {
+  const {
+    contents, label, iconName, onItemSelected,
+  } = props;
+
+  const { data: currentContents, mutate } = useCurrentSidebarContents();
+  const { scheduleToPut } = useUserUISettings();
+
+  const isSelected = contents === currentContents;
+
+  const itemSelectedHandler = useCallback(() => {
+    if (onItemSelected != null) {
+      onItemSelected(contents);
+    }
+
+    mutate(contents, false);
+
+    scheduleToPut({ currentSidebarContents: contents });
+  }, [contents, mutate, onItemSelected, scheduleToPut]);
+
+  const labelForTestId = label.toLowerCase().replace(' ', '-');
+
+  return (
+    <button
+      type="button"
+      data-testid={`grw-sidebar-nav-primary-${labelForTestId}`}
+      className={`d-block btn btn-primary ${isSelected ? 'active' : ''}`}
+      onClick={itemSelectedHandler}
+    >
+      <i className="material-icons">{iconName}</i>
+    </button>
+  );
+};
+
+export const PrimaryItems: FC = memo(() => {
+
+  const { scheduleToPut } = useUserUISettings();
+
+  const { data: isDrawerMode } = useDrawerMode();
+  const { data: currentContents } = useCurrentSidebarContents();
+  const { data: isCollapsed, mutate: mutateSidebarCollapsed } = useSidebarCollapsed();
+
+  const itemSelectedHandler = useCallback((selectedContents) => {
+    if (isDrawerMode) {
+      return;
+    }
+
+    let newValue = false;
+
+    // already selected
+    if (currentContents === selectedContents) {
+      // toggle collapsed
+      newValue = !isCollapsed;
+    }
+
+    mutateSidebarCollapsed(newValue, false);
+    scheduleToPut({ isSidebarCollapsed: newValue });
+
+  }, [currentContents, isCollapsed, isDrawerMode, mutateSidebarCollapsed, scheduleToPut]);
+
+  return (
+    <div className={styles['grw-primary-items']}>
+      <PrimaryItem contents={SidebarContentsType.TREE} label="Page Tree" iconName="format_list_bulleted" onItemSelected={itemSelectedHandler} />
+      <PrimaryItem contents={SidebarContentsType.CUSTOM} label="Custom Sidebar" iconName="code" onItemSelected={itemSelectedHandler} />
+      <PrimaryItem contents={SidebarContentsType.RECENT} label="Recent Changes" iconName="update" onItemSelected={itemSelectedHandler} />
+      <PrimaryItem contents={SidebarContentsType.BOOKMARKS} label="Bookmarks" iconName="bookmark" onItemSelected={itemSelectedHandler} />
+      <PrimaryItem contents={SidebarContentsType.TAG} label="Tags" iconName="local_offer" onItemSelected={itemSelectedHandler} />
+      <InAppNotificationDropdown />
+    </div>
+  );
+});

+ 41 - 0
apps/app/src/components/Sidebar/SidebarNav/SecondaryItems.module.scss

@@ -0,0 +1,41 @@
+@use '@growi/core/scss/bootstrap/init' as bs;
+
+@use './button-styles';
+
+.grw-secondary-items :global {
+  .btn {
+    @extend %btn-primary-basis;
+
+    i {
+      opacity: 0.6;
+
+      &:hover,
+      &:focus {
+        opacity: 0.8;
+      }
+    }
+  }
+}
+
+// == Colors
+.grw-secondary-items :global {
+  .btn.btn-primary {
+    @extend %btn-primary-color-vars;
+  }
+}
+@include bs.color-mode(light) {
+  .grw-secondary-items :global {
+    .btn-primary {
+      --bs-btn-color: var(--grw-sidebar-nav-btn-color, var(--grw-primary-600));
+      --bs-btn-hover-bg: var(--grw-sidebar-nav-btn-hover-bg, var(--grw-highlight-700));
+    }
+  }
+}
+@include bs.color-mode(dark) {
+  .grw-secondary-items :global {
+    .btn-primary {
+      --bs-btn-color: var(--grw-sidebar-nav-btn-color, var(--grw-primary-500));
+      --bs-btn-hover-bg: var(--grw-sidebar-nav-btn-hover-bg, var(--grw-highlight-700));
+    }
+  }
+}

+ 49 - 0
apps/app/src/components/Sidebar/SidebarNav/SecondaryItems.tsx

@@ -0,0 +1,49 @@
+import { FC, memo } from 'react';
+
+import dynamic from 'next/dynamic';
+import Link from 'next/link';
+
+import { useGrowiCloudUri, useIsAdmin } from '~/stores/context';
+
+import styles from './SecondaryItems.module.scss';
+
+
+const PersonalDropdown = dynamic(() => import('../PersonalDropdown').then(mod => mod.PersonalDropdown), { ssr: false });
+
+
+type SecondaryItemProps = {
+  label: string,
+  href: string,
+  iconName: string,
+  isBlank?: boolean,
+}
+
+const SecondaryItem: FC<SecondaryItemProps> = (props: SecondaryItemProps) => {
+  const { iconName, href, isBlank } = props;
+
+  return (
+    <Link
+      href={href}
+      className="d-block btn btn-primary"
+      target={`${isBlank ? '_blank' : ''}`}
+      prefetch={false}
+    >
+      <i className="material-icons">{iconName}</i>
+    </Link>
+  );
+};
+
+export const SecondaryItems: FC = memo(() => {
+
+  const { data: isAdmin } = useIsAdmin();
+  const { data: growiCloudUri } = useGrowiCloudUri();
+
+  return (
+    <div className={styles['grw-secondary-items']}>
+      <PersonalDropdown />
+      <SecondaryItem label="Help" iconName="help" href={growiCloudUri != null ? 'https://growi.cloud/help/' : 'https://docs.growi.org'} isBlank />
+      {isAdmin && <SecondaryItem label="Admin" iconName="settings" href="/admin" />}
+      <SecondaryItem label="Trash" href="/trash" iconName="delete" />
+    </div>
+  );
+});

+ 0 - 93
apps/app/src/components/Sidebar/SidebarNav/SidebarNav.module.scss

@@ -19,116 +19,23 @@
     }
   }
 
-  .grw-apperance-mode-dropdown,
-  .grw-personal-dropdown {
-    .dropdown-menu {
-      min-width: 15rem;
-
-      .grw-icon-container svg {
-        width: 18px;
-        height: 18px;
-      }
-    }
-  }
-
-  .btn {
-    width: var.$grw-sidebar-nav-width;
-    height: var.$grw-sidebar-nav-height;
-    padding-top: .75rem;
-    padding-bottom: .75rem;
-    line-height: 1em;
-    border: 0;
-    border-radius: 0;
-    box-shadow: none !important;
-
-    // icon opacity
-    &:not(.active) {
-      i {
-        opacity: 0.7;
-      }
-      &:hover,
-      &:focus {
-        i {
-          opacity: 0.8;
-        }
-      }
-    }
-  }
-
-  .grw-sidebar-nav-primary-container {
-    $btn-active-indicator-height: 34px;
-
-    .btn {
-      &.active {
-        position: relative;
-
-        // indicator
-        &:after {
-          position: absolute;
-          top: 0;
-          left: 0;
-          display: block;
-          width: 3px;
-          height: $btn-active-indicator-height;
-          content: '';
-          background-color: var(--bs-primary);
-          transform: translateY(#{(var.$grw-sidebar-nav-height - $btn-active-indicator-height) / 2});
-        }
-      }
-    }
-  }
-
   .grw-sidebar-nav-secondary-container {
     position: fixed;
     bottom: 1.5rem;
-
-    .btn {
-      i {
-        opacity: 0.4;
-      }
-    }
   }
 }
 
 
 // == Colors
 .grw-sidebar-nav :global {
-  .btn.btn-primary {
-    --bs-btn-bg: transparent;
-    --bs-btn-active-bg: transparent;
-    --bs-btn-hover-color: var(
-      --grw-sidebar-nav-btn-hover-color,
-      var(
-        --grw-sidebar-nav-btn-color,
-        var(--bs-btn-color)
-      ),
-    );
-    --bs-btn-active-color: var(
-      --grw-sidebar-nav-btn-active-color,
-      var(
-        --grw-sidebar-nav-btn-color,
-        var(--bs-btn-color)
-      ),
-    );
-  }
 }
 @include bs.color-mode(light) {
   .grw-sidebar-nav :global {
     background-color: var(--grw-sidebar-nav-bg, var(--grw-highlight-100));
-
-    .btn-primary {
-      --bs-btn-color: var(--grw-sidebar-nav-btn-color, var(--grw-primary-500));
-      --bs-btn-hover-bg: var(--grw-sidebar-nav-btn-hover-bg, var(--grw-highlight-300));
-    }
   }
 }
 @include bs.color-mode(dark) {
   .grw-sidebar-nav :global {
     background-color: var(--grw-sidebar-nav-bg, var(--grw-highlight-800));
-
-    .btn-primary {
-      --bs-btn-color: var(--grw-sidebar-nav-btn-color, var(--grw-primary-400));
-      --bs-btn-hover-bg: var(--grw-sidebar-nav-btn-hover-bg, var(--grw-highlight-700));
-    }
   }
 }

+ 11 - 100
apps/app/src/components/Sidebar/SidebarNav/SidebarNav.tsx

@@ -1,105 +1,24 @@
 import React, {
-  FC, memo, useCallback,
+  FC, memo,
 } from 'react';
 
-import dynamic from 'next/dynamic';
 import Link from 'next/link';
 
-import { useUserUISettings } from '~/client/services/user-ui-settings';
-import { SidebarContentsType } from '~/interfaces/ui';
-import {
-  useIsAdmin, useGrowiCloudUri, useIsDefaultLogo,
-} from '~/stores/context';
-import { useCurrentSidebarContents } from '~/stores/ui';
+import { useIsDefaultLogo } from '~/stores/context';
 
-import DrawerToggler from '../Navbar/DrawerToggler';
+import DrawerToggler from '../../Navbar/DrawerToggler';
+import { SidebarBrandLogo } from '../SidebarBrandLogo';
 
-import { SidebarBrandLogo } from './SidebarBrandLogo';
+import { PrimaryItems } from './PrimaryItems';
+import { SecondaryItems } from './SecondaryItems';
 
 import styles from './SidebarNav.module.scss';
 
 
-const PersonalDropdown = dynamic(() => import('./PersonalDropdown').then(mod => mod.PersonalDropdown), { ssr: false });
-const InAppNotificationDropdown = dynamic(() => import('../InAppNotification/InAppNotificationDropdown')
-  .then(mod => mod.InAppNotificationDropdown), { ssr: false });
+export const SidebarNav: FC = memo(() => {
 
-
-type PrimaryItemProps = {
-  contents: SidebarContentsType,
-  label: string,
-  iconName: string,
-  onItemSelected: (contents: SidebarContentsType) => void,
-}
-
-const PrimaryItem: FC<PrimaryItemProps> = (props: PrimaryItemProps) => {
-  const {
-    contents, label, iconName, onItemSelected,
-  } = props;
-
-  const { data: currentContents, mutate } = useCurrentSidebarContents();
-  const { scheduleToPut } = useUserUISettings();
-
-  const isSelected = contents === currentContents;
-
-  const itemSelectedHandler = useCallback(() => {
-    if (onItemSelected != null) {
-      onItemSelected(contents);
-    }
-
-    mutate(contents, false);
-
-    scheduleToPut({ currentSidebarContents: contents });
-  }, [contents, mutate, onItemSelected, scheduleToPut]);
-
-  const labelForTestId = label.toLowerCase().replace(' ', '-');
-
-  return (
-    <button
-      type="button"
-      data-testid={`grw-sidebar-nav-primary-${labelForTestId}`}
-      className={`d-block btn btn-primary ${isSelected ? 'active' : ''}`}
-      onClick={itemSelectedHandler}
-    >
-      <i className="material-icons">{iconName}</i>
-    </button>
-  );
-};
-
-type SecondaryItemProps = {
-  label: string,
-  href: string,
-  iconName: string,
-  isBlank?: boolean,
-}
-
-const SecondaryItem: FC<SecondaryItemProps> = memo((props: SecondaryItemProps) => {
-  const { iconName, href, isBlank } = props;
-
-  return (
-    <Link
-      href={href}
-      className="d-block btn btn-primary"
-      target={`${isBlank ? '_blank' : ''}`}
-      prefetch={false}
-    >
-      <i className="material-icons">{iconName}</i>
-    </Link>
-  );
-});
-SecondaryItem.displayName = 'SecondaryItem';
-
-
-type Props = {
-  onItemSelected: (contents: SidebarContentsType) => void,
-}
-
-export const SidebarNav: FC<Props> = (props: Props) => {
-  const { data: isAdmin } = useIsAdmin();
-  const { data: growiCloudUri } = useGrowiCloudUri();
   const { data: isDefaultLogo } = useIsDefaultLogo();
 
-  const { onItemSelected } = props;
-
   return (
     <div className={`grw-sidebar-nav ${styles['grw-sidebar-nav']}`}>
       {/* Brand Logo  */}
@@ -107,24 +26,16 @@ export const SidebarNav: FC<Props> = (props: Props) => {
         <Link href="/" className="grw-logo d-block">
           <SidebarBrandLogo isDefaultLogo={isDefaultLogo} />
         </Link>
-        <DrawerToggler />
       </div>
+      <DrawerToggler />
 
       <div className="grw-sidebar-nav-primary-container" data-vrt-blackout-sidebar-nav>
-        <PrimaryItem contents={SidebarContentsType.TREE} label="Page Tree" iconName="format_list_bulleted" onItemSelected={onItemSelected} />
-        <PrimaryItem contents={SidebarContentsType.CUSTOM} label="Custom Sidebar" iconName="code" onItemSelected={onItemSelected} />
-        <PrimaryItem contents={SidebarContentsType.RECENT} label="Recent Changes" iconName="update" onItemSelected={onItemSelected} />
-        <PrimaryItem contents={SidebarContentsType.BOOKMARKS} label="Bookmarks" iconName="bookmark" onItemSelected={onItemSelected} />
-        <PrimaryItem contents={SidebarContentsType.TAG} label="Tags" iconName="local_offer" onItemSelected={onItemSelected} />
-        <InAppNotificationDropdown />
+        <PrimaryItems />
       </div>
       <div className="grw-sidebar-nav-secondary-container">
-        <PersonalDropdown />
-        <SecondaryItem label="Help" iconName="help" href={growiCloudUri != null ? 'https://growi.cloud/help/' : 'https://docs.growi.org'} isBlank />
-        {isAdmin && <SecondaryItem label="Admin" iconName="settings" href="/admin" />}
-        <SecondaryItem label="Trash" href="/trash" iconName="delete" />
+        <SecondaryItems />
       </div>
     </div>
   );
 
-};
+});

+ 31 - 0
apps/app/src/components/Sidebar/SidebarNav/_button-styles.scss

@@ -0,0 +1,31 @@
+@use '~/styles/variables' as var;
+
+%btn-primary-basis {
+  width: var.$grw-sidebar-nav-width;
+  height: var.$grw-sidebar-nav-height;
+  padding-top: .75rem;
+  padding-bottom: .75rem;
+  line-height: 1em;
+  border: 0;
+  border-radius: 0;
+  box-shadow: none !important;
+}
+
+%btn-primary-color-vars {
+  --bs-btn-bg: transparent;
+  --bs-btn-active-bg: transparent;
+  --bs-btn-hover-color: var(
+    --grw-sidebar-nav-btn-hover-color,
+    var(
+      --grw-sidebar-nav-btn-color,
+      var(--bs-btn-color)
+    ),
+  );
+  --bs-btn-active-color: var(
+    --grw-sidebar-nav-btn-active-color,
+    var(
+      --grw-sidebar-nav-btn-color,
+      var(--bs-btn-color)
+    ),
+  );
+}

+ 1 - 0
apps/app/src/components/Sidebar/SidebarNav/index.ts

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