Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
c4901bc
fix(integrations): support dark mode whiteIcon and standardize compon…
tejaswiverma121-byte Oct 1, 2026
66a1879
fix(integrations): circular icon badges, expand card size, and align …
tejaswiverma121-byte Oct 2, 2026
334737d
fix(integrations): improve icon fallback robustness, initial render, …
tejaswiverma121-byte Oct 2, 2026
f495264
Merge branch 'master' into fix/8146-integration-component-icons-dark-…
tejaswiverma121-byte Oct 2, 2026
9bd650d
fix(integrations): use unique key with index in component grid
tejaswiverma121-byte Oct 2, 2026
bead3ba
fix(integrations): make component icon fallback theme-aware
tejaswiverma121-byte Oct 2, 2026
f7ac96a
fix(integrations): try alternate component icon before integration fa…
tejaswiverma121-byte Oct 2, 2026
c79d1c6
fix(integrations): initialize component grid as empty until icons val…
tejaswiverma121-byte Oct 2, 2026
574af28
Merge branch 'master' into fix/8146-integration-component-icons-dark-…
tejaswiverma121-byte Oct 4, 2026
da49eaf
fix(integrations): prioritize integration fallback icon over alternat…
tejaswiverma121-byte Oct 8, 2026
f959735
Merge branch 'master' of https://github.com/layer5io/layer5 into fix/…
tejaswiverma121-byte Oct 13, 2026
b072c7f
fix(integrations): add onError safety net and use validComponents count
tejaswiverma121-byte Oct 15, 2026
db39b88
Merge branch 'master' into fix/8146-integration-component-icons-dark-…
tejaswiverma121-byte Oct 16, 2026
293fd50
fix(integrations): revert unrelated formatting, drop svg swap, and fi…
tejaswiverma121-byte Oct 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,6 @@ export const ComponentsWrapper = styled.div`
font-weight: normal;
}
}
.componentimg {
width: 80px;
height: 80px;
}
.componentimg img {
width: 100%;
height: 100%;
object-fit: contain;
}

.componentsSection {
display: flex;
Expand All @@ -29,24 +20,44 @@ export const ComponentsWrapper = styled.div`
padding: 3rem 2rem 5rem 2rem;
justify-content: center;
}

.componentimg {
width: 48px;
height: 48px;
min-width: 48px;
display: grid;
place-items: center;
border-radius: 50%;
background-color: ${(props) => props.theme.blackToWhite};
padding: 8px;
}

.componentimg img {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
}

.maincontainer {
display: flex;
align-items: center;
gap: 1rem;
background-color: ${(props) => props.theme.grey212121ToGreyEEEEEE};
padding: 0.5rem 1rem;
padding: 0.85rem 1.25rem;
border-radius: 0.85rem;
width: 100%;
flex: 30%;
max-width: 350px;
flex: 1 1 360px;
max-width: 400px;
min-height: 72px;
}

.items {
border-radius: 0.625rem;
text-transform: uppercase;
margin: 0;
color: ${(props) => props.theme.text};
font-size: 0.875rem;
transition: all .1s ease-in-out;
line-height: 1.1875rem;
width: 100%;
line-height: 1.25;
text-transform: uppercase;
word-break: break-word;
}
`;
Original file line number Diff line number Diff line change
@@ -1,56 +1,135 @@
import React, { useEffect, useState } from "react";
import { ComponentsWrapper } from "./Component.style";
import { checkImageUrlValidity } from "../../../../utils/imageValidate";
import { useStyledDarkMode } from "../../../../theme/app/useStyledDarkMode";

const getFallbackIcon = (frontmatter, isDarkActive) => {
if (isDarkActive) {
return (
frontmatter?.darkModeIntegrationIcon?.publicURL ||
frontmatter?.integrationIcon?.publicURL ||
frontmatter?.integrationIcon_svg?.publicURL ||
""
);
}

return (
frontmatter?.integrationIcon?.publicURL ||
frontmatter?.integrationIcon_svg?.publicURL ||
frontmatter?.darkModeIntegrationIcon?.publicURL ||
""
);
};

const getPreferredIcon = (component, isDarkActive, fallbackIcon) => {
const primary = isDarkActive
? component?.whiteIcon?.publicURL
: component?.colorIcon?.publicURL;
const alternate = isDarkActive
? component?.colorIcon?.publicURL
: component?.whiteIcon?.publicURL;

return primary || alternate || fallbackIcon || "";
};

const ComponentsGrid = ({ frontmatter }) => {
const components = frontmatter.components.map((component) => {
const { name, colorIcon } = component; // currently we don't have description for components
return { name, colorIcon };
});
const [validComponents, setValidComponents] = useState([]);
const { isDark } = useStyledDarkMode();
const darkModeActive = Boolean(isDark);
const fallbackIcon = getFallbackIcon(frontmatter, darkModeActive);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const candidateComponents = (frontmatter?.components || []).map(
(component) => ({
...component,
preferredIcon: getPreferredIcon(component, darkModeActive, fallbackIcon),
}),
);

const [validComponents, setValidComponents] = useState(candidateComponents);

useEffect(() => {
const fetchData = async () => {
const promises = components.map(async (item) => {
const isSvgPathValid = await checkImageUrlValidity(
item.colorIcon.publicURL
);
if (isSvgPathValid) {
return item;
} else {
item.colorIcon.publicURL = frontmatter.integrationIcon.publicURL;
return item; // Return fallback image
let mounted = true;

const loadIcons = async () => {
let isFallbackValid = null;
const checkFallback = async () => {
if (!fallbackIcon) return false;
if (isFallbackValid === null) {
isFallbackValid = await checkImageUrlValidity(fallbackIcon);
}
});
return isFallbackValid;
};

const validItems = await Promise.all(
candidateComponents.map(async (item) => {
const primaryIcon = darkModeActive
? item.whiteIcon?.publicURL
: item.colorIcon?.publicURL;
const alternateIcon = darkModeActive
? item.colorIcon?.publicURL
: item.whiteIcon?.publicURL;

const validItems = await Promise.all(promises);
// Filter out null values (items that are not valid)
const filteredValidComponents = validItems.filter(
(item) => item !== null
if (primaryIcon && (await checkImageUrlValidity(primaryIcon))) {
return {
...item,
preferredIcon: primaryIcon,
};
}

if (
alternateIcon &&
alternateIcon !== primaryIcon &&
(await checkImageUrlValidity(alternateIcon))
) {
return {
...item,
preferredIcon: alternateIcon,
};
}

if (
fallbackIcon &&
fallbackIcon !== primaryIcon &&
fallbackIcon !== alternateIcon &&
(await checkFallback())
) {
return {
...item,
preferredIcon: fallbackIcon,
};
}

return null;
}),
);

setValidComponents(filteredValidComponents);
if (mounted) {
setValidComponents(validItems.filter(Boolean));
}
};

fetchData();
}, []);
loadIcons();
return () => {
mounted = false;
};
}, [frontmatter, darkModeActive, fallbackIcon]);

return (
<ComponentsWrapper>
<section className="heading">
<h1>
{frontmatter.title} Components ({components.length})
{frontmatter?.title} Components ({candidateComponents.length})
</h1>
</section>

<section className="componentsSection">
{validComponents.map((item) => (
<div key={item.id} className="maincontainer">
{validComponents.map((item, index) => (
<div key={`${item.name}-${index}`} className="maincontainer">
<div className="componentimg">
<img src={item.colorIcon.publicURL} alt={item.name} />
{item.preferredIcon && (
<img src={item.preferredIcon} alt={item.name || ""} />
)}
</div>
<p className="items">{item.name.replaceAll("-", " ")}</p>
{/* <div className="textcontent">
</div> */}
<p className="items">{item.name?.replaceAll("-", " ") || ""}</p>
</div>
))}
</section>
Expand Down
46 changes: 26 additions & 20 deletions src/templates/integrations.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import React from "react";
import { graphql } from "gatsby";


import SEO from "../components/seo";

import IndividualIntegrations from "../sections/Meshery/Meshery-integrations/Individual-Integrations";

const LiteModeNotice = ({ entity }) => (
Expand All @@ -20,16 +17,15 @@ const LiteModeNotice = ({ entity }) => (
{`This ${entity} page is skipped when BUILD_FULL_SITE=false to keep local builds fast.`}
</p>
<p style={{ marginTop: "0.75rem" }}>
Run <code>make site-full</code> (or set <code>BUILD_FULL_SITE=true</code>) to render the full content.
Run <code>make site-full</code> (or set <code>BUILD_FULL_SITE=true</code>)
to render the full content.
</p>
</section>
);


export const query = graphql`
query IntegrationsBySlug($slug: String!, $name: String!) {
mdx(fields:{slug:{eq: $slug}}) {

mdx(fields: { slug: { eq: $slug } }) {
frontmatter {
title
subtitle
Expand All @@ -39,6 +35,10 @@ export const query = graphql`
extension
publicURL
}
darkModeIntegrationIcon {
extension
publicURL
}
docURL
category
components {
Expand All @@ -64,7 +64,11 @@ export const query = graphql`
}
}
screenshots_raster: allFile(
filter: {relativeDirectory: {eq: $name}, sourceInstanceName: {eq: "integrations"}, extension: {ne: "svg"}}
filter: {
relativeDirectory: { eq: $name }
sourceInstanceName: { eq: "integrations" }
extension: { ne: "svg" }
}
) {
nodes {
extension
Expand All @@ -75,7 +79,11 @@ export const query = graphql`
}
}
screenshots_svg: allFile(
filter: {relativeDirectory: {eq: $name}, sourceInstanceName: {eq: "integrations"}, extension: {eq: "svg"}}
filter: {
relativeDirectory: { eq: $name }
sourceInstanceName: { eq: "integrations" }
extension: { eq: "svg" }
}
) {
nodes {
extension
Expand All @@ -90,18 +98,10 @@ const Integrations = ({ data, children }) => {
return <LiteModeNotice entity="integration" />;
}


return (

<>


<IndividualIntegrations data={data}>
{children}
</IndividualIntegrations>

<IndividualIntegrations data={data}>{children}</IndividualIntegrations>
</>

);
};
export default Integrations;
Expand All @@ -117,5 +117,11 @@ export const Head = ({ data }) => {
);
}

return <SEO title={frontmatter.title} image={frontmatter.integrationIcon?.publicURL} description={frontmatter.subtitle}/>;
};
return (
<SEO
title={frontmatter.title}
image={frontmatter.integrationIcon?.publicURL}
description={frontmatter.subtitle}
/>
);
};