mirror of
https://github.com/koodo-reader/koodo-reader.git
synced 2026-10-08 22:04:11 -04:00
Implement sorting functionality in NavList component with UI for sort options
This commit is contained in:
1 parent
5f3fd700fa
commit
01ef97b5fa
4 files changed
+182
-10
No files matched your search
@@ -990,6 +990,7 @@
|
||||
"This feature is not available in the free version": "免费版不支持此功能",
|
||||
"Data": "数据",
|
||||
"View": "查看",
|
||||
"Sort": "排序",
|
||||
"Select format": "选择格式",
|
||||
"Enable Discord Rich Presence": "启用 Discord Rich Presence",
|
||||
"Show your reading status and the book your're reading on your Discord profile. Discord needs to be running on your computer": "启用后会在您的 Discord 个人资料上显示您的阅读状态和正在阅读的图书。需要您在电脑上运行 Discord 客户端",
|
||||
|
||||
@@ -21,6 +21,22 @@ class NavList extends React.Component<NavListProps, NavListState> {
|
||||
constructor(props: NavListProps) {
|
||||
super(props);
|
||||
this.highlightUtil = new HighlightUtil(ConfigService);
|
||||
let sortCode = 1;
|
||||
let orderCode = 2;
|
||||
const navSortCode = ConfigService.getReaderConfig("navSortCode");
|
||||
if (navSortCode) {
|
||||
try {
|
||||
const parsed = JSON.parse(navSortCode);
|
||||
if (parsed && (parsed.sort === 1 || parsed.sort === 2)) {
|
||||
sortCode = parsed.sort;
|
||||
}
|
||||
if (parsed && (parsed.order === 1 || parsed.order === 2)) {
|
||||
orderCode = parsed.order;
|
||||
}
|
||||
} catch {
|
||||
// ignore malformed config, fall back to defaults
|
||||
}
|
||||
}
|
||||
this.state = {
|
||||
deleteIndex: -1,
|
||||
currentData: [],
|
||||
@@ -28,6 +44,9 @@ class NavList extends React.Component<NavListProps, NavListState> {
|
||||
searchKeyword: "",
|
||||
searchResults: [],
|
||||
isComposing: false,
|
||||
isSortOpen: false,
|
||||
sortCode,
|
||||
orderCode,
|
||||
};
|
||||
this.searchInputRef = React.createRef<HTMLInputElement>();
|
||||
}
|
||||
@@ -203,9 +222,9 @@ class NavList extends React.Component<NavListProps, NavListState> {
|
||||
if (currentTab === "bookmarks") {
|
||||
this.setState(
|
||||
{
|
||||
currentData: bookmarks
|
||||
.filter((item) => item.bookKey === currentBook.key)
|
||||
.reverse(),
|
||||
currentData: bookmarks.filter(
|
||||
(item) => item.bookKey === currentBook.key
|
||||
),
|
||||
},
|
||||
() => {
|
||||
if (this.state.searchKeyword.trim()) {
|
||||
@@ -290,6 +309,35 @@ class NavList extends React.Component<NavListProps, NavListState> {
|
||||
|
||||
return this.highlightUtil.buildHighlightPreviewStyle(styleType, color);
|
||||
};
|
||||
toggleSortOpen = () => {
|
||||
this.setState({ isSortOpen: !this.state.isSortOpen });
|
||||
};
|
||||
handleSortSelect = (code: number) => {
|
||||
this.setState({ sortCode: code, isSortOpen: false }, () => {
|
||||
ConfigService.setReaderConfig(
|
||||
"navSortCode",
|
||||
JSON.stringify({ sort: code, order: this.state.orderCode })
|
||||
);
|
||||
});
|
||||
};
|
||||
handleOrderSelect = (code: number) => {
|
||||
this.setState({ orderCode: code, isSortOpen: false }, () => {
|
||||
ConfigService.setReaderConfig(
|
||||
"navSortCode",
|
||||
JSON.stringify({ sort: this.state.sortCode, order: code })
|
||||
);
|
||||
});
|
||||
};
|
||||
getSortedData = (data: (Bookmark | Note)[]) => {
|
||||
const { sortCode, orderCode } = this.state;
|
||||
return [...data].sort((a: any, b: any) => {
|
||||
const diff =
|
||||
sortCode === 1
|
||||
? (Number(a.key) || 0) - (Number(b.key) || 0)
|
||||
: (Number(a.percentage) || 0) - (Number(b.percentage) || 0);
|
||||
return orderCode === 1 ? diff : -diff;
|
||||
});
|
||||
};
|
||||
renderBookNavList = (displayData: (Bookmark | Note)[]) => {
|
||||
return displayData.map((item: any, index: number) => {
|
||||
const bookmarkProps = {
|
||||
@@ -355,9 +403,10 @@ class NavList extends React.Component<NavListProps, NavListState> {
|
||||
render() {
|
||||
const isSearching =
|
||||
this.state.searchKeyword.trim().length > 0 && !this.state.isComposing;
|
||||
const displayData = isSearching
|
||||
const baseList = isSearching
|
||||
? this.state.searchResults
|
||||
: this.state.currentData;
|
||||
const displayData = this.getSortedData(baseList);
|
||||
|
||||
return (
|
||||
<div className="book-bookmark-container">
|
||||
@@ -365,12 +414,95 @@ class NavList extends React.Component<NavListProps, NavListState> {
|
||||
<div>
|
||||
<Trans>Total</Trans>: {this.state.currentData.length}
|
||||
</div>
|
||||
<div onClick={this.toggleSearch} className="book-nav-expand">
|
||||
<span
|
||||
className="icon-search"
|
||||
style={{ paddingRight: "5px" }}
|
||||
></span>
|
||||
<Trans>{this.state.isSearchOpen ? "Cancel" : "Search"}</Trans>
|
||||
<div className="book-nav-actions">
|
||||
<div
|
||||
className="nav-sort-wrap"
|
||||
onMouseLeave={() => {
|
||||
this.setState({ isSortOpen: false });
|
||||
}}
|
||||
>
|
||||
<div className="book-nav-expand" onClick={this.toggleSortOpen}>
|
||||
<span
|
||||
className="icon-sort-desc"
|
||||
style={{ paddingRight: "5px" }}
|
||||
></span>
|
||||
<Trans>Sort</Trans>
|
||||
</div>
|
||||
{this.state.isSortOpen && (
|
||||
<div className="sort-dialog-container nav-sort-dialog-container">
|
||||
<ul className="sort-by-category">
|
||||
{["Sort by Date", "Reading progress"].map((item, index) => {
|
||||
return (
|
||||
<li
|
||||
className="sort-by-category-list"
|
||||
onClick={() => {
|
||||
this.handleSortSelect(index + 1);
|
||||
}}
|
||||
style={
|
||||
this.state.sortCode === index + 1
|
||||
? {}
|
||||
: { opacity: 0.34 }
|
||||
}
|
||||
key={index + 1}
|
||||
>
|
||||
<Trans>{item}</Trans>
|
||||
{this.state.sortCode === index + 1 && (
|
||||
<span
|
||||
className="icon-check"
|
||||
style={{ fontWeight: "bold" }}
|
||||
></span>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<div className="sort-dialog-seperator"></div>
|
||||
<ul className="sort-by-order">
|
||||
<li
|
||||
className="sort-by-order-list"
|
||||
onClick={() => {
|
||||
this.handleOrderSelect(1);
|
||||
}}
|
||||
style={
|
||||
this.state.orderCode === 1 ? {} : { opacity: 0.34 }
|
||||
}
|
||||
>
|
||||
<Trans>Ascend</Trans>
|
||||
{this.state.orderCode === 1 && (
|
||||
<span
|
||||
className="icon-check"
|
||||
style={{ fontWeight: "bold" }}
|
||||
></span>
|
||||
)}
|
||||
</li>
|
||||
<li
|
||||
className="sort-by-order-list"
|
||||
onClick={() => {
|
||||
this.handleOrderSelect(2);
|
||||
}}
|
||||
style={
|
||||
this.state.orderCode === 2 ? {} : { opacity: 0.34 }
|
||||
}
|
||||
>
|
||||
<Trans>Descend</Trans>
|
||||
{this.state.orderCode === 2 && (
|
||||
<span
|
||||
className="icon-check"
|
||||
style={{ fontWeight: "bold" }}
|
||||
></span>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div onClick={this.toggleSearch} className="book-nav-expand">
|
||||
<span
|
||||
className="icon-search"
|
||||
style={{ paddingRight: "5px" }}
|
||||
></span>
|
||||
<Trans>{this.state.isSearchOpen ? "Cancel" : "Search"}</Trans>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{this.state.isSearchOpen && (
|
||||
|
||||
@@ -20,4 +20,7 @@ export interface NavListState {
|
||||
searchKeyword: string;
|
||||
searchResults: (BookmarkModel | NoteModel)[];
|
||||
isComposing: boolean;
|
||||
isSortOpen: boolean;
|
||||
sortCode: number;
|
||||
orderCode: number;
|
||||
}
|
||||
@@ -98,3 +98,39 @@
|
||||
font-size: 15px;
|
||||
opacity: 0.64;
|
||||
}
|
||||
.book-nav-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.nav-sort-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.nav-sort-dialog-container {
|
||||
position: absolute;
|
||||
left: auto;
|
||||
right: 0;
|
||||
top: 30px;
|
||||
z-index: 10;
|
||||
}
|
||||
.nav-sort-dialog-container .sort-by-category-list,
|
||||
.nav-sort-dialog-container .sort-by-order-list {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
min-height: 30px;
|
||||
line-height: 1.5;
|
||||
width: calc(100% - 30px);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.nav-sort-dialog-container .sort-dialog-seperator {
|
||||
width: 100%;
|
||||
height: 0px;
|
||||
margin: 6px 0px;
|
||||
}
|
||||
Reference in new issue
Block a user