Skip to content

Commit 3c0fa36

Browse files
authored
Merge pull request backstage#17559 from antoniobergas/feat/microsite-plugins-dropdown-filter
✨ feat(pluginsFilter): added dropdown filter for plugins list
2 parents 2d98053 + e64ebe6 commit 3c0fa36

4 files changed

Lines changed: 219 additions & 42 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ChipCategory } from '@site/src/util/types';
2+
import React from 'react';
3+
4+
type Props = {
5+
categories: ChipCategory[];
6+
handleChipClick: (name: string) => void;
7+
};
8+
9+
const PluginsFilter = ({ categories, handleChipClick }: Props) => {
10+
return (
11+
<div className="dropdown dropdown--hoverable">
12+
<button className="button button--info dropdown__toggle">
13+
Categories Filter
14+
</button>
15+
<ul className="dropdown__menu">
16+
{categories.map(chip => {
17+
return (
18+
<li key={chip.name} onClick={() => handleChipClick(chip.name)}>
19+
<div className="dropdown__item">
20+
<input
21+
type="checkbox"
22+
className="dropdown__checkbox"
23+
checked={chip.isSelected}
24+
onChange={() => handleChipClick(chip.name)}
25+
/>
26+
<span className="dropdown__label">{chip.name}</span>
27+
</div>
28+
</li>
29+
);
30+
})}
31+
</ul>
32+
</div>
33+
);
34+
};
35+
36+
export default PluginsFilter;
Lines changed: 128 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import Link from '@docusaurus/Link';
22
import Layout from '@theme/Layout';
33
import clsx from 'clsx';
4-
import React from 'react';
5-
4+
import React, { useState } from 'react';
65
import { IPluginData, PluginCard } from './_pluginCard';
76
import pluginsStyles from './plugins.module.scss';
7+
import { ChipCategory } from '@site/src/util/types';
88
import { truncateDescription } from '@site/src/util/truncateDescription';
9+
import PluginsFilter from '@site/src/components/pluginsFilter/pluginsFilter';
910

10-
//#region Plugin data import
1111
const pluginsContext = require.context(
1212
'../../../data/plugins',
1313
false,
@@ -29,50 +29,137 @@ const plugins = pluginsContext.keys().reduce(
2929

3030
plugins.corePlugins.sort((a, b) => a.order - b.order);
3131
plugins.otherPlugins.sort((a, b) => a.order - b.order);
32-
//#endregion
33-
34-
const Plugins = () => (
35-
<Layout>
36-
<div
37-
className={clsx('container', 'padding--lg', pluginsStyles.pluginsPage)}
38-
>
39-
<div className="marketplaceBanner">
40-
<div className="marketplaceContent">
41-
<h2>Plugin Marketplace</h2>
42-
43-
<p>
44-
Open source plugins that you can add to your Backstage deployment.
45-
Learn how to build a <Link to="/docs/plugins">plugin</Link>.
46-
</p>
47-
</div>
4832

49-
<Link
50-
to="/docs/plugins/add-to-marketplace"
51-
className="button button--outline button--primary"
52-
>
53-
Add to Marketplace
54-
</Link>
55-
</div>
33+
const Plugins = () => {
34+
const allCategoriesSet = new Set(
35+
[...plugins.corePlugins, ...plugins.otherPlugins].map(
36+
({ category }) => category,
37+
),
38+
);
39+
const allCategoriesArray = Array.from(allCategoriesSet).map(category => ({
40+
name: category,
41+
isSelected: false,
42+
}));
43+
const [categories, setCategories] =
44+
useState<ChipCategory[]>(allCategoriesArray);
45+
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
46+
const [showCoreFeatures, setShowCoreFeatures] = useState(true);
47+
const [showOtherPlugins, setShowOtherPlugins] = useState(true);
5648

57-
<div className="bulletLine margin-bottom--lg"></div>
49+
const handleChipClick = (categoryName: string) => {
50+
const isSelected =
51+
categories.find(category => category.name === categoryName)?.isSelected ||
52+
false;
5853

59-
<h2>Core Features</h2>
54+
const newSelectedCategories = isSelected
55+
? selectedCategories.filter(c => c !== categoryName)
56+
: [...selectedCategories, categoryName];
6057

61-
<div className="pluginsContainer margin-bottom--lg">
62-
{plugins.corePlugins.map(pluginData => (
63-
<PluginCard key={pluginData.title} {...pluginData}></PluginCard>
64-
))}
65-
</div>
58+
setSelectedCategories(newSelectedCategories);
59+
60+
const newCategories = categories.map(category => {
61+
if (category.name === categoryName) {
62+
return { ...category, isSelected: !isSelected };
63+
}
64+
return category;
65+
});
66+
67+
setCategories(newCategories);
68+
69+
if (!newSelectedCategories.includes('Core Feature')) {
70+
setShowCoreFeatures(false);
71+
} else {
72+
setShowCoreFeatures(true);
73+
}
74+
75+
if (
76+
newSelectedCategories.length === 1 &&
77+
newSelectedCategories[0] === 'Core Feature'
78+
) {
79+
setShowOtherPlugins(false);
80+
} else {
81+
setShowOtherPlugins(true);
82+
}
6683

67-
<h2>All Plugins</h2>
84+
if (newSelectedCategories.length === 0) {
85+
setShowOtherPlugins(true);
86+
setShowCoreFeatures(true);
87+
}
88+
};
6889

69-
<div className="pluginsContainer margin-bottom--lg">
70-
{plugins.otherPlugins.map(pluginData => (
71-
<PluginCard key={pluginData.title} {...pluginData}></PluginCard>
72-
))}
90+
return (
91+
<Layout>
92+
<div
93+
className={clsx('container', 'padding--lg', pluginsStyles.pluginsPage)}
94+
>
95+
<div className="marketplaceBanner">
96+
<div className="marketplaceContent">
97+
<h2>Plugin Marketplace</h2>
98+
99+
<p>
100+
Open source plugins that you can add to your Backstage deployment.
101+
Learn how to build a <Link to="/docs/plugins">plugin</Link>.
102+
</p>
103+
</div>
104+
105+
<Link
106+
to="/docs/plugins/add-to-marketplace"
107+
className="button button--outline button--primary"
108+
>
109+
Add to Marketplace
110+
</Link>
111+
</div>
112+
113+
<div className="bulletLine margin-bottom--lg"></div>
114+
<div className="pluginsFilterBox">
115+
<PluginsFilter
116+
categories={categories}
117+
handleChipClick={handleChipClick}
118+
/>
119+
</div>
120+
121+
{showCoreFeatures && (
122+
<div>
123+
<h2>Core Features</h2>
124+
<div className="pluginsContainer margin-bottom--lg">
125+
{plugins.corePlugins
126+
.filter(
127+
pluginData =>
128+
!selectedCategories.length ||
129+
selectedCategories.includes(pluginData.category),
130+
)
131+
.map(pluginData => (
132+
<PluginCard
133+
key={pluginData.title}
134+
{...pluginData}
135+
></PluginCard>
136+
))}
137+
</div>
138+
</div>
139+
)}
140+
141+
{showOtherPlugins && (
142+
<div>
143+
<h2>All Plugins</h2>
144+
<div className="pluginsContainer margin-bottom--lg">
145+
{plugins.otherPlugins
146+
.filter(
147+
pluginData =>
148+
!selectedCategories.length ||
149+
selectedCategories.includes(pluginData.category),
150+
)
151+
.map(pluginData => (
152+
<PluginCard
153+
key={pluginData.title}
154+
{...pluginData}
155+
></PluginCard>
156+
))}
157+
</div>
158+
</div>
159+
)}
73160
</div>
74-
</div>
75-
</Layout>
76-
);
161+
</Layout>
162+
);
163+
};
77164

78165
export default Plugins;

microsite/src/pages/plugins/plugins.module.scss

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,60 @@
2828
:global(.pluginsContainer) {
2929
gap: 1rem;
3030
display: grid;
31-
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
31+
grid-template-columns: repeat(auto-fit, minmax(250px, 300px));
32+
}
33+
34+
@media (max-width: 768px) {
35+
:global(.pluginsContainer) {
36+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
37+
}
38+
}
39+
40+
:global(.hidePluginsHeader) {
41+
display: none;
3242
}
3343

3444
:global(.fit-content) {
3545
width: fit-content;
3646
}
47+
48+
:global(.pluginsFilterBox) {
49+
width: 100%;
50+
margin-bottom: 1rem;
51+
height: 1rem;
52+
}
53+
54+
:global(.dropdown) {
55+
float: right;
56+
margin-bottom: 1rem;
57+
}
58+
59+
:global(.button--info) {
60+
background-color: transparent;
61+
border-color: var(--ifm-color-primary);
62+
color: var(--ifm-color-primary);
63+
min-width: 250px;
64+
}
65+
66+
:global(label.dropdown__item) {
67+
display: flex;
68+
align-items: center;
69+
cursor: pointer;
70+
margin-top: 5px;
71+
72+
&:hover {
73+
background-color: var(--ifm-color-primary);
74+
color: black;
75+
}
76+
}
77+
78+
:global(.dropdown__label) {
79+
font-size: 15px;
80+
cursor: pointer;
81+
}
82+
83+
:global(.dropdown__checkbox) {
84+
margin-right: 10px;
85+
cursor: pointer;
86+
}
3787
}

microsite/src/util/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type ChipCategory = {
2+
name: string;
3+
isSelected: boolean;
4+
};

0 commit comments

Comments
 (0)