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

Merge pull request #6957 from weseek/feat/gw7861-move-bookmarked-item-to-bookmark-folder

feat: gw7861 move bookmarked item to bookmark folder
Kaori Tokashiki 3 лет назад
Родитель
Сommit
3743be5187

+ 8 - 70
packages/app/src/components/Sidebar/Bookmarks.tsx

@@ -3,88 +3,26 @@ import React from 'react';
 
 import { useTranslation } from 'react-i18next';
 
-import { toastSuccess } from '~/client/util/apiNotification';
-import { IPageToDeleteWithMeta } from '~/interfaces/page';
-import { OnDeletedFunction } from '~/interfaces/ui';
-import { useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
 import { useIsGuestUser } from '~/stores/context';
-import { usePageDeleteModal } from '~/stores/modal';
 
-
-import BookmarkFolder from './Bookmarks/BookmarkFolder';
-import BookmarkItem from './Bookmarks/BookmarkItem';
+import BookamrkContents from './Bookmarks/BookmarkContents';
 
 const Bookmarks = () : JSX.Element => {
   const { t } = useTranslation();
   const { data: isGuestUser } = useIsGuestUser();
-  const { data: currentUserBookmarksData, mutate: mutateCurrentUserBookmarks } = useSWRxCurrentUserBookmarks();
-  const { open: openDeleteModal } = usePageDeleteModal();
-
-
-  const deleteMenuItemClickHandler = (pageToDelete: IPageToDeleteWithMeta) => {
-    const pageDeletedHandler : OnDeletedFunction = (pathOrPathsToDelete, _isRecursively, isCompletely) => {
-      if (typeof pathOrPathsToDelete !== 'string') {
-        return;
-      }
-      const path = pathOrPathsToDelete;
-
-      if (isCompletely) {
-        toastSuccess(t('deleted_pages_completely', { path }));
-      }
-      else {
-        toastSuccess(t('deleted_pages', { path }));
-      }
-      mutateCurrentUserBookmarks();
-    };
-    openDeleteModal([pageToDelete], { onDeleted: pageDeletedHandler });
-  };
-
-
-  const renderBookmarkList = () => {
-    if (currentUserBookmarksData?.length === 0) {
-      return (
-        <h4 className="pl-3">
-          { t('No bookmarks yet') }
-        </h4>
-      );
-    }
-    return (
-      <ul className="grw-bookmarks-list list-group p-3">
-        <div className="grw-bookmarks-item-container">
-          { currentUserBookmarksData?.map((currentUserBookmark) => {
-            return (
-              <BookmarkItem
-                key={currentUserBookmark._id}
-                bookmarkedPage={currentUserBookmark}
-                onUnbookmarked={mutateCurrentUserBookmarks}
-                onRenamed={mutateCurrentUserBookmarks}
-                onClickDeleteMenuItem={deleteMenuItemClickHandler}
-              />
-            );
-          })}
-        </div>
-      </ul>
-    );
-  };
 
   return (
     <>
       <div className="grw-sidebar-content-header p-3">
         <h3 className="mb-0">{t('Bookmarks')}</h3>
       </div>
-      {!isGuestUser && (
-        <>
-          <BookmarkFolder />
-        </>
-      )
-      }
-      { isGuestUser
-        ? (
-          <h4 className="pl-3">
-            { t('Not available for guest') }
-          </h4>
-        ) : renderBookmarkList()
-      }
+      {isGuestUser ? (
+        <h4 className="pl-3">
+          { t('Not available for guest') }
+        </h4>
+      ) : (
+        <BookamrkContents />
+      )}
     </>
   );
 };

+ 11 - 3
packages/app/src/components/Sidebar/Bookmarks/BookmarkFolder.tsx → packages/app/src/components/Sidebar/Bookmarks/BookmarkContents.tsx

@@ -11,7 +11,7 @@ import BookmarkFolderNameInput from './BookmarkFolderNameInput';
 import BookmarkFolderTree from './BookmarkFolderTree';
 
 
-const BookmarkFolder = (): JSX.Element => {
+const BookmarkContents = (): JSX.Element => {
 
   const { t } = useTranslation();
   const [isRenameInputShown, setIsRenameInputShown] = useState<boolean>(false);
@@ -36,7 +36,7 @@ const BookmarkFolder = (): JSX.Element => {
 
   }, [mutateChildBookmarkData, t]);
 
-  return (
+  const renderAddNewBookmarkFolder = () => (
     <>
       <div className="col-8 mb-2 ">
         <button
@@ -57,9 +57,17 @@ const BookmarkFolder = (): JSX.Element => {
           </div>
         )
       }
+    </>
+  );
+
+  return (
+    <>
+      {
+        renderAddNewBookmarkFolder()
+      }
       <BookmarkFolderTree />
     </>
   );
 };
 
-export default BookmarkFolder;
+export default BookmarkContents;

+ 4 - 0
packages/app/src/components/Sidebar/Bookmarks/BookmarkFolderTree.module.scss

@@ -58,6 +58,10 @@ $grw-foldertree-item-padding-left: 10px;
         min-width: 35px;
         height: 40px;
       }
+      .bookmark-item-list{
+        min-width: 30px;
+        height: 35px;
+      }
     }
   }
   &:global{

+ 63 - 12
packages/app/src/components/Sidebar/Bookmarks/BookmarkFolderTree.tsx

@@ -1,27 +1,78 @@
 
+import { useCallback } from 'react';
+
+import { useTranslation } from 'next-i18next';
+
+import { toastSuccess } from '~/client/util/apiNotification';
+import { IPageToDeleteWithMeta } from '~/interfaces/page';
+import { OnDeletedFunction } from '~/interfaces/ui';
+import { useSWRxCurrentUserBookmarks } from '~/stores/bookmark';
 import { useSWRxBookamrkFolderAndChild } from '~/stores/bookmark-folder';
+import { usePageDeleteModal } from '~/stores/modal';
 
 import BookmarkFolderItem from './BookmarkFolderItem';
+import BookmarkItem from './BookmarkItem';
 
 import styles from './BookmarkFolderTree.module.scss';
 
 
 const BookmarkFolderTree = (): JSX.Element => {
+  const { t } = useTranslation();
+  const { data: currentUserBookmarksData, mutate: mutateCurrentUserBookmarks } = useSWRxCurrentUserBookmarks();
   const { data: bookmarkFolderData } = useSWRxBookamrkFolderAndChild();
+  const { open: openDeleteModal } = usePageDeleteModal();
+
+  const deleteMenuItemClickHandler = useCallback((pageToDelete: IPageToDeleteWithMeta) => {
+    const pageDeletedHandler : OnDeletedFunction = (pathOrPathsToDelete, _isRecursively, isCompletely) => {
+      if (typeof pathOrPathsToDelete !== 'string') {
+        return;
+      }
+      const path = pathOrPathsToDelete;
+
+      if (isCompletely) {
+        toastSuccess(t('deleted_pages_completely', { path }));
+      }
+      else {
+        toastSuccess(t('deleted_pages', { path }));
+      }
+      mutateCurrentUserBookmarks();
+    };
+    openDeleteModal([pageToDelete], { onDeleted: pageDeletedHandler });
+  }, [mutateCurrentUserBookmarks, openDeleteModal, t]);
+
   if (bookmarkFolderData != null) {
     return (
-
-      <ul className={`grw-foldertree ${styles['grw-foldertree']} list-group p-3`}>
-        {bookmarkFolderData.map((item) => {
-          return (
-            <BookmarkFolderItem
-              key={item._id}
-              bookmarkFolder={item}
-              isOpen={false}
-            />
-          );
-        })}
-      </ul>
+      <>
+        <ul className={`grw-foldertree ${styles['grw-foldertree']} list-group p-3`}>
+          {bookmarkFolderData.map((item) => {
+            return (
+              <BookmarkFolderItem
+                key={item._id}
+                bookmarkFolder={item}
+                isOpen={false}
+              />
+            );
+          })}
+          {currentUserBookmarksData?.length === 0 && (
+            <div className="pt-3">
+              <h5 className="pl-3">
+                { t('No bookmarks yet') }
+              </h5>
+            </div>
+          )}
+          { currentUserBookmarksData?.map((currentUserBookmark) => {
+            return (
+              <BookmarkItem
+                key={currentUserBookmark._id}
+                bookmarkedPage={currentUserBookmark}
+                onUnbookmarked={mutateCurrentUserBookmarks}
+                onRenamed={mutateCurrentUserBookmarks}
+                onClickDeleteMenuItem={deleteMenuItemClickHandler}
+              />
+            );
+          })}
+        </ul>
+      </>
     );
   }
   return <></>;

+ 4 - 4
packages/app/src/components/Sidebar/Bookmarks/BookmarkItem.tsx

@@ -96,8 +96,8 @@ const BookmarkItem = (props: Props): JSX.Element => {
   }, [bookmarkedPage, onClickDeleteMenuItem]);
 
   return (
-    <div className="d-flex justify-content-between" key={bookmarkedPage._id}>
-      <li className="list-group-item list-group-item-action border-0 py-0 pr-3 d-flex align-items-center" id={bookmarkItemId}>
+    <div className="grw-foldertree-item-container" key={bookmarkedPage._id}>
+      <li className="bookmark-item-list list-group-item list-group-item-action border-0 py-0 pl-3 d-flex align-items-center" id={bookmarkItemId}>
         { isRenameInputShown ? (
           <ClosableTextInput
             value={nodePath.basename(bookmarkedPage.path ?? '')}
@@ -107,7 +107,7 @@ const BookmarkItem = (props: Props): JSX.Element => {
             inputValidator={inputValidator}
           />
         ) : (
-          <a href={`/${bookmarkedPage._id}`} className="grw-bookmarks-title-anchor flex-grow-1">
+          <a href={`/${bookmarkedPage._id}`} className="grw-foldertree-title-anchor flex-grow-1 pr-3">
             <p className={`text-truncate m-auto ${bookmarkedPage.isEmpty && 'grw-sidebar-text-muted'}`}>{pageTitle}</p>
           </a>
         )}
@@ -130,7 +130,7 @@ const BookmarkItem = (props: Props): JSX.Element => {
           target={bookmarkItemId}
           fade={false}
         >
-          { formerPagePath }
+          { formerPagePath !== null ? `${formerPagePath}/` : '/' }
         </UncontrolledTooltip>
       </li>
     </div>

+ 5 - 4
packages/app/src/server/models/bookmark-folder.ts

@@ -32,6 +32,8 @@ const bookmarkFolderSchema = new Schema<BookmarkFolderDocument, BookmarkFolderMo
   name: { type: String },
   owner: { type: Schema.Types.ObjectId, ref: 'User', index: true },
   parent: { type: Schema.Types.ObjectId, ref: 'BookmarkFolder', required: false },
+}, {
+  toObject: { virtuals: true },
 });
 
 bookmarkFolderSchema.virtual('children', {
@@ -40,7 +42,6 @@ bookmarkFolderSchema.virtual('children', {
   foreignField: 'parent',
 });
 
-
 bookmarkFolderSchema.statics.createByParameters = async function(params: IBookmarkFolder): Promise<BookmarkFolderDocument> {
   const { name, owner, parent } = params;
   let bookmarkFolder;
@@ -69,10 +70,11 @@ bookmarkFolderSchema.statics.findFolderAndChildren = async function(
     userId: Types.ObjectId | string,
     parentId?: Types.ObjectId | string,
 ): Promise<BookmarkFolderItems[]> {
+
   const parentFolder = await this.findById(parentId) as unknown as BookmarkFolderDocument;
-  const bookmarks = await this.find({ owner: userId, parent: parentFolder })
+  const bookmarkFolders = await this.find({ owner: userId, parent: parentFolder })
     .populate({ path: 'children' }).exec() as unknown as BookmarkFolderItems[];
-  return bookmarks;
+  return bookmarkFolders;
 };
 
 bookmarkFolderSchema.statics.findChildFolderById = async function(parentFolderId: Types.ObjectId | string): Promise<BookmarkFolderDocument[]> {
@@ -104,6 +106,5 @@ bookmarkFolderSchema.statics.updateBookmarkFolder = async function(bookmarkFolde
 
 };
 
-bookmarkFolderSchema.set('toObject', { virtuals: true });
 
 export default getOrCreateModel<BookmarkFolderDocument, BookmarkFolderModel>('BookmarkFolder', bookmarkFolderSchema);