diff --git a/public/assets/styles/blue.css b/public/assets/styles/blue.css index ded4cd02..3651dda7 100644 --- a/public/assets/styles/blue.css +++ b/public/assets/styles/blue.css @@ -4,7 +4,6 @@ .delete-dialog-comfirm, .book-item-config, .book-cover-item-config, -.side-menu-selector-container, .download-desk-button, .edit-dialog-comfirm, .change-location-button, diff --git a/public/assets/styles/dark.css b/public/assets/styles/dark.css index 5654f483..011de038 100644 --- a/public/assets/styles/dark.css +++ b/public/assets/styles/dark.css @@ -62,7 +62,6 @@ body, .delete-dialog-comfirm, .book-item-config, .book-cover-item-config, -.side-menu-selector-container, .download-desk-button, .edit-dialog-comfirm, .change-location-button, diff --git a/public/assets/styles/default.css b/public/assets/styles/default.css index f86b1e8b..b59fb738 100644 --- a/public/assets/styles/default.css +++ b/public/assets/styles/default.css @@ -76,7 +76,6 @@ body, .delete-dialog-comfirm, .book-item-config, .book-cover-item-config, -.side-menu-selector-container, .download-desk-button, .edit-dialog-comfirm, .change-location-button, diff --git a/public/assets/styles/green.css b/public/assets/styles/green.css index e5072f7a..1b9827af 100644 --- a/public/assets/styles/green.css +++ b/public/assets/styles/green.css @@ -4,7 +4,6 @@ .delete-dialog-comfirm, .book-item-config, .book-cover-item-config, -.side-menu-selector-container, .download-desk-button, .edit-dialog-comfirm, .change-location-button, diff --git a/public/assets/styles/purple.css b/public/assets/styles/purple.css index b93893ae..0314f22b 100644 --- a/public/assets/styles/purple.css +++ b/public/assets/styles/purple.css @@ -4,7 +4,6 @@ .delete-dialog-comfirm, .book-item-config, .book-cover-item-config, -.side-menu-selector-container, .download-desk-button, .edit-dialog-comfirm, .change-location-button, diff --git a/public/assets/styles/red.css b/public/assets/styles/red.css index 65648cfa..adfe35cf 100644 --- a/public/assets/styles/red.css +++ b/public/assets/styles/red.css @@ -13,7 +13,6 @@ .update-dialog-container-button, .import-from-local, .single-control-switch, -.side-menu-selector-container, .previous-chapter-single-container, .next-chapter-single-container, .book-bookmark-link, diff --git a/src/assets/locales/cn/translation.json b/src/assets/locales/cn/translation.json index 0076f2e1..efffcaa8 100644 --- a/src/assets/locales/cn/translation.json +++ b/src/assets/locales/cn/translation.json @@ -350,9 +350,10 @@ "Chinese Conversion": "繁简转换", "Don't use first page as PDF cover": "不使用 PDF 首页作为封面", "Don't crop book cover": "不裁剪图书封面", - "Add to favorite": "添加到喜爱", - "Remove from favorite": "从喜爱移除", + "Add to Favorite": "添加到喜爱", + "Remove from Favorite": "从喜爱移除", "Details": "详细信息", + "Multiple Select": "多选", "You may see this error when the book you're importing is not supported by Koodo Reader, try converting it with Calibre": "暂不支持此图书,请尝试使用 Calibre 转化之后重新导入", "Shelf title can't be pure number": "书架名不能是纯数字", "Open Console": "打开控制台", diff --git a/src/assets/locales/en/translation.json b/src/assets/locales/en/translation.json index 4943394e..6cf64321 100644 --- a/src/assets/locales/en/translation.json +++ b/src/assets/locales/en/translation.json @@ -128,6 +128,7 @@ "Add to favorite": "Add to favorite", "Remove from favorite": "Remove from favorite", "Details": "Details", + "Multiple Select": "Multiple Select", "You may see this error when the book you're importing is not supported by Koodo Reader, try converting it with Calibre": "You may see this error when the book you're importing is not supported by Koodo Reader, try converting it with Calibre", "Simplified To Traditional": "Simplified To Traditional", "Traditional To Simplified": "Traditional To Simplified", diff --git a/src/assets/styles/fonts/icomoon.eot b/src/assets/styles/fonts/icomoon.eot index c1909b54..290881b9 100644 Binary files a/src/assets/styles/fonts/icomoon.eot and b/src/assets/styles/fonts/icomoon.eot differ diff --git a/src/assets/styles/fonts/icomoon.svg b/src/assets/styles/fonts/icomoon.svg index 5fb7b239..0f0205dd 100644 --- a/src/assets/styles/fonts/icomoon.svg +++ b/src/assets/styles/fonts/icomoon.svg @@ -74,4 +74,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/styles/fonts/icomoon.ttf b/src/assets/styles/fonts/icomoon.ttf index edd948ff..01af9d2c 100644 Binary files a/src/assets/styles/fonts/icomoon.ttf and b/src/assets/styles/fonts/icomoon.ttf differ diff --git a/src/assets/styles/fonts/icomoon.woff b/src/assets/styles/fonts/icomoon.woff index 5834b3fb..892bdbea 100644 Binary files a/src/assets/styles/fonts/icomoon.woff and b/src/assets/styles/fonts/icomoon.woff differ diff --git a/src/assets/styles/style.css b/src/assets/styles/style.css index ffa9e29e..aac06ab6 100644 --- a/src/assets/styles/style.css +++ b/src/assets/styles/style.css @@ -1,10 +1,10 @@ @font-face { font-family: 'icomoon'; - src: url('fonts/icomoon.eot?o3qvp2'); - src: url('fonts/icomoon.eot?o3qvp2#iefix') format('embedded-opentype'), - url('fonts/icomoon.ttf?o3qvp2') format('truetype'), - url('fonts/icomoon.woff?o3qvp2') format('woff'), - url('fonts/icomoon.svg?o3qvp2#icomoon') format('svg'); + src: url('fonts/icomoon.eot?43s8j0'); + src: url('fonts/icomoon.eot?43s8j0#iefix') format('embedded-opentype'), + url('fonts/icomoon.ttf?43s8j0') format('truetype'), + url('fonts/icomoon.woff?43s8j0') format('woff'), + url('fonts/icomoon.svg?43s8j0#icomoon') format('svg'); font-weight: normal; font-style: normal; font-display: block; @@ -25,6 +25,39 @@ -moz-osx-font-smoothing: grayscale; } +.icon-bookshelf-line:before { + content: "\e94b"; +} +.icon-highlight-line:before { + content: "\e94c"; +} +.icon-select:before { + content: "\e94d"; +} +.icon-trash-line:before { + content: "\e943"; +} +.icon-detail:before { + content: "\e944"; +} +.icon-bookshelf:before { + content: "\e945"; +} +.icon-edit-line:before { + content: "\e946"; +} +.icon-address-book:before { + content: "\e947"; +} +.icon-idea-line:before { + content: "\e948"; +} +.icon-heart:before { + content: "\e949"; +} +.icon-home-line:before { + content: "\e94a"; +} .icon-day:before { content: "\e936"; } diff --git a/src/components/dialogs/actionDialog/component.tsx b/src/components/dialogs/actionDialog/component.tsx index 805a9253..b7c8dd08 100644 --- a/src/components/dialogs/actionDialog/component.tsx +++ b/src/components/dialogs/actionDialog/component.tsx @@ -55,6 +55,11 @@ class ActionDialog extends React.Component< toast.success(this.props.t("Add Successfully")); this.props.handleActionDialog(false); }; + handleMultiSelect = () => { + this.props.handleSelectBook(true); + this.props.handleSelectedBooks([this.props.currentBook.key]); + this.props.handleActionDialog(false); + }; handleCancelLoveBook = () => { AddFavorite.clear(this.props.currentBook.key); if ( @@ -125,14 +130,14 @@ class ActionDialog extends React.Component< } }} > - +

{AddFavorite.getAllFavorite().indexOf( this.props.currentBook.key ) > -1 ? ( - Remove from favorite + Remove from Favorite ) : ( - Add to favorite + Add to Favorite )}

@@ -142,18 +147,29 @@ class ActionDialog extends React.Component< this.handleAddShelf(); }} > - +

Add to Shelf

+
{ + this.handleMultiSelect(); + }} + > + +

+ Multiple Select +

+
{ this.handleDeleteBook(); }} > - +

Delete

@@ -164,7 +180,7 @@ class ActionDialog extends React.Component< this.handleEditBook(); }} > - +

Edit

@@ -176,10 +192,10 @@ class ActionDialog extends React.Component< }} > -

+

Details

@@ -206,8 +222,10 @@ class ActionDialog extends React.Component< className="icon-more view-icon" style={{ display: "inline-block", - marginRight: "15px", + marginRight: "12px", + marginLeft: "3px", transform: "rotate(90deg)", + fontSize: "12px", }} > More Actions diff --git a/src/components/dialogs/actionDialog/index.tsx b/src/components/dialogs/actionDialog/index.tsx index 0a8d89c0..00c8495d 100644 --- a/src/components/dialogs/actionDialog/index.tsx +++ b/src/components/dialogs/actionDialog/index.tsx @@ -2,7 +2,9 @@ import { connect } from "react-redux"; import { handleEditDialog, handleDeleteDialog, + handleSelectBook, handleAddDialog, + handleSelectedBooks, handleActionDialog, handleReadingBook, handleFetchBooks, @@ -19,6 +21,8 @@ const mapStateToProps = (state: stateType) => { currentBook: state.book.currentBook, books: state.manager.books, notes: state.reader.notes, + isSelectBook: state.manager.isSelectBook, + deletedBooks: state.manager.deletedBooks, }; }; @@ -30,6 +34,8 @@ const actionCreator = { handleActionDialog, handleFetchBooks, handleDetailDialog, + handleSelectBook, + handleSelectedBooks, }; export default connect( mapStateToProps, diff --git a/src/components/dialogs/actionDialog/interface.tsx b/src/components/dialogs/actionDialog/interface.tsx index b33bee5c..3894ed5d 100644 --- a/src/components/dialogs/actionDialog/interface.tsx +++ b/src/components/dialogs/actionDialog/interface.tsx @@ -11,6 +11,8 @@ export interface ActionDialogProps extends RouteComponentProps { left: number; top: number; mode: string; + isSelectBook: boolean; + handleFetchBooks: () => void; handleDeleteDialog: (isShow: boolean) => void; handleFetchBookmarks: () => void; @@ -21,6 +23,8 @@ export interface ActionDialogProps extends RouteComponentProps { handleAddDialog: (isShow: boolean) => void; handleActionDialog: (isShow: boolean) => void; handleDetailDialog: (isShow: boolean) => void; + handleSelectBook: (isSelectBook: boolean) => void; + handleSelectedBooks: (selectedBooks: string[]) => void; } export interface ActionDialogState { isShowExport: boolean; diff --git a/src/components/selectBook/component.tsx b/src/components/selectBook/component.tsx index d7a9f697..31f4d039 100644 --- a/src/components/selectBook/component.tsx +++ b/src/components/selectBook/component.tsx @@ -35,7 +35,7 @@ class SelectBook extends React.Component { }} className="book-manage-title" > - {this.props.isSelectBook ? "Cancel" : "Select"} + {this.props.isSelectBook ? "Cancel" : ""} {this.props.isSelectBook && ( <> diff --git a/src/components/shelfSelector/component.tsx b/src/components/shelfSelector/component.tsx index ca12988c..4898b6b0 100644 --- a/src/components/shelfSelector/component.tsx +++ b/src/components/shelfSelector/component.tsx @@ -42,6 +42,9 @@ class ShelfSelector extends React.Component< this.props.handleMode("shelf"); }); }; + handleDeletePopup = (isOpenDelete: boolean) => { + this.setState({ isOpenDelete }); + }; renderShelfList = () => { let shelfList = ShelfUtil.getShelf(); let shelfTitle = Object.keys(shelfList); @@ -59,9 +62,7 @@ class ShelfSelector extends React.Component< ); }); }; - handleDeletePopup = (isOpenDelete: boolean) => { - this.setState({ isOpenDelete }); - }; + render() { if (isElectron) { //兼容之前的版本 diff --git a/src/constants/sideMenu.tsx b/src/constants/sideMenu.tsx index 41b4122d..dd509695 100644 --- a/src/constants/sideMenu.tsx +++ b/src/constants/sideMenu.tsx @@ -1,28 +1,28 @@ export const sideMenu = [ { name: "Books", - icon: "home", + icon: "home-line", mode: "home", }, { name: "Favorites", - icon: "love", + icon: "heart", mode: "favorite", }, { name: "Notes", - icon: "idea", + icon: "idea-line", mode: "note", }, { name: "Highlights", - icon: "digest", + icon: "highlight-line", mode: "digest", }, { name: "Deleted Books", - icon: "trash", + icon: "trash-line", mode: "trash", }, ]; diff --git a/src/containers/lists/bookList/booklist.css b/src/containers/lists/bookList/booklist.css index 3b39867e..d2c2f20f 100644 --- a/src/containers/lists/bookList/booklist.css +++ b/src/containers/lists/bookList/booklist.css @@ -1,6 +1,6 @@ .book-list-container-parent { position: absolute; - top: 125px; + top: 80px; left: 220px; width: calc(100% - 220px); height: calc(100% - 125px); @@ -11,7 +11,7 @@ align-items: center; justify-content: space-between; position: absolute; - top: 85px; + bottom: 10px; left: 220px; width: calc(100% - 220px); } diff --git a/src/containers/lists/bookList/component.tsx b/src/containers/lists/bookList/component.tsx index 3c39be2c..007929d4 100644 --- a/src/containers/lists/bookList/component.tsx +++ b/src/containers/lists/bookList/component.tsx @@ -16,7 +16,6 @@ import ViewMode from "../../../components/viewMode"; import { backup } from "../../../utils/syncUtils/backupUtil"; import { isElectron } from "react-device-detect"; import SelectBook from "../../../components/selectBook"; -import ShelfSelector from "../../../components/shelfSelector"; declare var window: any; class BookList extends React.Component { constructor(props: BookListProps) { @@ -191,12 +190,11 @@ class BookList extends React.Component { } > -
+ {/*
-
+
*/} -
{ constructor(props: SidebarProps) { super(props); this.state = { index: 0, hoverIndex: -1, + hoverShelfIndex: -1, + isCollpaseShelf: false, + isOpenDelete: false, + shelfIndex: 0, isCollapsed: StorageUtil.getReaderConfig("isCollapsed") === "yes" || false, }; @@ -35,6 +40,9 @@ class Sidebar extends React.Component { handleHover = (index: number) => { this.setState({ hoverIndex: index }); }; + handleShelfHover = (index: number) => { + this.setState({ hoverShelfIndex: index }); + }; handleCollapse = (isCollapsed: boolean) => { this.setState({ isCollapsed }); this.props.handleCollapse(isCollapsed); @@ -43,6 +51,20 @@ class Sidebar extends React.Component { handleJump = (url: string) => { openExternalUrl(url); }; + handleDeleteShelf = () => { + if (this.state.shelfIndex < 1) return; + let shelfTitles = Object.keys(ShelfUtil.getShelf()); + //获取当前书架名 + let currentShelfTitle = shelfTitles[this.state.shelfIndex]; + ShelfUtil.removeShelf(currentShelfTitle); + this.setState({ shelfIndex: 0 }, () => { + this.props.handleShelfIndex(0); + this.props.handleMode("shelf"); + }); + }; + handleDeletePopup = (isOpenDelete: boolean) => { + this.setState({ isOpenDelete }); + }; render() { const renderSideMenu = () => { return sideMenu.map((item, index) => { @@ -50,7 +72,7 @@ class Sidebar extends React.Component {
  • { }} style={this.props.isCollapsed ? { width: 40, marginLeft: 15 } : {}} > - {this.state.index === index ? ( + {this.state.index === index && this.props.mode !== "shelf" ? (
    ) : null} - {this.state.hoverIndex === index ? ( + {this.state.hoverIndex === index && this.props.mode !== "shelf" ? (
    ) : null}
    { > @@ -111,36 +133,162 @@ class Sidebar extends React.Component { ); }); }; - return ( -
    -
    { - this.handleCollapse(!this.state.isCollapsed); - }} - > - -
    + const renderSideShelf = () => { + let shelfList = ShelfUtil.getShelf(); + let shelfTitle = Object.keys(shelfList); - { - this.handleJump("https://koodo.960960.xyz"); - }} - style={this.state.isCollapsed ? { display: "none" } : {}} - className="logo" - /> -
    -
      {renderSideMenu()}
    -
    -
    + return shelfTitle.map((item, index) => { + return ( +
  • { + this.props.handleShelfIndex(index); + if (index > 0) { + this.props.handleMode("shelf"); + } else { + this.props.handleMode("home"); + } + this.setState({ index: -1 }); + }} + onMouseEnter={() => { + this.handleShelfHover(index); + }} + onMouseLeave={() => { + this.handleShelfHover(-1); + }} + style={ + index === 0 + ? { display: "none" } + : this.props.isCollapsed + ? { width: 40, marginLeft: 15 } + : {} + } + > + {this.props.shelfIndex === index ? ( +
    + ) : null} + {this.state.hoverShelfIndex === index ? ( +
    + ) : null} +
    +
    + +
    + + + {this.props.t(item)} + +
    +
  • + ); + }); + }; + const deletePopupProps = { + mode: "shelf", + name: Object.keys(ShelfUtil.getShelf())[this.state.shelfIndex], + title: "Delete this shelf", + description: "This action will clear and remove this shelf", + handleDeletePopup: this.handleDeletePopup, + handleDeleteOpearion: this.handleDeleteShelf, + }; + return ( + <> + {" "} +
    +
    { + this.handleCollapse(!this.state.isCollapsed); + }} + > + +
    + + { + this.handleJump("https://koodo.960960.xyz"); + }} + style={this.state.isCollapsed ? { display: "none" } : {}} + className="logo" + /> +
    +
      {renderSideMenu()}
    +
    +
    我的书架
    + { + this.setState({ + isCollpaseShelf: !this.state.isCollpaseShelf, + }); + }} + style={ + this.state.isCollpaseShelf + ? { transform: "rotate(-90deg)" } + : {} + } + > +
    + + {!this.state.isCollpaseShelf && ( +
      {renderSideShelf()}
    + )} +
    +
    {" "} + {this.state.isOpenDelete && } + ); } } diff --git a/src/containers/sidebar/index.tsx b/src/containers/sidebar/index.tsx index 5960a511..25e4afd5 100644 --- a/src/containers/sidebar/index.tsx +++ b/src/containers/sidebar/index.tsx @@ -12,7 +12,11 @@ import { withTranslation } from "react-i18next"; import Sidebar from "./component"; const mapStateToProps = (state: stateType) => { - return { mode: state.sidebar.mode, isCollapsed: state.sidebar.isCollapsed }; + return { + mode: state.sidebar.mode, + isCollapsed: state.sidebar.isCollapsed, + shelfIndex: state.sidebar.shelfIndex, + }; }; const actionCreator = { handleMode, diff --git a/src/containers/sidebar/interface.tsx b/src/containers/sidebar/interface.tsx index 6da23b31..d8b5c9d8 100644 --- a/src/containers/sidebar/interface.tsx +++ b/src/containers/sidebar/interface.tsx @@ -3,6 +3,8 @@ import { RouteComponentProps } from "react-router"; export interface SidebarProps extends RouteComponentProps { mode: string; isCollapsed: boolean; + shelfIndex: number; + handleMode: (mode: string) => void; handleSearch: (isSearch: boolean) => void; handleCollapse: (isCollapsed: boolean) => void; @@ -15,5 +17,9 @@ export interface SidebarProps extends RouteComponentProps { export interface SidebarState { index: number; hoverIndex: number; + hoverShelfIndex: number; isCollapsed: boolean; + isCollpaseShelf: boolean; + shelfIndex: number; + isOpenDelete: boolean; } diff --git a/src/containers/sidebar/sidebar.css b/src/containers/sidebar/sidebar.css index ccc1c94f..3c60b3d7 100644 --- a/src/containers/sidebar/sidebar.css +++ b/src/containers/sidebar/sidebar.css @@ -14,8 +14,22 @@ position: relative; top: 85px; width: 210px; - height: 100%; - overflow: hidden; + height: calc(100% - 100px); + overflow-x: hidden; + overflow-y: scroll; +} +.side-menu-container-parent:hover::-webkit-scrollbar-thumb, +.side-menu-container-parent:active::-webkit-scrollbar-thumb, +.side-menu-container-parent:focus::-webkit-scrollbar-thumb { + display: block; + width: 1px; +} +.side-menu-container-parent::-webkit-scrollbar-thumb { + display: none; +} +.side-menu-container-parent::-webkit-scrollbar { + width: 2px; + height: 0.5rem; } .sidebar-list { margin-right: 5px; @@ -42,8 +56,13 @@ .side-menu-container { /* overflow: hidden; */ width: 100%; - height: 100%; - overflow-y: scroll; + padding-right: 17px; /* Increase/decrease this value for cross-browser compatibility */ + box-sizing: content-box; + position: relative; +} +.side-shelf-container { + /* overflow: hidden; */ + width: 100%; padding-right: 17px; /* Increase/decrease this value for cross-browser compatibility */ box-sizing: content-box; position: relative; @@ -51,7 +70,7 @@ .side-menu-icon { /* float: left; */ - font-size: 17px; + font-size: 22px; margin: 9px 12px 7px 18px; display: flex; justify-content: center; @@ -68,7 +87,7 @@ text-overflow: ellipsis; white-space: nowrap; margin-left: -20px; - margin-bottom: 10px; + margin-bottom: 3px; position: relative; bottom: 1px; overflow: hidden; @@ -99,7 +118,27 @@ white-space: nowrap; overflow-x: hidden; } - +.side-shelf-title { + font-size: 17px; + font-weight: 600; + margin-bottom: 10px; + margin-top: 10px; + display: inline-block; +} +.side-shelf-title-container { + width: 70%; + margin-left: 10%; + border-bottom: 1px solid #ccc; +} +.side-shelf-title-icon { + margin-top: 13px; + float: right; + font-weight: 500; + font-size: 14px; + transform-origin: center center; + transition: transform 0.1s ease; + cursor: pointer; +} .side-menu-selector-container { width: 100%; height: 39px;