🌁 Generalizing the card component Part 1

This commit is contained in:
2021-08-19 15:38:18 -07:00
parent 2184b20887
commit 7aa3db125b
5 changed files with 196 additions and 92 deletions

View File

@@ -49,6 +49,19 @@ $border-color: red;
overflow: hidden;
text-overflow: ellipsis;
}
.partial-rounded-card-image {
img {
border-top-left-radius: 0.3rem;
border-top-right-radius: 0.3rem;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
.rounded-card-image {
img {
border-radius: 0.3rem;
}
}
}
.card-container {
display: grid;
@@ -59,7 +72,7 @@ $border-color: red;
.card {
// max-width: 500px;
margin: 0 0 15px 0;
.card-image {
.partial-rounded-card-image {
img {
border-top-left-radius: 0.3rem;
border-top-right-radius: 0.3rem;
@@ -67,6 +80,9 @@ $border-color: red;
border-bottom-right-radius: 0;
}
}
.rounded-card-image {
border-radius: 0.3rem;
}
.is-horizontal {
flex-direction: row;
@@ -126,18 +142,18 @@ $border-color: red;
// Search
.search {
.main-search-bar {
border: 0;
border-bottom: 1px solid #999;
border-radius: 0;
outline: 0;
background: transparent;
box-shadow: none;
border: 0;
border-bottom: 1px solid #999;
border-radius: 0;
outline: 0;
background: transparent;
box-shadow: none;
}
}
// Library
.library {
table {
tr{
tr {
td {
border: 0 none;
.card {
@@ -147,8 +163,7 @@ $border-color: red;
}
}
}
}
}
tbody {
padding: 10px 0 0 0;
}

View File

@@ -0,0 +1,52 @@
import React, { ReactElement } from "react";
import PropTypes from "prop-types";
import { isEmpty, isNil } from "lodash";
interface ICardProps {
orientation: string;
imageUrl: string;
hasDetails: boolean;
title?: PropTypes.ReactElementLike | null;
children?: PropTypes.ReactNodeLike;
}
const renderCard = (props): ReactElement => {
switch (props.orientation) {
case "horizontal":
return <>horiztonal</>;
case "vertical":
return (
<div>
<div className="card generic-card">
<div>
<div
className={
props.hasDetails
? "partial-rounded-card-image"
: "rounded-card-image"
}
>
<figure>
<img src={props.imageUrl} alt="Placeholder image" />
</figure>
</div>
{props.hasDetails && (
<div className="card-content">
{isNil(props.title) ? "No Name" : props.title}
{props.children}
</div>
)}
</div>
</div>
</div>
);
default:
return <></>;
}
};
export const Card = (props: ICardProps): ReactElement => {
return renderCard(props);
};
export default Card;

View File

@@ -1,13 +1,13 @@
import React, { useState, useEffect, useCallback, ReactElement } from "react";
import { useParams } from "react-router-dom";
import Card from "./Card";
import Card from "./Carda";
import MatchResult from "./MatchResult";
import ComicVineSearchForm from "./ComicVineSearchForm";
import { css } from "@emotion/react";
import PuffLoader from "react-spinners/PuffLoader";
import { isEmpty, isUndefined, isNil } from "lodash";
import { IExtractedComicBookCoverFile, RootState } from "threetwo-ui-typings";
import { RootState } from "threetwo-ui-typings";
import { fetchComicVineMatches } from "../actions/fileops.actions";
import { getComicBookDetailById } from "../actions/comicinfo.actions";
import { Drawer, Divider } from "antd";
@@ -16,6 +16,10 @@ const prettyBytes = require("pretty-bytes");
import "antd/dist/antd.css";
import { useDispatch, useSelector } from "react-redux";
import {
removeLeadingPeriod,
escapePoundSymbol,
} from "../shared/utils/formatting.utils";
type ComicDetailProps = {};
/**
@@ -60,7 +64,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
setVisible(false);
};
const [active, setActive] = useState(0);
const [active, setActive] = useState(1);
const createDescriptionMarkup = (html) => {
return { __html: html };
};
@@ -71,7 +75,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
// Tab groups for ComicVine metadata
const tabGroup = [
{
id: 0,
id: 1,
name: "Volume Information",
content: isComicBookMetadataAvailable ? (
<>
@@ -130,7 +134,7 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
) : null,
},
{
id: 1,
id: 2,
name: "Other Metadata",
content: <div>bastard</div>,
},
@@ -158,85 +162,96 @@ export const ComicDetail = ({}: ComicDetailProps): ReactElement => {
);
};
const RawFileDetails = (props) => (
<div className="content comic-detail">
<dl>
<dt>Raw File Details</dt>
<dd>{props.data.containedIn}</dd>
<dd>{prettyBytes(props.data.fileSize)}</dd>
<dd>{props.data.path}</dd>
<dd>
<span className="tag is-primary">{props.data.extension}</span>
</dd>
</dl>
</div>
);
const ComicVineDetails = (props) => (
<div className="content comic-detail">
<dl>
<dt>ComicVine Metadata</dt>
<dd className="is-size-7">
Last scraped on{" "}
{dayjs(props.updatedAt).format("MMM D YYYY [at] h:mm a")}
</dd>
<dd>
<h6>{props.data.name}</h6>
</dd>
<dd>{props.data.number}</dd>
<dd>
<div className="field is-grouped is-grouped-multiline">
<div className="control">
<div className="tags has-addons">
<span className="tag is-light">Type</span>
<span className="tag is-warning">
{props.data.resource_type}
</span>
</div>
</div>
<div className="control">
<div className="tags has-addons">
<span className="tag is-light">ComicVine Issue ID</span>
<span className="tag is-success">{props.data.id}</span>
</div>
</div>
</div>
</dd>
</dl>
</div>
);
let imagePath = "";
let comicBookTitle = "";
if (!isNil(comicBookDetailData.rawFilDetails)) {
const encodedFilePath = encodeURI(
"http://localhost:3000" +
removeLeadingPeriod(comicBookDetailData.rawFilDetails.path),
);
imagePath = escapePoundSymbol(encodedFilePath);
comicBookTitle = comicBookDetailData.rawFilDetails.name;
} else if (
!isNil(comicBookDetailData.sourcedMetadata) &&
!isNil(comicBookDetailData.sourcedMetadata.comicvine)
) {
imagePath = comicBookDetailData.sourcedMetadata.comicvine.image.small_url;
comicBookTitle = comicBookDetailData.sourcedMetadata.comicvine.name;
}
return (
<section className="container">
<div className="section">
{!isNil(comicBookDetailData) && !isEmpty(comicBookDetailData) && (
<>
<h1 className="title">{comicBookDetailData.rawFileDetails.name}</h1>
<h1 className="title">{comicBookTitle}</h1>
<div className="columns">
<div className="column is-narrow">
<Card
comicBookCoversMetadata={comicBookDetailData.rawFileDetails}
hasTitle={false}
isHorizontal={false}
imageUrl={imagePath}
orientation={"vertical"}
hasDetails={false}
/>
</div>
<div className="column">
<div className="content comic-detail">
<dl>
<dt>Raw File Details</dt>
<dd>{comicBookDetailData.rawFileDetails.containedIn}</dd>
<dd>
{prettyBytes(comicBookDetailData.rawFileDetails.fileSize)}
</dd>
<dd>{comicBookDetailData.rawFileDetails.path}</dd>
<dd>
<span className="tag is-primary">
{comicBookDetailData.rawFileDetails.extension}
</span>
</dd>
</dl>
</div>
{!isNil(comicBookDetailData.sourcedMetadata.comicvine) && (
<div className="content comic-detail">
{!isNil(comicBookDetailData.rawFileDetails) && (
<>
<RawFileDetails data={comicBookDetailData.rawFileDetails} />
<Divider />
<dl>
<dt>ComicVine Metadata</dt>
<dd className="is-size-7">
Last scraped on{" "}
{dayjs(comicBookDetailData.updatedAt).format(
"MMM D YYYY [at] h:mm a",
)}
</dd>
<dd>
<h6>
{comicBookDetailData.sourcedMetadata.comicvine.name}
</h6>
</dd>
<dd>
{comicBookDetailData.sourcedMetadata.comicvine.number}
</dd>
<dd>
<div className="field is-grouped is-grouped-multiline">
<div className="control">
<div className="tags has-addons">
<span className="tag is-light">Type</span>
<span className="tag is-warning">
{
comicBookDetailData.sourcedMetadata.comicvine
.resource_type
}
</span>
</div>
</div>
<div className="control">
<div className="tags has-addons">
<span className="tag is-light">
ComicVine Issue ID
</span>
<span className="tag is-success">
{
comicBookDetailData.sourcedMetadata.comicvine
.id
}
</span>
</div>
</div>
</div>
</dd>
</dl>
</div>
</>
)}
{!isNil(comicBookDetailData.sourcedMetadata.comicvine) && (
<ComicVineDetails
data={comicBookDetailData.sourcedMetadata.comicvine}
updatedAt={comicBookDetailData.updatedAt}
/>
)}
<button
className="button is-small"

View File

@@ -56,6 +56,7 @@ const mapDispatchToProps = (dispatch) => ({
paginationOptions: {
page: 0,
limit: 5,
sort: { updatedAt: "-1" },
},
}),
);

View File

@@ -1,6 +1,12 @@
import React from "react";
import Card from "./Card";
import { map } from "lodash";
import React, { ReactElement } from "react";
import Card from "./Carda";
import { Link } from "react-router-dom";
import ellipsize from "ellipsize";
import {
removeLeadingPeriod,
escapePoundSymbol,
} from "../shared/utils/formatting.utils";
import { isNil, map } from "lodash";
type RecentlyImportedProps = {
comicBookCovers: any;
@@ -8,17 +14,32 @@ type RecentlyImportedProps = {
export const RecentlyImported = ({
comicBookCovers,
}: RecentlyImportedProps) => (
}: RecentlyImportedProps): ReactElement => (
<section className="card-container">
{map(comicBookCovers.docs, ({ _id, rawFileDetails }) => {
{map(comicBookCovers.docs, ({ _id, rawFileDetails, sourcedMetadata }) => {
let imagePath = "";
let comicName = "";
if (!isNil(rawFileDetails)) {
const encodedFilePath = encodeURI(
"http://localhost:3000" + removeLeadingPeriod(rawFileDetails.path),
);
imagePath = escapePoundSymbol(encodedFilePath);
comicName = rawFileDetails.name;
} else if (!isNil(sourcedMetadata)) {
imagePath = sourcedMetadata.comicvine.image.small_url;
comicName = sourcedMetadata.comicvine.name;
}
const titleElement = (
<Link to={"/comic/details/" + _id}>{ellipsize(comicName, 18)}</Link>
);
return (
<Card
key={_id}
comicBookCoversMetadata={rawFileDetails}
mongoObjId={_id}
hasTitle
isHorizontal={false}
/>
orientation={"vertical"}
imageUrl={imagePath}
hasDetails
title={comicName ? titleElement : null}
></Card>
);
})}
</section>