175 lines
4.2 KiB
JavaScript
175 lines
4.2 KiB
JavaScript
import "./bookCard.css";
|
|
import axios from "axios";
|
|
import Skeleton from "react-loading-skeleton";
|
|
import { useEffect, useState } from "react";
|
|
import { Link } from "react-router-dom";
|
|
import IconButton from "../../md-components/IconButton";
|
|
import Icon from "../../md-components/Icon";
|
|
|
|
function personToString(person) {
|
|
let tmpString;
|
|
if (person.lastName) {
|
|
tmpString = person.lastName;
|
|
} else {
|
|
tmpString = person.firstName;
|
|
}
|
|
if (person.middleName) {
|
|
tmpString += " " + person.middleName[0] + ".";
|
|
}
|
|
if (person.lastName && person.firstName) {
|
|
tmpString += " " + person.firstName[0] + ".";
|
|
}
|
|
return tmpString;
|
|
}
|
|
function authorsString(authors) {
|
|
let authorsStr = authors
|
|
.slice(0, 2)
|
|
.map((author) => personToString(author))
|
|
.join(", ");
|
|
if (authors.length > 2) {
|
|
authorsStr += " и др.";
|
|
}
|
|
return authorsStr;
|
|
}
|
|
|
|
const BookCard = ({
|
|
id,
|
|
title,
|
|
authors,
|
|
reader,
|
|
offline,
|
|
fromSearch,
|
|
collectionDelId,
|
|
fixed,
|
|
filetype,
|
|
}) => {
|
|
const [loaded, setLoaded] = useState(false);
|
|
const [bookImgSrc, setBookImgSrc] = useState("");
|
|
|
|
async function loadImgFromCache() {
|
|
if (window.caches === undefined) {
|
|
setBookImgSrc(axios.defaults.baseURL + "/book/" + id + "/cover");
|
|
return;
|
|
}
|
|
let cache = await window.caches.open("bookCovers");
|
|
let img = await cache.match(`/api/book/${id}/cover`);
|
|
if (img === undefined) {
|
|
if (window.onLine) {
|
|
setBookImgSrc(axios.defaults.baseURL + "/book/" + id + "/cover");
|
|
return;
|
|
} else {
|
|
setBookImgSrc("/favicon.png");
|
|
return;
|
|
}
|
|
}
|
|
let blob = await img.blob();
|
|
setBookImgSrc(URL.createObjectURL(blob));
|
|
}
|
|
useEffect(() => {
|
|
loadImgFromCache();
|
|
}, []);
|
|
return (
|
|
<Link
|
|
className={"book_card" + (fixed ? " fixed" : "")}
|
|
to={
|
|
!offline && !window.onLine
|
|
? false
|
|
: reader === undefined
|
|
? `/book/${id}${fromSearch ? "?from_search=" + fromSearch : ""}`
|
|
: `/reader/${id}`
|
|
}
|
|
style={{
|
|
color: "black",
|
|
textDecoration: "none",
|
|
}}
|
|
>
|
|
{!offline && !window.onLine ? (
|
|
<div className="book_card_deactivate"></div>
|
|
) : (
|
|
<md-ripple></md-ripple>
|
|
)}
|
|
<div
|
|
style={{
|
|
width: "100%",
|
|
overflow: "hidden",
|
|
backgroundImage: "url(" + bookImgSrc + ")",
|
|
backgroundSize: "100%",
|
|
}}
|
|
className="book_card_image"
|
|
>
|
|
<div
|
|
style={{
|
|
position: "absolute",
|
|
left: 5,
|
|
top: 5,
|
|
zIndex: 1,
|
|
background: "var(--md-sys-color-inverse-primary)",
|
|
padding: 5,
|
|
borderRadius: 10,
|
|
}}
|
|
>
|
|
<b>{filetype}</b>
|
|
</div>
|
|
{/* {
|
|
collectionDelId ?
|
|
<div className="book_actions">
|
|
<IconButton onClick={() => {
|
|
axios.post("/collection/"+collectionDelId, {book_id: String(id)})
|
|
}}>
|
|
<Icon>delete</Icon>
|
|
</IconButton>
|
|
</div> : <></>
|
|
} */}
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
height: "100%",
|
|
backdropFilter: "blur(5px)",
|
|
}}
|
|
>
|
|
{loaded ? (
|
|
<></>
|
|
) : (
|
|
<Skeleton
|
|
style={{
|
|
width: 240,
|
|
height: 380,
|
|
lineHeight: "revert",
|
|
}}
|
|
/>
|
|
)}
|
|
<img
|
|
onLoad={() => setLoaded(true)}
|
|
style={{
|
|
pointerEvents: "none",
|
|
boxShadow: "0px 0px 20px gray",
|
|
width: "100%",
|
|
}}
|
|
src={bookImgSrc}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
style={{
|
|
padding: "10px 0px",
|
|
}}
|
|
>
|
|
<span className="h-fit line-clamp-2 break-words">
|
|
<b>{title}</b>
|
|
</span>
|
|
<span
|
|
style={{
|
|
color: "gray",
|
|
}}
|
|
>
|
|
{authorsString(authors)}
|
|
</span>
|
|
</div>
|
|
</Link>
|
|
);
|
|
};
|
|
|
|
export default BookCard;
|