Merge pull request #17559 from antoniobergas/feat/microsite-plugins-dropdown-filter
✨ feat(pluginsFilter): added dropdown filter for plugins list
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { ChipCategory } from '@site/src/util/types';
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
categories: ChipCategory[];
|
||||
handleChipClick: (name: string) => void;
|
||||
};
|
||||
|
||||
const PluginsFilter = ({ categories, handleChipClick }: Props) => {
|
||||
return (
|
||||
<div className="dropdown dropdown--hoverable">
|
||||
<button className="button button--info dropdown__toggle">
|
||||
Categories Filter
|
||||
</button>
|
||||
<ul className="dropdown__menu">
|
||||
{categories.map(chip => {
|
||||
return (
|
||||
<li key={chip.name} onClick={() => handleChipClick(chip.name)}>
|
||||
<div className="dropdown__item">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="dropdown__checkbox"
|
||||
checked={chip.isSelected}
|
||||
onChange={() => handleChipClick(chip.name)}
|
||||
/>
|
||||
<span className="dropdown__label">{chip.name}</span>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PluginsFilter;
|
||||
@@ -1,13 +1,13 @@
|
||||
import Link from '@docusaurus/Link';
|
||||
import Layout from '@theme/Layout';
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { IPluginData, PluginCard } from './_pluginCard';
|
||||
import pluginsStyles from './plugins.module.scss';
|
||||
import { ChipCategory } from '@site/src/util/types';
|
||||
import { truncateDescription } from '@site/src/util/truncateDescription';
|
||||
import PluginsFilter from '@site/src/components/pluginsFilter/pluginsFilter';
|
||||
|
||||
//#region Plugin data import
|
||||
const pluginsContext = require.context(
|
||||
'../../../data/plugins',
|
||||
false,
|
||||
@@ -29,50 +29,137 @@ const plugins = pluginsContext.keys().reduce(
|
||||
|
||||
plugins.corePlugins.sort((a, b) => a.order - b.order);
|
||||
plugins.otherPlugins.sort((a, b) => a.order - b.order);
|
||||
//#endregion
|
||||
|
||||
const Plugins = () => (
|
||||
<Layout>
|
||||
<div
|
||||
className={clsx('container', 'padding--lg', pluginsStyles.pluginsPage)}
|
||||
>
|
||||
<div className="marketplaceBanner">
|
||||
<div className="marketplaceContent">
|
||||
<h2>Plugin Marketplace</h2>
|
||||
const Plugins = () => {
|
||||
const allCategoriesSet = new Set(
|
||||
[...plugins.corePlugins, ...plugins.otherPlugins].map(
|
||||
({ category }) => category,
|
||||
),
|
||||
);
|
||||
const allCategoriesArray = Array.from(allCategoriesSet).map(category => ({
|
||||
name: category,
|
||||
isSelected: false,
|
||||
}));
|
||||
const [categories, setCategories] =
|
||||
useState<ChipCategory[]>(allCategoriesArray);
|
||||
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
||||
const [showCoreFeatures, setShowCoreFeatures] = useState(true);
|
||||
const [showOtherPlugins, setShowOtherPlugins] = useState(true);
|
||||
|
||||
<p>
|
||||
Open source plugins that you can add to your Backstage deployment.
|
||||
Learn how to build a <Link to="/docs/plugins">plugin</Link>.
|
||||
</p>
|
||||
const handleChipClick = (categoryName: string) => {
|
||||
const isSelected =
|
||||
categories.find(category => category.name === categoryName)?.isSelected ||
|
||||
false;
|
||||
|
||||
const newSelectedCategories = isSelected
|
||||
? selectedCategories.filter(c => c !== categoryName)
|
||||
: [...selectedCategories, categoryName];
|
||||
|
||||
setSelectedCategories(newSelectedCategories);
|
||||
|
||||
const newCategories = categories.map(category => {
|
||||
if (category.name === categoryName) {
|
||||
return { ...category, isSelected: !isSelected };
|
||||
}
|
||||
return category;
|
||||
});
|
||||
|
||||
setCategories(newCategories);
|
||||
|
||||
if (!newSelectedCategories.includes('Core Feature')) {
|
||||
setShowCoreFeatures(false);
|
||||
} else {
|
||||
setShowCoreFeatures(true);
|
||||
}
|
||||
|
||||
if (
|
||||
newSelectedCategories.length === 1 &&
|
||||
newSelectedCategories[0] === 'Core Feature'
|
||||
) {
|
||||
setShowOtherPlugins(false);
|
||||
} else {
|
||||
setShowOtherPlugins(true);
|
||||
}
|
||||
|
||||
if (newSelectedCategories.length === 0) {
|
||||
setShowOtherPlugins(true);
|
||||
setShowCoreFeatures(true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div
|
||||
className={clsx('container', 'padding--lg', pluginsStyles.pluginsPage)}
|
||||
>
|
||||
<div className="marketplaceBanner">
|
||||
<div className="marketplaceContent">
|
||||
<h2>Plugin Marketplace</h2>
|
||||
|
||||
<p>
|
||||
Open source plugins that you can add to your Backstage deployment.
|
||||
Learn how to build a <Link to="/docs/plugins">plugin</Link>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
to="/docs/plugins/add-to-marketplace"
|
||||
className="button button--outline button--primary"
|
||||
>
|
||||
Add to Marketplace
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
to="/docs/plugins/add-to-marketplace"
|
||||
className="button button--outline button--primary"
|
||||
>
|
||||
Add to Marketplace
|
||||
</Link>
|
||||
<div className="bulletLine margin-bottom--lg"></div>
|
||||
<div className="pluginsFilterBox">
|
||||
<PluginsFilter
|
||||
categories={categories}
|
||||
handleChipClick={handleChipClick}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showCoreFeatures && (
|
||||
<div>
|
||||
<h2>Core Features</h2>
|
||||
<div className="pluginsContainer margin-bottom--lg">
|
||||
{plugins.corePlugins
|
||||
.filter(
|
||||
pluginData =>
|
||||
!selectedCategories.length ||
|
||||
selectedCategories.includes(pluginData.category),
|
||||
)
|
||||
.map(pluginData => (
|
||||
<PluginCard
|
||||
key={pluginData.title}
|
||||
{...pluginData}
|
||||
></PluginCard>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showOtherPlugins && (
|
||||
<div>
|
||||
<h2>All Plugins</h2>
|
||||
<div className="pluginsContainer margin-bottom--lg">
|
||||
{plugins.otherPlugins
|
||||
.filter(
|
||||
pluginData =>
|
||||
!selectedCategories.length ||
|
||||
selectedCategories.includes(pluginData.category),
|
||||
)
|
||||
.map(pluginData => (
|
||||
<PluginCard
|
||||
key={pluginData.title}
|
||||
{...pluginData}
|
||||
></PluginCard>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="bulletLine margin-bottom--lg"></div>
|
||||
|
||||
<h2>Core Features</h2>
|
||||
|
||||
<div className="pluginsContainer margin-bottom--lg">
|
||||
{plugins.corePlugins.map(pluginData => (
|
||||
<PluginCard key={pluginData.title} {...pluginData}></PluginCard>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<h2>All Plugins</h2>
|
||||
|
||||
<div className="pluginsContainer margin-bottom--lg">
|
||||
{plugins.otherPlugins.map(pluginData => (
|
||||
<PluginCard key={pluginData.title} {...pluginData}></PluginCard>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Plugins;
|
||||
|
||||
@@ -28,10 +28,60 @@
|
||||
:global(.pluginsContainer) {
|
||||
gap: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 300px));
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
:global(.pluginsContainer) {
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
:global(.hidePluginsHeader) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:global(.fit-content) {
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
:global(.pluginsFilterBox) {
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
:global(.dropdown) {
|
||||
float: right;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
:global(.button--info) {
|
||||
background-color: transparent;
|
||||
border-color: var(--ifm-color-primary);
|
||||
color: var(--ifm-color-primary);
|
||||
min-width: 250px;
|
||||
}
|
||||
|
||||
:global(label.dropdown__item) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
margin-top: 5px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ifm-color-primary);
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.dropdown__label) {
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:global(.dropdown__checkbox) {
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export type ChipCategory = {
|
||||
name: string;
|
||||
isSelected: boolean;
|
||||
};
|
||||
Reference in New Issue
Block a user