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

Merge pull request #6292 from weseek/feat/gw7832-show-bookmarks-item-on-sidebar

feat: gw7832 show bookmarks item on sidebar
cao 3 лет назад
Родитель
Сommit
a42b871cfa

+ 108 - 7
packages/app/src/components/Sidebar/Bookmarks.tsx

@@ -1,16 +1,117 @@
-import React, { FC } from 'react';
 
+import React, { useCallback, useEffect, useState } from 'react';
+
+import { DevidedPagePath } from '@growi/core';
 import { useTranslation } from 'react-i18next';
+import { UncontrolledTooltip } from 'reactstrap';
+
+import { toastError } from '~/client/util/apiNotification';
+import { apiv3Get } from '~/client/util/apiv3-client';
+import { IPageHasId } from '~/interfaces/page';
+import { useCurrentUser, useIsGuestUser } from '~/stores/context';
+import loggerFactory from '~/utils/logger';
+
+const logger = loggerFactory('growi:BookmarkList');
+
+// TODO: Remove pagination and apply  scrolling (not infinity)
+const ACTIVE_PAGE = 1;
+
+type Props = {
+  pages: IPageHasId[]
+}
 
-const Bookmarks: FC = () => {
-  const { t } = useTranslation('');
+const BookmarksItem = (props: Props) => {
+  const { pages } = props;
+
+  const generateBookmarkedPageList = pages.map((page) => {
+    const dPagePath = new DevidedPagePath(page.path, false, true);
+    const { latter: pageTitle, former: formerPagePath } = dPagePath;
+    return (
+      <div key={page._id}>
+        <li className="list-group-item list-group-item-action border-0 py-0 pr-3 d-flex align-items-center" id={`bookmark-item-${page._id}`}>
+          <a href={`/${page._id}`} className="grw-bookmarks-title-anchor flex-grow-1">
+            <p className={`text-truncate m-auto ${page.isEmpty && 'grw-sidebar-text-muted'}`}>{pageTitle}</p>
+          </a>
+        </li>
+        <UncontrolledTooltip
+          modifiers={{ preventOverflow: { boundariesElement: 'window' } }}
+          autohide={false}
+          placement="right"
+          target={`bookmark-item-${page._id}`}
+        >
+          { formerPagePath || '/' }
+        </UncontrolledTooltip>
+      </div>
+    );
+  });
 
-  // TODO Add bookmarks item
 
   return (
-    <div className="grw-sidebar-content-header p-3">
-      <h3 className="mb-0">{t('Bookmarks')}</h3>
-    </div>
+    <>
+      <ul className="grw-bookmarks-list list-group p-3">
+        <div className="grw-bookmarks-item-container">
+          {generateBookmarkedPageList}
+        </div>
+      </ul>
+    </>
+  );
+};
+
+
+const Bookmarks = () : JSX.Element => {
+  const { t } = useTranslation();
+  const { data: currentUser } = useCurrentUser();
+  const { data: isGuestUser } = useIsGuestUser();
+  const [pages, setPages] = useState<IPageHasId[]>([]);
+
+  const getMyBookmarkList = useCallback(async() => {
+    // TODO: Remove pagination and apply  scrolling (not infinity)
+    const page = ACTIVE_PAGE;
+
+    try {
+      const res = await apiv3Get(`/bookmarks/${currentUser?._id}`, { page });
+      const { paginationResult } = res.data;
+      setPages(paginationResult.docs.map((page) => {
+        return {
+          ...page.page,
+        };
+      }));
+    }
+    catch (error) {
+      logger.error('failed to fetch data', error);
+      toastError(error, 'Error occurred in bookmark page list');
+    }
+  }, [currentUser]);
+
+  useEffect(() => {
+    getMyBookmarkList();
+  }, [getMyBookmarkList]);
+
+  const renderBookmarksItem = () => {
+    if (pages.length === 0) {
+      return (
+        <h3 className="pl-3">
+          { t('No bookmarks yet') }
+        </h3>
+      );
+    }
+    return <BookmarksItem pages={pages} />;
+  };
+
+  return (
+    <>
+      <div className="grw-sidebar-content-header p-3">
+        <h3 className="mb-0">{t('Bookmarks')}</h3>
+      </div>
+      { isGuestUser
+        ? (
+          <h3 className="pl-3">
+            { t('Not available for guest') }
+          </h3>
+        ) : renderBookmarksItem()
+      }
+
+    </>
   );
 
 };

+ 3 - 3
packages/app/src/stores/context.tsx

@@ -7,7 +7,7 @@ import { SupportedActionType } from '~/interfaces/activity';
 import { GrowiRendererConfig } from '~/interfaces/services/renderer';
 
 import { TargetAndAncestors } from '../interfaces/page-listing-results';
-import { IUser } from '../interfaces/user';
+import { IUser, IUserHasId } from '../interfaces/user';
 
 import { useStaticSWR } from './use-static-swr';
 
@@ -23,8 +23,8 @@ export const useSiteUrl = (initialData?: string): SWRResponse<string, Error> =>
   return useStaticSWR<string, Error>('siteUrl', initialData);
 };
 
-export const useCurrentUser = (initialData?: Nullable<IUser>): SWRResponse<Nullable<IUser>, Error> => {
-  return useStaticSWR<Nullable<IUser>, Error>('currentUser', initialData);
+export const useCurrentUser = (initialData?: Nullable<IUserHasId>): SWRResponse<Nullable<IUserHasId>, Error> => {
+  return useStaticSWR<Nullable<IUserHasId>, Error>('currentUser', initialData);
 };
 
 export const useRevisionId = (initialData?: Nullable<any>): SWRResponse<Nullable<any>, Error> => {

+ 38 - 0
packages/app/src/styles/_bookmarks.scss

@@ -0,0 +1,38 @@
+$grw-sidebar-content-header-height: 58px;
+$grw-sidebar-content-footer-height: 50px;
+
+.grw-bookmarks-list {
+  min-height: calc(100vh - ($grw-navbar-height + $grw-navbar-border-width + $grw-sidebar-content-header-height + $grw-sidebar-content-footer-height));
+
+  .btn-page-item-control {
+    .icon-plus::before {
+      font-size: 18px;
+    }
+  }
+
+  .list-group-item {
+    .grw-visible-on-hover {
+      display: none;
+    }
+
+    &:hover {
+      .grw-visible-on-hover {
+        display: block;
+      }
+    }
+
+    .grw-bookmarks-title-anchor {
+      width: 100%;
+      overflow: hidden;
+      text-decoration: none;
+    }
+
+  }
+  .grw-bookmarks-item-container {
+    .list-group-item {
+      min-width: 35px;
+      height: 40px;
+    }
+  }
+
+}

+ 1 - 0
packages/app/src/styles/style-app.scss

@@ -36,6 +36,7 @@
 // growi component
 @import 'admin';
 @import 'attachments';
+@import 'bookmarks';
 @import 'comment';
 @import 'comment_growi';
 @import 'drawio';

+ 13 - 0
packages/app/src/styles/theme/_apply-colors-dark.scss

@@ -300,6 +300,19 @@ ul.pagination {
       box-shadow: none !important;
     }
   }
+
+  // bookmarks
+  .grw-bookmarks-list {
+    @include override-list-group-item-for-pagetree(
+      $color-sidebar-context,
+      lighten($bgcolor-sidebar-context, 8%),
+      lighten($bgcolor-sidebar-context, 15%),
+      darken($color-sidebar-context, 15%),
+      darken($color-sidebar-context, 10%),
+      lighten($bgcolor-sidebar-context, 18%),
+      lighten($bgcolor-sidebar-context, 24%)
+    );
+  }
   .private-legacy-pages-link {
     &:hover {
       background: $bgcolor-list-hover;

+ 13 - 0
packages/app/src/styles/theme/_apply-colors-light.scss

@@ -198,6 +198,19 @@ $dropdown-link-active-bg: $bgcolor-dropdown-link-active;
       @include button-outline-svg-icon-variant($gray-400, $primary);
     }
   }
+
+  // bookmark
+  .grw-bookmarks-list {
+    @include override-list-group-item-for-pagetree(
+      $color-sidebar-context,
+      darken($bgcolor-sidebar-context, 5%),
+      darken($bgcolor-sidebar-context, 12%),
+      lighten($color-sidebar-context, 10%),
+      lighten($color-sidebar-context, 8%),
+      darken($bgcolor-sidebar-context, 15%),
+      darken($bgcolor-sidebar-context, 24%)
+    );
+  }
   .private-legacy-pages-link {
     &:hover {
       background: $bgcolor-list-hover;

+ 1 - 0
packages/app/src/styles/theme/_apply-colors.scss

@@ -317,6 +317,7 @@ ul.pagination {
       }
     }
   }
+
 }
 
 /*