added spinner

This commit is contained in:
philip-ellis-sp
2023-06-06 10:24:05 -05:00
parent a5d637faa3
commit 5834da640b
9 changed files with 114 additions and 57 deletions

16
package-lock.json generated
View File

@@ -21,6 +21,7 @@
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-markdown": "^8.0.7", "react-markdown": "^8.0.7",
"react-spinners": "^0.13.8",
"react-tabs": "^4.3.0" "react-tabs": "^4.3.0"
}, },
"devDependencies": { "devDependencies": {
@@ -11305,6 +11306,15 @@
"react": ">=15" "react": ">=15"
} }
}, },
"node_modules/react-spinners": {
"version": "0.13.8",
"resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz",
"integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==",
"peerDependencies": {
"react": "^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-tabs": { "node_modules/react-tabs": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-4.3.0.tgz", "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-4.3.0.tgz",
@@ -21875,6 +21885,12 @@
"tiny-warning": "^1.0.0" "tiny-warning": "^1.0.0"
} }
}, },
"react-spinners": {
"version": "0.13.8",
"resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz",
"integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==",
"requires": {}
},
"react-tabs": { "react-tabs": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-4.3.0.tgz", "resolved": "https://registry.npmjs.org/react-tabs/-/react-tabs-4.3.0.tgz",

View File

@@ -34,6 +34,7 @@
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-markdown": "^8.0.7", "react-markdown": "^8.0.7",
"react-spinners": "^0.13.8",
"react-tabs": "^4.3.0" "react-tabs": "^4.3.0"
}, },
"overrides": { "overrides": {

View File

@@ -4,23 +4,14 @@ import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import ThemedImage from '@theme/ThemedImage'; import ThemedImage from '@theme/ThemedImage';
import {addDarkToFileName} from '../../../util/util'; import {addDarkToFileName} from '../../../util/util';
import ReactMarkdown from 'react-markdown'
export default function MarketplaceCard({ export default function MarketplaceCard({
link, post,
title,
tags,
creatorImage,
image,
excerpt,
name,
views,
replies,
readTime,
openDialogFunc, openDialogFunc,
rawData
}) { }) {
function setFilters(e) { function setFilters(e) {
openDialogFunc({"rawData": rawData, "title": title, "image": image}); openDialogFunc({"rawData": post.raw, "title": post.title, "image": post.image, "link": post.link});
} }
return ( return (
@@ -29,31 +20,29 @@ export default function MarketplaceCard({
<div className={styles.cardData}> <div className={styles.cardData}>
<img className={styles.cardEye} src={useBaseUrl('/blog/eye-regular.svg')}></img> <img className={styles.cardEye} src={useBaseUrl('/blog/eye-regular.svg')}></img>
<div className={styles.cardCommentText}>{views}</div> <div className={styles.cardCommentText}>{post.views}</div>
<img className={styles.cardComment} src={useBaseUrl('/blog/comment-light.svg')}></img> <img className={styles.cardComment} src={useBaseUrl('/blog/comment-light.svg')}></img>
<div className={styles.cardCommentText}>{replies}</div> <div className={styles.cardCommentText}>{post.replies}</div>
<img className={styles.cardComment} src={useBaseUrl('/blog/clock-light.svg')}></img>
<div className={styles.cardCommentText}>{readTime} minute read</div>
</div> </div>
<div className={styles.cardUser}> <div className={styles.cardUser}>
<img className={styles.cardFace} src={useBaseUrl(creatorImage)}></img> <img className={styles.cardFace} src={useBaseUrl(post.creatorImage)}></img>
<div className={styles.cardName}>{name}</div> <div className={styles.cardName}>{post.name}</div>
</div> </div>
<div className={styles.cardText}> <div className={styles.cardText}>
<img className={styles.cardImage} src={useBaseUrl(image)}></img> <img className={styles.cardImage} src={useBaseUrl(post.image)}></img>
<div className={styles.cardTitle}>{title}</div> <div className={styles.cardTitle}>{post.title}</div>
<div className={styles.tags}> <div className={styles.tags}>
{tags?.map((tag, index) => { {post.tags?.map((tag, index) => {
if (index > 2) { if (index > 2) {
return ''; return '';
} }
return <div key={tag} className={styles.tag}>{tag}</div>; return <div key={tag} className={styles.tag}>{tag}</div>;
})} })}
</div> </div>
<div className={styles.cardBody}>{excerpt}</div> <ReactMarkdown className={styles.cardBody}>{post.excerpt}</ReactMarkdown>
</div> </div>

View File

@@ -125,3 +125,4 @@
font-size: 16px; font-size: 16px;
} }

View File

@@ -23,6 +23,10 @@ export default function MarketplaceCardDetail({
} }
const goToLink = (link) => {
window.open(link, '_blank')
}
return ( return (
<div className={styles.detailContainer}> <div className={styles.detailContainer}>
@@ -40,6 +44,13 @@ export default function MarketplaceCardDetail({
<TabPanel> <TabPanel>
<ReactMarkdown className={styles.detailTabContent}>{getDivText(details.rawData, "details")}</ReactMarkdown> <ReactMarkdown className={styles.detailTabContent}>{getDivText(details.rawData, "details")}</ReactMarkdown>
<button
className={styles.modalButton}
onClick={async () => {
goToLink(details.link);
}}>
See More
</button>
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<ReactMarkdown className={styles.detailTabContent}>{getDivText(details.rawData, "requirements")}</ReactMarkdown> <ReactMarkdown className={styles.detailTabContent}>{getDivText(details.rawData, "requirements")}</ReactMarkdown>

View File

@@ -28,3 +28,26 @@
.detailTabs { .detailTabs {
margin: 10px; margin: 10px;
} }
.modalButton {
border: 1px solid var(--ifm-color-primary);
box-shadow: 1px 4px 10px rgba(0, 0, 0, 0.12);
border-radius: 24px;
color: var(--ifm-color-primary);
margin: 10px;
padding: 10px;
text-align: center;
width: 100px;
background-color: #ffffff31;
}
.modalButton:hover {
cursor: pointer;
top: -2px;
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.4);
background-color: #dae1e9;
color: #005fc4;
}

View File

@@ -2,6 +2,9 @@ import React from 'react';
import styles from './styles.module.css'; import styles from './styles.module.css';
import MarketplaceCard from '../MarketplaceCard'; import MarketplaceCard from '../MarketplaceCard';
import Modal from 'react-modal'; import Modal from 'react-modal';
import useBaseUrl from '@docusaurus/useBaseUrl';
import BounceLoader from "react-spinners/BounceLoader";
import {getMarketplacePosts, getMarketplaceTopic, getMarketplaceTopicRaw} from '../../../services/DiscourseService'; import {getMarketplacePosts, getMarketplaceTopic, getMarketplaceTopicRaw} from '../../../services/DiscourseService';
import MarketplaceCardDetail from '../MarketplaceCardDetail'; import MarketplaceCardDetail from '../MarketplaceCardDetail';
@@ -11,6 +14,7 @@ export default function BlogCards({
const [cardData, setCardData] = React.useState(); const [cardData, setCardData] = React.useState();
const [detailsOpen, setDetailsOpen] = React.useState(false); const [detailsOpen, setDetailsOpen] = React.useState(false);
const [details, setDetails] = React.useState(""); const [details, setDetails] = React.useState("");
const [loadingCards, setLoadingCards] = React.useState(true);
const getPosts = async () => { const getPosts = async () => {
const data = await getMarketplacePosts(filterCallback.join(',')); const data = await getMarketplacePosts(filterCallback.join(','));
@@ -23,7 +27,7 @@ export default function BlogCards({
} else { } else {
setCardData(undefined); setCardData(undefined);
} }
setLoadingCards(false)
}; };
const openDialog = (data) => { const openDialog = (data) => {
@@ -33,6 +37,8 @@ export default function BlogCards({
Modal.setAppElement('#__docusaurus'); Modal.setAppElement('#__docusaurus');
React.useEffect(() => { React.useEffect(() => {
getPosts(); getPosts();
setCardData(undefined);
setLoadingCards(true);
}, [filterCallback]); }, [filterCallback]);
if (cardData) { if (cardData) {
@@ -41,20 +47,9 @@ export default function BlogCards({
<div className={styles.gridContainer}> <div className={styles.gridContainer}>
{cardData.map(function(a, index){ {cardData.map(function(a, index){
return <MarketplaceCard return <MarketplaceCard
key={a.link} post={a}
id={index + a.link} id={index + a.link}
excerpt={a.excerpt}
name={a.name}
tags={a.tags}
link={a.link}
image={a.image}
title={a.title}
views={a.views}
replies={a.replies}
readTime={a.readTime}
creatorImage={a.creatorImage}
openDialogFunc={openDialog} openDialogFunc={openDialog}
rawData={a.raw}
></MarketplaceCard> ></MarketplaceCard>
})} })}
</div> </div>
@@ -65,18 +60,26 @@ export default function BlogCards({
<div> <div>
<MarketplaceCardDetail details={details}></MarketplaceCardDetail> <MarketplaceCardDetail details={details}></MarketplaceCardDetail>
</div> </div>
<button <img className={styles.cardExit} src={useBaseUrl('/icons/circle-xmark-regular.svg')}
className={styles.modalButton}
onClick={async () => { onClick={async () => {
setDetailsOpen(false); setDetailsOpen(false);
}}> }}
OK ></img>
</button>
</Modal> </Modal>
</div> </div>
); );
} else if (loadingCards) {
return <BounceLoader
className={styles.spinnerCenter}
color={"#0033a1"}
loading={true}
size={150}
aria-label="Loading Spinner"
data-testid="loader"
/>
} else { } else {
return <div className={styles.noFound}> No Marketplace Item Found with the Given Search Criteria</div>; return <div className={styles.noFound}> No Marketplace Item Found with the Given Search Criteria</div>;
} }
@@ -89,6 +92,7 @@ async function getPostList(topic) {
console.log(fullTopic) console.log(fullTopic)
console.log(fullTopicRaw) console.log(fullTopicRaw)
return { return {
id: topic.id,
raw: fullTopicRaw, raw: fullTopicRaw,
name: fullTopic.details.created_by.name, name: fullTopic.details.created_by.name,
excerpt: styleExcerpt(topic.excerpt), excerpt: styleExcerpt(topic.excerpt),
@@ -115,6 +119,8 @@ function getavatarURL(avatar) {
function styleExcerpt(excerpt) { function styleExcerpt(excerpt) {
if (excerpt) { if (excerpt) {
// remove any strings that have colons between them
excerpt = excerpt.replace(/:[^:]*:/g,"")
if (excerpt.length > 150) { if (excerpt.length > 150) {
return excerpt.slice(0, 150) + "..." return excerpt.slice(0, 150) + "..."
} else { } else {

View File

@@ -47,23 +47,32 @@
overflow-y: auto; overflow-y: auto;
} }
.modalButton {
border: 1px solid var(--ifm-color-primary);
box-shadow: 1px 4px 10px rgba(0, 0, 0, 0.12);
border-radius: 24px;
color: var(--ifm-color-primary);
margin: 10px;
padding: 10px;
text-align: center;
width: 120px;
background-color: #ffffff31;
.cardExit {
position: absolute;
top: 6px;
right: 6px;
fill: #96a9bb;
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
filter: invert(79%) sepia(12%) saturate(484%) hue-rotate(168deg) brightness(84%) contrast(84%);
margin-left: 5px;
height: 24px;
width: 24px;
transition: all 0.2s;
} }
.modalButton:hover { .cardExit:hover {
top: 8px;
cursor: pointer; cursor: pointer;
top: -4px; height: 23px;
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.4); width: 23px;
background-color: #dae1e9; }
color: #005fc4;
.spinnerCenter {
margin: 100px auto;
max-width: 1300px;
margin-bottom: 50px;
} }

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"/></svg>

After

Width:  |  Height:  |  Size: 574 B