diff --git a/src/sections/Meshery/Meshery-integrations/Individual-Integrations/Component.style.js b/src/sections/Meshery/Meshery-integrations/Individual-Integrations/Component.style.js index 100fadbc40c74e..ffec5bb134685c 100755 --- a/src/sections/Meshery/Meshery-integrations/Individual-Integrations/Component.style.js +++ b/src/sections/Meshery/Meshery-integrations/Individual-Integrations/Component.style.js @@ -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: grid; @@ -37,23 +28,43 @@ export const ComponentsWrapper = styled.div` } } + .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%; + min-height: 72px; } .items { - border-radius: 0.625rem; - text-transform: uppercase; + margin: 0; color: ${(props) => props.theme.text}; font-size: 0.875rem; - transition: all 0.1s ease-in-out; - line-height: 1.1875rem; + line-height: 1.25; + text-transform: uppercase; + word-break: break-word; width: 100%; + transition: all 0.1s ease-in-out; } `; diff --git a/src/sections/Meshery/Meshery-integrations/Individual-Integrations/ComponentsGrid.js b/src/sections/Meshery/Meshery-integrations/Individual-Integrations/ComponentsGrid.js index e1bf17205dbe86..e61afb4d120240 100644 --- a/src/sections/Meshery/Meshery-integrations/Individual-Integrations/ComponentsGrid.js +++ b/src/sections/Meshery/Meshery-integrations/Individual-Integrations/ComponentsGrid.js @@ -1,56 +1,150 @@ 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 || fallbackIcon || alternate || ""; +}; 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 { isDark } = useStyledDarkMode(); + const darkModeActive = Boolean(isDark); + const fallbackIcon = getFallbackIcon(frontmatter, darkModeActive); + + const candidateComponents = (frontmatter?.components || []).map( + (component) => ({ + ...component, + preferredIcon: getPreferredIcon(component, darkModeActive, fallbackIcon), + }), + ); + const [validComponents, setValidComponents] = useState([]); + 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; + + if (primaryIcon && (await checkImageUrlValidity(primaryIcon))) { + return { + ...item, + preferredIcon: primaryIcon, + }; + } - const validItems = await Promise.all(promises); - // Filter out null values (items that are not valid) - const filteredValidComponents = validItems.filter( - (item) => item !== null + // 1. Fallback to the theme-aware integration icon + if ( + fallbackIcon && + fallbackIcon !== primaryIcon && + (await checkFallback()) + ) { + return { + ...item, + preferredIcon: fallbackIcon, + }; + } + + // 2. Last resort: opposite-theme component icon + if ( + alternateIcon && + alternateIcon !== primaryIcon && + alternateIcon !== fallbackIcon && + (await checkImageUrlValidity(alternateIcon)) + ) { + return { + ...item, + preferredIcon: alternateIcon, + }; + } + + return null; + }), ); - setValidComponents(filteredValidComponents); + if (mounted) { + setValidComponents(validItems.filter(Boolean)); + } + }; + + loadIcons(); + return () => { + mounted = false; }; + }, [frontmatter, darkModeActive, fallbackIcon]); - fetchData(); - }, []); + const handleImageError = (nameToRemove) => { + setValidComponents((prev) => + prev.filter((item) => item.name !== nameToRemove), + ); + }; return (

- {frontmatter.title} Components ({components.length}) + {frontmatter?.title} Components ({validComponents.length})

{validComponents.map((item) => ( -
+
- {item.name} + {item.preferredIcon && ( + {item.name { + e.currentTarget.onerror = null; + handleImageError(item.name); + }} + /> + )}
-

{item.name.replaceAll("-", " ")}

- {/*
-
*/} +

{item.name?.replaceAll("-", " ") || ""}

))}
diff --git a/src/sections/Resources/Resources-error/emptyStateTemplate.js b/src/sections/Resources/Resources-error/emptyStateTemplate.js index 11788a911e877a..000e89a6c520e6 100644 --- a/src/sections/Resources/Resources-error/emptyStateTemplate.js +++ b/src/sections/Resources/Resources-error/emptyStateTemplate.js @@ -9,11 +9,11 @@ const NoResources = ({ errorMessage,errorSubtitle }) => {
- - + + service meshes - +

{errorMessage}

{errorSubtitle}

diff --git a/src/sections/Resources/Resources-grid/resourceGrid.style.js b/src/sections/Resources/Resources-grid/resourceGrid.style.js index 5ce57d05329451..25de50edbc8cfc 100644 --- a/src/sections/Resources/Resources-grid/resourceGrid.style.js +++ b/src/sections/Resources/Resources-grid/resourceGrid.style.js @@ -75,21 +75,12 @@ export const ResourcePageWrapper = styled.div` margin: 1rem; box-shadow: 0px 3px 10px 1px rgba(0, 179, 159, 0.5); - - .empty-state-row { - flex-wrap: wrap; - } - .errorMessage { font-size: 2rem; line-height: 2rem; - overflow-wrap: break-word; - word-break: break-word; } .error-text{ margin-top: 5rem; - overflow-wrap: break-word; - word-break: break-word; } .errorSubtitle { font-weight: 400; @@ -97,68 +88,15 @@ export const ResourcePageWrapper = styled.div` color: gray; font-style: italic; margin-top: 2.5rem; - overflow-wrap: break-word; - word-break: break-word; } img{ display: block; margin:auto; margin-top: 3.125rem; width: 14rem; - max-width: 100%; - height: auto; - object-fit: contain; - } - - @media only screen and (max-width: 992px) { - padding: 2rem 1.5rem 3rem; - text-align: center; - - .empty-state-row { - justify-content: center; - } - - img { - margin: 1rem auto 0; - width: 12rem; - max-width: 100%; - height: auto; - } - - .error-text { - margin-top: 1.5rem; - text-align: center; - } - - .errorMessage { - font-size: 1.5rem; - line-height: 1.3; - } - - .errorSubtitle { - font-size: 1.15rem; - line-height: 1.4; - margin-top: 1rem; - } - } - - @media only screen and (max-width: 575px) { - padding: 1.5rem 1rem 2.5rem; - margin: 0.5rem; - - img { - width: 9rem; - max-width: 100%; - } - - .errorMessage { - font-size: 1.25rem; - } - - .errorSubtitle { - font-size: 1rem; - margin-top: 0.75rem; + @media only screen and (max-width:700px){ + max-width: 100%; + } } } - } `; diff --git a/src/templates/integrations.js b/src/templates/integrations.js index e719aa3ecb84fd..34fcf5910ec69d 100644 --- a/src/templates/integrations.js +++ b/src/templates/integrations.js @@ -39,6 +39,10 @@ export const query = graphql` extension publicURL } + darkModeIntegrationIcon { + extension + publicURL + } docURL category components {