mirror of
https://github.com/LukeHagar/developer.sailpoint.com.git
synced 2025-12-09 12:27:47 +00:00
created initial marketplace with linking to details
This commit is contained in:
21
src/components/marketplace/MarketplaceBanner/index.js
Normal file
21
src/components/marketplace/MarketplaceBanner/index.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
|
||||||
|
export default function MarketplaceBanner() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div className={styles.imageContainer}>
|
||||||
|
<div className={styles.blogHeaderText}>
|
||||||
|
SailPoint Developer Marketplace
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
.blogHeaderText {
|
||||||
|
position: relative;
|
||||||
|
color: var(--ifm-color-primary);
|
||||||
|
font-size: 30px;
|
||||||
|
max-width: 396px;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 100%;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.background {
|
||||||
|
width: 100%;
|
||||||
|
object-fit: repeat;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageContainer {
|
||||||
|
width: 100%;
|
||||||
|
height: 180px;
|
||||||
|
background-image: url('../../../../static/blog/blog_banner_template.png');
|
||||||
|
background-repeat: repeat;
|
||||||
|
}
|
||||||
65
src/components/marketplace/MarketplaceCard/index.js
Normal file
65
src/components/marketplace/MarketplaceCard/index.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import ThemedImage from '@theme/ThemedImage';
|
||||||
|
import {addDarkToFileName} from '../../../util/util';
|
||||||
|
export default function MarketplaceCard({
|
||||||
|
link,
|
||||||
|
title,
|
||||||
|
tags,
|
||||||
|
creatorImage,
|
||||||
|
image,
|
||||||
|
excerpt,
|
||||||
|
name,
|
||||||
|
views,
|
||||||
|
replies,
|
||||||
|
readTime,
|
||||||
|
openDialogFunc,
|
||||||
|
rawData
|
||||||
|
}) {
|
||||||
|
|
||||||
|
function setFilters(e) {
|
||||||
|
openDialogFunc(rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div onClick={(e) => setFilters(e)}>
|
||||||
|
<div className={styles.card} >
|
||||||
|
|
||||||
|
<div className={styles.cardData}>
|
||||||
|
<img className={styles.cardEye} src={useBaseUrl('/blog/eye-regular.svg')}></img>
|
||||||
|
<div className={styles.cardCommentText}>{views}</div>
|
||||||
|
<img className={styles.cardComment} src={useBaseUrl('/blog/comment-light.svg')}></img>
|
||||||
|
<div className={styles.cardCommentText}>{replies}</div>
|
||||||
|
<img className={styles.cardComment} src={useBaseUrl('/blog/clock-light.svg')}></img>
|
||||||
|
<div className={styles.cardCommentText}>{readTime} minute read</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.cardUser}>
|
||||||
|
<img className={styles.cardFace} src={useBaseUrl(creatorImage)}></img>
|
||||||
|
<div className={styles.cardName}>{name}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div className={styles.cardText}>
|
||||||
|
<img className={styles.cardImage} src={useBaseUrl(image)}></img>
|
||||||
|
<div className={styles.cardTitle}>{title}</div>
|
||||||
|
<div className={styles.tags}>
|
||||||
|
{tags?.map((tag, index) => {
|
||||||
|
if (index > 2) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return <div key={tag} className={styles.tag}>{tag}</div>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className={styles.cardBody}>{excerpt}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
127
src/components/marketplace/MarketplaceCard/styles.module.css
Normal file
127
src/components/marketplace/MarketplaceCard/styles.module.css
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/* Getting Started Card */
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 20px;
|
||||||
|
height: 650px;
|
||||||
|
/* UI Properties */
|
||||||
|
background: var(--dev-card-background);
|
||||||
|
box-shadow: var(--dev-card-shadow);
|
||||||
|
border: 1px solid var(--dev-card-background);
|
||||||
|
border-radius: 40px;
|
||||||
|
opacity: 1;
|
||||||
|
transition: all 0.3s;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
transform: translate(0px, -5px);
|
||||||
|
box-shadow: var(--dev-card-selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.cardText {
|
||||||
|
position: absolute;
|
||||||
|
margin: 22px;
|
||||||
|
min-width: 170px;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cardTitle {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardBody {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--dev-secondary-text);
|
||||||
|
background-color: var(--dev-tag-highlight);
|
||||||
|
padding: 0px 8px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
margin: 0px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.cardUser {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 25px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardFace {
|
||||||
|
border-radius: 9999px;
|
||||||
|
margin: auto;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardName {
|
||||||
|
min-width: 170px;
|
||||||
|
margin-top: 7px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.cardData {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 50px;
|
||||||
|
left: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardEye {
|
||||||
|
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: 18px;
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardComment {
|
||||||
|
margin-left: 10px;
|
||||||
|
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%);
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardCommentText {
|
||||||
|
color: #96a9ba;
|
||||||
|
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
17
src/components/marketplace/MarketplaceCardDetail/index.js
Normal file
17
src/components/marketplace/MarketplaceCardDetail/index.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import ThemedImage from '@theme/ThemedImage';
|
||||||
|
import {addDarkToFileName} from '../../../util/util';
|
||||||
|
export default function MarketplaceCardDetail({
|
||||||
|
details
|
||||||
|
}) {
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div onClick={(e) => setFilters(e)}>
|
||||||
|
<div>{details}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/* Getting Started Card */
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
margin-top: 20px;
|
||||||
|
height: 650px;
|
||||||
|
/* UI Properties */
|
||||||
|
background: var(--dev-card-background);
|
||||||
|
box-shadow: var(--dev-card-shadow);
|
||||||
|
border: 1px solid var(--dev-card-background);
|
||||||
|
border-radius: 40px;
|
||||||
|
opacity: 1;
|
||||||
|
transition: all 0.3s;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
transform: translate(0px, -5px);
|
||||||
|
box-shadow: var(--dev-card-selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.cardText {
|
||||||
|
position: absolute;
|
||||||
|
margin: 22px;
|
||||||
|
min-width: 170px;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cardTitle {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardBody {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--dev-secondary-text);
|
||||||
|
background-color: var(--dev-tag-highlight);
|
||||||
|
padding: 0px 8px;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
margin: 0px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.cardUser {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 25px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardFace {
|
||||||
|
border-radius: 9999px;
|
||||||
|
margin: auto;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardName {
|
||||||
|
min-width: 170px;
|
||||||
|
margin-top: 7px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.cardData {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 50px;
|
||||||
|
left: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardEye {
|
||||||
|
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: 18px;
|
||||||
|
width: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardComment {
|
||||||
|
margin-left: 10px;
|
||||||
|
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%);
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardCommentText {
|
||||||
|
color: #96a9ba;
|
||||||
|
/* computed from codepen https://codepen.io/sosuke/pen/Pjoqqp */
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
129
src/components/marketplace/MarketplaceCards/index.js
Normal file
129
src/components/marketplace/MarketplaceCards/index.js
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
import MarketplaceCard from '../MarketplaceCard';
|
||||||
|
import Modal from 'react-modal';
|
||||||
|
|
||||||
|
import {getMarketplacePosts, getMarketplaceTopic, getMarketplaceTopicRaw} from '../../../services/DiscourseService';
|
||||||
|
import MarketplaceCardDetail from '../MarketplaceCardDetail';
|
||||||
|
export default function BlogCards({
|
||||||
|
filterCallback
|
||||||
|
}) {
|
||||||
|
const [cardData, setCardData] = React.useState();
|
||||||
|
const [detailsOpen, setDetailsOpen] = React.useState(false);
|
||||||
|
const [details, setDetails] = React.useState("");
|
||||||
|
|
||||||
|
const getPosts = async () => {
|
||||||
|
const data = await getMarketplacePosts(filterCallback.join(','));
|
||||||
|
const resultset = []
|
||||||
|
if (data.topics) {
|
||||||
|
for (const topic of data.topics) {
|
||||||
|
resultset.push(await getPostList(topic))
|
||||||
|
}
|
||||||
|
setCardData(resultset);
|
||||||
|
} else {
|
||||||
|
setCardData(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const openDialog = (data) => {
|
||||||
|
setDetails(data);
|
||||||
|
setDetailsOpen(true);
|
||||||
|
}
|
||||||
|
Modal.setAppElement('#__docusaurus');
|
||||||
|
React.useEffect(() => {
|
||||||
|
getPosts();
|
||||||
|
}, [filterCallback]);
|
||||||
|
|
||||||
|
if (cardData) {
|
||||||
|
return (
|
||||||
|
<div className={styles.center}>
|
||||||
|
<div className={styles.gridContainer}>
|
||||||
|
{cardData.map(function(a, index){
|
||||||
|
return <MarketplaceCard
|
||||||
|
key={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}
|
||||||
|
rawData={a.raw}
|
||||||
|
></MarketplaceCard>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<Modal
|
||||||
|
isOpen={detailsOpen}
|
||||||
|
className={styles.modal}
|
||||||
|
contentLabel="Details">
|
||||||
|
<div>
|
||||||
|
Modal Works!
|
||||||
|
<MarketplaceCardDetail details={details}></MarketplaceCardDetail>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className={styles.modalButton}
|
||||||
|
onClick={async () => {
|
||||||
|
setDetailsOpen(false);
|
||||||
|
}}>
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <div className={styles.noFound}> No Marketplace Item Found with the Given Search Criteria</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPostList(topic) {
|
||||||
|
console.log(topic)
|
||||||
|
const fullTopic = await getMarketplaceTopic(topic.id);
|
||||||
|
const fullTopicRaw = await getMarketplaceTopicRaw(topic.id);
|
||||||
|
console.log(fullTopic)
|
||||||
|
console.log(fullTopicRaw)
|
||||||
|
return {
|
||||||
|
raw: fullTopicRaw,
|
||||||
|
name: fullTopic.details.created_by.name,
|
||||||
|
excerpt: styleExcerpt(topic.excerpt),
|
||||||
|
creatorImage: getavatarURL(fullTopic.details.created_by.avatar_template),
|
||||||
|
tags: topic.tags,
|
||||||
|
image: fullTopic.image_url,
|
||||||
|
link:
|
||||||
|
'https://developer.sailpoint.com/discuss/t/' +
|
||||||
|
topic.slug +
|
||||||
|
'/' +
|
||||||
|
topic.id,
|
||||||
|
title: topic.title,
|
||||||
|
views: fullTopic.views,
|
||||||
|
liked: topic.like_count,
|
||||||
|
replies: fullTopic.posts_count,
|
||||||
|
solution: topic.has_accepted_answer,
|
||||||
|
readTime: parseInt(fullTopic.word_count/100),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getavatarURL(avatar) {
|
||||||
|
return "https://developer.sailpoint.com" + avatar.replace("{size}", "120")
|
||||||
|
}
|
||||||
|
|
||||||
|
function styleExcerpt(excerpt) {
|
||||||
|
if (excerpt) {
|
||||||
|
if (excerpt.length > 150) {
|
||||||
|
return excerpt.slice(0, 150) + "..."
|
||||||
|
} else {
|
||||||
|
return excerpt.replace("…", "")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/* Getting Started Card container */
|
||||||
|
.gridContainer {
|
||||||
|
display: grid;
|
||||||
|
place-content: center;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(345px, 1fr));
|
||||||
|
grid-gap: 40px;
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-right: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
margin: 0px auto;
|
||||||
|
max-width: 1300px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noFound {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--dev-secondary-text);
|
||||||
|
padding: 8px;
|
||||||
|
margin: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 50px;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
margin-right: -50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
box-shadow: 2px 3px 10px rgba(0, 0, 0, 0.25);
|
||||||
|
border-radius: 20px;
|
||||||
|
background-color: var(--dev-card-background);
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalButton:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
top: -4px;
|
||||||
|
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.4);
|
||||||
|
background-color: #dae1e9;
|
||||||
|
color: #005fc4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
|
||||||
|
export default function BlogSidebarButton({
|
||||||
|
filterCallback,
|
||||||
|
text
|
||||||
|
}) {
|
||||||
|
const [isActive, setIsActive] = React.useState(false);
|
||||||
|
const activeClass = isActive ? styles.tagSelected : ''
|
||||||
|
function setFilters(e, f) {
|
||||||
|
filterCallback(f)
|
||||||
|
setIsActive(current => !current);
|
||||||
|
}
|
||||||
|
return <div key={text} onClick={(e) => setFilters(e, text)} className={activeClass + ' ' + styles.tag}>{text}</div>
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--dev-secondary-text);
|
||||||
|
padding: 8px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: var(--dev-text-color-normal);
|
||||||
|
transition: background-color 500ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagSelected {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
background-color: var(--dev-secondary-text);
|
||||||
|
color: var(--dev-card-background);
|
||||||
|
padding: 8px;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: var(--dev-text-color-normal);
|
||||||
|
transition: background-color 500ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--dev-text-color-normal);
|
||||||
|
color: var(--dev-card-background);
|
||||||
|
}
|
||||||
|
|
||||||
72
src/components/marketplace/MarketplaceSidebar/index.js
Normal file
72
src/components/marketplace/MarketplaceSidebar/index.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import { getTags } from '../../../services/DiscourseService';
|
||||||
|
import BlogSidebarButton from './BlogSidebarButton';
|
||||||
|
|
||||||
|
export default function BlogSidebar({
|
||||||
|
filterCallback
|
||||||
|
}) {
|
||||||
|
const [tagProductData, setTagProductData] = React.useState();
|
||||||
|
const [tagTechnologyData, setTagTechnologyData] = React.useState();
|
||||||
|
const [filterTags, setFilterTags] = React.useState(true);
|
||||||
|
|
||||||
|
const getTagData = async () => {
|
||||||
|
const data = await getTags();
|
||||||
|
const tagTechnologyResultset = []
|
||||||
|
const tagProductResultset = []
|
||||||
|
for (const tagGroup of data.extras.tag_groups) {
|
||||||
|
if (tagGroup.id === 20) {
|
||||||
|
for (const tag of tagGroup.tags) {
|
||||||
|
tagProductResultset.push(tag.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tagGroup.id === 17) {
|
||||||
|
for (const tag of tagGroup.tags) {
|
||||||
|
tagTechnologyResultset.push(tag.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTagProductData(tagProductResultset)
|
||||||
|
setTagTechnologyData(tagTechnologyResultset)
|
||||||
|
};
|
||||||
|
|
||||||
|
function toggleSeeAll() {
|
||||||
|
filterTags ? setFilterTags(false) : setFilterTags(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
getTagData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const filterText = filterTags ? 'See All Tags' : 'See Less Tags'
|
||||||
|
|
||||||
|
if (tagProductData && tagTechnologyData) {
|
||||||
|
return (
|
||||||
|
<div className={styles.sidebar}>
|
||||||
|
<div className={styles.tagHeader}>Posts by Product</div>
|
||||||
|
<div className={styles.tagContainer}>
|
||||||
|
{tagProductData.map(function(a, index){
|
||||||
|
return <BlogSidebarButton key={a} text={a} filterCallback={filterCallback}></BlogSidebarButton>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className={styles.tagHeader}>Posts by Identity Governance</div>
|
||||||
|
<div className={styles.tagContainer}>
|
||||||
|
{tagTechnologyData.map(function(a, index){
|
||||||
|
return <div key={'div' + a} className={index > 10 && filterTags ? styles.hidden : ''} > <BlogSidebarButton key={a} text={a} filterCallback={filterCallback}></BlogSidebarButton></div>
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className={styles.seeAll} onClick={(e) => toggleSeeAll()}>
|
||||||
|
{filterText}
|
||||||
|
{/* <img className={styles.caretDown} src={useBaseUrl('/blog/caret-down-thin.svg')}></img> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <div></div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
.sidebar {
|
||||||
|
width: 400px;
|
||||||
|
height: 100%;
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagHeader {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tagContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.seeAll {
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--dev-secondary-text);
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
width: 100%;
|
||||||
|
transition: background-color 500ms;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.seeAll:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: var(--dev-text-color-normal);
|
||||||
|
color: var(--dev-card-background);
|
||||||
|
}
|
||||||
41
src/pages/marketplace.js
Normal file
41
src/pages/marketplace.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import Link from '@docusaurus/Link';
|
||||||
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
|
import Layout from '@theme/Layout';
|
||||||
|
import MarketplaceBanner from '../components/marketplace/MarketplaceBanner';
|
||||||
|
|
||||||
|
import styles from './marketplace.module.css';
|
||||||
|
import MarketplaceCards from '../components/marketplace/MarketplaceCards';
|
||||||
|
import MarketplaceSidebar from '../components/marketplace/MarketplaceSidebar';
|
||||||
|
|
||||||
|
export default function Marketplace() {
|
||||||
|
const [filteredProduct, setFilteredProduct] = React.useState([]);
|
||||||
|
|
||||||
|
const {siteConfig} = useDocusaurusContext();
|
||||||
|
|
||||||
|
const handleClick = (data) => {
|
||||||
|
var tempFilter = filteredProduct.slice()
|
||||||
|
|
||||||
|
const index = tempFilter.indexOf(data);
|
||||||
|
if (index !== -1) {
|
||||||
|
tempFilter.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
tempFilter.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilteredProduct(tempFilter)
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Layout description="The SailPoint Developer Community has everything you need to build, extend, and automate scalable identity solutions.">
|
||||||
|
<main>
|
||||||
|
<MarketplaceBanner />
|
||||||
|
<div className={styles.blogContainer}>
|
||||||
|
<div className={styles.blogSidbarContainer}><MarketplaceSidebar filterCallback={handleClick}/></div>
|
||||||
|
<div className={styles.blogCardContainer}><MarketplaceCards filterCallback={filteredProduct}/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
src/pages/marketplace.module.css
Normal file
17
src/pages/marketplace.module.css
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.blogContainer {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blogSidbarContainer {
|
||||||
|
flex: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 870px) {
|
||||||
|
.blogSidbarContainer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blogCardContainer {
|
||||||
|
flex: 95%;
|
||||||
|
}
|
||||||
@@ -26,6 +26,23 @@ export async function getBlogPosts(tags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getMarketplacePosts(tags) {
|
||||||
|
let url = ''
|
||||||
|
if (tags) {
|
||||||
|
url = 'https://developer.identitysoon.com/discuss/search.json?q=category:show-and-tell+tags:' + tags
|
||||||
|
} else {
|
||||||
|
url = 'https://developer.identitysoon.com/discuss/search.json?q=category:show-and-tell'
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
url,
|
||||||
|
);
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getTopic(id) {
|
export async function getTopic(id) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@@ -37,6 +54,28 @@ export async function getTopic(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getMarketplaceTopic(id) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
'https://developer.identitysoon.com/discuss/t/' + id + '.json',
|
||||||
|
);
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMarketplaceTopicRaw(id) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
'https://developer.identitysoon.com/discuss/raw/' + id + '.json',
|
||||||
|
);
|
||||||
|
return await response.text();
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function getTags() {
|
export async function getTags() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
|
|||||||
Reference in New Issue
Block a user