Skip to content

Commit b62d11c

Browse files
Improve responsive styling for integration category chips
- Invert chip styling: active chips now use light bg with border, inactive chips use dark filled bg (fixes #7593) - Replace react-slick slider with responsive flexbox/scroll layout - Add proper button elements with data-category attrs for robust filtering - Add ARIA attributes (role, aria-pressed, aria-label) for accessibility - Add focus-visible ring, reduced-motion support - Add mobile horizontal scroll with snap and overflow fade indicator - Add smooth hover/active transitions with Keppel theme colors - Touch-friendly sizing on mobile with no clipping or overflow issues - Full dark mode support using existing theme tokens Signed-off-by: shteypandey28-hue <shteypandey28@gmail.com>
1 parent 1c3fbfb commit b62d11c

2 files changed

Lines changed: 175 additions & 120 deletions

File tree

src/sections/Meshery/Meshery-integrations/Integration.style.js

Lines changed: 141 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import styled from "styled-components";
2-
import Slider from "react-slick";
32

43
export const HoneycombGrid = styled.div`
54
.heading {
@@ -33,26 +32,7 @@ export const HoneycombGrid = styled.div`
3332
justify-content: center;
3433
}
3534
36-
.items {
37-
background-color: #d2d8da; //#E7EFF3;
38-
padding: 0.625rem 1.5625rem;
39-
border-radius: 0.625rem;
40-
text-transform: uppercase;
41-
color: #1e2117;
42-
font-size: 0.875rem;
43-
cursor: pointer;
44-
transition: all 0.1s ease-in-out;
45-
46-
&:hover {
47-
opacity: 0.8;
48-
box-shadow: 0px 0px 6px -2px rgb(60, 73, 79);
49-
}
50-
}
5135
52-
.selected {
53-
background-color: ${(props) => props.theme.darkJungleGreenColor};
54-
color: ${(props) => props.theme.whiteToBlack};
55-
}
5636
5737
ul {
5838
margin: 2.5rem 0 0 0;
@@ -220,71 +200,162 @@ export const IntegrationCard = styled.div`
220200
// }
221201
`;
222202

223-
export const IntegrationSlider = styled(Slider)`
224-
.slick-prev:hover,
225-
.slick-next:hover {
226-
box-shadow: none;
227-
outline: none;
228-
}
203+
export const CategoryFilterBar = styled.div`
204+
position: relative;
205+
margin: 1.5rem 0 2rem;
206+
padding: 0 0.5rem;
229207
230-
.slick-arrow {
231-
width: 2rem;
232-
height: 3rem;
233-
}
208+
.category-chips-wrapper {
209+
display: flex;
210+
flex-wrap: wrap;
211+
justify-content: center;
212+
gap: 0.5rem;
213+
padding: 0.25rem 0;
214+
215+
@media screen and (max-width: 768px) {
216+
flex-wrap: nowrap;
217+
overflow-x: auto;
218+
justify-content: flex-start;
219+
scroll-behavior: smooth;
220+
-webkit-overflow-scrolling: touch;
221+
scroll-snap-type: x proximity;
222+
padding: 0.5rem 0.25rem;
223+
margin: 0 -0.5rem;
224+
padding-left: 0.5rem;
225+
padding-right: 0.5rem;
234226
235-
.slick-list {
236-
padding-top: 0.2rem;
227+
/* Hide scrollbar but keep functionality */
228+
scrollbar-width: none;
229+
-ms-overflow-style: none;
230+
&::-webkit-scrollbar {
231+
display: none;
232+
}
233+
}
237234
}
238235
239-
.slick-disabled {
236+
/* Overflow fade indicators for mobile scroll */
237+
&::after {
238+
content: "";
239+
position: absolute;
240+
top: 0;
241+
right: 0;
242+
bottom: 0;
243+
width: 2.5rem;
240244
pointer-events: none;
241-
opacity: 0.3;
242-
}
245+
opacity: 0;
246+
transition: opacity 0.3s ease;
243247
244-
.slick-arrow:before {
245-
color: ${(props) => props.theme.whiteToBlack};
246-
font-size: 4rem;
247-
display: inline-block;
248-
height: 1rem;
249-
-webkit-text-size-adjust: none;
250-
transition: 0.8s cubic-bezier(0.2, 0.8, 0.2, 1);
248+
@media screen and (max-width: 768px) {
249+
opacity: 1;
250+
background: linear-gradient(
251+
to right,
252+
transparent,
253+
${(props) =>
254+
props.theme.DarkTheme
255+
? "rgba(18,18,18,0.85)"
256+
: "rgba(255,255,255,0.85)"}
257+
);
258+
}
251259
}
252260
253-
.slick-arrow:hover:before {
254-
color: #00b39f;
255-
}
261+
.category-chip {
262+
/* ── Inactive (default) = dark / filled ── */
263+
display: inline-flex;
264+
align-items: center;
265+
gap: 0.375rem;
266+
padding: 0.5rem 1.125rem;
267+
border-radius: 2rem;
268+
font-size: 0.8125rem;
269+
font-weight: 600;
270+
letter-spacing: 0.025em;
271+
text-transform: uppercase;
272+
white-space: nowrap;
273+
cursor: pointer;
274+
user-select: none;
275+
border: 1.5px solid transparent;
276+
outline: none;
277+
scroll-snap-align: start;
256278
257-
.slick-slide {
258-
width: auto !important;
259-
margin: 0 0.5rem;
260-
}
279+
background: ${(props) =>
280+
props.theme.DarkTheme
281+
? "rgba(255,255,255,0.08)"
282+
: props.theme.darkJungleGreenColor};
283+
color: ${(props) =>
284+
props.theme.DarkTheme ? "rgba(255,255,255,0.7)" : "#ffffff"};
261285
262-
.slick-next {
263-
right: -2.5rem;
264-
}
286+
transition:
287+
background 0.25s ease,
288+
color 0.25s ease,
289+
border-color 0.25s ease,
290+
box-shadow 0.25s ease,
291+
transform 0.15s ease;
265292
266-
.slick-prev {
267-
left: -2.5rem;
268-
}
293+
&:hover {
294+
background: ${(props) =>
295+
props.theme.DarkTheme ? "rgba(255,255,255,0.14)" : "#2d3328"};
296+
transform: translateY(-1px);
297+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
298+
}
269299
270-
.slick-prev:before {
271-
content: "‹";
272-
line-height: 0;
273-
opacity: 1;
274-
}
300+
&:focus-visible {
301+
border-color: ${(props) => props.theme.keppelColor};
302+
box-shadow: 0 0 0 3px
303+
${(props) =>
304+
props.theme.DarkTheme
305+
? "rgba(0,211,169,0.35)"
306+
: "rgba(0,179,159,0.3)"};
307+
}
275308
276-
.slick-track {
277-
display: flex;
278-
}
309+
&:active {
310+
transform: scale(0.97);
311+
}
312+
313+
/* ── Active / Selected = light / outlined ── */
314+
&.selected {
315+
background: ${(props) =>
316+
props.theme.DarkTheme ? "rgba(0,211,169,0.15)" : "#f0fdfb"};
317+
color: ${(props) =>
318+
props.theme.DarkTheme
319+
? props.theme.keppelColor
320+
: props.theme.secondaryColor};
321+
border-color: ${(props) =>
322+
props.theme.DarkTheme
323+
? props.theme.keppelColor
324+
: props.theme.secondaryColor};
325+
font-weight: 700;
326+
327+
&:hover {
328+
background: ${(props) =>
329+
props.theme.DarkTheme ? "rgba(0,211,169,0.22)" : "#e0f9f5"};
330+
box-shadow: 0 2px 12px
331+
${(props) =>
332+
props.theme.DarkTheme
333+
? "rgba(0,211,169,0.2)"
334+
: "rgba(0,179,159,0.18)"};
335+
}
336+
}
279337
280-
.slick-next:before {
281-
content: "›";
282-
line-height: 0;
283-
opacity: 1;
338+
.chip-count {
339+
font-size: 0.6875rem;
340+
font-weight: 500;
341+
opacity: 0.7;
342+
margin-left: 0.125rem;
343+
}
344+
345+
/* Touch-friendly sizing on mobile */
346+
@media screen and (max-width: 768px) {
347+
padding: 0.5rem 1rem;
348+
font-size: 0.75rem;
349+
min-height: 2.25rem;
350+
}
284351
}
285352
286-
.slick-prev,
287-
.slick-next {
288-
top: 1.5rem;
353+
@media (prefers-reduced-motion: reduce) {
354+
.category-chip {
355+
transition: none;
356+
}
357+
.category-chips-wrapper {
358+
scroll-behavior: auto;
359+
}
289360
}
290361
`;

src/sections/Meshery/Meshery-integrations/IntegrationsGrid.js

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useEffect, useRef } from "react";
22
import { Link, useStaticQuery, graphql } from "gatsby";
3-
import { HoneycombGrid, IntegrationSlider } from "./Integration.style";
3+
import { HoneycombGrid, CategoryFilterBar } from "./Integration.style";
44
import useDataList from "../../../utils/usedataList";
55
import SearchBox from "../../../reusecore/Search";
66
import EmptyResources from "../../Resources/Resources-error/emptyStateTemplate";
@@ -38,36 +38,6 @@ const IntegrationsGrid = ({ category, count }) => {
3838
}
3939
`);
4040

41-
const settings = {
42-
initialSlide: 0,
43-
variableWidth: true,
44-
infinite: false,
45-
slidesToShow: 5.25,
46-
swipeToSlide: true,
47-
slidesToScroll: 1,
48-
// useTransform: false,
49-
50-
responsive: [
51-
{
52-
breakpoint: 900,
53-
settings: {
54-
initialSlide: 0,
55-
infinite: false,
56-
arrows: true,
57-
slidesToShow: 3,
58-
},
59-
},
60-
{
61-
breakpoint: 500,
62-
settings: {
63-
initialSlide: 0,
64-
arrows: true,
65-
infinite: false,
66-
slidesToShow: 1.5,
67-
},
68-
},
69-
],
70-
};
7141

7242
const [searchQuery, setSearchQuery] = useState("");
7343
const { queryResults, searchData } = useDataList(
@@ -162,10 +132,9 @@ const IntegrationsGrid = ({ category, count }) => {
162132
const setFilter = (event) => {
163133
let count = 0;
164134
let tempCategoryList = [...categoryNameList];
165-
let selectedCategory = event.target.innerHTML.includes("&amp;")
166-
? event.target.innerHTML.replace("&amp;", "&")
167-
: event.target.innerHTML;
168-
selectedCategory = selectedCategory.split("(")[0].trim();
135+
const btn = event.currentTarget;
136+
let selectedCategory =
137+
btn.getAttribute("data-category") || btn.textContent.split("(")[0].trim();
169138

170139
if (selectedCategory === "All") {
171140
tempCategoryList.forEach((item) => {
@@ -232,21 +201,36 @@ const IntegrationsGrid = ({ category, count }) => {
232201
focusSearch={false}
233202
/>
234203

235-
<section style={{ margin: "0 2.6rem" }}>
236-
<IntegrationSlider {...settings}>
237-
{!hideFilter &&
238-
categoryNameList.map((item) => {
239-
return (
240-
<p
241-
key={item.id}
242-
className={item.isSelected ? "items selected" : "items"}
243-
onClick={setFilter}
244-
>
245-
{`${item.name} (${item.count})`}
246-
</p>
247-
);
248-
})}
249-
</IntegrationSlider>
204+
<section>
205+
{!hideFilter && (
206+
<CategoryFilterBar>
207+
<div
208+
className="category-chips-wrapper"
209+
role="group"
210+
aria-label="Filter integrations by category"
211+
>
212+
{categoryNameList.map((item) => {
213+
return (
214+
<button
215+
key={item.id}
216+
type="button"
217+
className={
218+
item.isSelected
219+
? "category-chip selected"
220+
: "category-chip"
221+
}
222+
onClick={setFilter}
223+
data-category={item.name}
224+
aria-pressed={item.isSelected}
225+
>
226+
{item.name}
227+
<span className="chip-count">({item.count})</span>
228+
</button>
229+
);
230+
})}
231+
</div>
232+
</CategoryFilterBar>
233+
)}
250234
</section>
251235

252236
{searchQuery.length > 0 && queryResults.length < 1 ? (

0 commit comments

Comments
 (0)